メインコンテンツに移動

モバイル実装ガイド

このガイドでは、CDKウィジェットをモバイルアプリケーションに統合するためのベストプラクティスについて説明します。Webでは、ウィジェットは通常iframeに埋め込まれますが、モバイルアプリではウィジェットURLを効果的に表示するために異なるアプローチが必要です。

概要

CDKウィジェットは、年齢ゲート、VPC、データ通知、権限管理を含む完全なコンプライアンスフローを含むAPI呼び出しから返されるURLです。これらのウィジェットをモバイルアプリケーションに統合する場合、表示するためのいくつかのオプションがあり、それぞれ異なる機能とトレードオフがあります。主な考慮事項は次のとおりです:

  • AgeKeysサポート: ユーザーが将来の確認のためにAgeKeys(FIDOベースのパスキー)を作成して使用できるかどうか
  • 結果の通信: ウィジェット結果がアプリにどのように配信されるか
  • ユーザーエクスペリエンス: 統合のレベルとネイティブ感

モバイル実装方法

Androidオプション

Androidは、ウィジェットURLを表示するための3つの主要な方法を提供します:

  • Chrome Custom Tabs推奨 - アプリのブランディングを維持するカスタマイズされたChromeブラウザタブでウィジェットURLを開きます。これにより、ユーザーをアプリのコンテキスト内に保ちながら、完全なブラウザ機能を提供します。Custom TabsはChromeとCookieと認証状態を共有し、シームレスなエクスペリエンスを可能にします。

  • WebView - AndroidのネイティブWebViewコンポーネントを使用して、アプリ内にWebコンテンツを直接埋め込みます。実装は簡単ですが、WebViewは最新のWeb標準へのサポートが限られており、特定のブラウザ機能にアクセスできません。

推奨されません

WebViewはAgeKeysに必要なWebAuthnをサポートしていません。WebViewを使用してウィジェットを埋め込む場合、ユーザーはAgeKeysを作成または使用できません。完全なAgeKeysサポートを備えた最適なユーザーエクスペリエンスを得るには、代わりにChrome Custom Tabsを使用してください。

  • Trusted Web Activity (TWA) - 主にProgressive Web Apps向けに設計されたフルスクリーンモードでWebコンテンツを表示します。TWAは、アプリとk-IDドメイン間でデジタルアセットリンクを確立する必要があります。デジタルアセットリンクが検出されない場合、TWAは自動的にChrome Custom Tabsにフォールバックします。
推奨されません

Trusted Web Activitiesはウィジェット統合ではサポートされていません。k-IDのドメインでデジタルアセットリンクを設定する必要がありますが、これは利用できません。この場合、TWAはChrome Custom Tabsにフォールバックするため、より簡単な実装のためにChrome Custom Tabsを直接使用することをお勧めします。

iOSオプション

iOSは、ウィジェットURLを表示するための3つの主要な方法を提供します:

  • ASWebAuthenticationSession推奨 - 安全な認証フロー専用に設計されたこの方法は、システム管理のブラウザビューでWebコンテンツを表示します。SafariとCookieを共有し、WebAuthnなどの最新のWeb機能へのアクセスを提供するため、確認フローに最適です。

  • SFSafariViewController - SafariとCookieと認証状態を共有するSafariライクなインターフェースでWebコンテンツを表示します。これにより、アプリのコンテキストを維持しながら、馴染みのあるブラウジングエクスペリエンスを提供します。

  • WKWebView - アプリ内にWebコンテンツを埋め込むAppleの最新のWebビューコンポーネントです。AndroidのWebViewと同様に、WKWebViewは特定のWeb標準に制限があり、すべてのブラウザ機能にアクセスできません。

推奨されません

WKWebViewはAgeKeysに必要なWebAuthnをサポートしていません。WKWebViewを使用してウィジェットを埋め込む場合、ユーザーはAgeKeysを作成または使用できません。完全なAgeKeysサポートを備えた最適なユーザーエクスペリエンスを得るには、代わりにASWebAuthenticationSessionを使用してください。

AgeKeysサポートの制限

AgeKeysは、FIDOおよびWebAuthn標準に基づく再利用可能な匿名の年齢証明資格情報です。ユーザーは一度年齢を確認し、個人情報を開示することなく、異なるサービス間でその確認を再利用できます。

AgeKeysの制限

AgeKeysにはWebAuthnサポートが必要ですが、これはAndroid WebViewまたはiOS WKWebViewでは利用できません。これらのコンポーネントを使用してウィジェットを埋め込む場合、ユーザーは確認中にAgeKeysをオプションとして表示されず、確認成功後にAgeKeysを作成できません。

ユーザーに対してAgeKeysを有効にするには、次のいずれかの方法を使用する必要があります:

ウィジェット結果の受信

モバイルアプリは、ユーザーがウィジェットフローを完了した後に結果を受信する必要があります。2つのアプローチがあり、それぞれ異なる可用性があります:

コールバックURL(ユニバーサル方法)

推奨アプローチ

すべての実装方法で推奨されるアプローチは、コールバックURLを使用することです。ウィジェットURLを生成するためにAPIを呼び出す際に、redirectUrlパラメータを含めます。ウィジェットフローが完了すると、ウィジェットは結果をクエリパラメータとして含めてこのURLにリダイレクトします。

コールバックURLの利点:

  • すべての実装方法で動作
  • DOMメッセージよりも信頼性が高い
  • モバイルアプリの標準的なディープリンクパターン
  • アプリがバックグラウンドに移動しても、結果は常に配信されます

コールバックURLの仕組み

  1. アプリにディープリンクハンドラーを登録します(例:myapp://vpc-complete
  2. APIを呼び出す際に、ディープリンクをredirectUrlとして含めます
  3. ウィジェットは完了後にディープリンクにリダイレクトします
  4. アプリがディープリンクを処理し、結果を抽出します
備考

リダイレクトは、ウィジェットURLがブラウザまたはWebビューで直接開かれた場合にのみ発生し、iframeに埋め込まれた場合は発生しません。

コールバックURLパラメータ

ウィジェットがコールバックURLにリダイレクトする際、ウィジェットタイプに関連するクエリパラメータが含まれます。例えば:

  • Age GateウィジェットにはverificationIdresultが含まれる場合があります
  • セッション関連のウィジェットにはsessionIdとステータス情報が含まれる場合があります

コールバックURLの例:

myapp://vpc-complete?sessionId=608616da-4fd2-4742-82bf-ec1d4ffd8187&result=PASS

コールバックURLの実装

CDKウィジェットAPIを呼び出す際に、リクエストにredirectUrlを含めます。URLは次のいずれかになります:

  • HTTPS URL: https://example.com/vpc-complete
  • カスタムディープリンク: myapp://vpc-complete
備考

すべてのCDKウィジェットエンドポイントがまだredirectUrlをサポートしているわけではありません。可用性については、特定のAPIエンドポイントのドキュメントを確認してください。redirectUrlが利用できない場合、WebViewまたはWKWebViewでDOMメッセージを使用してください。

DOMメッセージ(WebView/WKWebViewのみ)

Android WebViewまたはiOS WKWebViewを使用する場合、ウィジェットから送信されるJavaScriptメッセージをリッスンできます。これにより、以下が可能になります:

  • ウィジェット結果をリアルタイムで受信
  • Webビューを閉じるタイミングを制御
  • ウィジェットイベントに基づいてアプリのUIを更新

CDKウィジェットは、ウィジェットタイプに応じて異なるDOMイベントを発行します:

DOMメッセージは、ネイティブコードでインターセプトできるpostMessageイベントとして送信されます。利用可能なイベントの詳細については、DOMイベントの概要を参照してください。

限定的な可用性

DOMメッセージはWebViewとWKWebViewでのみ機能します。Chrome Custom TabsTrusted Web ActivityASWebAuthenticationSession、またはSFSafariViewControllerでは利用できません。

方法の比較

方法プラットフォームAgeKeysDOMメッセージコールバックURL最適な用途
WebViewAndroid推奨されません(AgeKeysサポートなし)
Chrome Custom TabsAndroidほとんどのユースケース(推奨)
Trusted Web ActivityAndroid推奨されません(デジタルアセットリンクが必要)
WKWebViewiOS推奨されません(AgeKeysサポートなし)
ASWebAuthenticationSessioniOSほとんどのユースケース(推奨)
SFSafariViewControlleriOSSafariライクなエクスペリエンス

推奨実装

Android: Chrome Custom Tabs

機能とユーザーエクスペリエンスの最適なバランスを得るために、コールバックURLと共にChrome Custom Tabsを使用します。

Chrome Custom Tabsを選ぶ理由:

  • WebAuthnによる完全なAgeKeysサポート
  • すべての最新Web機能へのアクセス
  • アプリブランディングによるシームレスなユーザーエクスペリエンス
  • 信頼性の高いコールバックメカニズム
  • Chromeと認証状態を共有

実装手順:

  1. コールバックURLのディープリンクハンドラーを登録します
  2. APIリクエストにredirectUrlを含めます(エンドポイントがサポートしている場合)
  3. Chrome Custom Tabsを使用してウィジェットURLを開きます
  4. ウィジェット結果でディープリンクコールバックを処理します

iOS: ASWebAuthenticationSession

安全でネイティブ感のあるコンプライアンスフローのために、コールバックURLと共にASWebAuthenticationSessionを使用します。

ASWebAuthenticationSessionを選ぶ理由:

  • WebAuthnによる完全なAgeKeysサポート
  • すべての最新Web機能へのアクセス
  • システム管理のセキュリティUI
  • SafariとCookieを共有
  • 信頼性の高いコールバックメカニズム

実装手順:

  1. コールバックURLのURLスキームハンドラーを登録します
  2. APIリクエストにredirectUrlを含めます(エンドポイントがサポートしている場合)
  3. ASWebAuthenticationSessionを使用してウィジェットURLを表示します
  4. ウィジェット結果でURLスキームコールバックを処理します

完全な実装例

推奨アプローチを実装するためのステップバイステップの例と完全なコードサンプルを以下に示します:

ステップ1: ディープリンクハンドラーの登録

Info.plistにURLスキームを登録します:

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>

ステップ2: コールバック付きウィジェットURLの生成

import Foundation

func generateWidgetUrl(completion: @escaping (URL?) -> Void) {
guard let url = URL(string: "https://game-api.k-id.com/api/v1/widget/generate-e2e-url") else {
completion(nil)
return
}
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer YOUR_API_KEY", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")

let requestBody: [String: Any] = [
"jurisdiction": "US-CA",
"options": [
"redirectUrl": "myapp://vpc-complete"
]
]

guard let httpBody = try? JSONSerialization.data(withJSONObject: requestBody) else {
completion(nil)
return
}
request.httpBody = httpBody

URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
completion(nil)
return
}

guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode),
let data = data,
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let widgetUrlString = json["url"] as? String,
let widgetUrl = URL(string: widgetUrlString) else {
completion(nil)
return
}
completion(widgetUrl)
}.resume()
}

ステップ3: ウィジェットの表示

import AuthenticationServices

// セッションをプロパティとして保存して、解放を防ぐ
var authSession: ASWebAuthenticationSession?

func displayWidget(widgetUrl: URL) {
authSession = ASWebAuthenticationSession(
url: widgetUrl,
callbackURLScheme: "myapp"
) { callbackURL, error in
if let error = error {
// エラーを処理(ユーザーがキャンセルした場合など)
return
}
if let callbackURL = callbackURL {
handleWidgetCallback(callbackURL)
}
}
authSession?.presentationContextProvider = self
authSession?.start()
}

ステップ4: コールバックの処理

func handleWidgetCallback(_ callbackURL: URL) {
guard let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems else {
return
}

let sessionId = queryItems.first(where: { $0.name == "sessionId" })?.value
let verificationId = queryItems.first(where: { $0.name == "verificationId" })?.value
let result = queryItems.first(where: { $0.name == "result" })?.value

// ウィジェット結果に基づいてUIを更新
if result == "PASS" {
// 成功したフローを処理
} else if result == "FAIL" {
// 失敗したフローを処理
}

// オプション:CDK APIエンドポイントを使用してサーバー側で確認
if let sessionId = sessionId {
verifyResultServerSide(sessionId: sessionId)
}
}

CDKウィジェットタイプ

CDKは、特定のコンプライアンスワークフロー向けに設計されたいくつかのウィジェットタイプを提供します:

各ウィジェットタイプとその特定のユースケースの詳細については、CDKドキュメントのガイドを参照してください。