Integración en apps móviles
Caputchin corre dentro de una app nativa a través de una página de incrustación alojada. Apuntas un WebView a esa página, el visitante supera el reto dentro de ella, y la página puentea el token resultante (y cualquier error) de vuelta a tu código nativo. La verificación en sí es idéntica a la web; solo difiere el shell anfitrión.
1. Abre la página de incrustación
Apunta un WebView a https://caputchin.com/embed con al menos una clave de sitio:
https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memoryOmite los parámetros de juego para la checkbox simple. Una lista games=a,b elige uno al azar por sesión.
Parámetros de query
| Parámetro | Obligatorio | Efecto |
|---|---|---|
sitekey | sí | Tu clave pública (cpt_pub_...). Si falta, renderiza un shell de error sin widget. |
game | no | Un id de juego del marketplace (owner/repo, o owner/repo/leaf). |
games | no | Una lista separada por comas; uno se elige al azar por sesión. |
game-src | no | URL de tu propio bundle de juego alojado, para un juego autoalojado. |
layout | no | inline, modal, fullscreen o auto. Por defecto inline en la incrustación. |
locale / skin / config | no | Se reenvían al widget para elegir idioma, skin o configuración. |
no-verify | no | Corre el juego sin gate de verificación (solo juego, sin token). |
postMessageTarget | no | Solo para incrustadores en iframe de navegador (ver abajo). Se ignora en un WebView nativo. |
Omite los tres game / games / game-src para la checkbox simple. No hay un parámetro mode; el widget conduce el disparador por sí mismo.
2. Puentea el token a tu código
Cuando el visitante pasa, la página de incrustación empuja el token por el canal que corresponde a tu anfitrión. Registra el handler que corresponda.
iOS (WKWebView, Swift)
El token llega como una cadena en bruto en un message handler llamado caputchin:
class TokenHandler: NSObject, WKScriptMessageHandler {
func userContentController(_ controller: WKUserContentController,
didReceive message: WKScriptMessage) {
guard let token = message.body as? String else { return }
// send `token` to your backend
}
}
let config = WKWebViewConfiguration()
config.userContentController.add(TokenHandler(), name: "caputchin")
let webView = WKWebView(frame: .zero, configuration: config)
webView.load(URLRequest(url: URL(string: "https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory")!))Android (WebView, Kotlin)
El token llega como una cadena en bruto en un @JavascriptInterface llamado caputchin:
class TokenBridge {
@JavascriptInterface
fun onToken(token: String) {
// send `token` to your backend
}
}
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(TokenBridge(), "caputchin")
webView.loadUrl("https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory")React Native (react-native-webview)
La incrustación postea una cadena JSON por el único canal de React Native. Parséala y ramifica según type:
<WebView
source={{ uri: "https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory" }}
onMessage={(e) => {
const msg = JSON.parse(e.nativeEvent.data);
if (msg.type === "caputchin-token") {
// send msg.token to your backend
} else if (msg.type === "caputchin-error") {
// msg.code, msg.message, msg.originalCode (optional)
}
}}
/>Iframe de navegador (postMessage)
Si incrustas la página en un <iframe> de navegador en lugar de un WebView nativo, el relay al padre está desactivado por defecto y se dispara solo cuando lo activas con un origin objetivo exacto vía ?postMessageTarget=<origin> (por ejemplo postMessageTarget=https://app.example.com). Un comodín (*), una ruta, o cualquier cosa que no parsee a un esquema, host y puerto a secas se rechaza, así que el token de un solo uso, ligado al sitio, nunca se difunde a un padre no verificado. Escucha en el padre y comprueba event.origin antes de fiarte del mensaje:
window.addEventListener("message", (event) => {
if (event.origin !== "https://embed-host.example.com") return;
const msg = event.data;
if (msg.type === "caputchin-token") {
// msg.token
} else if (msg.type === "caputchin-error") {
// msg.code, msg.message
}
});3. Verifica en tu backend
Esto es igual que en la web: haz POST del token a /siteverify con tu secreto. Mira Integración del lado del servidor.
Recibir errores (opcional)
Cada vez que el widget topa con un error, la página de incrustación lo refleja por un conjunto paralelo de canales: el message handler caputchinError de iOS, la interfaz caputchinError de Android (onError(json)), el canal de React Native como { type: "caputchin-error", ... }, y el mismo relay de iframe con gate. El payload lleva { code, message, originalCode? }. iOS y Android lo reciben como una cadena JSON; React Native y el relay de iframe reciben el sobre tipado.
Esto es del todo opcional. Una app que no registra ningún handler de error simplemente no recibe errores, y la página de incrustación ya muestra una UI de reintento dentro del WebView de todos modos.
Véase también
- Integración del lado del servidor para la comprobación del token.
- Integración del lado del cliente para el equivalente web.