Integración de compras in-app: de sitio web a app Flutter
Esta guía explica cómo preparar compras in-app nativas en una app Wrapply: productos de tienda, product IDs, llamadas de compra, restauración y validación de recibos en backend.
Comandos bridge para compras in-app
Cuando activas el módulo de compras in-app, la app generada expone comandos JavaScript reales dentro de la WebView. Tu sitio los llama y tu backend debe verificar la compra antes de desbloquear la función de pago.
| Comando | Uso | Payload | Respuesta típica |
|---|---|---|---|
window.Wrapply.iap.getProducts(payload) | Lee los productos configurados en Google Play o App Store | { productIds: ['premium_monthly'] } | { ok, available, products, notFoundIds } |
window.Wrapply.iap.purchase(payload) | Inicia el flujo de compra nativo | { productId, consumable, applicationUserName } | { ok, purchaseStarted, product } |
window.Wrapply.iap.restorePurchases(payload) | Restaura compras no consumibles o suscripciones | { applicationUserName } | { ok, restoreStarted, latestPurchases } |
window.Wrapply.iap.getStatus(payload) | Comprueba si el billing de la tienda está disponible y lee los últimos eventos | {} | { ok, available, latestPurchases } |
Configuración necesaria en las tiendas
Crea los productos en Google Play Console y App Store Connect con los mismos product IDs usados por el sitio. Prueba en dispositivos reales y valida recibos en el backend antes de desbloquear suscripciones, créditos o contenido premium.
if (window.Wrapply?.__nativeBridgeReady) return callback(window.Wrapply);
window.addEventListener('wrapplyNativeBridgeReady', () => callback(window.Wrapply), { once: true });
}
onWrapplyReady(async (Wrapply) => {
if (!Wrapply.iap) return;
const products = await Wrapply.iap.getProducts({ productIds: ['premium_monthly', 'credits_10'] });
console.log(products);
});
if (!window.Wrapply?.iap) return showWebCheckoutFallback();
const result = await window.Wrapply.iap.purchase({
productId: 'premium_monthly',
consumable: false,
applicationUserName: currentUser.id
});
await fetch('/api/iap/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(result)
});
}
if (!window.Wrapply?.iap) return;
const restored = await window.Wrapply.iap.restorePurchases({
applicationUserName: currentUser.id
});
await fetch('/api/iap/restore', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(restored)
});
}
Ejemplos de integración
Puedes usar el mismo patrón bridge en JavaScript, React, Vue, Angular, PHP/Laravel, WordPress o jQuery. Lo importante es esperar el bridge nativo antes de llamarlo.
JavaScript
if (!window.Wrapply?.iap) return;
const result = await window.Wrapply.iap.purchase({
productId: 'premium_monthly',
consumable: false,
applicationUserName: currentUser.id
});
await fetch('/api/wrapply-event', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(result)
});
}
Hook React
export function useWrapplyBridge() {
const [ready, setReady] = useState(false);
useEffect(() => {
if (window.Wrapply?.__nativeBridgeReady) return setReady(true);
const onReady = () => setReady(true);
window.addEventListener('wrapplyNativeBridgeReady', onReady);
return () => window.removeEventListener('wrapplyNativeBridgeReady', onReady);
}, []);
return { ready, Wrapply: ready ? window.Wrapply : null };
}
Composable Vue
export function useWrapplyBridge() {
const ready = ref(false);
onMounted(() => {
if (window.Wrapply?.__nativeBridgeReady) ready.value = true;
else window.addEventListener('wrapplyNativeBridgeReady', () => ready.value = true, { once: true });
});
return { ready };
}
Servicio Angular
export class WrapplyBridgeService {
async callNative(payload = {}) {
if (!window.Wrapply?.iap) return { ok: false, error: 'Bridge unavailable' };
return window.Wrapply.iap.getStatus(payload);
}
}
jQuery
if (!window.Wrapply?.iap) return;
const result = await window.Wrapply.iap.getStatus({});
$('#wrapply-output').text(JSON.stringify(result, null, 2));
});
CMS / plantilla backend
<script>
window.addEventListener('wrapplyNativeBridgeReady', function () {
document.body.classList.add('wrapply-native-app');
});
</script>