WebView bridge
A web page inside a native shell cannot reach StoreKit or Play Billing. The bridge lets the page call getProducts, purchase, restore, getCustomer and ads.showRewarded through postMessage. The native side runs them with the SDK and posts the result back.
Native side
Section titled “Native side”import { useMemo, useRef } from "react";import { WebView } from "react-native-webview";import { Kasskeep, KASSKEEP_WEBVIEW_INJECTED_JS, createKasskeepWebViewBridge } from "@kasskeep/react-native";
export function GameScreen() { const ref = useRef<WebView>(null); const bridge = useMemo( () => createKasskeepWebViewBridge({ webViewRef: ref, allowedOrigins: ["https://game.example.com"], methods: ["getProducts", "purchase", "restore", "getCustomer", "setAppUserId"], onAppUserId: (id) => { if (Kasskeep.appUserId) Kasskeep.setAppUserId(id); else Kasskeep.configure({ apiKey: "pk_...", baseUrl: "https://api.kasskeep.com", appUserId: id }); }, }), [], ); return ( <WebView ref={ref} source={{ uri: "https://game.example.com/" }} originWhitelist={["https://game.example.com"]} injectedJavaScriptBeforeContentLoaded={KASSKEEP_WEBVIEW_INJECTED_JS} onMessage={(e) => { if (bridge.onMessage(e)) return; }} /> );}createKasskeepWebViewBridge(options) returns { onMessage(event): boolean, dispose() }. onMessage returns false for messages that are not bridge messages, so the shell can handle its own.
| Option | Meaning |
|---|---|
webViewRef |
Ref to the WebView |
allowedOrigins |
Required. Exact scheme://host[:port] origins. Messages from other origins are dropped without an answer |
methods |
Allow-list. Default getProducts, purchase, restore, getCustomer, ads.showRewarded. setAppUserId only when listed |
onAppUserId(id) |
Called for setAppUserId, typically to call Kasskeep.configure after the page logs in |
onRejected(r) |
Called with { reason: "origin" | "version" | "method" | "malformed", origin, method? } |
Protocol
Section titled “Protocol”Version 1. The page posts:
{"tag": "kasskeep", "v": 1, "id": "<request id>", "method": "purchase", "params": {}}The native side answers by calling window.__kasskeepBridgeReceive with {"tag": "kasskeep", "v": 1, "id": "<same id>", "ok": true, "result": ...} or {"ok": false, "error": {"code", "message", "retryable?", "status?"}}. The answer is delivered only while location.origin is still the origin of the request. Results are JSON-escaped so they cannot break out of the injected script.
On the page side use kasskeep-web.js, which implements this protocol.