---
type: how-to
title: モバイルアプリの連携
summary: iOS、Android、React Native、またはブラウザ iframe の WebView にウィジェットを埋め込み、検証済みトークンをあなたのコードへ橋渡しします。
---

Caputchin は、ホスト型の埋め込みページを通じてネイティブアプリの中で動きます。WebView をそのページに向けると、訪問者がその中でチャレンジをクリアし、ページが結果のトークン（とエラーがあればそれも）をあなたのネイティブコードへ橋渡しします。検証そのものはウェブと同一で、違うのはホストのシェルだけです。

## 1. 埋め込みページを開く

WebView を `https://caputchin.com/embed` に、少なくともサイトキーを付けて向けます：

```
https://caputchin.com/embed?sitekey=cpt_pub_...&game=caputchin/games/leaf-memory
```

素のチェックボックスにする場合はゲームのパラメータを省きます。`games=a,b` リストはセッションごとに 1 つをランダムで選びます。

<Callout type="warn">
サイトキーでゲームゲートがオン（その **検証にゲームを必須にする** 設定）になっていると、素のチェックボックスは通れません。埋め込みはゲートされたキーでゲームを動かさなければなりません。`game`（または `games`）パラメータを渡してください。ゲームのパラメータがない素のチェックボックス埋め込みは、そこで `gate-unavailable` エラーを出します。これは設計どおりで、ゲートが Caputchin 側で強制されるからです。[ゲームゲート](/docs/site-keys/games) を参照してください。
</Callout>

### クエリパラメータ

| パラメータ | 必須 | 効果 |
|---|---|---|
| `sitekey` | はい | あなたの公開鍵（`cpt_pub_...`）。欠けると、ウィジェットのないエラーシェルがレンダリングされます。 |
| `game` | いいえ | 単一のマーケットプレイスのゲーム id（`owner/repo`、または `owner/repo/leaf`）。 |
| `games` | いいえ | カンマ区切りのリスト。セッションごとに 1 つがランダムで選ばれます。 |
| `game-src` | いいえ | セルフホストのゲーム用の、あなた自身のホスト型ゲームバンドルの URL。 |
| `layout` | いいえ | `inline`、`modal`、`fullscreen`、または `auto`。埋め込みでは `inline` が既定です。 |
| `overlay-width` / `overlay-height` | いいえ | `modal` / `fullscreen` で、ゲームのダイアログのサイズを決めます。`full`、ピクセル数、または `auto`（ゲーム自身の好みのサイズ）。[サイズとレイアウト](/docs/references/widget-sizing) を参照。 |
| `locale` / `skin` / `config` | いいえ | 言語、スキン、設定を選ぶためにウィジェットへ転送されます。 |
| `no-verify` | いいえ | 検証ゲートなしでゲームを実行します（ゲームのみ、トークンなし）。 |
| `postMessageTarget` | いいえ | ブラウザ iframe 埋め込み側のみ（下記参照）。ネイティブ WebView では無視されます。 |

素のチェックボックスにする場合は `game` / `games` / `game-src` の 3 つすべてを省きます。`mode` パラメータはありません。ウィジェット自身がトリガーを駆動します。

## 2. トークンをあなたのコードへ橋渡しする

訪問者が通ると、埋め込みページはあなたのホストに合うチャネルを通じてトークンを押し出します。合致するハンドラーを登録してください。

### iOS（WKWebView、Swift）

トークンは `caputchin` という名前のメッセージハンドラーに、生の文字列として届きます：

```swift
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）

トークンは `caputchin` という名前の `@JavascriptInterface` に、生の文字列として届きます：

```kotlin
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）

埋め込みは、単一の React Native チャネルで JSON 文字列をポストします。それをパースして `type` で分岐します：

```jsx
<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（postMessage）

ページをネイティブ WebView ではなくブラウザの `<iframe>` に埋め込む場合、親への中継は **既定でオフ** で、`?postMessageTarget=<origin>` で正確なターゲットオリジンを指定してオプトインしたときだけ発火します（たとえば `postMessageTarget=https://app.example.com`）。ワイルドカード（`*`）、パス、あるいは素のスキーム・ホスト・ポートにパースされない何かは拒否されるので、一度きりでサイトに紐づいたトークンが、検証されていない親へ決して送出されません。親で待ち受け、メッセージを信頼する前に `event.origin` を確認してください：

```js
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. バックエンドで検証する

これはウェブと同じです。トークンをシークレットとともに `/siteverify` へ POST します。[サーバー側の連携](/docs/integration-guides/verify-on-your-backend) を参照してください。

## エラーを受け取る（任意）

ウィジェットがエラーに当たるたび、埋め込みページは並行するチャネル群を通じてそれをミラーします：iOS の `caputchinError` メッセージハンドラー、Android の `caputchinError` インターフェース（`onError(json)`）、React Native チャネルでの `{ type: "caputchin-error", ... }`、そして同じゲートされた iframe 中継。ペイロードは `{ code, message, originalCode? }` を運びます。iOS と Android はそれを JSON 文字列として受け取り、React Native と iframe 中継は型付きのエンベロープを受け取ります。

これは完全に任意です。エラーハンドラーを登録しないアプリは、単にエラーを受け取らないだけで、埋め込みページはいずれにせよ WebView の中ですでに再試行 UI を表示します。

## あわせて読む

- トークンの確認については [サーバー側の連携](/docs/integration-guides/verify-on-your-backend)。
- ウェブ版については [クライアント側の連携](/docs/integration-guides/cdn)。
