# IOS - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: ja Generated on: 2026-07-01T16:29:19.420Z Total files: 44 --- # File: sdk-installation-ios --- --- title: "iOS SDKのインストールと設定" description: "サブスクリプションアプリ向けに、iOS で Adapty SDK をインストールするステップバイステップガイド。" --- Adapty SDK には、モバイルアプリにシームレスに統合するための 2 つの主要モジュールが含まれています。 - **Core Adapty**: アプリで Adapty を正しく動作させるために必要な必須 SDK です。 - **AdaptyUI**: ノーコードでクロスプラットフォームのペイウォールを簡単に作成できるツール [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なオプションモジュールです。 :::tip 実際のモバイルアプリへの Adapty SDK 統合例を見たい方は、[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)をご覧ください。ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップが確認できます。 ::: 実装の詳細なウォークスルーは、以下の動画でも確認できます。
## 必要要件 \{#requirements\} Adapty iOS SDK は iOS 15.0 以降が必要です。 :::important Xcode 26.4 以降でビルドする場合は、Adapty SDK 3.15.7 以上が必要です。 ::: --- no_index: true --- import Callout from '../../../components/Callout.astro'; SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ## Adapty SDK のインストール \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-iOS.svg?style=flat&logo=apple)](https://github.com/adaptyteam/AdaptySDK-iOS/releases) Adapty SDK は Swift Package Manager でインストールします。Xcode で **File** -> **Add Package Dependency...** を選択してください。パッケージ依存関係の追加手順は Xcode のバージョンによって異なる場合があるため、必要に応じて Xcode のドキュメントを参照してください。 1. リポジトリ URL を入力します。 ``` https://github.com/adaptyteam/AdaptySDK-iOS.git ``` 2. バージョンを選択し(最新の安定版を推奨)、**Add Package** をクリックします。 3. **Choose Package Products** ウィンドウで、必要なモジュールを選択します。 - **Adapty**(コアモジュール) - **AdaptyUI**(オプション - ペイウォールビルダーを使用する場合のみ) :::note 注意: - [キッズモード](kids-mode)を有効にするには、**Adapty** の代わりに **Adapty_KidsMode** を選択してください。 - リストに表示される他のパッケージは選択しないでください。それらは不要です。 ::: 4. **Add Package** をクリックしてインストールを完了します。 5. **インストールの確認:** プロジェクトナビゲーターの **Package Dependencies** 以下に「Adapty」(および選択した場合は「AdaptyUI」)が表示されていることを確認してください。 :::important Adapty iOS SDK 4.0 はプレリリース版です。Swift Package Manager は **Up to Next Major Version**(`from:`)ルールではベータ版を解決しないため、正確なバージョンを固定する必要があります。Xcode では **Dependency Rule** を **Exact Version** に設定し、`4.0.0-beta.1` と入力してください。`Package.swift` では `.exact("4.0.0-beta.1")` を使用します。詳しくは [Adapty iOS SDK を v4 へ移行する](migration-to-ios-sdk-v4)をご覧ください。 ::: ## Adapty SDK の Adapty モジュールを有効化する \{#activate-adapty-module-of-adapty-sdk\} アプリのコードで Adapty SDK を有効化します。 :::note Adapty SDK の有効化はアプリ内で 1 度だけ行えば十分です。 ::: **Public SDK Key** を取得するには: 1. Adapty ダッシュボードを開き、[**App settings → General**](https://app.adapty.io/settings/general) に移動します。 2. **Api keys** セクションで、**Public SDK Key**(Secret Key ではない)をコピーします。 3. コード内の `"YOUR_PUBLIC_SDK_KEY"` を置き換えます。 または、[Adapty CLI](developer-cli) を使ってプログラムから取得することもできます: ``` npm install -g adapty adapty auth login adapty apps list ``` あるいは、直接実行する場合: ``` npx adapty auth login adapty apps list ``` - Adapty の初期化には必ず **Public SDK key** を使用してください。**Secret key** は[サーバーサイド API](getting-started-with-server-side-api) 専用です。 - **SDK keys** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 ```swift showLineNumbers @main struct YourApp: App { init() { // Configure Adapty SDK let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard Adapty.logLevel = .verbose // recommended for development and the first production release let config = configurationBuilder.build() // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } var body: some Scene { WindowGroup { // Your content view } } } } ``` ```swift showLineNumbers // In your AppDelegate class: // If you only use an AppDelegate, place the following code in the // application(_:didFinishLaunchingWithOptions:) method. // If you use a SceneDelegate, place the following code in the // scene(_:willConnectTo:options:) method. Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(logLevel: .verbose) // recommended for development and the first production release let config = configurationBuilder.build() try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` :::important 他の Adapty SDK メソッドを呼び出す前に、`activate` の完了を待ってください。完全な呼び出し順序については [iOS SDK の呼び出し順序](ios-sdk-call-order)をご覧ください。 ::: 次に、アプリでペイウォールを設定します。 - [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、まず下記の [AdaptyUI モジュールを有効化する](#activate-adaptyui-module-of-adapty-sdk)を行い、その後[ペイウォールビルダーのクイックスタート](ios-quickstart-paywalls)に従ってください。 - 独自のペイウォール UI を構築する場合は、[カスタムペイウォールのクイックスタート](ios-quickstart-manual)をご覧ください。 ## Adapty SDK の AdaptyUI モジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する予定があり、[AdaptyUI モジュールをインストール済み](sdk-installation-ios#install-adapty-sdk)の場合は、AdaptyUI も有効化する必要があります。 :::important コード内では、AdaptyUI を有効化する前に必ずコアの Adapty モジュールを有効化してください。 ::: ```swift showLineNumbers title="Swift" @main struct YourApp: App { init() { // ...ConfigurationBuilder steps // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: config) try await AdaptyUI.activate() } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } // main body... } } ``` ```swift showLineNumbers title="UIKit" // If you only use an AppDelegate, place the following code in the // application(_:didFinishLaunchingWithOptions:) method. // If you use a SceneDelegate, place the following code in the // scene(_:willConnectTo:options:) method. Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(logLevel: .verbose) // recommended for development let config = configurationBuilder.build() try await Adapty.activate(with: config) try await AdaptyUI.activate() } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` :::tip AdaptyUI を有効化する際に、オプションとして[ペイウォールのデフォルトキャッシュ設定を上書き](#set-up-media-cache-configuration-for-adaptyui)することができます。 ::: ## オプション設定 \{#optional-setup\} ### ログ \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty は、何が起きているかを把握できるように、エラーや重要な情報をログに記録します。利用可能なレベルは以下のとおりです。 | レベル | 説明 | | ---------- | ------------------------------------------------------------ | | `error` | エラーのみをログに記録します | | `warn` | エラーと、重大なエラーではないが注意が必要な SDK からのメッセージをログに記録します | | `info` | エラー、警告、および各種情報メッセージをログに記録します | | `verbose` | 関数呼び出し、API クエリなど、デバッグ時に役立つ追加情報をすべてログに記録します | ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(logLevel: .verbose) // recommended for development ``` #### ログシステムのメッセージをリダイレクトする \{#redirect-the-logging-system-messages\} Adapty のログメッセージを独自のシステムに送信したり、ファイルに保存したりする必要がある場合は、`setLogHandler` メソッドを使用して、その中にカスタムのログロジックを実装してください。このハンドラーは、メッセージ内容と重大度レベルを含むログレコードを受け取ります。 ```swift showLineNumbers title="Swift" Adapty.setLogHandler { record in writeToLocalFile("Adapty \(record.level): \(record.message)") } ``` ### データポリシー \{#data-policies\} Adapty は、明示的に送信しない限りユーザーの個人データを保存しませんが、ストアや各国のガイドラインに準拠するために、追加のデータセキュリティポリシーを実装することができます。 #### IDFA の収集と共有を無効にする \{#disable-idfa-collection-and-sharing\} Adapty モジュールを有効化する際に、`idfaCollectionDisabled` を `true` に設定すると、IDFA の収集と共有を無効にできます。 このパラメーターは、App Store レビューガイドラインに準拠する場合や、アプリで IDFA が不要なときに App Tracking Transparency のプロンプトが表示されるのを避けるために使用してください。デフォルト値は `false` です。IDFA 収集の詳細については、[アナリティクス連携](analytics-integration#disable-collection-of-advertising-identifiers)セクションを参照してください。 ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(idfaCollectionDisabled: true) ``` #### IP の収集と共有を無効にする \{#disable-ip-collection-and-sharing\} Adapty モジュールを有効化する際に、`ipAddressCollectionDisabled` を `true` に設定すると、ユーザーの IP アドレスの収集と共有を無効にできます。デフォルト値は `false` です。 このパラメーターは、ユーザーのプライバシーを強化する場合、GDPR や CCPA などの地域データ保護規制に準拠する場合、またはアプリで IP ベースの機能が不要なときに不要なデータ収集を減らす場合に使用してください。 ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(ipAddressCollectionDisabled: true) ``` #### AdaptyUI のペイウォール向けメディアキャッシュ設定 \{#set-up-media-cache-configuration-for-adaptyui\} AdaptyUI の設定はオプションです。設定なしで AdaptyUI モジュールを有効化することもできます。ただし、設定を使用する場合はすべてのパラメーターが必須です。 ```swift showLineNumbers title="Swift" // Configure AdaptyUI let adaptyUIConfiguration = AdaptyUI.Configuration( mediaCacheConfiguration: .init( memoryStorageTotalCostLimit: 100 * 1024 * 1024, memoryStorageCountLimit: .max, diskStorageSizeLimit: 100 * 1024 * 1024 ) ) // Activate AdaptyUI AdaptyUI.activate(configuration: adaptyUIConfiguration) ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :-------------------------- | :------- | :----------------------------------------------------------- | | memoryStorageTotalCostLimit | 必須 | ストレージの合計コスト上限(バイト単位)。 | | memoryStorageCountLimit | 必須 | メモリストレージのアイテム数上限。 | | diskStorageSizeLimit | 必須 | ストレージのディスク上のファイルサイズ上限(バイト単位)。0 は上限なしを意味します。 | ### トランザクション終了の動作 \{#transaction-finishing-behavior\} :::info この機能は SDK バージョン 3.12.0 以降で利用できます。 ::: デフォルトでは、Adapty は検証が成功した後にトランザクションを自動的に終了します。ただし、高度なトランザクション検証(サーバーサイドのレシート検証、不正検出、カスタムビジネスロジックなど)が必要な場合は、SDK が手動でトランザクションを終了するように設定できます。 ```swift showLineNumbers title="Swift" let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(transactionsFinishBehavior: .manual) // .auto is the default ``` トランザクションの終了方法の詳細については、[ガイド](ios-transaction-management)をご覧ください。 ### バックアップ復元時のデータ消去 \{#clear-data-on-backup-restore\} `clearDataOnBackup` を `true` に設定すると、SDK はアプリが iCloud バックアップから復元されたことを検知し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールを含むローカルに保存されたすべての SDK データを削除します。SDK はその後クリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルの SDK キャッシュのみです。Apple とのトランザクション履歴および Adapty サーバー上のユーザーデータは変更されません。 ::: ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(clearDataOnBackup: true) // default – false ``` ## トラブルシューティング \{#troubleshooting\} #### Tuist での Swift 6 並行性エラー \{#swift-6-concurrency-error-with-tuist\} [Tuist](https://tuist.dev/) でビルドすると、Swift 6 の strict concurrency コンパイルエラーが発生することがあります。典型的な症状としては、`AdaptyUIBuilderLogic` での `@Sendable` 属性の不一致や、類似したモジュール間の Sendability エラーがあります。 これは、Tuist が SPM パッケージから Xcode プロジェクトを生成する際に `swift-tools-version: 6.0` の設定を保持しないために発生します。その結果、一部の Adapty ターゲット(`Adapty`、`AdaptyUI`、`AdaptyUIBuilder`)が Swift 5 のルールでコンパイルされ、他のターゲットが Swift 6 を使用するため、モジュール間で `@Sendable` の不一致が生じます。 **修正方法**: Adapty SDK **3.15.5** 以降にアップグレードしてください。Swift の言語バージョンが混在していても問題が解消されます。 **回避策**: アップグレードできない場合は、Tuist の設定で 3 つの Adapty ターゲットすべてに対して明示的に Swift 6 を設定してください。 ```swift showLineNumbers targetSettings: [ "Adapty": .init().swiftVersion("6"), "AdaptyUI": .init().swiftVersion("6"), "AdaptyUIBuilder": .init().swiftVersion("6"), ] ``` --- # File: ios-quickstart-paywalls --- --- title: "iOS SDKでFlow Builderを使ってアプリ内課金を有効にする" description: "Adapty Flow Builderを使ったアプリ内課金のクイックスタートガイド。" --- アプリ内課金を有効にするには、3つの重要なコンセプトを理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセスなど) - [**フロー**](adapty-flow-builder) – ノーコードのFlow Builderで作成された、ユーザーにプロダクトを提示する画面シーケンス。SDKは`getFlow`を通じてフローを取得します。UIを自分のコードで構築したい場合はペイウォールを使ってください。詳しくは[ペイウォールを手動で実装する](ios-quickstart-manual)を参照してください。 - [**プレースメント**](placements) – アプリのどこでいつフローを表示するかを定義します(`main`、`onboarding`、`settings`など)。ダッシュボードでフローをプレースメントに紐付けて、コードではプレースメントIDで取得します。これにより、A/Bテストの実行や異なるユーザーへの異なるフロー表示が簡単になります。 Adaptyでは、アプリ内課金を有効にする3つの方法を提供しています。アプリの要件に応じて選択してください。 | 実装方法 | 複雑さ | 使用タイミング | |---|---|---| | Adapty Flow Builder | ✅ 簡単 | [ノーコードビルダーで購入準備が整ったフローを作成](quickstart-paywalls)します。Adaptyが自動的にレンダリングし、複雑な購入フロー、レシート検証、サブスクリプション管理をすべて処理します。 | | 手動で作成したペイウォール | 🟡 中程度 | アプリのコードでペイウォールUIを実装しつつ、プロダクト提供の柔軟性を保つためにAdaptyからフローオブジェクトを取得します。詳しくは[ガイド](ios-quickstart-manual)を参照してください。 | | オブザーバーモード | 🔴 難しい | すでに独自の購入処理インフラがあり、それを継続して使いたい場合。オブザーバーモードにはAdaptyでの制限があります。詳しくは[こちら](observer-vs-full-mode)を参照してください。 | :::important **以下の手順は、Adapty Flow Builderで作成したフローを実装する方法を示しています。** ペイウォールUIを自分で構築したい場合は、[ペイウォールを手動で実装する](ios-quickstart-manual)を参照してください。 ::: Adapty Flow Builderで作成したフローをアプリで表示するには、コードで行うことは次の3つだけです。 1. **フローの取得**: Adaptyからフローを取得します。 2. **表示する — 購入はAdaptyが処理**: アプリにビューを表示します。 3. **ボタンアクションの処理**: ユーザーの操作をアプリの応答に紐付けます。例えば、リンクを開いたり、ユーザーがボタンをタップしたときにフローを閉じたりします。 ## 始める前に \{#before-you-start\} 始める前に、以下の手順を完了してください。 1. Adapty ダッシュボードで[アプリをApp Storeに接続](initial_ios)する。 2. Adaptyで[プロダクトを作成](create-product)する。 3. [フローを作成してプロダクトを追加](create-paywall)する。 4. [プレースメントを作成してフローを追加](create-placement)する。 5. アプリのコードに[Adapty SDKをインストールして有効化](sdk-installation-ios)する。このガイドではAdapty iOS SDK v4(ベータ版)のAPIを使用します。 ## 1. フローを取得する \{#1-get-the-flow\} フローはダッシュボードで設定したプレースメントに紐付けられています。プレースメントを使うと、異なるオーディエンスに対して異なるフローを実行したり、[A/Bテスト](ab-tests)を実行したりできます。 Adapty Flow Builderで作成したフローを取得するには、次の手順を行います。 1. `getFlow`メソッドを使って[プレースメント](placements)IDからフローオブジェクトを取得し、ビュー設定があるかどうかを確認する。 2. `getFlowConfiguration`メソッドを使ってビュー設定を取得する。このビュー設定には、フローの表示に必要なUI要素とスタイリングが含まれています。 ```swift func loadFlow() async { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } ``` ## 2. フローを表示する \{#2-display-the-flow\} フロー設定を取得したら、数行追加するだけでフローを表示できます。 SwiftUIでは、フローを表示する際にイベントも処理する必要があります。`didFailPurchase`、`didFinishRestore`、`didFailRestore`、`didReceiveError`は必須です。テスト中は、以下のスニペットのコードをコピーしてこれらのイベントをログ出力することができます。 :::tip `didFinishPurchase`の処理は必須ではありませんが、購入成功後にアクションを実行したい場合に便利です。このコールバックを実装しない場合、フローは自動的に閉じられます。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in flowPresented = false print("Flow error: \(error)") } ) ``` ```swift func presentFlow(with config: AdaptyUI.FlowConfiguration) { let flowController = try AdaptyUI.flowController( with: config, delegate: self ) present(flowController, animated: true) } ``` イベントを処理するために`AdaptyFlowControllerDelegate`を実装します。最低限、デフォルト実装がない3つのメソッド(必須のエラーハンドラー)を実装してください。 ```swift extension YourViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError) { print("Purchase failed: \(error)") } func flowController(_ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile) { print("Restore finished successfully") } func flowController(_ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError) { print("Restore failed: \(error)") } } ``` :::info フローの表示方法の詳細については、[ガイド](ios-present-paywalls)を参照してください。 ::: ## 3. ボタンアクションを処理する \{#3-handle-button-actions\} ユーザーがボタンをタップすると、iOS SDKは購入、復元、フローのクローズ、リンクの開封を自動的に処理します。 ただし、他のボタンにはカスタムまたは事前定義されたIDがあり、コードでアクションを処理する必要があります。または、デフォルトの動作を上書きしたい場合もあります。 例えば、クローズボタンの処理方法を次に示します。UIKitでは、`.close`が発火すると SDKが自動的にコントローラーを閉じます — カスタム動作が必要な場合のみオーバーライドしてください。SwiftUIでは、`isPresented`バインディングを自分で`false`に設定する必要があります。 :::tip ボタンの[アクション](handle-paywall-actions)と[イベント](ios-handling-events)の処理方法については、各ガイドを参照してください。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow when the user taps close default: break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` ```swift extension YourViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didPerform action: AdaptyUI.Action) { switch action { case .close: controller.dismiss(animated: true) // default behavior — override only if needed default: break } } } ``` ## 次のステップ \{#next-steps\} --- no_index: true --- import Callout from '../../../components/Callout.astro'; ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! フローをアプリで表示する準備ができました。[サンドボックスモードで購入をテスト](test-purchases-in-sandbox)して、テスト購入が正常に完了できることを確認してください。 次に、適切なユーザーにフローを表示したり有料機能へのアクセスを付与したりするために、[ユーザーのアクセスレベルを確認](ios-check-subscription-status)する必要があります。 ## 完全なサンプル \{#full-example\} このガイドのすべての手順をアプリに統合した例を以下に示します。 ```swift struct ContentView: View { @State private var flowPresented = false @State private var flowConfiguration: AdaptyUI.FlowConfiguration? @State private var isLoading = false @State private var hasInitialized = false var body: some View { VStack { if isLoading { ProgressView("Loading...") } else { Text("Your App Content") } } .task { guard !hasInitialized else { return } await initializeFlow() hasInitialized = true } .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in print("Flow error: \(error)") flowPresented = false } ) } private func initializeFlow() async { isLoading = true defer { isLoading = false } await loadFlow() flowPresented = true } private func loadFlow() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } catch { print("Failed to load: \(error)") } } } ``` ```swift class ViewController: UIViewController { private var flowConfiguration: AdaptyUI.FlowConfiguration? override func viewDidLoad() { super.viewDidLoad() Task { await initializeFlow() } } private func initializeFlow() async { do { flowConfiguration = try await loadFlow() if let flowConfiguration { await MainActor.run { presentFlow(with: flowConfiguration) } } } catch { print("Error initializing: \(error)") } } private func loadFlow() async throws -> AdaptyUI.FlowConfiguration? { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return nil } return try await AdaptyUI.getFlowConfiguration(forFlow: flow) } private func presentFlow(with config: AdaptyUI.FlowConfiguration) { guard let flowController = try? AdaptyUI.flowController( with: config, delegate: self ) else { return } present(flowController, animated: true) } } extension ViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError) { print("Purchase failed for \(product.vendorProductId): \(error)") guard error.adaptyErrorCode != .paymentCancelled else { return } let message = switch error.adaptyErrorCode { case .paymentNotAllowed: "Purchases are not allowed on this device." default: "Purchase failed. Please try again." } let alert = UIAlertController(title: "Purchase Error", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) } func flowController(_ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile) { print("Restore finished successfully") controller.dismiss(animated: true) } func flowController(_ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError) { print("Restore failed: \(error)") } func flowController(_ controller: AdaptyFlowController, didReceiveError error: AdaptyUIError) { print("Flow error: \(error)") controller.dismiss(animated: true) } } ``` --- # File: ios-check-subscription-status --- --- title: "iOS SDKでサブスクリプションステータスを確認する" description: "AdaptyでiOSアプリのサブスクリプションステータスを確認する方法を学びます。" --- ユーザーが有料コンテンツにアクセスできるか、ペイウォールを表示するかを判断するには、プロファイルの[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態にアクセスして、ユーザーにペイウォールを表示するか有料機能へのアクセスを許可するかを判断する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ペイウォールまたは有料コンテンツを表示するかどうかを決める際は、プロファイルの[アクセスレベル](access-level)を確認します。方法は2つあります: - 最新のプロファイルデータが即座に必要な場合(アプリ起動時など)や強制的に更新したい場合は `getProfile` を呼び出す。 - **プロファイルの自動更新**を設定して、サブスクリプションステータスが変わるたびにローカルコピーを自動更新する。 :::important デフォルトでは、`premium` アクセスレベルがAdaptyにすでに存在します。アクセスレベルを複数設定する必要がない場合は、`premium` をそのまま使用できます。 ::: ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得する最も簡単な方法は、`getProfile` メソッドを使ってプロファイルにアクセスすることです: ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` ### サブスクリプション更新を受け取る \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取りたい場合: 1. 任意の型で `AdaptyDelegate` プロトコルに準拠し、`didLoadLatestProfile` メソッドを実装します。ユーザーのサブスクリプションステータスが変わるたびに、Adaptyがこのメソッドを自動的に呼び出します。以下の例では、サブスクリプションのワークフローやユーザープロファイルの処理を支援する `SubscriptionManager` 型を使用しています。この型は依存性注入で渡したり、UIKitアプリのシングルトンとして設定したり、アプリのメイン構造体からSwiftUI環境に追加したりできます。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存して、追加のネットワークリクエストなしにアプリ全体で使用できるようにします。 ```swift class SubscriptionManager: AdaptyDelegate { nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { let hasAccess = profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false // Update UI, unlock content, etc. } } // Set delegate after Adapty activation Adapty.delegate = subscriptionManager ``` :::note Adaptyはアプリ起動時に `didLoadLatestProfile` を自動的に呼び出し、デバイスがオフラインの場合でもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールのロジックを連携させる \{#connect-profile-with-paywall-logic\} ペイウォールを表示するか有料機能へのアクセスを許可するかを即座に判断したい場合、ユーザーのプロファイルを直接確認できます。このアプローチは、アプリ起動時、プレミアムセクションへの入場時、特定コンテンツを表示する前などのシナリオで役立ちます。 ```swift private func checkAccessLevel() async -> Bool { do { let profile = try await Adapty.getProfile() return profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false } catch { print("Error checking access level: \(error)") return false } } // In your initialization logic: let hasAccess = await checkAccessLevel() if !hasAccess { paywallPresented = true // Show paywall if no access } ``` ```swift private func checkAccessLevel() async throws -> Bool { let profile = try await Adapty.getProfile() return profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false } // In your initialization logic: let hasAccess = try await checkAccessLevel() if !hasAccess { presentPaywall(with: paywallConfiguration) } ``` ## 次のステップ \{#next-steps\} サブスクリプションステータスの追跡方法がわかったところで、[ユーザープロファイルの操作方法](ios-quickstart-identify)を確認して、既存の認証システムや有料アクセスの共有設定と適切に連携していることを確かめましょう。 独自の認証システムがない場合でも、Adaptyがユーザーを管理しますので問題はありません。ただし、Adaptyが匿名ユーザーをどのように扱うかについては[ガイド](ios-quickstart-identify)を参照することをおすすめします。 --- # File: ios-quickstart-identify --- --- title: "iOS SDKでのユーザー識別" description: "アプリ内サブスクリプション管理のためのAdaptyセットアップ クイックスタートガイド。" --- :::important このガイドは、独自の認証システムをお持ちの方を対象としています。ここでは、既存の認証システムに合わせてAdaptyのユーザープロファイルを管理する方法を説明します。 ::: ユーザーの購入履歴をどのように管理するかは、アプリの認証モデルによって異なります。 - バックエンド認証を使用せず、ユーザーデータを保存しないアプリの場合は、[匿名ユーザーに関するセクション](#anonymous-users)を参照してください。 - バックエンド認証を使用している(または使用予定の)アプリの場合は、[識別済みユーザーに関するセクション](#identified-users)を参照してください。 **主要な概念**: - **プロファイル**はSDKが動作するために必要なエンティティです。Adaptyが自動的に作成します。 - プロファイルは匿名 **(カスタマーユーザーIDなし)** または識別済み **(カスタマーユーザーIDあり)** のどちらかになります。 - **カスタマーユーザーID**を提供することで、Adaptyのプロファイルと社内の認証システムを紐付けられます。 匿名ユーザーと識別済みユーザーの違いは次のとおりです。 | | 匿名ユーザー | 識別済みユーザー | |-------------------------|---------------------------------------------------|-------------------------------------------------------------------------| | **購入管理** | ストアレベルの購入復元 | カスタマーユーザーIDを通じたデバイス間での購入履歴の維持 | | **プロファイル管理** | 再インストールのたびに新しいプロファイルが作成される | セッションとデバイスをまたいで同一プロファイルを使用 | | **データの永続性** | 匿名ユーザーのデータはアプリインストールに紐付く | 識別済みユーザーのデータはアプリインストールをまたいで保持される | ## 匿名ユーザー \{#anonymous-users\} バックエンド認証を使用していない場合、**アプリコード内で認証処理を実装する必要はありません**。 1. アプリの初回起動時にSDKが有効化されると、Adaptyは**ユーザーの新しいプロファイルを作成します**。 2. ユーザーがアプリ内で何かを購入すると、その購入は**ユーザーのAdaptyプロファイルとストアアカウントに紐付けられます**。 3. ユーザーがアプリを**再インストール**したり、**新しいデバイス**にインストールしたりすると、Adaptyは有効化時に**新しい匿名プロファイルを作成します**。 4. ユーザーがアプリ内で以前に購入を行っていた場合、デフォルトではSDKの有効化時にApp Storeから購入履歴が自動的に同期されます。 :::note バックアップからの復元は再インストールとは動作が異なります。デフォルトでは、ユーザーがバックアップから復元した場合、SDKはキャッシュデータを保持し、新しいプロファイルを作成しません。この動作は`clearDataOnBackup`設定で変更できます。[詳細はこちら](sdk-installation-ios#clear-data-on-backup-restore)。 ::: 匿名ユーザーの場合、インストールのたびに新しいプロファイルが作成されますが、Adaptyのアナリティクスで[新規インストールとして扱う基準を設定できる](general#4-installs-definition-for-analytics)ため、問題ありません。 匿名ユーザーの場合、インストール数は**デバイスID**でカウントする必要があります。この場合、再インストールを含め、デバイスでのアプリインストールが1件としてカウントされます。 ## 識別済みユーザー \{#identified-users\} アプリ内でユーザーを識別する方法は2つあります。 - [**ログイン/サインアップ時:**](#during-loginsignup) アプリ起動後にユーザーがサインインする場合、認証時にカスタマーユーザーIDを指定して`identify()`を呼び出します。 - [**SDK有効化時:**](#during-the-sdk-activation) アプリ起動時にカスタマーユーザーIDが既にわかっている場合は、`activate()`を呼び出す際に送信します。 :::important デフォルトでは、Adaptyが別のカスタマーユーザーIDに現在紐付いているカスタマーユーザーIDから購入を受け取った場合、アクセスレベルは共有されます。つまり、両方のプロファイルが有料アクセスを持つことになります。この設定を変更して、一方のプロファイルから他方へ有料アクセスを移行したり、共有を完全に無効にしたりすることもできます。詳細は[こちらの記事](general#6-sharing-paid-access-between-user-accounts)を参照してください。 ::: ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(たとえば、アプリへのログイン後やサインアップ後)、`identify`メソッドを使用してカスタマーユーザーIDを設定します。 - **このカスタマーユーザーIDを以前使用したことがない**場合、Adaptyは自動的に現在のプロファイルに紐付けます。 - **このカスタマーユーザーIDでユーザーを以前識別したことがある**場合、AdaptyはそのカスタマーユーザーIDに紐付いたプロファイルに切り替えます。 :::important カスタマーユーザーIDはユーザーごとに一意である必要があります。パラメーター値をハードコードすると、すべてのユーザーが同一として扱われます。 ::: 他のSDKメソッドを呼び出す前に、必ず`identify`を`await`してください。並列呼び出しを行うと`#3006 profileWasChanged`が発生するか、匿名プロファイルが対象になります。詳細は[iOS SDKの呼び出し順序](ios-sdk-call-order)を参照してください。 ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` ### SDK有効化時 \{#during-the-sdk-activation\} SDKを有効化する時点でカスタマーユーザーIDが既にわかっている場合は、`identify`を別途呼び出す代わりに、`activate`メソッドで送信できます。 カスタマーユーザーIDがわかっているにもかかわらず、有効化後にのみ設定した場合、有効化時にAdaptyが新しい匿名プロファイルを作成し、`identify`を呼び出した後に既存のプロファイルへ切り替えることになります。 既存のカスタマーユーザーID(以前使用したもの)でも新しいものでも渡すことができます。新しいものを渡した場合、有効化時に作成された新しいプロファイルが自動的にそのカスタマーユーザーIDに紐付けられます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスのダッシュボードに影響しません。これはインストール数がデバイスIDに基づいてカウントされるためです。 デバイスIDはデバイス上のストアからのアプリの単一インストールを表し、アプリの再インストール後にのみ再生成されます。 初回インストールか再インストールかに関わらず、また既存のカスタマーユーザーIDを使用するかどうかにも依存しません。 プロファイルの作成(SDKの有効化またはログアウト時)、ログイン、または再インストールなしのアプリアップグレードでは、追加のインストールイベントは発生しません。 デバイスではなくユニークユーザーに基づいてインストールをカウントしたい場合は、**App settings**で[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```swift showLineNumbers // Place in the app main struct for SwiftUI or in AppDelegate for UIKit let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } ``` ```swift showLineNumbers // Place in the app main struct for SwiftUI or in AppDelegate for UIKit let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` ### ユーザーのログアウト \{#log-users-out\} ユーザーをログアウトさせるボタンがある場合は、`logout`メソッドを使用します。 :::important ユーザーをログアウトすると、そのユーザーの新しい匿名プロファイルが作成されます。 ::: ```swift showLineNumbers do { try await Adapty.logout() } catch { // handle the error } ``` ```swift showLineNumbers Adapty.logout { error in if error == nil { // successful logout } } ``` :::info ユーザーをアプリに再ログインさせるには、`identify`メソッドを使用します。 ::: ### ログインなしでの購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリにログインする前後どちらでも購入できる場合、ログイン後もアクセスが維持されるようにする必要があります。 1. ログアウト状態のユーザーが購入を行うと、Adaptyはその購入を匿名プロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルへの切り替えを行います。 - 新しいカスタマーユーザーIDの場合(たとえば、登録前に購入が行われた場合)、AdaptyはカスタマーユーザーIDを現在のプロファイルに割り当て、購入履歴がすべて維持されます。 - 既存のカスタマーユーザーIDの場合(カスタマーユーザーIDがすでにプロファイルに紐付いている場合)、プロファイル切り替え後に実際のアクセスレベルを取得する必要があります。識別後すぐに[`getProfile`](ios-check-subscription-status)を呼び出すか、データが自動的に同期されるよう[プロファイルの更新をリッスンする](ios-check-subscription-status)ことができます。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内決済のロジックを実装できました!アプリのマネタイズがうまくいくことを願っています。 Adaptyをさらに活用するために、以下のトピックもご覧ください。 - [**テスト**](test-purchases-in-sandbox): すべてが期待どおりに動作するか確認する - [**オンボーディング**](ios-onboardings): オンボーディングでユーザーを引き込みリテンションを高める - [**インテグレーション**](configuration): マーケティングアトリビューションおよびアナリティクスサービスとわずか1行のコードで連携する - [**カスタムプロファイル属性の設定**](setting-user-attributes): ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/B テストを実施したり異なるユーザーに異なるペイウォールを表示したりする --- # File: adapty-sdk-integration-skill --- --- title: "SDKインテグレーションスキルを使ってAdaptyをiOSアプリに統合する" description: "adapty-sdk-integrationスキルを使用して、AIコーディングツールでAdapty SDKをiOSアプリにエンドツーエンドで統合します。" --- :::important このスキルはベータ版です。途中で止まったり、予期しない動作をした場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor)を参照してください。AIツールが各ステップを適切なドキュメントとともに進められるように案内します。 ::: --- no_index: true --- [adapty-sdk-integration スキル](https://github.com/adaptyteam/adapty-sdk-integration-skill)は、Adapty のインテグレーションをエンドツーエンドで自動化します。ダッシュボードのセットアップ、SDK のインストール、ペイウォール、各ステージの検証まで対応しています。プラットフォームを自動検出し、各ステージで関連する Adapty ドキュメントを取得します。 **対応ツール**: Claude Code、GitHub Copilot CLI、OpenAI Codex、Gemini CLI。 インストールするには、お使いのツール向けのフォームを選択してください。完全なリストは[スキルの README](https://github.com/adaptyteam/adapty-sdk-integration-skill) をご覧ください。 **Claude Code** ``` claude plugin marketplace add adaptyteam/adapty-sdk-integration-skill claude plugin install adapty-sdk-integration@adapty ``` **GitHub Copilot CLI** ``` gh skill install adaptyteam/adapty-sdk-integration-skill ``` **Gemini CLI** ``` gemini skills install https://github.com/adaptyteam/adapty-sdk-integration-skill ``` **OpenAI Codex またはその他のツール**: リポジトリをクローンし、`plugins/adapty-sdk-integration/skills/adapty-sdk-integration/` をツールのスキルディレクトリにコピーしてください。 インストール後、プロジェクト内でスキルを実行します: ``` /adapty-sdk-integration ``` スキルがいくつかのセットアップ質問を行い、その後ダッシュボードのセットアップ、SDK のインストール、ペイウォール、検証の手順を案内します。 --- # File: adapty-cursor --- --- title: "AIアシスタントを使ってAdaptyをiOSアプリに組み込む" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使ってAdaptyをiOSアプリに組み込むためのステップバイステップガイドです。" --- このガイドでは、AIコーディングツールを使ってAdaptyをiOSアプリに段階的に組み込む方法を説明します。正しいAdaptyドキュメントを正しい順序でAIに渡すことがポイントです。 For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## 始める前に:ダッシュボードのセットアップ \{#before-you-start-dashboard-setup\} AdaptyはSDKコードを書く前に、ダッシュボードでいくつかの設定が必要です。インタラクティブなLLMスキルを使うか、ダッシュボードから手動で設定することができます。 ### スキルを使う方法(推奨) \{#skill-approach-recommended\} Adapty CLIスキルを使うと、LLMがアプリ、プロダクト、アクセスレベル、ペイウォール、プレースメントを直接設定できます。ダッシュボードを各ステップで開く必要はありません。[ストアの接続](integrate-payments)だけはダッシュボードで行う必要があります。 ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` スキルを追加したら、エージェントで `/adapty-cli` を実行してください。ストアの接続のためにダッシュボードを開くタイミングも含め、各ステップをガイドしてくれます。 ### ダッシュボードを使う方法 \{#dashboard-approach\} すべてを手動で設定したい場合は、コードを書く前に以下の準備が必要です。LLMはダッシュボードの値を自動で調べることはできないので、自分で確認して提供する必要があります。 1. **アプリストアに接続する**: Adapty ダッシュボードで **App settings → General** を開きます。購入機能を動かすために必須の設定です。 [App Store に接続する](integrate-payments) 2. **公開SDKキーをコピーする**: Adapty ダッシュボードで **App settings → General** を開き、**API keys** セクションを確認します。コード上では、`Adapty.activate("YOUR_PUBLIC_SDK_KEY")` に渡す文字列です。 3. **プロダクトを少なくとも1つ作成する**: Adapty ダッシュボードの **Products** ページで作成します。コードからプロダクトを直接参照することはありません — Adaptlyはフローやペイウォールを通じてプロダクトを配信します。 [プロダクトを追加する](quickstart-products) 4. **フローまたはペイウォールとプレースメントを作成する**: Adapty ダッシュボードでフロー(またはUIを自分で作る場合はペイウォール)を作成し、**Placements** ページでプレースメントに割り当てます。コード上では、`Adapty.getFlow("YOUR_PLACEMENT_ID")` に渡すプレースメントIDが該当します。 [フローを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**: Adapty ダッシュボードの **Products** ページで各プロダクトに設定します。コード上では、`profile.accessLevels["premium"]` で確認する文字列です。ほとんどのアプリではデフォルトの `premium` アクセスレベルで十分です。プロダクトによって(たとえば `basic` プランと `pro` プラン)ユーザーがアクセスできる機能が異なる場合は、コーディングを始める前に[追加のアクセスレベルを作成](assigning-access-level-to-a-product)してください。 :::tip 5つすべてが揃ったら、コードを書く準備完了です。LLMに「公開SDKキーはX、プレースメントIDはY」と伝えておくと、正確な初期化コードとペイウォール取得コードを生成してもらえます。 ::: ### 後から設定するもの \{#set-up-when-ready\} コーディングを始めるためには必須ではありませんが、組み込みが進んだ段階で必要になります。 - **A/B テスト**: **Placements** ページで設定します。コードの変更は不要です。 [A/B テスト](ab-tests) - **フローやプレースメントの追加**: 別のプレースメントIDで `getFlow` を追加で呼び出します。 - **アナリティクス連携**: **Integrations** ページで設定します。連携ごとに設定方法が異なります。[アナリティクス連携](analytics-integration)と[アトリビューション連携](attribution-integration)を参照してください。 ## AdaptyドキュメントをLLMに渡す \{#feed-adapty-docs-to-your-llm\} ### Context7を使う(推奨) \{#use-context7-recommended\} [Context7](https://context7.com)は、LLMが最新のAdaptyドキュメントに直接アクセスできるようにするMCPサーバーです。質問内容に応じて適切なドキュメントを自動で取得するため、URLを手動で貼り付ける手間がありません。 Context7は**Cursor**、**Claude Code**、**Windsurf**、その他のMCP対応ツールで動作します。セットアップするには以下を実行してください。 ``` npx ctx7 setup ``` このコマンドがエディタを自動検出してContext7サーバーを設定します。手動でセットアップする場合は、[Context7 GitHubリポジトリ](https://github.com/upstash/context7)を参照してください。 設定後は、プロンプト内でAdaptyライブラリを参照してください。 ``` Use the adaptyteam/adapty-docs library to look up how to install the iOS SDK ``` :::warning Context7を使えばドキュメントのURLを手動で貼り付ける必要はなくなりますが、実装の順序は重要です。すべてが正しく動くよう、以下の[実装ウォークスルー](#implementation-walkthrough)をステップごとに進めてください。 ::: ### プレーンテキストのドキュメントを使う \{#use-plain-text-docs\} AdaptyのドキュメントはプレーンテキストのMarkdownとして取得できます。URLの末尾に `.md` を付けるか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例: [adapty-cursor.md](https://adapty.io/docs/ja/adapty-cursor.md) 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステージには、「LLMに送る内容」ブロックがあり、貼り付け用の `.md` リンクが含まれています。 まとめて多くのドキュメントが必要な場合は、以下の[インデックスファイルとプラットフォーム別のサブセット](#plain-text-doc-index-files)を参照してください。 ## 実装ウォークスルー \{#implementation-walkthrough\} このガイドの残りの部分では、実装の順序に沿ってAdaptyの組み込みを進めていきます。各ステージには、LLMに送るドキュメント、完了時に確認できる内容、よくある問題が記載されています。 ### 組み込みを計画する \{#plan-your-integration\} コードに入る前に、LLMにプロジェクトを分析させて実装計画を立ててもらいましょう。AIツールにプランニングモード(CursorやClaude Codeのプランモードなど)があれば、コードを書く前にプロジェクト構造とAdaptyドキュメントの両方を確認させるために活用してください。 購入処理にどのアプローチを使うかをLLMに伝えてください — これによって参照すべきガイドが変わります。 - [**Adapty Flow Builder**](adapty-flow-builder): Adaptのノーコードビルダーでフローを作成し、SDKが自動でレンダリングします。 - [**手動作成のペイウォール**](ios-quickstart-manual): 独自のペイウォールUIをコードで構築しますが、プロダクトの取得と購入処理にはAdaptyを使います。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラをそのまま維持し、アナリティクスと連携のみAdaptyを使います。 どれを選べばよいかわからない場合は、[クイックスタートの比較表](ios-quickstart-paywalls)をご覧ください。 ### SDKをインストールして設定する \{#install-and-configure-the-sdk\} XcodeのSwift Package ManagerでAdapty SDKパッケージをインストールし、公開SDKキーで有効化します。これが基盤となるステップで、これなしには他の機能は動きません。 **ガイド:** [Adapty SDKのインストールと設定](sdk-installation-ios) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-ios.md ``` :::tip[チェックポイント] - **期待される結果:** アプリがビルドして起動する。XcodeコンソールにAdaptyの有効化ログが表示される。 - **注意点:** "Public API key is missing" → App settingsで取得した実際のキーがプレースホルダーと置き換えられているか確認する。 ::: ### フローまたはペイウォールを表示して購入を処理する \{#show-flows-or-paywalls-and-handle-purchases\} プレースメントIDでフローまたはペイウォールを取得して表示し、購入イベントを処理します。必要なガイドは購入の処理方法によって異なります。 進めながらサンドボックスで都度購入をテストしてください — 最後まで待たずに行いましょう。セットアップ手順は[サンドボックスでの購入テスト](test-purchases-in-sandbox)を参照してください。 **ガイド:** - [Flow Builderで購入を有効にする(クイックスタート)](ios-quickstart-paywalls) - [フローとその設定を取得する](get-pb-paywalls) - [フローを表示する](ios-present-paywalls) - [フローのイベントを処理する](ios-handling-events) - [ボタンアクションに対応する](handle-paywall-actions) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-quickstart-paywalls.md - https://adapty.io/docs/ja/get-pb-paywalls.md - https://adapty.io/docs/ja/ios-present-paywalls.md - https://adapty.io/docs/ja/ios-handling-events.md - https://adapty.io/docs/ja/handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される結果:** 設定したプロダクトがフローに表示される。プロダクトをタップするとサンドボックスの購入ダイアログが表示される。 - **注意点:** フローが空または `getFlow` エラー → プレースメントIDがダッシュボードと完全に一致しているか、プレースメントにオーディエンスが割り当てられているか確認する。 ::: **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](ios-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products) - [リモートコンフィグで設計されたペイウォールを表示する](present-remote-config-paywalls) - [購入を行う](making-purchases) - [購入を復元する](restore-purchase) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products.md - https://adapty.io/docs/ja/present-remote-config-paywalls.md - https://adapty.io/docs/ja/making-purchases.md - https://adapty.io/docs/ja/restore-purchase.md ``` :::tip[チェックポイント] - **期待される結果:** カスタムペイウォールにAdaptyから取得したプロダクトが表示される。プロダクトをタップするとサンドボックスの購入ダイアログが表示される。 - **注意点:** プロダクト配列が空 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、プレースメントにオーディエンスがあるか確認する。 ::: **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードを実装する](implement-observer-mode) - [オブザーバーモードでトランザクションを報告する](report-transactions-observer-mode) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/observer-vs-full-mode.md - https://adapty.io/docs/ja/implement-observer-mode.md - https://adapty.io/docs/ja/report-transactions-observer-mode.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローでサンドボックス購入を行った後、Adaptのダッシュボード **Event Feed** にトランザクションが表示される。 - **注意点:** イベントが表示されない → Adaptにトランザクションを報告しているか、App Store Server Notificationsが設定されているか確認する。 ::: ### サブスクリプションのステータスを確認する \{#check-subscription-status\} 購入後、ユーザープロファイルでアクティブなアクセスレベルを確認して、プレミアムコンテンツへのアクセスを制限します。 **ガイド:** [サブスクリプションのステータスを確認する](ios-check-subscription-status) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックス購入後、`profile.accessLevels["premium"]?.isActive` が `true` を返す。 - **注意点:** 購入後も `accessLevels` が空 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているか確認する。 ::: ### ユーザーを識別する \{#identify-users\} アプリのユーザーアカウントをAdaptyのプロファイルに紐付けて、デバイスをまたいで購入が引き継がれるようにします。 :::important アプリに認証機能がない場合はこのステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](ios-quickstart-identify) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-quickstart-identify.md ``` :::tip[チェックポイント] - **期待される結果:** `Adapty.identify("your-user-id")` を呼び出した後、ダッシュボードの **Profiles** セクションにカスタムユーザーIDが表示される。 - **注意点:** 匿名プロファイルへのアトリビューションを避けるため、`identify` はアクティベーション後、ペイウォール取得前に呼び出す。 ::: ### リリースの準備をする \{#prepare-for-release\} サンドボックスで組み込みが動作したら、すべてが本番環境に対応しているかリリースチェックリストを確認しましょう。 **ガイド:** [リリースチェックリスト](release-checklist) LLMに送る内容: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ja/release-checklist.md ``` :::tip[チェックポイント] - **期待される結果:** すべてのチェックリスト項目が確認済み:ストア接続、サーバー通知、購入フロー、アクセスレベルチェック、プライバシー要件。 - **注意点:** App Store Server Notificationsが未設定 → **App settings → iOS SDK** で設定しないと、イベントがダッシュボードに表示されません。 ::: ## プレーンテキストのドキュメントインデックスファイル \{#plain-text-doc-index-files\} 個別ページを超えてLLMに広いコンテキストを提供したい場合、Adaptyドキュメント全体をリスト化または統合したインデックスファイルを提供しています。 - [`llms.txt`](https://adapty.io/docs/ja/llms.txt): すべてのページを `.md` リンク付きでリスト化しています。LLMがウェブサイトにアクセスしやすくするための[新興標準](https://llmstxt.org/)です。一部のAIエージェント(ChatGPTなど)では、`llms.txt` をダウンロードしてチャットにファイルとしてアップロードする必要があります。 - [`llms-full.txt`](https://adapty.io/docs/ja/llms-full.txt): Adaptyドキュメントサイト全体を1つのファイルにまとめたものです。非常に大きいため、全体像が必要な場合のみ使用してください。 - iOS専用の [`ios-llms.txt`](https://adapty.io/docs/ja/ios-llms.txt) と [`ios-llms-full.txt`](https://adapty.io/docs/ja/ios-llms-full.txt): サイト全体と比べてトークンを節約できる、プラットフォーム別のサブセットです。 --- # File: get-pb-paywalls --- --- title: "フローとペイウォールを取得する - iOS" description: "iOSアプリでAdaptyからフローとペイウォールを取得する方法。" --- [フローまたはペイウォールビルダーのペイウォールを設計](adapty-paywall-builder)したら、それをモバイルアプリに表示できます。最初のステップは、以下の説明に従って、プレースメントに関連付けられたフローまたはペイウォールとそのビュー設定を取得することです。 :::tip Adapty SDK をモバイルアプリに統合した実例を見たいですか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示す[サンプルアプリ](sample-apps)をご確認ください。 :::
始める前に 1. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成し、プロダクトを組み込み](create-paywall)ます。 3. Adapty ダッシュボードで[プレースメントを作成し、フロー/ペイウォールを組み込み](create-placement)ます。 4. モバイルアプリに [Adapty SDK](sdk-installation-ios) をインストールします。
## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} フロービルダーまたはペイウォールビルダーを使ってフローやペイウォールをデザインした場合、それをモバイルアプリのコードでレンダリングしてユーザーに表示することを心配する必要はありません。このようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてIDを取得し、ビュー設定を準備した上で、モバイルアプリに表示する必要があります。 フローまたはペイウォールとその[ビュー設定](get-pb-paywalls#fetch-the-view-configuration)は、できるだけ早い段階で取得してください。表示する直前ではなく、理想的にはずっと前に取得しましょう。ビュー設定を取得した時点で、SDKはバックグラウンドで画像のダウンロードとキャッシュを開始します。早く取得するほど、ダウンロードが完了するまでの時間が長く確保できます。フローまたはペイウォールを表示する頃には、設定と画像がすでにキャッシュ済みで表示できる状態になっています。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します: ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") // the requested flow/paywall } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow/paywall case let .failure(error): // handle the error } } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュデータを返します。この方法を推奨するのは、ユーザーが常に最新のデータを受け取れるためです。

ただし、ユーザーが不安定なインターネット環境を利用していると想定される場合は、`.returnCacheDataElseLoad` を使用することを検討してください。これにより、キャッシュが存在する場合はキャッシュデータを返します。この場合、最新のデータが取得できないことがありますが、通信環境に左右されずに読み込み時間を短縮できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けたい場面での使用も安全です。

キャッシュはアプリを再起動しても保持され、アプリの再インストールや手動でのクリアを行った場合にのみ削除されます。

Adapty SDK はペイウォールをローカルに2つの層で保存しています。1つは上記の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。また、CDN を使用してペイウォールをより高速に取得し、CDN に接続できない場合のスタンドアロンフォールバックサーバーも用意しています。このシステムは、常にペイウォールの最新バージョンを取得しつつ、インターネット接続が不安定な場合でも信頼性を確保するよう設計されています。

| | **loadTimeout** | デフォルト: 5秒 |

このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。

まれに、内部で複数のリクエストが発生する場合があるため、`loadTimeout` に指定した時間よりわずかに遅くタイムアウトすることがあります。

| レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------- | | Flow | プレースメント、識別子(`id`、`variationId`)、名前、リモートコンフィグ、およびフローにビュー設定が含まれるかどうかを示す `hasViewConfiguration` フラグを含む `AdaptyFlow` オブジェクトです。プリロード、カスタム UI、またはプログラムによるチェック用に実際のプロダクトを取得するには、`getPaywallProducts(flow:)` を呼び出してください。 | ## ビュー設定の取得 \{#fetch-the-view-configuration\} フローまたはペイウォールを取得したら、`flow.hasViewConfiguration` を使ってビュー設定が含まれているかどうかを確認します。このフラグは、Adapty ダッシュボードでプレースメントがどのように設計されたかを示します。 - **`true`** — プレースメントが **Flow Builder**(フロー)または **Paywall Builder**(ペイウォール)で設計されています。Adapty が UI をレンダリングします。以降の手順に従い、ビュー設定を取得して[フローまたはペイウォールを表示](ios-present-paywalls)してください。 - **`false`** — プレースメントはビルダー UI を持たないカスタムペイウォールです。 `getFlowConfiguration` メソッドを使用してビュー設定を読み込みます。 ```swift showLineNumbers guard flow.hasViewConfiguration else { // handle as remote config paywall return } let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :----------------------- | :------------- | :---------- | | **forFlow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | | **locale** |

任意

デフォルト: `nil`

| [ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子。`-` で区切られた1つまたは2つのサブタグを持つ言語コードで指定します(例: `en`、`pt-br`)。詳細は[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウトを制限する値です。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。内部で複数のリクエストが発生する場合があるため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。 | | **products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために、`AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **systemRequestsHandler** | 任意 | フローのアクションによってトリガーされるシステムの権限リクエストやレビューリクエストを処理する、`AdaptySystemRequestsHandler` に準拠したオブジェクト。フローにそのようなアクションが含まれる場合にのみ必要です。 | | **assetsResolver** | 任意 | フロー/ペイウォール内の画像や動画を上書きする `[String: AdaptyCustomAsset]` 辞書。詳細は[アセットのカスタマイズ](#customize-assets)を参照してください。 | | **timerResolver** | 任意 | 開発者が定義したタイマーの終了日時を提供する、`AdaptyTimerResolver` に準拠したオブジェクト。詳細は[開発者定義タイマーの設定](#set-up-developer-defined-timers)を参照してください。 | 読み込みが完了したら、[フロー/ペイウォールを表示](ios-present-paywalls)します。 ## デフォルトオーディエンスのフローまたはペイウォールを取得して高速化する \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、フローやペイウォールはほぼ瞬時に取得されるため、このプロセスの高速化を特に気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が不安定な場合は、フローやペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、何も表示しないよりもスムーズなユーザー体験を提供するために、デフォルトのフローまたはペイウォールを表示したいと思うかもしれません。 これに対処するために、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けのフローまたはペイウォールを取得します。ただし、推奨されるアプローチは `getFlow` メソッドでフローまたはペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)セクションをご覧ください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現在と将来)で別々のペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないペイウォールで問題が発生することを許容するかのどちらかを選択することになります。 - **ターゲティングの喪失**: すべてのユーザーに **All Users** オーディエンス向けに設計された同じペイウォールが表示されるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを許容してでもフローやペイウォールの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。それ以外の場合は、[上記](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)で説明した `getFlow` を使用してください。 ::: ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成した際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方式はユーザーが常に最新のデータを受け取れるため、こちらをお勧めします。

ただし、ユーザーのインターネット接続が不安定だと思われる場合は、`.returnCacheDataElseLoad` を使用すると、キャッシュが存在する場合にそれを返すことができます。この場合、ユーザーが最新データを取得できないことがありますが、接続状況に関わらず読み込みが速くなります。キャッシュはセッション中でも定期的に更新されるため、ネットワークリクエストを避ける目的でのキャッシュ使用は安全です。

なお、キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ削除されます。

| ## アセットのカスタマイズ \{#customize-assets\} ペイウォール/フローの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には事前定義済みのID(`hero_image`と`hero_video`)が割り当てられています。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定する](custom-media)必要があります。 たとえば、次のようなことができます。 - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 - 動画が読み込まれる前にプレイヤーがレイアウトスペースを確保できるよう、動画のピクセル解像度を指定する(アスペクト比 = `width / height`)。スキップするには `nil` を渡す。 カスタムアセットをシンプルな辞書で提供する方法の例を以下に示します: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image and a known resolution "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!), resolution: CGSize(width: 1080, height: 1920) ) ), ] let flowConfig = try await AdaptyUI.getFlowConfiguration( forFlow: flow, assetsResolver: customAssets ) ``` :::note アセットが見つからない場合、ペイウォール/フローはデフォルトの外観にフォールバックします。 ::: ## 開発者定義タイマーの設定 \{#set-up-developer-defined-timers\} モバイルアプリでカスタムタイマーを使用するには、`AdaptyTimerResolver` プロトコルに準拠したオブジェクトを作成します。このオブジェクトは、各カスタムタイマーのレンダリング方法を定義します。必要であれば、このプロトコルにすでに準拠している `[String: Date]` ディクショナリを直接使用することもできます。以下に例を示します: ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリは各タイマーを正しい値で動的に更新できます。例えば: - `CUSTOM_TIMER_NY`: 元日など、タイマーの終了までの残り時間。 - `CUSTOM_TIMER_6H`: ユーザーがペイウォールを開いてから始まった6時間のうち、残りの時間。
[Adapty ダッシュボード](adapty-paywall-builder)のペイウォールビルダーで[ペイウォールのビジュアルデザインを作成](adapty-paywall-builder)したら、それをモバイルアプリに表示できます。最初のステップは、以下の説明に従ってプレースメントに関連付けられたペイウォールとそのビュー設定を取得することです。 このトピックはペイウォールビルダーでカスタマイズされたペイウォールに関するものです。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォール用のペイウォールとプロダクトの取得](fetch-paywalls-and-products)を参照してください。 :::tip Adapty SDK をモバイルアプリに統合した実際の例を見たい方は、[サンプルアプリ](sample-apps)をご覧ください。ペイウォールの表示、購入処理、その他の基本的な機能を含む完全なセットアップを確認できます。 :::
モバイルアプリでペイウォールを表示する前に 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加する](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加する](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-ios) をインストールする。
## ペイウォールビルダーで作成したペイウォールを取得する \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーを使ってペイウォールをデザインした](adapty-paywall-builder)場合、ユーザーに表示するためのレンダリングコードをアプリに書く必要はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてペイウォールのIDを取得し、ビュー設定を取得してから、アプリ内に表示する必要があります。 最適なパフォーマンスを確保するために、ペイウォールとその[ビュー設定](get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します: ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値を使用します。 | | **locale** |

任意

デフォルト: `en`

|

[ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子です。このパラメータは、マイナス(**-**)で区切られた1つまたは2つのサブタグで構成された言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。

例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。

ロケールコードの詳細と推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。

| | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるようになるため、この設定を推奨します。

ただし、ユーザーの通信環境が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合はキャッシュデータを返すことを検討してください。この設定では最新データが取得できないことがありますが、通信が不安定な環境でも読み込みが速くなります。キャッシュはセッション中に定期的に更新されるため、ネットワークリクエストを減らす目的でキャッシュを利用しても問題ありません。

キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリアによってのみ削除されます。

Adapty SDK はペイウォールをローカルに2層で保存します。1つは上記の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより速く取得するために CDN を使用し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、通信環境が悪い場合でも常にペイウォールの最新バージョンを確実に取得できるよう設計されています。

| | **loadTimeout** | デフォルト: 5秒 |

このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルのフォールバックが返されます。

内部的に複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅くタイムアウトすることがあります。

| レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------- | | Paywall | プロダクトIDのリスト、ペイウォール識別子、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーで **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、ビュー設定が含まれているかどうかを確認してください。ビュー設定が存在する場合は、そのペイウォールがペイウォールビルダーで作成されたことを意味します。これにより、ペイウォールの表示方法が決まります。ビュー設定がある場合はペイウォールビルダーのペイウォールとして扱い、ない場合は[リモートコンフィグのペイウォールとして処理してください](present-remote-config-paywalls)。 `getPaywallConfiguration` メソッドを使って、ビュー設定を読み込みます。 ```swift showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, products: products ) // use loaded configuration } catch { // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------------- | :---------- | | **paywall** | 必須 | 対象のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。 | | **products** | 任意 | 画面上でのプロダクト表示タイミングを最適化するために、`AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡した場合、AdaptyUI が自動的に必要なプロダクトを取得します。 | :::note 複数の言語を使用している場合は、[ペイウォールビルダーのローカライゼーションを追加する方法](add-paywall-locale-in-adapty-paywall-builder)と、ロケールコードを正しく使用する方法を[こちら](localizations-and-locale-codes)でご確認ください。 ::: 読み込みが完了したら、[ペイウォールを表示](ios-present-paywalls)してください。 ## デフォルトオーディエンス向けペイウォールを取得してより速く表示する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ瞬時に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合は、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を提供することを検討するとよいでしょう。 この問題に対処するために、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の [ペイウォール情報の取得](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) セクションをご覧ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)に対して異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがレンダリングされないペイウォールに遭遇するリスクを許容するかのどちらかを選択しなければなりません。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを受け入れてでもペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` を使用してください。 ::: ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` :::note `getPaywallForDefaultAudience` メソッドは iOS SDK バージョン 2.11.2 以降で利用可能です。 ::: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

[ペイウォールのローカライズ](add-remote-config-locale)の識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語、2番目は地域を表します。

例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。

ロケールコードおよび推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。

| | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。

ただし、ユーザーが不安定なインターネット環境にある場合は、`.returnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュデータを返すため、最新データが得られない場合もありますが、接続状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを減らす目的で安全に利用できます。

キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ削除されます。

| ## アセットのカスタマイズ \{#customize-assets\} ペイウォールの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、`hero_image` と `hero_video` という定義済みIDがあります。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズできます。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のようなことができます。 - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty iOS SDK をバージョン 3.7.0 以上にアップデートしてください。 ::: カスタムアセットをシンプルな辞書形式で提供する方法の例を示します: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!) ) ), ] let paywallConfig = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, assetsResolver: customAssets ) ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの外観にフォールバックします。 ::: ## デベロッパー定義タイマーの設定 \{#set-up-developer-defined-timers\} モバイルアプリでカスタムタイマーを使用するには、`AdaptyTimerResolver` プロトコルに準拠したオブジェクトを作成します。このオブジェクトは、各カスタムタイマーのレンダリング方法を定義します。`[String: Date]` ディクショナリはすでにこのプロトコルに準拠しているため、直接使用することもできます。以下に例を示します。 ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリは各タイマーを正しい値で動的に更新できます。例えば: - `CUSTOM_TIMER_NY`: 元日など、タイマー終了までの残り時間。 - `CUSTOM_TIMER_6H`: ユーザーがペイウォールを開いてから始まった6時間のうち、残り時間。
--- # File: ios-present-paywalls --- --- title: "フローとペイウォールの表示 - iOS" description: "iOSアプリでユーザーにフローとペイウォールを表示します。" --- フローまたはペイウォールを作成した場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングを気にする必要はありません。フローやペイウォールには、表示する内容とその表示方法の両方が含まれています。 以下で使用する `AdaptyUI.FlowConfiguration` オブジェクトの取得方法については、[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 ## SwiftUI でフローとペイウォールを表示する \{#present-flows-and-paywalls-in-swiftui\} ### モーダルビューとして表示する \{#present-as-a-modal-view\} フローまたはペイウォールをモーダルビューとしてデバイス画面に表示するには、SwiftUI の `.flow` モディファイアを使用します。最小限の呼び出しには `isPresented`、`flowConfiguration`、および4つの必須コールバックが必要です。 ```swift showLineNumbers title="SwiftUI" .flow( isPresented: $flowPresented, flowConfiguration: , didFailPurchase: { _, _ in /* handle the error */ }, didFinishRestore: { _ in /* check access level and dismiss */ }, didFailRestore: { _ in /* handle the error */ }, didReceiveError: { _ in flowPresented = false } ) ``` ボタンタップを処理する `didPerformAction` や購入成功に反応する `didFinishPurchase` などのオプションコールバックを追加することで、より細かく制御できます。 ```swift showLineNumbers title="SwiftUI" @State var flowPresented = false // この変数の状態を管理し、フローまたはペイウォールを表示したいタイミングで `true` に設定してください var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: , didPerformAction: { action in switch action { case .close: flowPresented = false default: // Handle other actions break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) } ``` パラメータ: | パラメータ | 必須 | 説明 | |:-----------------------|:---------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | フローまたはペイウォール画面の表示状態を管理するバインディング。 | | **flowConfiguration** | 必須 | フローまたはペイウォールの視覚的な詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。`AdaptyUI.getFlowConfiguration(forFlow:)` メソッドを使用します。詳細は[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **didFailPurchase** | 必須 | `Adapty.makePurchase()` が失敗した際に呼び出されます。 | | **didFinishRestore** | 必須 | `Adapty.restorePurchases()` が正常に完了した際に呼び出されます。 | | **didFailRestore** | 必須 | `Adapty.restorePurchases()` が失敗した際に呼び出されます。 | | **didReceiveError** | 必須 | レンダリングエラーまたはフロースクリプトからのランタイムエラー(例:JavaScript例外、`AdaptyUIError` コード `4105`)が発生した際に呼び出されます。レンダリングエラーが発生した場合は、[Adapty サポート](mailto:support@adapty.io)にお問い合わせください。 | | **fullScreen** | 任意 | フローまたはペイウォールをフルスクリーンモードで表示するか、シートとして表示するかを決定します。デフォルトは `true` です。 | | **didAppear** | 任意 | フローまたはペイウォールのビューが表示された際に呼び出されます。 | | **didDisappear** | 任意 | フローまたはペイウォールのビューが閉じられた際に呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをタップした際に呼び出されます。`close` と `openURL` の2つのアクションIDが事前定義されており、その他はカスタムでビルダーで設定できます。 | | **didSelectProduct** | 任意 | ユーザーまたはシステムによって購入するプロダクトが選択された際に呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始した際に呼び出されます。 | | **didFinishPurchase** | 任意 | `Adapty.makePurchase()` が正常に完了した際に呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | Web決済のナビゲーションが完了した際に呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始した際に呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生した際に呼び出されます。再試行するには `true` を返します。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれた際に呼び出されます。 | | **showAlertItem** | 任意 | フローまたはペイウォールの上にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングするための関数。 | | **placeholderBuilder** | 任意 | フローまたはペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。デフォルトは `ProgressView` です。 | パラメータの詳細については、[iOS - イベントの処理](ios-handling-events)を参照してください。 ### 非モーダルビューとして表示する \{#present-as-a-non-modal-view\} フローやペイウォールを、アプリのナビゲーションフロー内のナビゲーション先またはインラインビューとして表示することもできます。SwiftUI ビューで `AdaptyFlowView` を直接使用してください。 ```swift showLineNumbers title="SwiftUI" AdaptyFlowView( flowConfiguration: , didFailPurchase: { product, error in // Handle purchase failure }, didFinishRestore: { profile in // Handle successful restore }, didFailRestore: { error in // Handle restore failure }, didReceiveError: { error in // Handle the error (rendering or JS exception from the flow script). } ) ``` ## UIKit でフローとペイウォールを表示する \{#present-flows-and-paywalls-in-uikit\} デバイス画面にフローまたはペイウォールを表示するには、次の手順を行います。 1. `AdaptyUI.flowController(with:delegate:)` メソッドを使用して、表示したいビジュアルフローを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualFlow = try AdaptyUI.flowController( with: , delegate: ) ``` リクエストパラメータ: | パラメータ | 必須 | 説明 | | :----------------------- | :------- | :---------- | | **flowConfiguration** | 必須 | フローまたはペイウォールの視覚的な詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。`AdaptyUI.getFlowConfiguration(forFlow:)` メソッドを使用します。詳細は[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **delegate** | 必須 | フローおよびペイウォールイベントをリッスンする `AdaptyFlowControllerDelegate`。詳細は[フロー&ペイウォールイベントの処理](ios-handling-events)を参照してください。 | 返り値: | オブジェクト | 説明 | | :---------------------- | :------------------------------------------------------- | | **AdaptyFlowController** | リクエストされたフローまたはペイウォール画面を表すオブジェクト。 | 2. オブジェクトが正常に作成されたら、デバイスの画面に表示できます。 ```swift showLineNumbers title="Swift" present(visualFlow, animated: true) ``` :::tip Adapty SDK がモバイルアプリに統合された実際の例を見てみましょう。ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示す[サンプルアプリ](sample-apps)をご確認ください。 ::: ペイウォールビルダーを使用してペイウォールをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングを気にする必要はありません。そのようなペイウォールには、ペイウォール内に表示する内容とその表示方法の両方が含まれています。 以下で使用する `AdaptyUI.PaywallConfiguration` オブジェクトの取得方法については、[ペイウォールビルダーのペイウォールとその設定の取得](get-pb-paywalls)を参照してください。 ## SwiftUI でペイウォールを表示する \{#present-paywalls-in-swiftui\} ### モーダルビューとして表示する \{#present-as-a-modal-view\} ビジュアルペイウォールをモーダルビューとしてデバイス画面に表示するには、SwiftUI の `.paywall` モディファイアを使用します。 ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false // この変数の状態を管理し、ペイウォールを表示したいタイミングで `true` に設定してください var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywallConfiguration: , didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishPurchase: { product, profile in paywallPresented = false }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } ) } ``` パラメータ: | パラメータ | 必須 | 説明 | |:----------------------------------|:---------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | ペイウォール画面の表示状態を管理するバインディング。 | | **paywallConfiguration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:)` メソッドを使用します。詳細は[ペイウォールビルダーのペイウォールとその設定の取得](get-pb-paywalls)を参照してください。 | | **didFailPurchase** | 必須 | `Adapty.makePurchase()` が失敗した際に呼び出されます。 | | **didFinishRestore** | 必須 | `Adapty.restorePurchases()` が正常に完了した際に呼び出されます。 | | **didFailRestore** | 必須 | `Adapty.restorePurchases()` が失敗した際に呼び出されます。 | | **didFailRendering** | 必須 | インターフェースのレンダリング中にエラーが発生した際に呼び出されます。この場合は、[Adapty サポート](mailto:support@adapty.io)にお問い合わせください。 | | **fullScreen** | 任意 | ペイウォールをフルスクリーンモードで表示するか、モーダルとして表示するかを決定します。デフォルトは `true` です。 | | **didAppear** | 任意 | ペイウォールのビューが表示された際に呼び出されます。 | | **didDisappear** | 任意 | ペイウォールのビューが閉じられた際に呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをタップした際に呼び出されます。ボタンごとに異なるアクションIDがあります。`close` と `openURL` の2つのアクションIDが事前定義されており、その他はカスタムでビルダーで設定できます。 | | **didSelectProduct** | 任意 | ユーザーまたはシステムによって購入するプロダクトが選択された場合に呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始した際に呼び出されます。 | | **didFinishPurchase** | 任意 | `Adapty.makePurchase()` が正常に完了した際に呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | Web決済のナビゲーションが完了した際に呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始した際に呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生した際に呼び出されます。再試行するには `true` を返します。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれた際に呼び出されます。 | | **showAlertItem** | 任意 | ペイウォールの上にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングするための関数。 | | **placeholderBuilder** | 任意 | ペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。 | パラメータの詳細については、[iOS - イベントの処理](ios-handling-events)を参照してください。 ### 非モーダルビューとして表示する \{#present-as-a-non-modal-view\} ペイウォールを、アプリのナビゲーションフロー内のナビゲーション先またはインラインビューとして表示することもできます。SwiftUI ビューで `AdaptyPaywallView` を直接使用してください。 ```swift showLineNumbers title="SwiftUI" AdaptyPaywallView( paywallConfiguration: , didFailPurchase: { product, error in // Handle purchase failure }, didFinishRestore: { profile in // Handle successful restore }, didFailRestore: { error in // Handle restore failure }, didFailRendering: { error in // Handle rendering error } ) ``` ## UIKit でペイウォールを表示する \{#present-paywalls-in-uikit\} デバイス画面にビジュアルペイウォールを表示するには、次の手順を行います。 1. `.paywallController(for:products:viewConfiguration:delegate:)` メソッドを使用して、表示したいビジュアルペイウォールを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( with: , delegate: ) ``` リクエストパラメータ: | パラメータ | 必須 | 説明 | | :----------------------- | :------- | :---------- | | **paywall configuration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` メソッドを使用します。詳細は[ペイウォールビルダーのペイウォールとその設定の取得](get-pb-paywalls)を参照してください。 | | **delegate** | 必須 | ペイウォールイベントをリッスンする `AdaptyPaywallControllerDelegate`。詳細は[ペイウォールイベントの処理](ios-handling-events)を参照してください。 | 返り値: | オブジェクト | 説明 | | :---------------------- | :--------------------------------------------------- | | **AdaptyPaywallController** | リクエストされたペイウォール画面を表すオブジェクト。 | 2. オブジェクトが正常に作成されたら、デバイスの画面に表示できます。 ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::tip Adapty SDK がモバイルアプリに統合された実際の例を見てみましょう。ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示す[サンプルアプリ](sample-apps)をご確認ください。 ::: --- # File: handle-paywall-actions --- --- title: "フローアクションへの応答 - iOS" description: "iOS アプリでペイウォールやオンボーディングフローのボタンアクションを処理し、ユーザー入力を扱う方法。" --- Adapty のフロービルダーまたはペイウォールビルダーを使用してフローやペイウォールを構築する場合、ボタンを適切に設定することが重要です。 1. [ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよび既存アクションをコードで処理する方法を説明します。 :::warning **フロー/ペイウォールのクローズと URL オープンのみ自動処理されます。** その他のボタンアクションはすべて、アプリコード側で適切な処理を実装する必要があります。 ::: :::note iOS SDKは、`AdaptySystemRequestsHandler`を通じて、プッシュ通知やカメラアクセスなどのシステム権限リクエストに応答できます。フローはまだこれらのリクエストをトリガーしないため、現時点では対応不要です。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローまたはペイウォールを閉じるボタンを追加するには: 1. ビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで `close` アクションのハンドラーを実装します。 :::info iOS SDK では、`close` アクションはデフォルトでフローまたはペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるフローを閉じると別のフローが開くようにすることもできます。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow or paywall default: break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in flowPresented = false } ) ``` ## フローとペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: フローまたはペイウォールにリンクを開くボタン(例:**Terms of use** や **Privacy policy**)を追加するには: 1. ビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 2. アプリのコードに、受け取ったURLをブラウザで開く `openURL` アクションのハンドラーを実装します。 :::info iOS SDK では、`openURL` アクションはデフォルトでURLを開く動作をします。ただし、必要に応じてコード内でこの動作を上書きすることができます。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case let .openURL(url): UIApplication.shared.open(url, options: [:]) // default behavior default: break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in flowPresented = false } ) ``` ## カスタムアクションを処理する \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ビルダーでボタンを追加し、**Custom** アクションを割り当て、ID を設定します。 2. アプリのコードに、作成したアクション ID に対応するハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます。 ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case let .custom(id): if id == "openNewPaywall" { // Display another flow or paywall } default: break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in flowPresented = false } ) ``` Adapty ペイウォールビルダーを使ってペイウォールを構築する場合、ボタンを適切に設定することが重要です: 1. [ペイウォールビルダーにボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、コード内でカスタムアクションおよび既存アクションを処理する方法を説明します。 :::warning **購入、復元、ペイウォールのクローズ、URL のオープンのみ自動的に処理されます。** その他のボタンアクションは、アプリのコードで適切に対応を実装する必要があります。 ::: ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info iOS SDK では、`close` アクションはデフォルトでペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコードでこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じることで別のペイウォールを開くようにすることも可能です。 ::: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case .close: controller.dismiss(animated: true) // default behavior break } } ``` ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: ペイウォールにリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info iOS SDKでは、`openUrl`アクションはデフォルトでURLを開く動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。 ::: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case let .openURL(url): UIApplication.shared.open(url, options: [:]) // default behavior break } } ``` ## アプリへのログイン \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコードで、ユーザーを識別する `login` アクションのハンドラーを実装します。 ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case .login: // Show a login screen let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") controller.present(loginVC, animated: true) } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当てて、IDを設定します。 2. アプリのコードで、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のペイウォールを表示するボタンを追加できます: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case let .custom(id): if id == "openNewPaywall" { // Display another paywall } } break } } ``` --- # File: ios-handling-events --- --- title: "フローとペイウォールのイベントを処理する - iOS" description: "iOSアプリでフローおよびペイウォールのイベントを処理する方法。" --- :::important このガイドでは、購入・復元・プロダクト選択・ペイウォール表示に関するイベント処理について説明します。また、ボタン操作(ペイウォールを閉じる、リンクを開くなど)の実装も必要です。詳しくは[ボタン操作の処理に関するガイド](handle-paywall-actions)をご覧ください。 ::: フローとペイウォールは、購入や購入の復元に追加のコードは不要です。ただし、アプリが反応できるイベントをいくつか生成します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や購入関連アクションの通知が含まれます。以下で、これらのイベントへの対応方法を説明します。 :::tip Adapty SDK をモバイルアプリに組み込む実際の例を見たいですか?ペイウォールの表示、購入、その他の基本的な機能を含む完全なセットアップを示す[サンプルアプリ](sample-apps)をぜひご確認ください。 ::: ## SwiftUI でのイベント処理 \{#handling-events-in-swiftui\} モバイルアプリ内のフローまたはペイウォール画面で発生するプロセスを制御・監視するには、SwiftUI の `.flow` モディファイアを使用します。 ```swift showLineNumbers title="Swift" @State var flowPresented = false var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false case let .openURL(url): // handle opening the URL (incl. for terms and privacy) default: // handle other actions } }, didSelectProduct: { product in /* Handle the event */ }, didStartPurchase: { product in /* Handle the event */ }, didFailPurchase: { product, error in /* handle the error */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false }, didFailLoadingProducts: { error in // Return `true` to retry loading return false } ) } ``` クロージャのパラメーターは必要なものだけ登録すれば、不要なものは省略できます。 | パラメータ | 必須 | 説明 | |:-----------------------|:-----|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | フローまたはペイウォール画面の表示を管理するバインディング。 | | **flowConfiguration** | 必須 | フローまたはペイウォールの視覚的な詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。詳細は[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **didFailPurchase** | 必須 | `Adapty.makePurchase()` が失敗したときに呼び出されます。 | | **didFinishRestore** | 必須 | `Adapty.restorePurchases()` が正常に完了したときに呼び出されます。 | | **didFailRestore** | 必須 | `Adapty.restorePurchases()` が失敗したときに呼び出されます。 | | **didReceiveError** | 必須 | フローでレンダリングエラーまたはフロースクリプトの実行時エラー(例:JavaScript例外、`AdaptyUIError` コード `4105`)が発生したときに呼び出されます。レンダリングエラーの場合は[Adapty サポート](mailto:support@adapty.io)にお問い合わせください。 | | **placeholderBuilder** | 任意 | フローまたはペイウォールの読み込み中にプレースホルダービューをレンダリングする関数。デフォルトは `ProgressView`。 | | **fullScreen** | 任意 | フローまたはペイウォールをフルスクリーンモードで表示するか、シートとして表示するかを決定します。デフォルトは `true`。 | | **didAppear** | 任意 | フローまたはペイウォールのビューが画面に表示されたときに呼び出されます。 | | **didDisappear** | 任意 | フローまたはペイウォールのビューが閉じられたときに呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをクリックしたときに呼び出されます。アクション ID として `close` と `openURL` が事前定義されており、その他はビルダーで設定できるカスタムIDです。 | | **didSelectProduct** | 任意 | ユーザーまたはシステムによってプロダクトが購入対象として選択されたときに呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始したときに呼び出されます。 | | **didFinishPurchase** | 任意 | `Adapty.makePurchase()` が正常に完了したときに呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | ウェブ決済のナビゲーションが完了したときに呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始したときに呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生したときに呼び出されます。`true` を返すと再読み込みを試みます。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれたときに呼び出されます。 | | **showAlertItem** | 任意 | フローまたはペイウォールの上にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングする関数。 | ## UIKitでのイベント処理 \{#handling-events-in-uikit\} UIKitアプリでは、`AdaptyFlowControllerDelegate`プロトコルを通じてイベントを処理します。`AdaptyFlowController`と`AdaptyFlowControllerDelegate`のセットアップ方法については、[フロー&ペイウォールの表示 - iOS](ios-present-paywalls)を参照してください。 このプロトコルには13のメソッドが定義されています。そのうち3つ(`didFailPurchase`、`didFinishRestoreWith`、`didFailRestoreWith`)はデフォルト実装がなく、プロトコルに準拠する際に必ず実装する必要があります。残りのメソッドはデフォルトで何も行わない実装が提供されており、カスタムの動作が必要な場合にオーバーライドできます。以下ではメソッドを目的別にグループ化して説明します。 ### ライフサイクル \{#lifecycle\} ```swift showLineNumbers title="Swift" func flowControllerDidAppear(_ controller: AdaptyFlowController) { } func flowControllerDidDisappear(_ controller: AdaptyFlowController) { } ``` これらはフローまたはペイウォールのビューが表示・非表示になったときに呼び出されます。 ### ユーザーアクション \{#user-actions\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didPerform action: AdaptyUI.Action ) { } ``` `AdaptyUI.Action` のケース: - `.close` — デフォルトの動作はコントローラーを閉じます。コントローラーを画面に残したり、追加のクリーンアップ処理を行う場合はオーバーライドしてください。 - `.openURL(url:)` — デフォルトの動作は `UIApplication.shared.open(...)` でURLを開きます。 - `.custom(id:)` — ビルダーでカスタムアクションIDが設定されたボタンがタップされたときに発火します。 ### プロダクト選択 \{#product-selection\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didSelectProduct product: AdaptyPaywallProduct ) { } ``` ユーザーまたはシステムによってプロダクトが購入対象として選択されたときに呼び出されます。プロダクトにはオファーの全情報が含まれており(v4 ではエリジビリティが自動で判定されるため、`AdaptyPaywallProductWithoutDeterminingOffer` という独立した型は存在しません)。 ### 購入イベント \{#purchase-events\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didStartPurchase product: AdaptyPaywallProduct ) { } func flowController( _ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { // Default: dismiss the controller unless the purchase was cancelled. } func flowController( _ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` `didFailPurchase` はデフォルト実装のない唯一の購入イベントです。`didFinishPurchase` は成功時にコントローラーを閉じるデフォルト実装が用意されています。カスタムの購入後処理が必要な場合のみオーバーライドしてください。 ### リストアイベント \{#restore-events\} ```swift showLineNumbers title="Swift" func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { } func flowController( _ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile ) { } func flowController( _ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError ) { } ``` `didFinishRestoreWith` と `didFailRestoreWith` にはデフォルト実装がありません。コントローラーを閉じる前に、返された `AdaptyProfile` に目的のアクセスレベルが含まれているかどうかを確認してください。 ### フローエラーとプロダクト読み込みエラー \{#flow-errors-and-product-loading-errors\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didReceiveError error: AdaptyUIError ) { } func flowController( _ controller: AdaptyFlowController, didFailLoadingProductsWith error: AdaptyError ) -> Bool { // Return `true` to retry product loading; default returns `false`. return false } func flowController( _ controller: AdaptyFlowController, didPartiallyLoadProducts failedIds: [String] ) { } ``` `didReceiveError` は、レンダリングエラーおよびフロースクリプトのランタイムエラー(JavaScript例外、`AdaptyUIError` コード `4105`)で発生します。レンダリングエラーが発生した場合は、[Adapty サポートにお問い合わせください](mailto:support@adapty.io)。読み込みエラーの場合は、`didFailLoadingProductsWith` から `true` を返すことでリトライできます。一時的なネットワーク障害に有効です。 ### Web支払いナビゲーション \{#web-payment-navigation\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, error: AdaptyError? ) { } ``` Webの支払いナビゲーションが完了した際(成功・失敗を問わず)に呼び出されます。 :::important このガイドでは、購入・復元・プロダクト選択・ペイウォール表示のイベント処理について説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の処理も実装する必要があります。詳しくは[ボタン操作のハンドリングに関するガイド](handle-paywall-actions)をご覧ください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定されたペイウォールは、購入や復元のために追加のコードは必要ありません。ただし、アプリが応答できるいくつかのイベントが生成されます。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連アクションの通知が含まれます。これらのイベントへの応答方法については、以下をご覧ください。 このガイドは、Adapty SDK v3.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。 :::tip Adapty SDK がモバイルアプリにどのように統合されるか、実際の例を見てみたいですか?[サンプルアプリ](sample-apps)では、ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを確認できます。 ::: ## SwiftUI でのイベント処理 \{#handling-events-in-swiftui\} モバイルアプリ内のペイウォール画面で発生するプロセスを制御・監視するには、SwiftUI の `.paywall` モディファイアを使用してください: ```swift showLineNumbers title="Swift" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywall: paywall, viewConfiguration: viewConfig, didPerformAction: { action in switch action { case .close: paywallPresented = false case let .openURL(url): // handle opening the URL (incl. for terms and privacy) default: // handle other actions } }, didSelectProduct: { /* Handle the event */ }, didStartPurchase: { /* Handle the event */ }, didFinishPurchase: { product, info in /* Handle the event */ }, didFailPurchase: { product, error in /* Handle the event */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { /* Handle the event */ }, didFailRestore: { /* Handle the event */ }, didFailRendering: { error in paywallPresented = false }, didFailLoadingProducts: { error in return false } ) } ``` 必要なクロージャパラメータだけを登録し、不要なものは省略できます。この場合、未使用のクロージャパラメータは作成されません。 | パラメータ | 必須 | 説明 | |:----------------------------------|:---------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | ペイウォール画面の表示を管理するバインディング。 | | **paywallConfiguration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:)` メソッドを使用してください。詳細は [ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls) を参照してください。 | | **didFailPurchase** | 必須 | エラー(支払い不可、ネットワークエラー、無効なプロダクトなど)によって購入が失敗した場合に呼び出されます。ユーザーによるキャンセルや保留中の支払いでは呼び出されません。 | | **didFinishRestore** | 必須 | 購入が正常に完了したときに呼び出されます。 | | **didFailRestore** | 必須 | 購入の復元に失敗したときに呼び出されます。 | | **didFailRendering** | 必須 | インターフェースのレンダリング中にエラーが発生した場合に呼び出されます。この場合は [Adapty サポートにお問い合わせください](mailto:support@adapty.io)。 | | **fullScreen** | 任意 | ペイウォールをフルスクリーンモードで表示するか、モーダルとして表示するかを指定します。デフォルトは `true` です。 | | **didAppear** | 任意 | ペイウォールビューが画面に表示されたときに呼び出されます。また、ユーザーがペイウォール内の [ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button) をタップしてインアプリブラウザでウェブペイウォールが開いたときにも呼び出されます。 | | **didDisappear** | 任意 | ペイウォールビューが閉じられたときに呼び出されます。また、ペイウォールからインアプリブラウザで開いた [ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button) が画面から消えたときにも呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをクリックしたときに呼び出されます。ボタンごとにアクション ID が異なります。`close` と `openURL` の 2 つのアクション ID は事前定義されており、その他はビルダーで設定できるカスタムのものです。 | | **didSelectProduct** | 任意 | プロダクトが(ユーザーまたはシステムによって)購入のために選択された場合に呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始したときに呼び出されます。 | | **didFinishPurchase** | 任意 | 購入が正常に完了したときに呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | 購入のために [ウェブペイウォール](web-paywall) を開こうとした後(成功・失敗を問わず)に呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始したときに呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生したときに呼び出されます。読み込みを再試行する場合は `true` を返してください。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれたときに呼び出されます。 | | **showAlertItem** | 任意 | ペイウォールの上部にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングするための関数。 | | **placeholderBuilder** | 任意 | ペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。 | ## UIKit でのイベント処理 \{#handling-events-in-uikit\} モバイルアプリのペイウォール画面で発生するプロセスを制御・監視するには、`AdaptyPaywallControllerDelegate` のメソッドを実装してください。 ### ユーザー生成イベント \{#user-generated-events\} #### プロダクトの選択 \{#product-selection\} ユーザーが購入するプロダクトを選択すると、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer ) { } ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController(_ controller: AdaptyPaywallController, didStartPurchase product: AdaptyPaywallProduct) { } ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
オブザーバーモードでは呼び出されません。詳細については、[iOS - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 #### ウェブペイウォールを使用して購入を開始した \{#started-purchase-using-a-web-paywall\} ユーザーが[ウェブペイウォール](web-paywall)を使って購入プロセスを開始すると、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, shouldContinueWebPaymentNavigation product: AdaptyPaywallProduct ) { } ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### 購入成功またはキャンセル \{#successful-or-canceled-purchase\} 購入が成功した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFinishPurchase product: AdaptyPaywallProductWithoutDeterminingOffer, purchaseResult: AdaptyPurchaseResult ) { } } ```
イベントの例(クリックして展開) ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Cancelled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "cancelled" } } ```
この場合は、ペイウォール画面を閉じることをお勧めします。 オブザーバーモードでは呼び出されません。詳細については、[iOS - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode) を参照してください。 #### 購入失敗 \{#failed-purchase\} 購入がエラーにより失敗した場合、このメソッドが呼び出されます。対象となるのは、StoreKit のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、システムエラーです。なお、ユーザーによるキャンセルは `didFinishPurchase` がキャンセル結果として呼び出され、このメソッドはトリガーされません。保留中の支払いについても同様です。 ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError ) { } ```
イベント例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ```
オブザーバーモードでは呼び出されません。詳細は [iOS - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode) をご覧ください。 #### Webペイウォールによる購入の失敗 \{#failed-purchase-using-a-web-paywall\} `Adapty.openWebPaywall()` が失敗した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFailWebPaymentNavigation product: AdaptyPaywallProduct, error: AdaptyError ) { } ```
イベント例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ```
#### 購入の復元に成功した場合 \{#successful-restore\} 購入の復元が成功した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFinishRestoreWith profile: AdaptyProfile ) { } ```
イベントの例(クリックして展開) ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ```
推奨する方法は、必要な `accessLevel` がある場合にスクリーンを閉じることです。確認方法については、[サブスクリプションのステータス](subscription-status)をご参照ください。 #### 復元の失敗 \{#failed-restore\} 購入の復元に失敗した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailRestoreWith error: AdaptyError ) { } ```
イベント例(クリックして展開) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクトの配列を渡さなかった場合、AdaptyUI はサーバーから必要なオブジェクトを自動的に取得します。この操作が失敗した場合、AdaptyUI は以下のメソッドを呼び出してエラーを通知します: ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailLoadingProductsWith error: AdaptyError ) -> Bool { return true } ```
イベント例(クリックして展開) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
`true` を返すと、AdaptyUI は 2 秒後にリクエストを再試行します。 #### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生した場合、このメソッドで通知されます: ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailRenderingWith error: AdaptyError ) { } ```
イベント例(クリックして展開) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ```
通常、このようなエラーは発生しないはずですので、もし見かけた場合はお知らせください。
--- # File: ios-use-fallback-paywalls --- --- title: "iOS - フォールバックを使用する" description: "ユーザーがオフラインの場合や Adapty サーバーが利用できない場合の処理方法" --- スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} 1. フォールバック JSON ファイルをプロジェクトバンドルに追加します。XCode で **File** メニューを開き、**Add Files to "YourProjectName"** を選択してください。 2. 対象のフロー、ペイウォール、またはオンボーディングを取得する**前に** `.setFallback` メソッドを呼び出してください。 ```swift showLineNumbers do { if let urlPath = Bundle.main.url(forResource: fileName, withExtension: "json") { try await Adapty.setFallback(fileURL: urlPath) } } catch { // handle the error } ``` ```swift showLineNumbers if let url = Bundle.main.url(forResource: "ios_fallback", withExtension: "json") { Adapty.setFallback(fileURL: url) } ``` パラメーター: | パラメーター | 説明 | | :---------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **fileURL** | フォールバック設定ファイルへのパス。 | --- # File: localizations-and-locale-codes --- --- title: "iOS SDKでローカライゼーションとロケールコードを使用する" description: "iOSアプリでグローバルなユーザーにリーチするために、アプリのローカライゼーションとロケールコードを管理します。" --- ## これが重要な理由 \{#why-this-is-important\} ロケールコードが関係するシナリオはいくつかあります。たとえば、アプリの現在のローカライゼーションに対応する正しいペイウォールを取得しようとする場合などです。 ロケールコードは複雑で、プラットフォームによって異なることがあります。そのため、Adaptyがサポートするすべてのプラットフォームに対して独自の内部標準を設けています。ただし、コードが複雑であるため、サーバーに何を送信しているのか、そして次に何が起こるのかを正確に把握することが重要です。これにより、期待通りの結果を常に受け取ることができます。 ## Adaptyのロケールコード標準 \{#locale-code-standard-at-adapty\} ロケールコードについて、Adaptyはわずかに変更した [BCP 47標準](https://en.wikipedia.org/wiki/IETF_language_tag) を使用しています。各コードはハイフンで区切られた小文字のサブタグで構成されています。例:`en`(英語)、`pt-br`(ポルトガル語(ブラジル))、`zh`(簡体字中国語)、`zh-hant`(繁体字中国語)。 ## ロケールコードのマッチング \{#locale-code-matching\} Adaptyがクライアント側SDKからロケールコード付きの呼び出しを受け取り、ペイウォールの対応するローカライゼーションを検索する際、以下の処理が行われます: 1. 受信したロケール文字列が小文字に変換され、すべてのアンダースコア(`_`)がハイフン(`-`)に置き換えられます 2. 完全に一致するロケールコードのローカライゼーションを検索します 3. 一致するものが見つからない場合、最初のハイフンの前の部分文字列(`pt-br`の場合は`pt`)を取り出し、一致するローカライゼーションを検索します 4. それでも一致するものが見つからない場合、デフォルトの`en`ローカライゼーションを返します これにより、`'pt_BR'`を送信したiOSデバイス、`pt-BR`を送信したAndroidデバイス、`pt-br`を送信した別のデバイスは、すべて同じ結果を受け取ります。 ## ローカライゼーションの実装:推奨方法 \{#implementing-localizations-recommended-way\} ローカライゼーションについて検討しているなら、すでにプロジェクト内のローカライズされた文字列ファイルを扱っているでしょう。その場合、各ローカライゼーションに対応するファイルに、意図したAdaptyロケールコードをキーと値のペアとして配置することをお勧めします。そして、次のようにSDKを呼び出す際にそのキーの値を取得します: ```swift showLineNumbers // 1. Modify your Localizable.strings files /* Localizable.strings - Spanish */ adapty_paywalls_locale = "es"; /* Localizable.strings - Portuguese (Brazil) */ adapty_paywalls_locale = "pt-br"; // 2. Extract and use the locale code let locale = NSLocalizedString("adapty_paywalls_locale", comment: "") // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` これにより、アプリのすべてのユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。 ## ローカライゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} ロケールコードをすべてのローカライゼーションに明示的に定義しなくても、類似した(ただし同一ではない)結果を得ることができます。その場合、プラットフォームが提供する他のオブジェクトからロケールコードを抽出することになります。例: ```swift showLineNumbers let locale = Locale.current.identifier // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` いくつかの理由から、このアプローチは推奨しません: 1. iOSでは、優先言語と現在のロケールは同一ではありません。ローカライゼーションを正しく選択したい場合、Appleのロジックに依存するか(ローカライズされた文字列ファイルを使用する推奨アプローチでは自動的に機能します)、それを再現する必要があります。 2. Adaptyのサーバーが何を受け取るかを予測するのが難しいです。たとえばiOSでは、デバイスから`ar_OM@numbers='latn'`のようなロケールを取得してサーバーに送信することがあります。この場合、期待していた`ar-om`ローカライゼーションではなく、`ar`が返ってくる可能性があり、意図しない結果になることがあります。 このアプローチを使用する場合は、関連するすべてのユースケースを網羅していることを確認してください。 --- # File: ios-troubleshoot-paywall-builder --- --- title: "Troubleshoot Paywall Builder in iOS SDK" description: "Troubleshoot Paywall Builder in iOS SDK" --- このガイドでは、iOS SDK でAdapty ペイウォールビルダーを使用して作成したペイウォールに関する一般的な問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: `getPaywallConfiguration` メソッドがペイウォール設定を取得できない。 **原因**: ペイウォールビルダーでデバイス表示が有効になっていない。 **解決策**: ペイウォールビルダーの **Show on device** トグルを有効にしてください。 ## ペイウォールの表示回数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールの表示回数が想定の2倍になっている。 **原因**: コード内で `logShowFlow`(iOS SDK v4+)/ `logShowPaywall` を呼び出している可能性があります。ペイウォールビルダーやフロービルダーで作成したペイウォール・フローを使用している場合、アナリティクスは自動的に記録されるため、このメソッドを呼び出すと表示回数が重複します。 **解決策**: ペイウォールビルダーまたはフロービルダーを使用している場合は、コード内で `logShowFlow`(iOS SDK v4+)/ `logShowPaywall` を呼び出していないことを確認してください。 ## その他の問題 \{#other-issues\} **問題**: 上記に該当しないペイウォールビルダー関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](ios-sdk-migration-guides)を参照し、SDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで修正されています。 --- # File: ios-present-paywall-builder-paywalls-in-observer-mode --- --- title: "iOS SDK のオブザーバーモードでペイウォールビルダーのペイウォールを表示する" description: "オブザーバーモードで PB ペイウォールを表示して詳細なインサイトを得る方法を学びましょう。" --- ペイウォールビルダーを使ってペイウォールをカスタマイズした場合、モバイルアプリのコードでユーザーへの表示処理を別途実装する必要はありません。このようなペイウォールには、表示内容と表示方法の両方が含まれています。 :::warning このセクションは[オブザーバーモード](observer-vs-full-mode)専用です。オブザーバーモードを使用していない場合は、[iOS - ペイウォールビルダーのペイウォールを表示する](ios-present-paywalls)を参照してください。 :::
フローの表示を始める前に(クリックして展開) 1. Adapty と [App Store](initial_ios) の初期連携を設定します。 2. Adapty SDK をインストールして設定します。`observerMode` パラメータを `true` に設定してください。[iOS SDK インストールガイド](sdk-installation-ios#activate-adapty-module-of-adapty-sdk)を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. [ビルダーでフローまたはペイウォールを設定](create-paywall)し、プロダクトを割り当てます。 5. [プレースメントを作成し、フローまたはペイウォールを割り当て](create-placement)ます。 6. モバイルアプリのコードで[フローとその設定を取得](get-pb-paywalls)します。

1. `AdaptyObserverModeResolver` オブジェクトを実装します。プロトコルは SDK v3 と同じです。オブザーバーモード自体はフローとペイウォールのレンダリング間で変わりません。 ```swift showLineNumbers title="Swift" func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // call onStartPurchase / onFinishPurchase to notify AdaptyUI about the purchase progress } func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, onFinishRestore: @escaping () -> Void) { // call onStartRestore / onFinishRestore to notify AdaptyUI about the restore progress } ``` 2. `observerModeResolver:` パラメータにリゾルバを渡して、フロー設定オブジェクトを作成します。 ```swift showLineNumbers title="Swift" do { let flowConfiguration = try await AdaptyUI.getFlowConfiguration( forFlow: flow, observerModeResolver: ) } catch { // handle the error } ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------- | | **forFlow** | 必須 | `Adapty.getFlow(placementId:)` で取得した `AdaptyFlow` オブジェクト。[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **observerModeResolver** | 必須 | 上記で実装した `AdaptyObserverModeResolver`。 | 3. `AdaptyUI.flowController(with:delegate:)` を使ってフローコントローラーを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualFlow = try AdaptyUI.flowController( with: flowConfiguration, delegate: ) ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------- | | **flowConfiguration** | 必須 | フローのビジュアル詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **delegate** | 必須 | フローイベントを受け取るための `AdaptyFlowControllerDelegate`。[フロー&ペイウォールイベントの処理](ios-handling-events)を参照してください。 | 返り値: | オブジェクト | 説明 | | :------------------- | :----------------------------------------------------- | | AdaptyFlowController | リクエストされたフロー画面を表すオブジェクト。 | 4. コントローラーを表示します。 ```swift showLineNumbers title="Swift" present(visualFlow, animated: true) ``` :::warning [ペイウォールを購入トランザクションに紐付ける](report-transactions-observer-mode)のを忘れないようにしてください。紐付けを行わないと、Adapty は購入元のペイウォールを特定できません。 ::: SwiftUI では、リゾルバを指定してフロー設定を取得し、`.flow` モディファイアに渡します。 ```swift showLineNumbers title="SwiftUI" @State var flowPresented = false @State var flowConfiguration: AdaptyUI.FlowConfiguration? var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) .task { flowConfiguration = try? await AdaptyUI.getFlowConfiguration( forFlow: flow, observerModeResolver: ) } } ``` `getFlowConfiguration` の `observerModeResolver:` パラメータにより、レンダリングされたフローがカスタム購入ロジックに従って動作します。モディファイア自体はフルモードと同じコールバックを使用します。 :::warning [ペイウォールを購入トランザクションに紐付ける](report-transactions-observer-mode)のを忘れないようにしてください。紐付けを行わないと、Adapty は購入元のペイウォールを特定できません。 :::
ペイウォールの表示を始める前に(クリックして展開) 1. Adapty と [Google Play](initial-android) および [App Store](initial_ios) の初期連携を設定します。 2. Adapty SDK をインストールして設定します。`observerMode` パラメータを `true` に設定してください。[iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk) のフレームワーク別手順を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. [ペイウォールを設定してプロダクトを割り当て](create-paywall)、Adapty ダッシュボードのペイウォールビルダーでカスタマイズします。 5. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを割り当て](create-placement)ます。 6. モバイルアプリのコードで[ペイウォールビルダーのペイウォールとその設定を取得](get-pb-paywalls)します。

1. `AdaptyObserverModeResolver` オブジェクトを実装します。 ```swift showLineNumbers title="Swift" func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, onFinishRestore: @escaping () -> Void) { // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore } ``` `observerMode(didInitiatePurchase:onStartPurchase:onFinishPurchase:)` イベントは、ユーザーが購入を開始したことを通知します。このコールバックに応じて、カスタム購入フローをトリガーできます。 `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)` イベントは、ユーザーが復元を開始したことを通知します。このコールバックに応じて、カスタム復元フローをトリガーできます。 また、購入または復元の進行状況を AdaptyUI に通知するために、以下のコールバックを呼び出すのを忘れないようにしてください。これはローダーの表示など、ペイウォールの正常な動作に必要です。 | コールバック | 説明 | | :----------------- | :------------------------------------------------------------------------------- | | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出します。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出します。 | | onStartRestore() | 復元が開始されたことを AdaptyUI に通知するために呼び出します。 | | onFinishRestore() | 復元が完了したことを AdaptyUI に通知するために呼び出します。 | 2. ペイウォール設定オブジェクトを作成します。 ```swift showLineNumbers title="Swift" do { let paywallConfiguration = try AdaptyUI.getPaywallConfiguration( forPaywall: , observerModeResolver: ) } catch { // handle the error } ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall** | 必須 | 対象ペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **ObserverModeResolver** | 必須 | 前の手順で実装した `AdaptyObserverModeResolver` オブジェクト。 | 3. `.paywallController(for:products:viewConfiguration:delegate:)` メソッドを使って、表示したいビジュアルペイウォールを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( with: , delegate: ) ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall Configuration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` メソッドを使用してください。詳細は[ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls)を参照してください。 | | **Delegate** | 必須 | ペイウォールイベントを受け取るための `AdaptyPaywallControllerDelegate`。詳細は[ペイウォールイベントの処理](ios-handling-events)を参照してください。 | 返り値: | オブジェクト | 説明 | | :---------------------- | :--------------------------------------------------- | | AdaptyPaywallController | リクエストされたペイウォール画面を表すオブジェクト。 | オブジェクトの作成に成功したら、次のように表示できます。 ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::warning [ペイウォールを購入トランザクションに紐付ける](report-transactions-observer-mode)のを忘れないようにしてください。紐付けを行わないと、Adapty は購入元のペイウォールを特定できません。 ::: デバイス画面にビジュアルペイウォールを表示するには、SwiftUI で `.paywall` モディファイアを使用します。 ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywallConfiguration: , didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } ) } ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall Configuration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` メソッドを使用してください。詳細は[ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls)を参照してください。 | | **Products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **TagResolver** | 任意 | カスタムタグとその解決値の辞書を定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツ用の特定の文字列に動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | | **ObserverModeResolver** | 任意 | 前の手順で実装した `AdaptyObserverModeResolver` オブジェクト。 | クロージャパラメータ: | クロージャパラメータ | 説明 | | :------------------- | :-------------------------------------------------------------------------------- | | **didFinishRestore** | `Adapty.restorePurchases()` が成功した場合に呼び出されます。 | | **didFailRestore** | `Adapty.restorePurchases()` が失敗した場合に呼び出されます。 | | **didFailRendering** | インターフェースのレンダリング中にエラーが発生した場合に呼び出されます。 | その他のクロージャパラメータについては、[iOS - イベントの処理](ios-handling-events)を参照してください。 :::warning [ペイウォールを購入トランザクションに紐付ける](report-transactions-observer-mode)のを忘れないようにしてください。紐付けを行わないと、Adapty は購入元のペイウォールを特定できません。 :::
ペイウォールの表示を始める前に(クリックして展開) 1. Adapty と [Google Play](initial-android) および [App Store](initial_ios) の初期連携を設定します。 1. Adapty SDK をインストールして設定します。`observerMode` パラメータを `true` に設定してください。[iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk)、[Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk) のフレームワーク別手順を参照してください。 2. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 3. [ペイウォールを設定してプロダクトを割り当て](create-paywall)、Adapty ダッシュボードのペイウォールビルダーでカスタマイズします。 4. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを割り当て](create-placement)ます。 5. モバイルアプリのコードで[ペイウォールビルダーのペイウォールとその設定を取得](get-pb-paywalls)します。

1. `AdaptyObserverModeDelegate` オブジェクトを実装します。 ```swift showLineNumbers title="Swift" func paywallController(_ controller: AdaptyPaywallController, didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } ``` `paywallController(_:didInitiatePurchase:onStartPurchase:onFinishPurchase:)` イベントは、ユーザーが購入を開始したことを通知します。このイベントに応じて、カスタム購入フローをトリガーできます。 また、購入の進行状況を AdaptyUI に通知するために、以下のコールバックを呼び出すのを忘れないようにしてください。これはローダーの表示など、ペイウォールの正常な動作に必要です。 | コールバック | 説明 | | :--------------- | :------------------------------------------------------------------------------- | | onStartPurchase | 購入が開始されたことを AdaptyUI に通知するために呼び出します。 | | onFinishPurchase | 購入が完了したことを AdaptyUI に通知するために呼び出します。 | 2. `.paywallController(for:products:viewConfiguration:delegate:observerModeDelegate:)` メソッドを使って、表示したいビジュアルペイウォールを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( for: , products: , viewConfiguration: , delegate: observerModeDelegate: ) ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :----------------------------------------------------------- | | **Paywall** | 必須 | 対象ペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **Products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **ViewConfiguration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.LocalizedViewConfiguration` オブジェクト。`AdaptyUI.getViewConfiguration(paywall:locale:)` メソッドを使用してください。詳細は[ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls)を参照してください。 | | **Delegate** | 必須 | ペイウォールイベントを受け取るための `AdaptyPaywallControllerDelegate`。詳細は[ペイウォールイベントの処理](ios-handling-events)を参照してください。 | | **ObserverModeDelegate** | 必須 | 前の手順で実装した `AdaptyObserverModeDelegate` オブジェクト。 | | **TagResolver** | 任意 | カスタムタグとその解決値の辞書を定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツ用の特定の文字列に動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | 返り値: | オブジェクト | 説明 | | :---------------------- | :--------------------------------------------------- | | AdaptyPaywallController | リクエストされたペイウォール画面を表すオブジェクト。 | オブジェクトの作成に成功したら、次のように表示できます。 ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::warning [ペイウォールを購入トランザクションに紐付ける](report-transactions-observer-mode)のを忘れないようにしてください。紐付けを行わないと、Adapty は購入元のペイウォールを特定できません。 ::: デバイス画面にビジュアルペイウォールを表示するには、SwiftUI で `.paywall` モディファイアを使用します。 ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywall: , configuration: , didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false }, observerModeDidInitiatePurchase: { product, onStartPurchase, onFinishPurchase in // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase }, ) } ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :---------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall** | 必須 | 対象ペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **Product** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **Configuration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.LocalizedViewConfiguration` オブジェクト。`AdaptyUI.getViewConfiguration(paywall:locale:)` メソッドを使用してください。詳細は[ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls)を参照してください。 | | **TagResolver** | 任意 | カスタムタグとその解決値の辞書を定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツ用の特定の文字列に動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | クロージャパラメータ: | クロージャパラメータ | 説明 | | :---------------------------------- | :-------------------------------------------------------------------------------- | | **didFinishRestore** | `Adapty.restorePurchases()` が成功した場合に呼び出されます。 | | **didFailRestore** | `Adapty.restorePurchases()` が失敗した場合に呼び出されます。 | | **didFailRendering** | インターフェースのレンダリング中にエラーが発生した場合に呼び出されます。 | | **observerModeDidInitiatePurchase** | ユーザーが購入を開始したときに呼び出されます。 | その他のクロージャパラメータについては、[iOS - イベントの処理](ios-handling-events)を参照してください。 :::warning [ペイウォールを購入トランザクションに紐付ける](report-transactions-observer-mode)のを忘れないようにしてください。紐付けを行わないと、Adapty は購入元のペイウォールを特定できません。 :::
--- # File: ios-quickstart-manual --- --- title: "iOS SDKのカスタムペイウォールで購入を有効にする" description: "Adapty SDKをカスタムiOSペイウォールに統合してアプリ内課金を有効にします。" --- このガイドでは、Adaptyをカスタムペイウォールに統合する方法を説明します。ペイウォールの実装を完全にコントロールしながら、Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を行います。 :::important **このガイドはカスタムペイウォールを実装する開発者向けです。** 購入を最も簡単に有効にしたい場合は、[Adapty フローBuilder](ios-quickstart-paywalls)を使用してください。フローBuilderを使えば、ノーコードのビジュアルエディターでフローを作成でき、Adaptyが購入ロジックをすべて自動的に処理します。アプリを再公開せずにさまざまなデザインをテストできます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトのセットアップ \{#set-up-products\} アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります: - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定。Adaptyでは、プロダクトを取得する唯一の方法がペイウォールですが、この設計によりアプリコードを変更せずにプロダクト、価格、オファーを変更できます。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings`など)。ダッシュボードでプレースメントにペイウォールを設定し、コード内でプレースメントIDを使ってリクエストします。これにより、A/B テストの実施やユーザーごとに異なるペイウォールの表示が簡単になります。 カスタムペイウォールを使用する場合でも、これらの概念を理解しておくことが重要です。基本的に、アプリで販売するプロダクトを管理するための仕組みです。 カスタムペイウォールを実装するには、**ペイウォール**を作成して**プレースメント**に追加する必要があります。この設定によりプロダクトを取得できるようになります。ダッシュボードで何をする必要があるかを理解するには、[こちら](quickstart)のクイックスタートガイドに従ってください。 ### ユーザーの管理 \{#manage-users\} バックエンド認証の有無にかかわらず作業できます。 ただし、Adapty SDKは匿名ユーザーと識別済みユーザーを異なる方法で処理します。[識別クイックスタートガイド](ios-quickstart-identify)を読んで、その詳細を理解し、ユーザーを適切に処理していることを確認してください。 ## ステップ1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、次の手順が必要です: 1. `getFlow`メソッドに[プレースメント](placements)IDを渡して`flow`オブジェクトを取得します。 2. `getPaywallProducts`メソッドを使ってこのフローのプロダクト配列を取得します。 ```swift func loadPaywall() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let products = try await Adapty.getPaywallProducts(flow: flow) // Use products to build your custom paywall UI } catch { // Handle the error } } ``` ```swift func loadPaywall() { Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): Adapty.getPaywallProducts(flow: flow) { result in switch result { case let .success(products): // Use products to build your custom paywall UI case let .failure(error): // Handle the error } } case let .failure(error): // Handle the error } } } ``` ## ステップ2. 購入を受け付ける \{#step-2-accept-purchases\} ユーザーがカスタムペイウォールのプロダクトをタップしたら、選択したプロダクトを引数に`makePurchase`メソッドを呼び出します。これにより購入フローが処理され、更新されたプロファイルが返されます。 ```swift func purchaseProduct(_ product: AdaptyPaywallProduct) async { do { let purchaseResult = try await Adapty.makePurchase(product: product) switch purchaseResult { case .userCancelled: // User canceled the purchase break case .pending: // Purchase is pending (e.g., awaiting parental approval) break case let .success(profile, transaction): // Purchase successful, profile updated break } } catch { // Handle the error } } ``` ```swift func purchaseProduct(_ product: AdaptyPaywallProduct) { Adapty.makePurchase(product: product) { result in switch result { case let .success(purchaseResult): switch purchaseResult { case .userCancelled: // User canceled the purchase break case .pending: // Purchase is pending (e.g., awaiting parental approval) break case let .success(profile, transaction): // Purchase successful, profile updated break } case let .failure(error): // Handle the error } } } ``` ## ステップ3. 購入を復元する \{#step-3-restore-purchases\} Appleは、サブスクリプションのあるすべてのアプリに対して、ユーザーが購入を復元できる手段を提供することを求めています。Apple IDでログインした際に購入は自動的に復元されますが、それでもアプリに復元ボタンを実装する必要があります。 ユーザーが復元ボタンをタップしたら`restorePurchases`メソッドを呼び出します。これにより購入履歴がAdaptyと同期され、更新されたプロファイルが返されます。 ```swift func restorePurchases() async { do { let profile = try await Adapty.restorePurchases() // Restore successful, profile updated } catch { // Handle the error } } ``` ```swift func restorePurchases() { Adapty.restorePurchases { result in switch result { case let .success(profile): // Restore successful, profile updated case let .failure(error): // Handle the error } } } ``` ## 次のステップ \{#next-steps\} --- no_index: true --- import Callout from '../../../components/Callout.astro'; ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ペイウォールはアプリに表示する準備ができました。[サンドボックスモードで購入をテスト](test-purchases-in-sandbox)して、ペイウォールからテスト購入を完了できることを確認してください。 次に、[ユーザーが購入を完了したかどうかを確認](ios-check-subscription-status)して、ペイウォールを表示するか有料機能へのアクセスを許可するかを判断してください。 --- # File: fetch-paywalls-and-products --- --- title: "iOS SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "AdaptyのiOS SDKでペイウォールとプロダクトを取得し、ユーザーの収益化を向上させます。" --- リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。**Flow Builder** または **Paywall Builder** でカスタマイズされたフローやペイウォールの取得方法については、[iOS](get-pb-paywalls)、[Android](android-get-pb-paywalls)、[React Native](react-native-get-pb-paywalls)、[Flutter](flutter-get-pb-paywalls)、および [Unity](unity-get-pb-paywalls)をご覧ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでフローとプロダクトの取得を開始する前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[フローまたはペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに[Adapty SDK をインストール](sdk-installation-ios)する。
## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)は App Store と Google Play 両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはフローやペイウォールに統合され、モバイルアプリの特定のプレースメントに表示できます。 プロダクトを表示するには、`getFlow` メソッドを使って[プレースメント](placements)のいずれかから `AdaptyFlow` を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードすべきIDはプレースメントIDのみです。フローはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変更される可能性があります。アプリはこれらの変更を動的に処理する必要があります。つまり、今日フローが2つのプロダクトを返し、明日3つを返す場合でも、コードを変更せずにすべてを表示できなければなりません。 ::: ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") // the requested flow } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。この設定を推奨します。ユーザーが常に最新のデータを取得できるためです。

ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用することを検討してください。キャッシュが存在する場合はキャッシュデータを返します。この場合、最新データが得られないことがありますが、接続状況にかかわらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために活用しても安全です。

キャッシュはアプリの再起動後も保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。

Adapty SDK はフローとペイウォールを 2 つのレイヤーで保存しています。上記の定期更新されるキャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、フローとペイウォールをより速く取得するために CDN を使用し、CDN が利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。

| | **loadTimeout** | デフォルト: 5 秒 |

このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。

まれに、内部で複数のリクエストが行われるため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトする場合があります。

| :::note v4 では、`locale` パラメータは `getFlow` から移動し、`getFlowConfiguration`(AdaptyUI でレンダリングする場合のみ使用)に設定するようになりました。カスタムペイウォールの場合、利用可能なすべてのロケールは `flow.remoteConfigs` にまとめて返されるため、ユーザーのデバイスまたはアプリの設定に合ったロケールを選んでください。 ::: プロダクトIDをハードコードしないでください!フローはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特典(無料トライアルなど)は随時変更される可能性があります。こうしたシナリオに対応できるようコードを作成してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはそれら2つを表示します。しかし後に3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できる必要があります。ハードコードが必要なのはプレースメントIDだけです。 レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | `AdaptyFlow` オブジェクト。プレースメント、識別子(`id`、`variationId`)、名前、設定済みロケールごとのエントリを含む `remoteConfigs` 配列、および `hasViewConfiguration` フラグを保持します。フローのプロダクトを取得するには `getPaywallProducts(flow:)` を呼び出してください。 | ## プロダクトを取得する \{#fetch-products\} フローを取得したら、そのフローに対応するプロダクトの配列を取得できます: ```swift showLineNumbers do { let products = try await Adapty.getPaywallProducts(flow: flow) // the requested products array } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywallProducts(flow: flow) { result in switch result { case let .success(products): // the requested products array case let .failure(error): // handle the error } } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他いくつかのプロパティを含みます。 | 独自のペイウォールデザインを実装する場合、[`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |---|---| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用してください。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づきます。 | | **Price** | ローカライズされた価格を表示するには、`product.localizedPrice` を使用してください。このローカライズはデバイスのロケール情報に基づきます。また、`product.price` で価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.currencySymbol` を使用してください。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.localizedSubscriptionPeriod` を使用してください。このローカライズはデバイスのロケールに基づきます。サブスクリプション期間をプログラムで取得するには、`product.subscriptionPeriod` を使用してください。そこから `unit` 列挙型にアクセスして期間の長さ(day、week、month、year、または unknown)を取得できます。`numberOfUnits` の値で期間単位の数を取得できます。たとえば、四半期ごとのサブスクリプションの場合、`unit` プロパティには `.month`、`numberOfUnits` プロパティには `3` が表示されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれていることを示すバッジやインジケーターを表示するには、`product.subscriptionOffer` プロパティを確認してください。このオブジェクトには以下の便利なプロパティがあります:
• `offerType`:`introductory`、`promotional`、`winBack` の値を持つ列挙型。無料トライアルや初期割引サブスクリプションは `introductory` タイプになります。
• `price`:割引価格を数値で表したもの。無料トライアルの場合は `0` を確認してください。
• `localizedPrice`:ユーザーのロケールに合わせてフォーマットされた割引価格。
• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列。たとえば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。
• `subscriptionPeriod`:オファー期間の個別の詳細はこのプロパティで取得することもできます。オファーに対してもサブスクリプション期間と同様に機能します。
• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | :::note v4では、`getPaywallProducts(flow:)` が返すすべてのプロダクトにオファーの適格性情報が含まれています。v3にあった `getPaywallProductsWithoutDeterminingOffer` の個別呼び出しは削除されました。 ::: ## デフォルトオーディエンスフローでフロー取得を高速化する \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ瞬時に取得されるため、この処理を高速化することを特に気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が不安定な場合、フローの取得に想定以上の時間がかかることがあります。そのような状況では、何も表示しないよりもデフォルトフローを表示して、スムーズなユーザー体験を確保したい場合があるでしょう。 これに対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けのフローを取得します。ただし、推奨されるアプローチは `getFlow` メソッドを使用してフローを取得することである点を理解しておくことが重要です。詳細は上記の[フロー情報の取得](fetch-paywalls-and-products#fetch-flow-information)セクションを参照してください。 :::warning `getFlow` の使用を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるフローを表示する必要がある場合、課題に直面する可能性があります。現在の(レガシー)バージョンに対応したフローを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないフローで問題に遭遇することを許容するかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じフローを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくターゲティングを含む)が失われます。 これらのデメリットを受け入れてでもフローの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。それ以外の場合は、[上記](fetch-paywalls-and-products#fetch-flow-information)の `getFlow` を使用してください。 ::: ```swift showLineNumbers do { let flow = try await Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") // the requested flow } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方式はユーザーが常に最新のデータを取得できるため、推奨しています。

ただし、ユーザーがネットワークの不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュされたデータを返します。この場合、最新のデータが届かない可能性はありますが、ネットワーク状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために活用しても安全です。

なお、キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリアした場合にのみ削除されます。

|
リモートコンフィグとカスタムペイウォールを表示する前に、それらに関する情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズされたペイウォールの取得方法については、[iOS](get-pb-paywalls)、[Android](android-get-pb-paywalls)、[React Native](react-native-get-pb-paywalls)、[Flutter](flutter-get-pb-paywalls)、[Unity](unity-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでペイウォールとプロダクトの取得を開始する前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトをペイウォールに追加](create-paywall)してください。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールをプレースメントに追加](create-placement)してください。 4. モバイルアプリに [Adapty SDK をインストール](sdk-installation-ios)してください。
## ペイウォール情報の取得 \{#fetch-paywall-information\} Adapty では、[プロダクト](product)はApp StoreとGoogle Playの両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはペイウォールに統合されており、モバイルアプリの特定のプレースメントで表示できます。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)のいずれかから[ペイウォール](paywalls)を取得する必要があります。 :::important **プロダクト ID をハードコードしないでください。** ハードコードするのはプレースメント ID のみにしてください。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更に動的に対応する必要があります。今日は 2 つのプロダクトを返すペイウォールが明日は 3 つを返すことになっても、コードを変更せずにすべて表示できるようにしてください。 ::: ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語を表し、2番目のサブタグは地域を表します。

例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。

ロケールコードの詳細とその推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。

| | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを取得できるからです。

ただし、ユーザーが不安定なインターネット環境を使用していると思われる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在すればそれを返すことを検討してください。この場合、ユーザーは最新のデータを取得できないことがありますが、インターネット接続が不安定な場合でも読み込み時間が短縮されます。キャッシュは定期的に更新されるため、ネットワークリクエストを避けるためにセッション中に使用しても安全です。

キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップによってのみ消去されます。

Adapty SDK はペイウォールを2つの層に保存します:上記の定期的に更新されるキャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより速く取得するために CDN を使用し、CDN が到達不能な場合に備えてスタンドアローンのフォールバックサーバーも使用しています。このシステムは、インターネット接続が限られている状況でも信頼性を確保しながら、常に最新バージョンのペイウォールを取得できるように設計されています。

| | **loadTimeout** | デフォルト: 5秒 |

このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。

まれに、このメソッドが `loadTimeout` で指定した時間よりもわずかに遅くタイムアウトすることがあります。これは、処理内部で複数のリクエストが実行される場合があるためです。

| プロダクトIDをハードコードしないでください!ペイウォールはリモートで設定されるため、利用可能なプロダクト、プロダクト数、特典(無料トライアルなど)は随時変更される可能性があります。これらのシナリオに対応できるよう、コードを実装してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはその2つのプロダクトを表示する必要があります。その後3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できなければなりません。ハードコードが必要なのはプレースメントIDのみです。 レスポンスのパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォールの識別子、リモートコンフィグなどのプロパティを含む [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) オブジェクト。 | ## プロダクトを取得する \{#fetch-products\} ペイウォールを取得したら、それに対応するプロダクトの配列をクエリできます: ```swift showLineNumbers do { let products = try await Adapty.getPaywallProducts(paywall: paywall) // the requested products array } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywallProducts(paywall: paywall) { result in switch result { case let .success(products): // 取得したプロダクトの配列 case let .failure(error): // エラーを処理する } } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトのリストで、プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティを含みます。 | 独自のペイウォールデザインを実装する際、[`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。以下によく使われるプロパティを示しますが、利用可能なすべてのプロパティの詳細はリンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **タイトル** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **価格** | ローカライズされた価格を表示するには、`product.localizedPrice` を使用します。このローカライズはデバイスのロケール情報に基づいています。`product.price` を使用すると価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.currencySymbol` を使用します。 | | **サブスクリプション期間** | 期間(週、月、年など)を表示するには、`product.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づいています。サブスクリプション期間をプログラムで取得するには、`product.subscriptionPeriod` を使用します。そこから `unit` 列挙型にアクセスして長さ(day、week、month、year、または unknown)を取得できます。`numberOfUnits` の値は期間単位の数を返します。たとえば四半期サブスクリプションの場合、unit プロパティには `.month`、numberOfUnits プロパティには `3` が表示されます。 | | **初回オファー** | サブスクリプションに初回オファーが含まれているかをバッジなどで表示するには、`product.subscriptionOffer` プロパティを確認します。このオブジェクト内には以下の便利なプロパティが含まれています。
• `offerType`: `introductory`、`promotional`、`winBack` の値を持つ列挙型。無料トライアルや初期割引サブスクリプションは `introductory` タイプになります。
• `price`: 割引後の価格(数値)。無料トライアルの場合は `0` になります。
• `localizedPrice`: ユーザーのロケールに合わせてフォーマットされた割引価格。
• `localizedNumberOfPeriods`: オファーの期間をデバイスのロケールでローカライズした文字列。たとえば3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。
• `subscriptionPeriod`: オファー期間の詳細を個別に取得する場合はこのプロパティを使用します。前のセクションで説明したのと同じ方法でオファーに対しても機能します。
• `localizedSubscriptionPeriod`: ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## iOS での初回オファー適格性の確認 \{#check-intro-offer-eligibility-on-ios\} デフォルトでは、`getPaywallProducts` メソッドが初回オファー、プロモーションオファー、ウィンバックオファーの適格性を確認します。SDK がオファーの適格性を判定する前にプロダクトを表示する必要がある場合は、代わりに `getPaywallProductsWithoutDeterminingOffer` メソッドを使用してください。 :::note 初期プロダクトを表示した後は、必ず通常の `getPaywallProducts` メソッドを呼び出して、正確なオファー適格性情報でプロダクトを更新してください。 ::: ```swift showLineNumbers do { let products = try await Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) // the requested products array without subscriptionOffer } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) { result in switch result { case let .success(products): // subscriptionOfferなしでリクエストしたプロダクト配列 case let .failure(error): // エラーを処理する } } ``` ## デフォルトオーディエンスのペイウォールでペイウォールの取得を高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ瞬時に取得されるため、このプロセスを高速化することを特に意識する必要はありません。しかし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を提供したい場合があるでしょう。 この問題を解決するために、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](fetch-paywalls-and-products#fetch-paywall-information)セクションをご覧ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)で異なるペイウォールを表示する必要がある場合、課題が生じることがあります。現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがペイウォールを正しく表示できないリスクを受け入れるかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、カスタム属性に基づくものを含む)が失われます。 これらのデメリットを許容してでもペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products#fetch-paywall-information)で説明した `getPaywall` を使用してください。 ::: ```swift showLineNumbers do { let paywall = try await Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` :::note `getPaywallForDefaultAudience` メソッドは iOS SDK バージョン 2.11.2 以降で利用できます。 ::: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメータは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードです。最初のサブタグは言語、2番目は地域を表します。

例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。

ロケールコードと推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。

| | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。

ただし、ユーザーがネットワークの不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在すればそれを返すことも検討してください。この場合、最新データが取得できないことがありますが、接続状況に左右されず読み込みが速くなります。キャッシュはセッション中も定期的に更新されるため、ネットワークリクエストを減らす目的で安全に使用できます。

キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動でのクリア時にのみ削除されます。

|
--- # File: present-remote-config-paywalls --- --- title: "iOS SDKでリモートコンフィグ設計のペイウォールをレンダリングする" description: "Adaptyでリモートコンフィグペイウォールを表示してユーザー体験をパーソナライズする方法を解説します。" --- リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリング処理をアプリのコードに実装する必要があります。リモートコンフィグは柔軟にカスタマイズできるため、ペイウォールに何を含めるか、どのように表示するかはすべて開発者次第です。Adapty はリモートコンフィグを取得するメソッドを提供しており、カスタムペイウォールを自由に表示できます。 [iOS で初回オファーの対象ユーザーを確認する](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios)ことを忘れずに、対象ユーザーの場合の処理もペイウォールに組み込んでください。 ## フローのリモートコンフィグを取得して表示する \{#get-flow-remote-config-and-present-it\} v4 では、フローは設定済みロケールごとに 1 つの `AdaptyRemoteConfig` エントリを `remoteConfigs` 配列に持ちます。ユーザーの設定に合ったロケールを選択し、必要な値を読み取ってください。 ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let config = flow.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow.remoteConfigs.first let headerText = config?.dictionary?["header_text"] as? String } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in let flow = try? result.get() let config = flow?.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow?.remoteConfigs.first let headerText = config?.dictionary?["header_text"] as? String } ``` 必要な値をすべて取得したら、それらを組み合わせて見栄えの良いページをレンダリングしましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、どのデバイスでもシームレスで使いやすい体験を提供してください。 :::warning 以下で説明する[ペイウォール表示イベントの記録](present-remote-config-paywalls#track-paywall-view-events)を必ず行ってください。これにより、Adapty アナリティクスがファネルや A/B テストの情報を取得できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入する際は、フローのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細は[購入処理](making-purchases)を参照してください。 [フォールバックペイウォールというバックアップペイウォールを作成する](fallback-paywalls)ことをおすすめします。インターネット接続がない場合やキャッシュが利用できない場合でも、このバックアップが表示されるためスムーズな体験が維持されます。 ## ペイウォール表示イベントのトラッキング \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見たタイミングを把握しているのが開発者だけのため、手動での記録が必要です。 ペイウォール表示イベントを記録するには、`.logShowFlow(flow)` を呼び出すだけです。ファネルや A/B テストのペイウォール指標に反映されます。 :::important [フロービルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示している場合は、`.logShowFlow(flow)` を呼び出す必要はありません。それらの場合、Adapty が自動的に表示をトラッキングします。 ::: ```swift showLineNumbers try await Adapty.logShowFlow(flow) ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :-------- | :------- |:-----------------------------------------------------------------------------------------| | **flow** | 必須 | `Adapty.getFlow(placementId:)` で取得した `AdaptyFlow` オブジェクト。 | リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリング処理をアプリのコードに実装する必要があります。リモートコンフィグは柔軟にカスタマイズできるため、ペイウォールに何を含めるか、どのように表示するかはすべて開発者次第です。Adapty はリモートコンフィグを取得するメソッドを提供しており、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 [iOS で初回オファーの対象ユーザーを確認する](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios)ことを忘れずに、対象ユーザーの場合の処理もペイウォールに組み込んでください。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") let headerText = paywall.remoteConfig?.dictionary?["header_text"] as? String } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") { result in let paywall = try? result.get() let headerText = paywall?.remoteConfig?.dictionary?["header_text"] as? String } ``` 必要な値をすべて取得したら、それらを組み合わせて見栄えの良いページをレンダリングしましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、どのデバイスでもシームレスで使いやすい体験を提供してください。 :::warning 以下で説明する[ペイウォール表示イベントの記録](present-remote-config-paywalls#track-paywall-view-events)を必ず行ってください。これにより、Adapty アナリティクスがファネルや A/B テストの情報を取得できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入する際は、ペイウォールのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細は[購入処理](making-purchases)を参照してください。 [フォールバックペイウォールというバックアップペイウォールを作成する](fallback-paywalls)ことをおすすめします。インターネット接続がない場合やキャッシュが利用できない場合でも、このバックアップが表示されるためスムーズな体験が維持されます。 ## ペイウォール表示イベントのトラッキング \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見たタイミングを把握しているのが開発者だけのため、手動での記録が必要です。 ペイウォール表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールを表示している場合は、`.logShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```swift showLineNumbers Adapty.logShowPaywall(paywall) ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- |:-----------------------------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) オブジェクト。 | --- # File: making-purchases --- --- title: "iOS SDKでモバイルアプリの購入を行う" description: "Adaptyを使用したアプリ内課金とサブスクリプションの処理に関するガイド。" --- モバイルアプリ内でペイウォールを表示することは、ユーザーにプレミアムコンテンツやサービスへのアクセスを提供するための重要なステップです。ただし、[ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしている場合に限り、ペイウォールを表示するだけで購入処理が完結します。 ペイウォールビルダーを使用しない場合は、購入を完了してコンテンツをアンロックするために `.makePurchase()` という別のメソッドを使用する必要があります。このメソッドは、ユーザーがペイウォールで操作を行い、目的のトランザクションを進めるための窓口となります。 ペイウォールにユーザーが購入しようとしているプロダクトに対して有効なプロモーションオファーがある場合、Adaptyは購入時に自動的にそれを適用します。 :::warning 初回オファーが自動的に適用されるのは、ペイウォールビルダーで設定されたペイウォールを使用している場合のみです。 それ以外の場合は、[iOS での初回オファーの利用資格を確認](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios)する必要があります。この手順を省略すると、リリース時にアプリが審査で却下される可能性があります。また、初回オファーの対象ユーザーに通常価格が請求される可能性もあります。 ::: 一つのステップも省略せずに[初期設定](quickstart)を完了していることを確認してください。設定が完了していないと、購入の検証ができません。 ## 購入を行う \{#make-purchase\} :::note **[ペイウォールビルダー](adapty-paywall-builder)を使用していますか?** 購入は自動的に処理されます。このステップはスキップできます。 **ステップバイステップのガイドが必要ですか?** 完全なコンテキストとエンドツーエンドの実装手順については、[クイックスタートガイド](ios-implement-paywalls-manually)をご覧ください。 ::: ```swift showLineNumbers do { let purchaseResult = try await Adapty.makePurchase(product: product) switch purchaseResult { case .userCancelled: // Handle the case where the user canceled the purchase case .pending: // Handle deferred purchases (e.g., the user will pay offline with cash) case let .success(profile, transaction): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // Grant access to the paid features } } } catch { // Handle the error } ``` ```swift showLineNumbers Adapty.makePurchase(product: product) { result in switch result { case let .success(purchaseResult): switch purchaseResult { case .userCancelled: // Handle the case where the user canceled the purchase case .pending: // Handle deferred purchases (e.g., the user will pay offline with cash) case let .success(profile, transaction): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // Grant access to the paid features } } case let .failure(error): // Handle the error } } ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクト。 | レスポンスパラメーター: | パラメーター | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

リクエストが成功した場合、レスポンスにはこのオブジェクトが含まれます。[AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクトは、アプリ内でのユーザーのアクセスレベル、サブスクリプション、非サブスクリプション購入に関する包括的な情報を提供します。

ユーザーがアプリへの必要なアクセス権を持っているかどうかを確認するために、アクセスレベルのステータスをチェックしてください。

| :::warning **注意:** Apple の StoreKit バージョンが v2.0 未満、かつ Adapty SDK バージョンが v2.9.0 未満の場合は、代わりに [Apple App Store 共有シークレット](app-store-connection-configuration#step-5-enter-app-store-shared-secret)を提供する必要があります。このメソッドは現在 Apple によって非推奨とされています。 ::: ## App Store からのアプリ内課金 \{#in-app-purchases-from-the-app-store\} ユーザーが App Store で購入を開始し、トランザクションがアプリに引き継がれる場合、2つの選択肢があります: - **トランザクションを即座に処理する:** `shouldAddStorePayment` で `true` を返します。これにより、Apple の購入システム画面がすぐに表示されます。 - **後処理のためにプロダクトオブジェクトを保存する:** `shouldAddStorePayment` で `false` を返し、後で保存したプロダクトを使って `makePurchase` を呼び出します。購入をトリガーする前にユーザーにカスタム画面を表示したい場合に便利です。 完全なコード例を以下に示します: ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. The Apple purchase system screen will show automatically. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` when the timing is appropriate func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## iOS でオファーコードを利用する \{#redeem-offer-codes-in-ios\} --- no_index: true --- import Callout from '../../../components/Callout.astro';
オファーコードについて オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、SNS、印刷物など、アプリの外で配布します。ユーザーはApp Storeでコードを入力するか、引き換えURLを使うか、アプリ内ダイアログから利用できます。 オファーコードを設定するには、App Store Connectでサブスクリプションを開き、**Offer Codes** セクションに移動してください。オファーコードは[3種類](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-subscription-offer-codes)作成できます。 - **Free** — 指定した期間はサブスクリプションが無料になり、次の更新から通常価格になります。 - **Pay as you go** — 指定した期間、各請求サイクルに割引価格が適用され、その後は通常価格で更新されます。 - **Pay up front** — オファー期間全体に対して一括で割引価格を支払い、その後は通常価格で更新されます。 オファーコードをAdaptyに追加する必要はありません。Appleはオファー期間中のすべてのトランザクションにオファーコードカテゴリのタグを付与します。これには最初の引き換えとその後の割引更新がすべて含まれます。Adaptyはこのタグを検出し、各トランザクションをオファーカテゴリ `offer_code` として記録します。オファー期間が終了してサブスクリプションが通常価格で更新されると、タグは付与されなくなります。[Adapty ダッシュボード](controls-filters-grouping-compare-proceeds)のアナリティクスで **Offer Code** オファータイプによるフィルタリングが可能です。 #### 収益の差異が生じた場合のトラブルシューティング \{#revenue-discrepancy-troubleshooting\} オファーコードのトランザクションが、割引価格ではなく通常価格でAdaptyに記録されている場合は、App Store Connectで以下を確認してください。 - オファーコードに、ユーザーが引き換え可能なすべての地域に対して正しい価格が設定されているか。 - ユーザーの特定の国や地域に対してオファー価格が設定されているか。Appleはトランザクションに地域価格を含めて送信します。その地域のオファー価格が設定されていない場合、Appleは通常価格を送信することがあります。 [Adapty ダッシュボード](controls-filters-grouping-compare-proceeds)で、**Offer Code** オファータイプと **Offer Discount Type** フィルターを使ってオファーコードのトランザクションをフィルタリング・確認できます。 #### レガシープロモコード(非推奨) \{#legacy-promo-codes-deprecated\} Appleは2026年3月にアプリ内課金向けのプロモコードを廃止しました。オファーコードはより多くの機能(適格性の設定、有効期限、四半期あたり最大100万コード)を備えた後継機能です。アプリ内課金にプロモコードを使用していた場合は、App Store Connectでオファーコードに移行してください。 レガシープロモコード(アプリのバージョンごとに最大100件)は、サブスクリプションへの無料アクセスを付与していました。オファーコードとは異なり、Appleはプロモコードのトランザクションに割引情報を含めず、レシートには通常価格が記載されていました。そのため、Adaptyはこれらのトランザクションを通常価格で記録し、Adaptyアナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。
アプリ内でコード引き換えシートを表示するには: ```swift showLineNumbers Adapty.presentCodeRedemptionSheet() ``` :::danger 確認された問題として、一部のアプリでオファーコード引き換えシートが正常に動作しない場合があります。ユーザーを直接 App Store にリダイレクトすることをお勧めします。 そのためには、以下の形式の URL を開く必要があります: `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: --- # File: restore-purchase --- --- title: "iOS SDKでのアプリ内購入の復元" description: "シームレスなユーザー体験を確保するために、Adaptyで購入を復元する方法を学びましょう。" --- 購入の復元とは、ユーザーが以前に購入したコンテンツ(サブスクリプションやアプリ内課金など)に、再度課金されることなくアクセスを取り戻せる機能です。アプリをアンインストール・再インストールした場合や、新しいデバイスに移行した場合でも、以前の購入内容に改めて支払うことなくアクセスできるため、特に便利な機能です。 :::note [ペイウォールビルダー](adapty-paywall-builder)で構築されたペイウォールでは、追加のコードなしに購入が自動的に復元されます。その場合は、この手順をスキップできます。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしていない場合に購入を復元するには、`.restorePurchases()` メソッドを呼び出してください。 ```swift showLineNumbers do { let profile = try await Adapty.restorePurchases() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } } catch { // handle the error } ``` ```swift showLineNumbers Adapty.restorePurchases { [weak self] result in switch result { case let .success(profile): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } case let .failure(error): // handle the error } } ``` レスポンスパラメーター: | パラメーター | 説明 | |---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

[`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクト。このモデルには、アクセスレベル、サブスクリプション、および非サブスクリプション購入に関する情報が含まれます。

ユーザーがアプリへのアクセス権を持っているかどうかを確認するには、**アクセスレベルのステータス**を確認してください。

| :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: ios-transaction-management --- --- title: "iOS SDKにおける高度なトランザクション管理" description: "Adapty SDKを使用してiOSアプリでトランザクションを手動で完了する方法を説明します。" --- :::note 高度なトランザクション管理は、Adapty iOS SDK バージョン3.12以降でサポートされています。 ::: Adaptyの高度なトランザクション管理を使用すると、トランザクションの処理、検証、完了をより細かく制御できます。 高度なトランザクション管理には、連携して動作する3つのオプション機能が含まれています。 | 機能 | 目的 | |-------------------------------------------------------------|----------| | [`appAccountToken`](#assign-appaccounttoken) | Appleのトランザクションを内部ユーザーIDに紐付ける | | [`jwsTransaction`](#access-the-jws-representation) | バリデーション用にAppleの署名済みトランザクションペイロードを提供する | | [手動完了](#control-transaction-finishing-behavior) | バックエンドが成功を確認した後にのみトランザクションを完了できる | これらのツールを組み合わせることで、AdaptyがバックエンドとのトランザクションSync機能を維持しながら、堅牢なカスタムバリデーションフローを構築できます。 :::important ほとんどのアプリにはこの機能は不要です。 デフォルトでは、AdaptyはStoreKitトランザクションを自動的に検証・完了します。 このガイドは、独自のバックエンドバリデーションを実行する場合や、購入ライフサイクルを完全に制御したい場合にのみ使用してください。 ::: ## `appAccountToken`を設定する \{#assign-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:))は、App Storeのトランザクションを内部ユーザーIDに紐付けるための**UUID**です。 StoreKitはこのトークンをすべてのトランザクションに関連付けるため、バックエンドでApp Storeのデータとユーザーを照合できます。 ユーザーごとに生成した安定したUUIDを使用し、デバイスをまたいで同じアカウントに対して再利用してください。 これにより、購入とApp Storeの通知が正しく紐付けられます。 トークンは2つの方法で設定できます。SDK初期化時またはユーザーを識別するときです。 :::important `appAccountToken`は必ず`customerUserId`と一緒に渡す必要があります。 トークンのみを渡した場合、トランザクションに含まれません。 ::: ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } // Or when identifying a user: do { try await Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) } catch { // handle the error } ``` ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: ) Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } // Or when identifying a user: Adapty.identify("YOUR_USER_ID", withAppAccountToken: ) { error in if let error { // handle the error } } ``` ## JWS表現にアクセスする \{#access-the-jws-representation\} 購入を行うと、結果にはAppleのトランザクションが[JWSコンパクトシリアライゼーション形式](https://developer.apple.com/documentation/storekit/verificationresult/jwsrepresentation-21vgo)で含まれます。 この値をバックエンドに転送して、独自のバリデーションやログ記録に活用できます。 ```swift let result = try await Adapty.makePurchase(product: paywallProduct) let jwsRepresentation = result.jwsTransaction ``` ## トランザクション完了の動作を制御する \{#control-transaction-finishing-behavior\} デフォルトでは、AdaptyはバリデーションAfterにStoreKitトランザクションを自動的に完了します。 バックエンドが成功を確認するまで完了を遅らせたい場合は、完了動作を手動に設定してください。 このモードでは: - Adaptyは引き続き購入を検証し、バックエンドとSyncします。 - `finish()`を明示的に呼び出すまで、トランザクションは未完了のままです。 ```swift var configBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_API_KEY") .with(transactionFinishBehavior: .manual) try await Adapty.activate(with: configBuilder.build()) ``` 手動トランザクション完了を使用する場合、未完了のトランザクションを処理するために`onUnfinishedTransaction`デリゲートメソッドを実装する必要があります。 ```swift showLineNumbers title="Swift" extension YourApp: AdaptyDelegate { func onUnfinishedTransaction(_ transaction: AdaptyUnfinishedTransaction) async { // Perform your custom validation logic here // When ready, finish the transaction await transaction.finish() } } ``` 現在の未完了トランザクションをすべて取得するには、`getUnfinishedTransactions()`メソッドを使用してください。 ```swift let unfinishedTransactions = try await Adapty.getUnfinishedTransactions() ``` --- # File: implement-observer-mode --- --- title: "iOS SDK でオブザーバーモードを実装する" description: "iOS SDK で Adapty のオブザーバーモードを実装し、ユーザーのサブスクリプションイベントを追跡する方法を説明します。" --- 独自の購入インフラを持っており、まだ Adapty への完全な移行を検討していない場合は、[オブザーバーモード](observer-vs-full-mode)を活用できます。基本的な使い方では、オブザーバーモードによって高度なアナリティクスや、アトリビューション・分析システムとのシームレスな連携が可能になります。 これで十分な場合は、以下の 2 つだけ対応すれば OK です: 1. Adapty SDK を設定する際に `observerMode` パラメータを `true` にしてオブザーバーモードを有効化する。 2. 既存の購入インフラから Adapty へ[トランザクションを報告する](report-transactions-observer-mode)。 ペイウォールや A/B テストも利用したい場合は、以下に説明する追加のセットアップが必要です。 ## オブザーバーモードのセットアップ \{#observer-mode-setup\} 購入やサブスクリプションのステータス管理を自分で行い、サブスクリプションイベントの送信やアナリティクスのために Adapty を使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作している場合、Adapty SDK はトランザクションをクローズしません。そのため、トランザクションの処理はご自身で行ってください。 ::: ```swift showLineNumbers @main struct YourApp: App { init() { // Configure Adapty SDK let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(observerMode: true) let config = configurationBuilder.build() // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: configurationBuilder) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } var body: some Scene { WindowGroup { // Your content view } } } } ``` ```swift showLineNumbers Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(observerMode: true) let config = configurationBuilder.build() try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` パラメータ: | パラメータ | 説明 | | --------------------------- | ------------------------------------------------------------ | | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御する真偽値です。デフォルト値は `false` です。 | ## オブザーバーモードで Adapty のペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adapty のペイウォールや A/B テスト機能も使用したい場合は可能ですが、オブザーバーモードでは追加のセットアップが必要です。上記の手順に加えて、以下を行ってください: 1. [リモートコンフィグペイウォール](present-remote-config-paywalls)は通常どおり表示する。ペイウォールビルダーのペイウォールについては、[iOS](ios-present-paywall-builder-paywalls-in-observer-mode) 向けの専用セットアップガイドに従う。 3. 購入トランザクションに[ペイウォールを紐付ける](report-transactions-observer-mode)。 --- # File: report-transactions-observer-mode --- --- title: "iOS SDKのObserverモードでトランザクションをレポートする" description: "iOS SDKのAdapty Observerモードで購入トランザクションをレポートし、ユーザーインサイトと収益追跡を行います。" --- Observerモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡できません。アプリストアからトランザクションを手動でレポートする必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を行うことが重要です。 `reportTransaction`を使用して、Adaptyが認識できるよう各トランザクションを明示的にレポートしてください。 :::warning **トランザクションのレポートをスキップしないでください!** `reportTransaction`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションをレポートする際に`variationId`を含めてください。これにより、購入がトリガーとなったペイウォールとリンクされ、正確なペイウォールアナリティクスが確保されます。 ```swift showLineNumbers do { // every time when calling transasction.finish() try await Adapty.reportTransaction(transaction, withVariationId: ) } catch { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- | ------------------------------------------------------------ | | **transaction** | 必須 |
  • StoreKit 1の場合:SKPaymentTransaction。
  • StoreKit 2の場合:Transaction。
| | **variationId** | 任意 | ペイウォールバリアントの一意のID。[AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall)オブジェクトの`variationId`プロパティから取得できます。 |
Observerモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡できません。アプリストアからトランザクションをレポートするか、リストアする必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を行うことが重要です。 `reportTransaction`を使用して、トランザクションデータをAdaptyに送信してください。 :::warning **トランザクションのレポートをスキップしないでください!** `reportTransaction`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションをレポートする際に`withVariationId`を含めてください。これにより、購入がトリガーとなったペイウォールとリンクされ、正確なペイウォールアナリティクスが確保されます。 ```swift showLineNumbers do { // every time when calling transasction.finish() try await Adapty.reportTransaction(transaction, withVariationId: ) } catch { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- | ------------------------------------------------------------ | | **transaction** | 必須 |
  • StoreKit 1の場合:SKPaymentTransaction。
  • StoreKit 2の場合:Transaction。
| | **variationId** | 任意 | ペイウォールバリアントの一意のID。[AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall)オブジェクトの`variationId`プロパティから取得できます。 |
**トランザクションのレポート** - 3.1.x以前のバージョンはApp Storeのトランザクションを自動的に監視するため、手動でのレポートは不要です。 - バージョン3.2はObserverモードをサポートしていません。 **トランザクションとペイウォールの関連付け** Adapty SDKは購入のソースを判断できません。購入の処理はお客様側で行うためです。そのため、Observerモードでペイウォールやおよび/またはA/Bテストを使用する場合は、アプリストアから受け取ったトランザクションをモバイルアプリのコード内で対応するペイウォールに関連付ける必要があります。アプリをリリースする前にこの設定を正しく行うことが重要です。そうしないと、アナリティクスにエラーが発生します。 ```swift let variationId = paywall.variationId // There are two overloads: for StoreKit 1 and StoreKit 2 Adapty.setVariationId(variationId, forPurchasedTransaction: transactionId) { error in if error == nil { // successful binding } } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | variationId | 必須 | バリアントの文字列識別子。[AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall)オブジェクトの`variationId`プロパティを使用して取得できます。 | | transactionId | 必須 |

StoreKit 1の場合:[SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction)オブジェクト。

StoreKit 2の場合:[Transaction](https://developer.apple.com/documentation/storekit/transaction)オブジェクト。

|
--- # File: ios-troubleshoot-purchases --- --- title: "iOSのSDKにおける購入のトラブルシューティング" description: "iOSのSDKにおける購入のトラブルシューティング" --- このガイドでは、iOS SDKで手動購入を実装する際によく発生する問題の解決方法を説明します。 ## オブザーバーモードでのAdaptyError.cantMakePayments \{#adaptyer-ror-cant-make-payments-in-observer-mode\} **問題**: オブザーバーモードで`makePurchase`を使用すると、`AdaptyError.cantMakePayments`が発生する。 **原因**: オブザーバーモードでは、Adaptyの`makePurchase`メソッドではなく、自分側で購入を処理する必要があります。 **解決策**: 購入に`makePurchase`を使用している場合は、オブザーバーモードをオフにしてください。`makePurchase`を使用するか、オブザーバーモードで自分側で購入を処理するか、どちらか一方を選択する必要があります。詳細は[オブザーバーモードの実装](implement-observer-mode)を参照してください。 ## makePurchasesCompletionHandlersが見つからない \{#not-found-makepurchasescompletionhandlers\} **問題**: `makePurchasesCompletionHandlers`が見つからないというエラーが発生している。 **原因**: これは通常、サンドボックステストに関連する問題です。 **解決策**: 新しいサンドボックスユーザーを作成して再試行してください。これにより、サンドボックス関連の購入完了ハンドラーの問題が解決されることがよくあります。 ## その他の問題 \{#other-issues\} **問題**: 上記で取り上げていない購入関連のその他の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](ios-sdk-migration-guides)を使用してSDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: ios-web-paywall --- --- title: "iOS SDKでウェブペイウォールを実装する" description: "App Storeの手数料や審査なしで決済を受け付けるウェブペイウォールを設定します。" --- :::important 始める前に、[ダッシュボードでウェブペイウォールを設定](web-paywall)済みであること、および Adapty SDK バージョン 3.6.1 以降がインストールされていることを確認してください。 ::: ## ウェブペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールを利用している場合は、SDK メソッドを使ってウェブペイウォールを処理する必要があります。`.openWebPaywall` メソッドは次の処理を行います。 1. 特定のユーザーに表示されたペイウォールとリダイレクト先のウェブページを Adapty が紐付けるための一意の URL を生成します。 2. ユーザーがアプリに戻ったタイミングを検知し、短い間隔で `.getProfile` を呼び出して、プロファイルのアクセス権が更新されたかどうかを確認します。 これにより、決済が成功してアクセス権が更新された場合、アプリ内でほぼ即座にサブスクリプションが有効化されます。 ```swift showLineNumbers title="Swift" do { try await Adapty.openWebPaywall(for: product) } catch { print("Failed to open web paywall: \(error)") } ``` :::note `openWebPaywall` メソッドには2つのバージョンがあります。 1. `openWebPaywall(product)` はペイウォールごとに URL を生成し、プロダクトのデータも URL に追加します。 2. `openWebPaywall(paywall)` はペイウォールごとに URL を生成しますが、プロダクトのデータは URL に追加しません。Adapty のペイウォールに設定されたプロダクトとウェブペイウォールのプロダクトが異なる場合に使用してください。 ::: ## エラーを処理する \{#handle-errors\} | エラー | 説明 | 推奨される対処法 | |-----------------------------------------|------------------------------------------------------|---------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | ペイウォールにウェブ購入 URL が設定されていない | Adapty ダッシュボードでペイウォールが正しく設定されているか確認してください | | AdaptyError.productWithoutPurchaseUrl | プロダクトにウェブ購入 URL が設定されていない | Adapty ダッシュボードでプロダクトの設定を確認してください | | AdaptyError.failedOpeningWebPaywallUrl | ブラウザで URL を開くことができなかった | デバイスの設定を確認するか、別の購入方法を提供してください | | AdaptyError.failedDecodingWebPaywallUrl | URL 内のパラメーターを正しくエンコードできなかった | URL パラメーターが有効かつ適切にフォーマットされているか確認してください | ## 実装例 \{#implementation-example\} ```swift showLineNumbers title="Swift" class SubscriptionViewController: UIViewController { var paywall: AdaptyPaywall? @IBAction func purchaseButtonTapped(_ sender: UIButton) { guard let paywall = paywall, let product = paywall.products.first else { return } Task { await offerWebPurchase(for: product) } } func offerWebPurchase(for paywallProduct: AdaptyPaywallProduct) async { do { // Attempt to open web paywall try await Adapty.openWebPaywall(for: paywallProduct) } catch let error as AdaptyError { switch error { case .paywallWithoutPurchaseUrl, .productWithoutPurchaseUrl: showAlert(message: "Web purchase is not available for this product.") case .failedOpeningWebPaywallUrl: showAlert(message: "Could not open web browser. Please try again.") default: showAlert(message: "An error occurred: \(error.localizedDescription)") } } catch { showAlert(message: "An unexpected error occurred.") } } // Helper methods private func showAlert(message: String) { /* ... */ } } ``` :::note ユーザーがアプリに戻った後は、プロファイルの更新を反映するために UI をリフレッシュしてください。`AdaptyDelegate` がプロファイル更新イベントを受信して処理します。 ::: ## アプリ内ブラウザでウェブペイウォールを開く \{#open-web-paywalls-in-an-in-app-browser\} :::important アプリ内ブラウザでのウェブペイウォール表示は、Adapty SDK v3.15 以降でサポートされています。 ::: デフォルトでは、ウェブペイウォールは外部ブラウザで開きます。 シームレスなユーザー体験を提供するために、アプリ内ブラウザでウェブペイウォールを開くことができます。これにより、アプリを切り替えることなく、アプリ内でウェブ購入ページを表示してトランザクションを完了できます。 この機能を有効にするには、`in` パラメーターを `.inAppBrowser` に設定します。 ```swift showLineNumbers title="Swift" do { try await Adapty.openWebPaywall(for: product, in: .inAppBrowser) // default – .externalBrowser } catch { print("Failed to open web paywall: \(error)") } ``` --- # File: identifying-users --- --- title: "iOS SDKでユーザーを識別する" description: "Adaptyでユーザーを識別し、パーソナライズされたサブスクリプション体験を向上させましょう。" --- Adaptyはすべてのユーザーに対して内部プロファイルIDを作成します。ただし、独自の認証システムがある場合は、独自のCustomer User IDを設定してください。[Profiles](profiles-crm)セクションでCustomer User IDによるユーザー検索が可能で、[サーバーサイドAPI](getting-started-with-server-side-api)でも使用できます。このIDはすべてのインテグレーションに送信されます。 ## 設定時にCustomer User IDを設定する \{#set-customer-user-id-on-configuration\} 設定時にユーザーIDが利用可能な場合は、`.activate()`メソッドの`customerUserId`パラメーターとして渡してください: ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } ``` ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## 設定後にCustomer User IDを設定する \{#set-customer-user-id-after-configuration\} SDKの設定時にユーザーIDがない場合は、`.identify()`メソッドを使っていつでも後から設定できます。最も一般的なユースケースは、登録や認証の後、ユーザーが匿名ユーザーから認証済みユーザーに切り替わるタイミングです。 ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") } catch { // handle the error } ``` ```swift showLineNumbers Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` リクエストパラメーター: - **Customer User ID**(必須): 文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信 ユーザーが再度ログインするなど、Adaptyのサーバーにすでにそのユーザーの情報が存在する場合があります。このような場合、Adapty SDKは自動的に新しいユーザーへ切り替えます。匿名ユーザーにカスタム属性やサードパーティネットワークからのアトリビューションなどのデータを渡していた場合は、識別済みユーザーに対してそのデータを再送信してください。 また、新しいユーザーのデータが異なる可能性があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得することが重要です。 ::: ## ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()`メソッドを呼び出すことで、いつでもユーザーをログアウトできます: ```swift showLineNumbers do { try await Adapty.logout() } catch { // handle the error } ``` ```swift showLineNumbers Adapty.logout { error in if error == nil { // successful logout } } ``` その後、`.identify()`メソッドを使ってユーザーをログインできます。 ## appAccountTokenを設定する \{#set-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:))は、AppleのStoreKit 2がアプリのインストールやデバイスをまたいでユーザーを識別するためのUUIDです。 Adapty iOS SDK 3.10.2以降、SDKの設定時またはユーザーの識別時に`appAccountToken`を渡せるようになりました: ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } // Or when identifying a user: do { try await Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) } catch { // handle the error } ``` ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } // Or when identifying a user: Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) { error in if let error { // handle the error } } ``` その後、`.identify()`メソッドを使ってユーザーをログインできます。 ## デバイスをまたいでユーザーを検出する \{#detect-users-across-devices\} --- no_index: true --- SDKが有効化されると、StoreKit(iOS)またはGoogle Play Billing(Android)からユーザーの既存のエンタイトルメントを自動的に読み取り、Adaptyバックエンドと同期します。有効なサブスクリプションは、アプリが`restorePurchases`を呼び出すことなく、Adaptyプロファイルに表示されます。 **自動では行われない**のは、新しいデバイスのプロファイルが元のデバイスと同じユーザーのものであることの認識です。AdaptyはCustomer User IDでプロファイルを照合するため、同一性の継続性はCUIDとして何を使用するかによって異なります。 **デバイス間でAdaptyが検出できること** | あなたの設定 | Adaptyが検出すること | 必要な対応 | | --- | --- | --- | | Customer User ID = `device_id`(アプリのログインなし) | 新しいデバイスは異なるCUIDを取得するため、異なるプロファイルが作成されます。サブスクリプションは**Access level updated**イベントを通じて新しいプロファイルに同期されますが、`subscription_started`は発火しません。新しいプロファイルは元の購入の継承者として扱われます。`subscription_started`に基づくアナリティクスは、リターニングユーザーをカウント不足します。 | リターニングユーザーが既存のプロファイルをデバイス間で照合できるよう、安定したアカウントIDをCustomer User IDとして使用してください。 | | Customer User ID = 安定したアカウントID(すべてのデバイスでログイン) | SDKは`activate()`でサブスクリプションを自動同期し、`identify()`がCUIDで既存のプロファイルを照合します。 | 追加の設定は不要です。IDとサブスクリプションの両方が自動的に解決されます。 | | Apple Family Sharing の継承者 | ファミリーメンバーは**Access level updated**イベントのみを通じてサブスクリプションを受け取ります。`subscription_started`は発火しません。 | **Access level updated**をリッスンしてください。完全なイベントマトリクスは[Apple Family Sharing](apple-family-sharing)を参照してください。 | | 同じApple/Googleアカウント、異なるアプリ内ユーザー | 最初に購入を記録したプロファイルが親になります。その後のプロファイルは継承者チェーンを通じてサブスクリプションを確認し、**Access level updated**イベントが1回発生します。 | ログインを必須にし、あなたのモデルに合った[共有モード](sharing-paid-access-between-user-accounts)を選択してください。 | **新しいデバイスでの購入の復元** ペイウォールにユーザーが操作できる「購入を復元」ボタンを設置してください。Apple App Review(ガイドライン3.1.1)で必須とされており、自動同期がエッジケースを見逃した場合のフォールバックとして機能します。このボタンはSDKの`restorePurchases`を呼び出す必要があります。 初回起動時にプログラムで`restorePurchases`を呼び出すことは、通常の使用では必要ありません。SDKはすでに`activate()`で同等の処理を実行しています。プログラムによる呼び出しは、`activate()`完了後にアクセスが欠落している場合のデバッグなど、強制的に新しいレシートチェックを行う場合にのみ使用してください。 --- # File: setting-user-attributes --- --- title: "iOS SDKでユーザー属性を設定する" description: "Adaptyでユーザー属性を設定し、より効果的なオーディエンスのセグメンテーションを実現する方法を学びましょう。" --- アプリのユーザーに対して、メールアドレスや電話番号などの任意の属性を設定できます。設定した属性は、ユーザーの[セグメント](segments)の作成や、CRMでの確認に利用できます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します。 ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") .with(phoneNumber: "+18888888888") .with(firstName: "John") .with(lastName: "Appleseed") .with(gender: .other) .with(birthday: Date()) do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } ``` ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") .with(phoneNumber: "+18888888888") .with(firstName: "John") .with(lastName: "Appleseed") .with(gender: .other) .with(birthday: Date()) Adapty.updateProfile(params: builder.build()) { error in if error != nil { // handle the error } } ``` `updateProfile` メソッドで以前に設定した属性はリセットされません。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 使用できるキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters.Builder` で使用できるキー `` と値 `` の一覧は以下のとおりです。 | キー | 値 | |---|-----| |

email

phoneNumber

firstName

lastName

| String | | gender | 列挙型。使用できる値: `female`、`male`、`other` | | birthday | Date | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定できます。カスタム属性は通常、アプリの使用状況に関連したものです。たとえば、フィットネスアプリなら週あたりの運動回数、語学学習アプリならユーザーの習熟度などが考えられます。カスタム属性をセグメントで活用して、ターゲットを絞ったペイウォールやオファーを作成したり、どのプロダクト指標が収益に最も影響するかをアナリティクスで分析したりできます。 ```swift showLineNumbers do { builder = try builder.with(customAttribute: "value1", forKey: "key1") } catch { // handle key/value validation error } ``` 既存のキーを削除するには、`.withRemoved(customAttributeForKey:)` メソッドを使用します。 ```swift showLineNumbers do { builder = try builder.withRemoved(customAttributeForKey: "key2") } catch { // handle error } ``` 事前にどのカスタム属性が設定されているかを確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning `customAttributes` の値は最新でない場合があります。ユーザー属性は異なるデバイスからいつでも送信される可能性があるため、最後の同期後にサーバー上の属性が変更されている場合があります。 ::: ### 制限事項 \{#limits\} - ユーザーあたりのカスタム属性は最大30個まで - キー名は最大30文字。キー名に使用できる文字は英数字と以下の記号です: `_` `-` `.` - 値は文字列または浮動小数点数で、50文字以内 --- # File: subscription-status --- --- title: "iOS SDK でサブスクリプションのステータスを確認する" description: "Adapty でユーザーのサブスクリプションステータスを追跡・管理して、顧客維持率を向上させましょう。" --- Adapty を使えば、サブスクリプションのステータス管理が簡単になります。プロダクト ID をコードに手動で埋め込む必要はなく、アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプションステータスをスムーズに把握できます。 サブスクリプションのステータス確認を始める前に、[App Store サーバー通知](enable-app-store-server-notifications)を設定してください。 ## アクセスレベルと AdaptyProfile オブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクトのプロパティです。アプリ起動時([ユーザーを識別する](identifying-users#set-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更が発生したときに更新することをおすすめします。こうすることで、都度リクエストを送ることなくプロファイルオブジェクトを活用できます。 プロファイルの更新通知を受け取るには、以下の[サブスクリプションステータスの更新をリッスンする](subscription-status#listening-for-subscription-status-updates)セクションで説明している方法でプロファイルの変更を監視してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()` メソッドを使用します。 ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` レスポンスパラメーター: | パラメーター | 説明 | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Profile |

[AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクト。通常、ユーザーがプレミアムアクセスを持っているかどうかを判断するには、プロファイルのアクセスレベルのステータスだけを確認すれば十分です。

`.getProfile` メソッドは常に API へのクエリを試みるため、最新の結果を返します。何らかの理由(インターネット接続がないなど)で Adapty SDK がサーバーから情報を取得できない場合は、キャッシュのデータが返されます。また、Adapty SDK は `AdaptyProfile` キャッシュを定期的に更新し、情報をできる限り最新の状態に保ちます。

| `.getProfile()` メソッドはユーザープロファイルを返し、そこからアクセスレベルのステータスを取得できます。アプリごとに複数のアクセスレベルを設定することも可能です。たとえばニュースアプリで複数のトピックのサブスクリプションを独立して販売する場合、「sports」や「science」といったアクセスレベルを作成できます。ただし、ほとんどの場合はアクセスレベルは 1 つで十分なので、デフォルトの「premium」アクセスレベルをそのまま使用できます。 デフォルトの「premium」アクセスレベルを確認する例を示します。 ```swift showLineNumbers do { let profile = try await Adapty.getProfile() let isPremium = profile.accessLevels["premium"]?.isActive ?? false // grant access to premium features } catch { // handle the error } ``` ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get(), profile.accessLevels["premium"]?.isActive ?? false { // grant access to premium features } } ``` ### サブスクリプションステータスの更新をリッスンする \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adapty はイベントを発火します。 Adapty からのメッセージを受け取るには、追加の設定が必要です。 ```swift showLineNumbers Adapty.delegate = self // To receive subscription updates, extend `AdaptyDelegate` with this method: nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { // handle any changes to subscription state } ``` Adapty はアプリ起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDK に実装されたキャッシュはプロファイルのサブスクリプションステータスを保持します。これにより、サーバーが利用できない場合でも、キャッシュされたデータからプロファイルのサブスクリプションステータス情報を取得できます。 ただし、キャッシュから直接データをリクエストすることはできません。SDK は 1 分ごとにサーバーに問い合わせて、プロファイルに関する更新や変更を確認します。新しいトランザクションなどの変更があった場合は、サーバーとの同期を維持するためにキャッシュデータへ反映されます。 --- # File: ios-deal-with-att --- --- title: "iOSのATTについて" description: "iOSでAdaptyを使い始めて、サブスクリプションの設定と管理を効率化しましょう。" --- アプリでAppTrackingTransparencyフレームワークを使用しており、ユーザーにアプリトラッキングの許可リクエストを表示している場合は、[認証ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/)をAdaptyに送信する必要があります。 ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } ``` ```swift showLineNumbers if #available(iOS 14, macOS 11.0, *) { let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) Adapty.updateProfile(params: builder.build()) { [weak self] error in if error != nil { // handle the error } } } ``` :::warning この値は変更されたタイミングでできるだけ早く送信することを強くお勧めします。そうすることで、設定済みのインテグレーションにデータがタイムリーに送信されます。 ::: --- # File: kids-mode --- --- title: "iOS SDK のキッズモード" description: "キッズモードを簡単に有効化して Apple のポリシーに準拠できます。iOS SDK では IDFA や広告データは収集されません。" --- iOS アプリがお子様向けの場合は、[Apple](https://developer.apple.com/kids/) のポリシーに従う必要があります。Adapty SDK を使用している場合、いくつかの簡単な手順でポリシーに準拠した設定を行い、App Store の審査を通過できます。 ## 必要な対応 \{#whats-required\} 以下の情報の収集を無効化するよう、Adapty SDK を設定する必要があります。 - [IDFA(広告識別子)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) - [IP アドレス](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) また、カスタマーユーザー ID の扱いにも注意が必要です。`<名前.苗字>` 形式のユーザー ID やメールアドレスは、個人情報の収集とみなされます。キッズモードでは、ランダム化または匿名化された識別子(ハッシュ化された ID やデバイスが生成した UUID など)を使用することがベストプラクティスです。 ## キッズモードの有効化 \{#enabling-kids-mode\} ### Adapty ダッシュボードでの設定 \{#updates-in-the-adapty-dashboard\} Adapty ダッシュボードで IP アドレスの収集を無効化する必要があります。[App settings](https://app.adapty.io/settings/general) に移動し、**Collect users' IP address** の下にある **Disable IP address collection** をクリックしてください。 ### アプリコードの変更 \{#updates-in-your-mobile-app-code\} ポリシーに準拠するために、ユーザーの IDFA と IP アドレスの収集を無効化してください。 Swift Package Manager を使用している場合、SDK インストール時に Xcode で **Adapty_KidsMode** モジュールを選択することでキッズモードを有効化できます。 Xcode で **File** -> **Add Package Dependency...** に進んでください。パッケージ依存関係の追加手順は Xcode のバージョンによって異なる場合があるため、必要に応じて Xcode のドキュメントを参照してください。 1. リポジトリ URL を入力します: ``` https://github.com/adaptyteam/AdaptySDK-iOS.git ``` 2. バージョンを選択し(最新の安定版を推奨)、**Add Package** をクリックします。 3. **Choose Package Products** ウィンドウで、必要なモジュールを選択します: - **Adapty_KidsMode**(コアモジュール) - **AdaptyUI_KidsMode**(オプション - ペイウォールビルダーを使用する場合のみ) 他のパッケージは不要です。 4. **Add Package** をクリックしてインストールを完了します。 5. コード内で `import Adapty` の代わりに `import Adapty_KidsMode`、`import AdaptyUI` の代わりに `import AdaptyUI_KidsMode` と記述します: ```swift ``` 1. Podfile を更新します: - `post_install` セクションが**ない**場合は、以下のコードブロック全体を追加してください。 - `post_install` セクションが**ある**場合は、ハイライトされた行をそこにマージしてください。 ```ruby showLineNumbers title="Podfile" def adapty_enable_kids_mode(installer) installer.pods_project.targets.each do |target| next unless target.name == 'Adapty' target.build_configurations.each do |config| flags = config.build_settings['OTHER_SWIFT_FLAGS'] || '$(inherited)' flags = flags.join(' ') if flags.is_a?(Array) config.build_settings['OTHER_SWIFT_FLAGS'] = "#{flags} -DADAPTY_KIDS_MODE" end target.frameworks_build_phase.files.dup.each do |bf| target.frameworks_build_phase.remove_build_file(bf) if bf.display_name.to_s.include?('AdSupport') end end installer.pods_project.save Dir.glob(File.join(installer.sandbox.root, 'Target Support Files', '**', '*.xcconfig')).each do |xc| File.write(xc, File.read(xc).gsub(/\s*-framework\s+"?AdSupport"?/, '')) end end post_install do |installer| # ... keep your existing post_install body (Flutter adds one automatically) ... adapty_enable_kids_mode(installer) # <-- enable Adapty Kids Mode end ``` 2. 以下のコマンドを実行して変更を適用します: ```sh showLineNumbers title="Shell" pod install ``` --- # File: get-onboardings --- --- title: "オンボーディングとその設定を取得する" description: "Adapty でオンボーディングを取得する方法を学びましょう。" --- :::tip **SDK v4(ベータ版)以降**、オンボーディングのより強力な代替として[フロー](get-pb-paywalls)を構築できます。オンボーディングが WebView 内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、アニメーションがスムーズになり、iOS の一貫した外観と操作感が得られ、読み込みが速く、WebView ランタイムへの依存もありません。詳しくは [Get flows & paywalls](get-pb-paywalls) および [Display flows & paywalls](ios-present-paywalls) をご覧ください。 ::: Adapty ダッシュボードのビルダーで[オンボーディングのビジュアル部分をデザイン](design-onboarding)したら、モバイルアプリにそれを表示できます。最初のステップは、プレースメントに関連付けられたオンボーディングとそのビュー設定を以下の手順で取得することです。 始める前に、次の点を確認してください: 1. [Adapty iOS、Android、React Native、または Flutter SDK](installation-of-adapty-sdks) バージョン 3.8.0 以上をインストールしていること。 2. [オンボーディングを作成](create-onboarding)していること。 3. オンボーディングを[プレースメント](placements)に追加していること。 ## オンボーディングを取得する \{#fetch-onboarding\} ノーコードビルダーで[オンボーディング](onboardings)を作成すると、アプリが取得して表示する必要のある設定を含むコンテナとして保存されます。このコンテナは、表示されるコンテンツ、表示方法、ユーザーのインタラクション(クイズの回答やフォームの入力など)の処理方法といった全体的なエクスペリエンスを管理します。また、コンテナは自動的にアナリティクスイベントを追跡するため、個別にビュートラッキングを実装する必要はありません。 パフォーマンスを最大限に発揮するために、ユーザーに表示する前に画像をダウンロードする時間を確保できるよう、オンボーディングの設定を早めに取得することをお勧めします。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```swift showLineNumbers do { let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // the requested onboarding } catch { // handle the error } ``` パラメーター: | パラメーター | 必須 / 任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

オンボーディングのローカライズ識別子。このパラメーターは、マイナス(**-**)で区切られた 1 つまたは 2 つのサブタグで構成される言語コードです。最初のサブタグは言語、2 番目のサブタグは地域を表します。

例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。

ロケールコードと推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。

| | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この設定では常に最新のデータが取得できるため、推奨しています。

ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータがあればそちらを返すことを検討してください。この場合、最新データが取得できないことがありますが、通信状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを減らす目的で安全に使用できます。

キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ消去されます。

Adapty SDK はオンボーディングをローカルに 2 層で保存しています:上記の定期更新キャッシュとフォールバックオンボーディングです。また、CDN を使用してオンボーディングをより速く取得し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムにより、インターネット接続が不安定な場合でも、常に最新バージョンのオンボーディングを確実に取得できます。

| | **loadTimeout** | デフォルト: 5 秒 |

このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。

内部で複数のリクエストが実行される場合があるため、まれに `loadTimeout` で指定した時間より少し遅くタイムアウトすることがあります。

| レスポンスパラメーター: | パラメーター | 説明 | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | オンボーディング識別子と設定、リモートコンフィグ、その他のプロパティを含む [`AdaptyOnboarding`](https://swift.adapty.io/documentation/adapty/adaptyonboarding) オブジェクト。 | ## デフォルトオーディエンスのオンボーディングで取得を高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ即座に取得されるため、このプロセスの高速化を特に意識する必要はありません。ただし、オーディエンスやオンボーディングが多数あり、ユーザーのインターネット接続が不安定な場合は、取得に想定以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないよりも、デフォルトのオンボーディングを表示してスムーズなユーザー体験を提供したい場合があるかもしれません。 これに対応するために、`getOnboardingForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンス向けオンボーディングを取得します。ただし、推奨されるアプローチは上記の[オンボーディングを取得する](#fetch-onboarding)セクションで説明した `getOnboarding` メソッドを使用することです。 :::warning `getOnboardingForDefaultAudience` の代わりに `getOnboarding` の使用を検討してください。前者には以下の重要な制限があります: - **互換性の問題**:複数のアプリバージョンをサポートする場合に問題が生じる可能性があります。後方互換性のあるデザインにするか、古いバージョンで正しく表示されないことを許容する必要があります。 - **パーソナライゼーションなし**:「All Users」オーディエンス向けのコンテンツのみが表示され、国・アトリビューション・カスタム属性に基づくターゲティングが機能しません。 ユースケースにおいて取得の高速化がこれらのデメリットを上回る場合は、以下に示す `getOnboardingForDefaultAudience` を使用してください。そうでない場合は、[上記](#fetch-onboarding)の `getOnboarding` を使用してください。 ::: ```swift showLineNumbers Adapty.getOnboardingForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(onboarding): // the requested onboarding case let .failure(error): // handle the error } } ``` パラメーター: | パラメーター | 必須 / 任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

オンボーディングのローカライズ識別子。このパラメーターは、マイナス(**-**)で区切られた 1 つまたは 2 つのサブタグで構成される言語コードです。最初のサブタグは言語、2 番目のサブタグは地域を表します。

例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。

ロケールコードと推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。

| | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この設定では常に最新のデータが取得できるため、推奨しています。

ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータがあればそちらを返すことを検討してください。この場合、最新データが取得できないことがありますが、通信状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを減らす目的で安全に使用できます。

キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ消去されます。

Adapty SDK はオンボーディングをローカルに 2 層で保存しています:上記の定期更新キャッシュとフォールバックオンボーディングです。また、CDN を使用してオンボーディングをより速く取得し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムにより、インターネット接続が不安定な場合でも、常に最新バージョンのオンボーディングを確実に取得できます。

| --- # File: ios-present-onboardings --- --- title: "iOS SDKでオンボーディングを表示する" description: "iOSでオンボーディングを表示してコンバージョンと収益を高める方法を説明します。" --- :::tip **SDK v4(ベータ版)以降**、オンボーディングのより強力な代替手段として[フロー](get-pb-paywalls)を構築できます。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、スムーズなアニメーション、iOSらしい一貫した外観、高速な読み込み、WebViewランタイムへの依存がなくなります。始めるには[フロー & ペイウォールの取得](get-pb-paywalls)と[フロー & ペイウォールの表示](ios-present-paywalls)をご覧ください。 ::: ビルダーを使ってオンボーディングをカスタマイズした場合、モバイルアプリのコードでレンダリング処理を実装する必要はありません。オンボーディングには、表示内容と表示方法がすべて含まれています。 開始する前に、以下を確認してください: 1. [Adapty iOS SDK](sdk-installation-ios) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## SwiftでオンボーディングををPresent \{#present-onboardings-in-swift\} デバイス画面にビジュアルオンボーディングを表示するには、以下の手順を実行します: 1. `.getOnboardingConfiguration` メソッドを使ってオンボーディングのビュー設定を取得します。 2. `.onboardingController` メソッドを使って表示したいビジュアルオンボーディングを初期化します: リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | |:-----------------------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding configuration** | 必須 | オンボーディングのすべてのプロパティを含む `AdaptyUI.OnboardingConfiguration` オブジェクト。`AdaptyUI.getOnboardingConfiguration` メソッドで取得します。 | | **delegate** | 必須 | オンボーディングのイベントを受け取るための `AdaptyOnboardingControllerDelegate`。 | 戻り値: | オブジェクト | 説明 | |:-------------------------------|:--------------------------------------------------------| | **AdaptyOnboardingController** | リクエストされたオンボーディング画面を表すオブジェクト | 3. オブジェクトの作成に成功したら、デバイスの画面に表示できます: ```swift showLineNumbers title="Swift" import Adapty import AdaptyUI // 0. Get an onboarding if you haven't done it yet let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Create Onboarding View Controller let onboardingController = try AdaptyUI.onboardingController( with: configuration, delegate: ) // 3. Present it to the user present(onboardingController, animated: true) ``` ## SwiftUIでオンボーディングをPresent \{#present-onboardings-in-swiftui\} SwiftUIでデバイス画面にビジュアルオンボーディングを表示するには: ```swift showLineNumbers title="SwiftUI" // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Display the Onboarding View within your view hierarchy AdaptyOnboardingView( configuration: configuration, placeholder: { Text("Your Placeholder View") }, onCloseAction: { action in // hide the onboarding view }, onError: { error in // handle the error } ) ``` ## スプラッシュ画面とオンボーディング間のトランジションをスムーズにする \{#add-smooth-transitions-between-the-splash-screen-and-onboarding\} デフォルトでは、スプラッシュ画面とオンボーディングの間、オンボーディングが完全に読み込まれるまでローディング画面が表示されます。よりスムーズなトランジションにしたい場合は、スプラッシュ画面を延長したり、別のコンテンツを表示するようにカスタマイズできます。 そのためには、プレースホルダー(オンボーディングの読み込み中に表示するもの)を定義してください。プレースホルダーを定義すると、オンボーディングはバックグラウンドで読み込まれ、準備ができ次第自動的に表示されます。 ```swift showLineNumbers extension YourOnboardingManagerClass: AdaptyOnboardingControllerDelegate { func onboardingsControllerLoadingPlaceholder( _ controller: AdaptyOnboardingController ) -> UIView? { // instantiate and return the UIView which will be presented while onboarding is being loaded } } ``` ```swift showLineNumbers AdaptyOnboardingView( configuration: configuration, placeholder: { // define your placeholder view, which will be presented while onboarding is being loaded }, // the rest of the implementation ) ``` ## オンボーディング内のリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディング内のリンクの開き方のカスタマイズは、Adapty SDK v3.15.1 以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、アプリを切り替えることなくウェブページをアプリ内で表示でき、シームレスなユーザー体験を提供します。 外部ブラウザでリンクを開きたい場合は、`externalUrlsPresentation` パラメータを `.externalBrowser` に設定することでこの動作をカスタマイズできます: ```swift showLineNumbers let configuration = try AdaptyUI.getOnboardingConfiguration( forOnboarding: onboarding, externalUrlsPresentation: .externalBrowser // default – .inAppBrowser ) ``` --- # File: ios-handling-onboarding-events --- --- title: "iOS SDKでオンボーディングイベントを処理する" description: "AdaptyのiOSを使用してオンボーディング関連のイベントを処理します。" --- :::tip **SDK v4(ベータ版)以降**、オンボーディングよりも強力な代替手段として[フロー](get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされます。これにより、よりスムーズなアニメーション、一貫したiOSのルック&フィール、高速な読み込み、そしてWebViewランタイムへの依存がなくなります。はじめに[フロー&ペイウォールを取得する](get-pb-paywalls)と[フロー&ペイウォールを表示する](ios-present-paywalls)をご覧ください。 ::: 始める前に、以下を確認してください。 1. [Adapty iOS SDK](sdk-installation-ios) 3.8.0以降をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ビルダーで設定されたオンボーディングは、アプリが応答できるイベントを生成します。これらのイベントへの応答方法について以下で説明します。 モバイルアプリのオンボーディング画面で発生するプロセスを制御または監視するには、`AdaptyOnboardingControllerDelegate`のメソッドを実装します。 ## カスタムアクション \{#custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。 このIDをコード内で使用し、カスタムアクションとして処理できます。たとえば、ユーザーが**ログイン**や**通知を許可**などのカスタムボタンをタップすると、デリゲートメソッド`onboardingController`が`.custom(id:)`ケースでトリガーされ、`actionId`パラメータはビルダーの**Action ID**になります。"allowNotifications"のような独自のIDを作成できます。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onCustomAction action: AdaptyOnboardingsCustomAction) { if action.actionId == "allowNotifications" { // Request notification permissions } } func onboardingController(_ controller: AdaptyOnboardingController, didFailWithError error: AdaptyUIError) { // Handle errors } ```
イベントの例(クリックして展開) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
## オンボーディングを閉じる \{#closing-onboarding\} オンボーディングは、ユーザーが**閉じる**アクションが割り当てられたボタンをタップすると閉じられたと見なされます。 :::important ユーザーがオンボーディングを閉じたときの処理を自分で実装する必要があります。たとえば、オンボーディング自体の表示を停止する必要があります。 ::: 例: ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onCloseAction action: AdaptyOnboardingsCloseAction) { controller.dismiss(animated: true) } ```
イベントの例(クリックして展開) ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
## ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合はこのイベントを処理してください。オンボーディングが閉じた後にペイウォールを開きたい場合は、[`AdaptyOnboardingsCloseAction`](#closing-onboarding)を処理してイベントデータに依存せずにペイウォールを開く、よりシンプルな方法があります。 ::: オンボーディングでペイウォールをシームレスに扱う最善の方法は、アクションIDをペイウォールのプレースメントIDと同じにすることです。これにより、`AdaptyOnboardingsOpenPaywallAction`の後、プレースメントIDを使用してすぐにペイウォールを取得して開くことができます。 一度に表示できるビュー(ペイウォールまたはオンボーディング)は1つだけです。オンボーディングの上にペイウォールを表示すると、バックグラウンドのオンボーディングをプログラムで制御することができません。オンボーディングを閉じようとすると、代わりにペイウォールが閉じられ、オンボーディングが表示されたままになります。これを避けるために、ペイウォールを表示する前に必ずオンボーディングビューを閉じてください。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onPaywallAction action: AdaptyOnboardingsOpenPaywallAction) { // Dismiss onboarding before presenting the flow controller.dismiss(animated: true) { Task { do { // Get the flow using the placement ID from the action let flow = try await Adapty.getFlow(placementId: action.actionId) // Get the flow configuration let flowConfiguration = try await AdaptyUI.getFlowConfiguration( forFlow: flow ) // Create and present the flow controller let flowController = try AdaptyUI.flowController( with: flowConfiguration, delegate: self ) // Present the flow from the root view controller if let rootVC = UIApplication.shared.windows.first?.rootViewController { rootVC.present(flowController, animated: true) } } catch { // Handle any errors that occur during flow loading print("Failed to present flow: \(error)") } } } } ```
イベントの例(クリックして展開) ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ```
## オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、このメソッドが呼び出されます。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, didFinishLoading action: OnboardingsDidFinishLoadingAction) { // Handle loading completion } ```
イベントの例(クリックして展開) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
## ナビゲーションの追跡 \{#tracking-navigation\} `onAnalyticsEvent`メソッドは、オンボーディングフロー中にさまざまなアナリティクスイベントが発生したときに呼び出されます。 `event`オブジェクトは以下のいずれかのタイプになります。 |タイプ | 説明 | |------------|-------------| | `onboardingStarted` | オンボーディングが読み込まれたとき | | `screenPresented` | 任意の画面が表示されたとき | | `screenCompleted` | 画面が完了したとき。オプションの`elementId`(完了した要素の識別子)とオプションの`reply`(ユーザーからの回答)が含まれます。ユーザーが画面を離れるためのアクションを実行したときにトリガーされます。 | | `secondScreenPresented` | 2番目の画面が表示されたとき | | `userEmailCollected` | 入力フィールドを通じてユーザーのメールアドレスが収集されたときにトリガーされます | | `onboardingCompleted` | ユーザーが`final` IDを持つ画面に到達したときにトリガーされます。このイベントが必要な場合は、[最後の画面に`final` IDを割り当ててください](design-onboarding)。 | | `unknown` | 認識できないイベントタイプの場合。`name`(不明なイベントの名前)と`meta`(追加のメタデータ)が含まれます | 各イベントには以下を含む`meta`情報が含まれます。 | フィールド | 説明 | |------------|-------------| | `onboardingId` | オンボーディングフローの一意の識別子 | | `screenClientId` | 現在の画面の識別子 | | `screenIndex` | フロー内の現在の画面の位置 | | `screensTotal` | フロー内の画面の総数 | 以下はアナリティクスイベントをトラッキングに使用する例です。 ```swift func onboardingController(_ controller: AdaptyOnboardingController, onAnalyticsEvent event: AdaptyOnboardingsAnalyticsEvent) { switch event { case .onboardingStarted(let meta): // Track onboarding start trackEvent("onboarding_started", meta: meta) case .screenPresented(let meta): // Track screen presentation trackEvent("screen_presented", meta: meta) case .screenCompleted(let meta, let elementId, let reply): // Track screen completion with user response trackEvent("screen_completed", meta: meta, elementId: elementId, reply: reply) case .onboardingCompleted(let meta): // Track successful onboarding completion trackEvent("onboarding_completed", meta: meta) case .unknown(let meta, let name): // Handle unknown events trackEvent(name, meta: meta) // Handle other cases as needed } } ```
イベントの例(クリックして展開) ```javascript // onboardingStarted { "name": "onboarding_started", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } // screenPresented { "name": "screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "interests_screen", "screen_index": 2, "total_screens": 4 } } // screenCompleted { "name": "screen_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 }, "params": { "element_id": "profile_form", "reply": "success" } } // secondScreenPresented { "name": "second_screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // userEmailCollected { "name": "user_email_collected", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // onboardingCompleted { "name": "onboarding_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
--- # File: ios-onboarding-input --- --- title: "iOS SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用して、iOSアプリのオンボーディングからデータを保存・活用する方法を説明します。" --- :::tip **SDK v4(ベータ版)以降**、オンボーディングのより強力な代替手段として[フロー](get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したiOSの外観、高速な読み込み、そしてWebViewランタイムへの依存がなくなります。詳細は[フローとペイウォールの取得](get-pb-paywalls)および[フローとペイウォールの表示](ios-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`onStateUpdatedAction` メソッドが呼び出されます。フィールドの種類をコード内で保存または処理することができます。 例: ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Store user preferences or responses switch action.params { case .select(let params): // Handle single selection case .multiSelect(let params): // Handle multiple selections case .input(let params): // Handle text input case .datePicker(let params): // Handle date selection } } ``` `action` オブジェクトに含まれる情報: | パラメーター | 説明 | |----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `elementId` | 入力要素の一意の識別子です。回答を保存する際に、質問と回答を紐付けるために使用できます。 | | `params` | ユーザーの入力データオブジェクトで、typeとvalueのプロパティを含みます。 | | `params.type` | 入力要素のタイプです。以下のいずれかになります:
• `"select"` - オプションからの単一選択
• `"multiSelect"` - オプションからの複数選択
• `"input"` - テキスト入力フィールド
• `"datePicker"` - 日付選択 | | `params.value` | ユーザーが選択または入力した値です。構造はタイプによって異なります:
• `select`:`id`、`value`、`label` を持つオブジェクト
• `multiSelect`:`id`、`value`、`label` を持つオブジェクトの配列
• `input`:`type`、`value` を持つオブジェクト
• `datePicker`:`day`、`month`、`year` を持つオブジェクト |
保存されたデータの例(実装によって異なる場合があります) ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ```
## ユースケース \{#use-cases\} ### ユーザープロファイルをデータで充実させる \{#enrich-user-profiles-with-data\} 入力データをユーザープロファイルにすぐに紐付けて、同じ情報を二度聞かないようにするには、アクションを処理する際に入力データで[ユーザープロファイルを更新](setting-user-attributes)する必要があります。 例えば、`name` というIDを持つテキストフィールドにユーザーの名前を入力してもらい、そのフィールドの値をユーザーの名前として設定したいとします。また、`email` フィールドにメールアドレスを入力してもらう場合、アプリのコードは次のようになります: ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Store user preferences or responses switch action.params { case .input(let params): // Handle text input let builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field switch action.elementId { case "name": builder.with(firstName: params.value.value) case "email": builder.with(email: params.value.value) default: break } // Delegate methods are synchronous; kick off the async update in a Task. Task { do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } } default: break } } ``` ### 回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングのクイズを活用して、ユーザーがオンボーディングを完了した後に表示するペイウォールをカスタマイズすることもできます。 例えば、スポーツの経験について質問し、ユーザーグループごとに異なるCTAとプロダクトを表示することができます。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、各オプションにわかりやすいIDを割り当てます。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](setting-user-attributes)します。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Handle quiz responses and set custom attributes switch action.params { case .select(let params): // Handle quiz selection let builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes switch action.elementId { case "experience": // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) try? builder.with(customAttribute: params.value.value, forKey: "experience") default: break } // Delegate methods are synchronous; kick off the async update in a Task. Task { do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } } default: break } } ``` 3. カスタム属性の値ごとに[セグメントを作成](segments)します。 4. [プレースメント](placements)を作成し、作成した各セグメントの[オーディエンス](audience)を追加します。 5. アプリのコードでそのプレースメントの[ペイウォールを表示](ios-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[そのボタンのアクションへの応答](ios-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: ios-sdk-call-order --- --- title: "iOS SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的な #2002 エラーを防ぎます。" --- `Adapty.activate()` が完了するまで、他のAdapty SDKメソッドを呼び出してはいけません。解決されるまで、SDKには状態がありません。`activate()` の前または並行して発行された呼び出しはすべて [`#2002 notActivated`](ios-sdk-error-handling#network-errors) で失敗します。 アプリがユーザー認証を行い、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `Adapty.identify()` を呼び出してください。`identify` が解決するまでユーザーアクションメソッドを呼び出さないでください。`identify` と競合する呼び出しは [`#3006 profileWasChanged`](ios-sdk-error-handling#general-errors) で失敗するか、アクティベーション時に作成された匿名プロファイルに対して実行されます。これが起きると、アトリビューション、`appsflyer_id` などのMMP ID、インストールの帰属が識別済みプロファイルに転送されないことがあります。アプリがユーザー認証を行わない場合は、`identify` をスキップして匿名プロファイルのまま使用してください。 MMP・アナリティクスSDK(AppsFlyer、Adjust、Branch、PostHog)も同じルールに従います。それらを先に初期化し、UIDコールバックを待ってから `Adapty.activate` を呼び出してください。そうしないと、MMP IDが短命な匿名プロファイルに紐づき、識別済みプロファイルに常に転送されるとは限りません。AppsFlyerの詳細については、[AppsFlyer](appsflyer) を参照してください。 ## 正しい順序 \{#the-correct-order\} どのパスを取るかは、カスタマーユーザーIDをいつ知るか、そしてMMPまたはアナリティクスSDKを使用するかどうかの2点によって決まります。 - **ステップ2と5**:すべてのアプリで必須です。SDKをアクティベートし、その後SDKメソッドを呼び出します。 - **ステップ1と3**:MMPまたはアナリティクスSDK(AppsFlyer、Adjust、Branch、PostHog)を統合する場合のみ必要です。 - **ステップ4**:アプリがユーザー認証を行い、起動後にカスタマーユーザーIDを収集する場合のみ必要です。 アプリ起動時にカスタマーユーザーIDがある場合は、`activate()` に直接渡してください(ステップ2a)。このパスでは匿名プロファイルが作成されないため、ステップ4は不要です。 | ステップ | 呼び出し | タイミング | 備考 | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | MMPまたはアナリティクスSDKの初期化(AppsFlyer、Adjust、PostHog、Branch) | アプリ起動時、最初に | MMPのUIDコールバック(例:`getAppsFlyerUID`)を待ってください。 | | 2a | `Adapty.activate(with: config)` に `customerUserId` をconfigに設定して呼び出す | アプリ起動時、ステップ1の後、カスタマーユーザーIDがある場合 | 推奨。匿名プロファイルは一切作成されません。 | | 2b | `Adapty.activate(with: config)` に `customerUserId` を設定せずに呼び出す | アプリ起動時、ステップ1の後、カスタマーユーザーIDがない場合(または収集しない場合) | Adaptyが匿名プロファイルを作成します。 | | 3 | 各MMPに対して `Adapty.setIntegrationIdentifier(...)` を呼び出す | ステップ2の後、ユーザーアクション呼び出しの前 | MMP IDが正しいプロファイルに紐づくために必要です。 | | 4 | `try await Adapty.identify("YOUR_USER_ID")` | ステップ3の後(またはMMPがない場合はステップ2の後)、ステップ5の前 — 認証ありのパス2bのみ | 必ず `await` してください。`identify` 中の並行呼び出しは `#3006 profileWasChanged` を発生させます。 | | 5 | `getPaywall`、`getPaywallProducts`、`restorePurchases`、`makePurchase`、`updateAttribution`、`updateProfile` | `identify` を呼び出す場合はステップ4の後、それ以外はステップ3の後(またはMMPがない場合はステップ2の後) | これらの呼び出しには安定したプロファイルが必要です。 | :::important これらのステップを省略すると、リターンユーザーのプレミアムアクセスの喪失、プロファイルへの `appsflyer_id` の欠落、間違ったオーディエンスに対してペイウォールが返される問題が発生します。 ::: ## Web2appとWebファネルのインストール \{#web2app-and-web-funnel-installs\} ユーザーがWebチェックアウト(Stripe、Paddle、FunnelFox)で購入し、その後ネイティブアプリをインストールする場合、デバイスで最初に `activate()` が呼ばれると新しい匿名プロファイルが作成されます。このプロファイルはWebプロファイルとリンクされていません。アプリ起動前にカスタマーユーザーIDを解決できる場合(認証フローやインストールリファラーから)、`activate()` に直接渡してください。そうしないと、`identify("YOUR_USER_ID")` を呼び出してから `restorePurchases` を実行するまで、Web購入はデバイスから見えません。 各Webチェックアウトで送信するメタデータについては、以下を参照してください: - [Stripe](stripe) - [Paddle](paddle) --- # File: ios-optimize-paywall-fetching --- --- title: "iOS SDKでペイウォールのフェッチを最適化する" description: "AdaptyのペイウォールをiOSで確実にフェッチする:タイミング、キャッシュ、フォールバックのパターン。" --- iOSで信頼性の高いペイウォールフェッチを実現するには、3つの要件を満たす必要があります。高速なレンダリング、オーディエンスターゲットに合ったペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバックです。以下のルールでは、それを実現するためのタイミング、キャッシュ、フォールバックのパターンを説明します。 :::tip 以下のルールは、`Adapty.activate()` と `Adapty.identify()` がすでに解決済みであることを前提としています。[iOS SDKのコール順序](ios-sdk-call-order)を参照してください。 ::: ## ルールと注意点 \{#rules-and-pitfalls\} | 推奨事項 | 避けるべき事項 | 理由 | |---|---|---| | 表示しようとしているプレースメントをフェッチする。 | 起動時にすべてのプレースメントを並列でプリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、バースト中に画面が真っ暗になる。 | | アトリビューションが解決される時間を確保してから `getPaywall` をフェッチする(例:`activate` から1〜2秒後、または `onProfileUpdate` が発火した後)。 | `App.init()` で `getPaywall` を呼び出す。 | アトリビューションがまだ取得されていない。ペイウォールはデフォルトのオーディエンスに対して解決され、セグメントやASAパーソナライゼーションが静かにバイパスされる。 | | `loadTimeout` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無期限に待機する。 | タイムアウトなしでは、接続が悪いユーザーはネットワークが解決するまで空白の画面を見続けるか、アプリを閉じてしまう。 | `fetchPolicy` と `loadTimeout` パラメーターのリファレンスについては[ペイウォールとプロダクトのフェッチ](fetch-paywalls-and-products)を、適切なプレースメントの選択については[プレースメント](placements)を参照してください。 ## 接続が悪い環境向けの調整 \{#tune-for-poor-connectivity\} 接続が安定しない市場(農村部、移動中、ルーティングの問題が多い地域)向けには: - 最初のフェッチを除くすべてのフェッチで `fetchPolicy: .returnCacheDataElseLoad` を設定する。 - Adapty ダッシュボードですべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeout` を3〜5秒に設定し、タイムアウトが発生した場合はフォールバックを受け入れる。 - ペイウォールの表示を `getProfile()` に依存させない。`getPaywall` は独立して呼び出すことで、プロファイルの取得が遅くてもUIをブロックしないようにする。 --- # File: ios-show-aa-targeted-paywall --- --- title: "iOS SDK の初回起動時に AA ターゲティングのペイウォールを表示する" description: "AdaptyProfile.appliedAttributionSources を使って、iOS で Apple Ads のアトリビューションを待ってからペイウォールをリクエストする方法。" --- Apple Ads(AA)のアトリビューションは、`Adapty.activate()` の後に非同期で届きます。`getPaywall` を早いタイミングで呼び出すと、アトリビューションがまだ反映されていないことが多く、Adapty はデフォルトのオーディエンスに対してプレースメントを解決してしまいます — つまり AA セグメントのペイウォールが適用されません。`AdaptyProfile.appliedAttributionSources` を使うと、AA アトリビューションがプロファイルに適用されたタイミングをアプリが検知できるため、AA セグメントが正しく解決されるまでペイウォールのリクエストを待機させられます。 ## はじめる前に \{#before-you-start\} 必要なもの: - Adapty iOS SDK **3.17.1** 以降。 - Adapty でアプリの Apple Ads を設定済みであること。詳しくは [Apple Ads](apple-search-ads) を参照してください。 ## 仕組み \{#how-it-works\} `Adapty.activate()` の後、SDK はバックグラウンドで Apple から Apple Ads のアトリビューションをリクエストし、その結果を Adapty のバックエンドに転送します。AA がプロファイルのアクティブなアトリビューションソースになると、SDK は更新された `AdaptyProfile` を配信します。この `appliedAttributionSources` 配列には `.appleAds` が含まれています。 配列が空の場合、以下のいずれかを意味します: - このプロファイルの Apple Ads アトリビューションがまだ処理されていない。 - アトリビューションが届いていない。 配列が空でも `getPaywall` の呼び出し自体は安全です — Adapty は現在のプロファイル状態に一致するオーディエンス(通常はデフォルトのオーディエンス)に対してリクエストを解決します。 :::important この待機処理は**初回起動時のみ**適用されます。Apple Ads のアトリビューションが一度記録されると、プロファイルに永続的に保存されます。2 回目以降の起動では、キャッシュされたプロファイルにすでに `.appleAds` が `appliedAttributionSources` に含まれているため、`didLoadLatestProfile` はその値ですぐに発火し、`getPaywall` は遅延なく Apple Ads セグメントのペイウォールを返します。 ::: ## 実装 \{#implementation\} 初回起動時は、プロファイル内の `.appleAds` を監視しながら、厳格なタイムアウトを設定してください — Apple Ads のアトリビューションが届かない場合でも、ユーザーにはペイウォールを表示する必要があります。 1. **SDK を有効化します。** [iOS SDK のインストールと設定](sdk-installation-ios) を参照してください。 2. **`AdaptyDelegate` に準拠して `didLoadLatestProfile` を実装することでプロファイルの更新を購読します。** デリゲートをまだ設定していない場合は、[サブスクリプションのアップデートを監視する](ios-check-subscription-status#listen-to-subscription-updates) を参照してください。 3. **`appliedAttributionSources` に `.appleAds` が含まれているか監視します。** 含まれている場合にペイウォールをリクエストすると、Adapty は AA セグメントのバリアントを返します: ```swift extension : AdaptyDelegate { nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { if profile.appliedAttributionSources.contains(where: { $0 == .appleAds }) { // load paywall via Adapty.getPaywall(placementId:) } } } ``` 4. **購読と並行して 3〜5 秒のタイマーを開始します。** タイマーが先に発火した場合は、`.appleAds` が現れなくてもペイウォールをリクエストします: どちらのパスが先に発火しても、その時点でペイウォールを読み込み、もう一方のパスはスキップします。ペイウォールが 2 回フェッチされないよう、単一の状態フラグ(例:`hasLoadedPaywall`)を使って重複を排除してください。ネットワークリクエストが失敗してもユーザーが詰まらないよう、プレースメントに [フォールバックペイウォール](fallback-paywalls) を設定してください。 ## 完全なサンプル \{#complete-example\} 以下の実装は、アトリビューションとタイムアウトを競争させ、デフォルトのオーディエンスのペイウォールを並行してプリフェッチし、適切なペイウォールを返します。呼び出し元は単一の非同期関数を await するだけで、呼び出し側でデリゲートや状態フラグを管理する必要はありません。 `ProfileObserver` は `AdaptyDelegate` からプロファイルの更新を公開する再利用可能なシングルトンです。`PaywallLoader.getPaywallOrDefault` は structured concurrency の `TaskGroup` を使って競争を実行します: - タイムアウト内にアトリビューションが届いた場合、`getPaywall(placementId:)` を通じてセグメント化されたペイウォールを返します。 - `timeout` が先に経過した場合、`getPaywallForDefaultAudience(placementId:)` を通じてプリフェッチ済みのデフォルトオーディエンスのペイウォールを返します。 ```swift title="PaywallLoader.swift" /// Demonstrates how to fetch a paywall that depends on attribution being applied, /// falling back to the default-audience paywall if attribution doesn't arrive in time. /// /// Stateless and self-contained: every call kicks off its own default-audience /// prefetch and races it against attribution + segmented fetch. enum PaywallLoader { static func getPaywallOrDefault( placementId: String, timeout: TimeInterval ) async throws -> AdaptyPaywall { struct TimedOut: Error {} // Kick off the default-audience request immediately so it has the full // `timeout` window to load. We'll either cancel it on success or await // its result on timeout — never a duplicate network call. let defaultPaywallTask = Task { try await Adapty.getPaywallForDefaultAudience(placementId: placementId) } do { // Race two child tasks: whichever finishes first wins. let result = try await withThrowingTaskGroup(of: AdaptyPaywall.self) { group in // 1. Wait for attribution, then ask Adapty for the segmented paywall. group.addTask { await waitForAttribution() return try await Adapty.getPaywall(placementId: placementId) } // 2. Time-bomb: throws `TimedOut` after `timeout` seconds. group.addTask { try await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000)) throw TimedOut() } guard let value = try await group.next() else { throw CancellationError() } group.cancelAll() // stop the loser (sleeper or the attribution wait). return value } // Segmented paywall won — we no longer need the default-audience prefetch. defaultPaywallTask.cancel() return result } catch is TimedOut { // Attribution didn't apply in time — return the prefetched default // (instant if already done, otherwise we await the in-flight request). return try await defaultPaywallTask.value } } /// Suspends until a profile with the desired attribution source is observed. /// `@Published.values` emits the current profile immediately on subscription, /// so this returns on the first iteration if attribution is already applied. @MainActor private static func waitForAttribution() async { for await profile in ProfileObserver.shared.$profile.values { if profile?.appliedAttributionSources.contains(.appleAds) == true { return } } } } @MainActor final class ProfileObserver: AdaptyDelegate { static let shared = ProfileObserver() @Published private(set) var profile: AdaptyProfile? nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { Task { @MainActor [weak self] in self?.profile = profile } } } ``` `Adapty.activate()` の完了後、一度だけ `ProfileObserver` を `AdaptyDelegate` に接続します: ```swift Adapty.delegate = ProfileObserver.shared ``` スプラッシュスクリーンから呼び出します: ```swift do { let paywall = try await PaywallLoader.getPaywallOrDefault( placementId: "YOUR_PLACEMENT_ID", timeout: 5 ) // present the paywall } catch { // handle the error or show a fallback paywall } ``` 他の目的(例:[サブスクリプションのアップデートを監視する](ios-check-subscription-status#listen-to-subscription-updates))のために既に `AdaptyDelegate` を使用している場合は、`Adapty.delegate = ProfileObserver.shared` を設定する代わりに、既存のデリゲートから `ProfileObserver.shared` に `didLoadLatestProfile` を転送してください。 --- # File: ios-test --- --- title: "iOSSDKのテストとリリース" description: "AdaptyでiOSアプリのサブスクリプション状態を確認する方法を学びましょう。" --- AdaptyのSDKをiOSアプリに実装したら、すべてが正しく設定されており、購入が期待どおりに動作することをテストしましょう。これには、SDKの統合と実際の購入の両方のテストが含まれます。 ## アプリをテストする \{#test-your-app\} サンドボックステストやTestFlightの検証を含むアプリ内課金の包括的なテストについては、[テストガイド](test-purchases-in-sandbox)をご覧ください。 ## リリースの準備 \{#prepare-for-release\} アプリをストアに申請する前に、[リリースチェックリスト](release-checklist)に従って以下を確認してください: - ストア接続とサーバー通知が設定されている - 購入が完了し、Adaptyに報告されている - アクセスが正しく解除および復元される - プライバシーおよびレビュー要件が満たされている --- # File: InvalidProductIdentifiers --- --- title: "Code-1000 noProductIDsFound エラーの修正" description: "Adapty でサブスクリプションを管理する際の無効なプロダクト識別子エラーを解決します。" --- 1000 コードエラー `noProductIDsFound` は、ペイウォールでリクエストしたプロダクトが App Store に登録されているにもかかわらず、購入可能な状態でないことを示します。このエラーには `InvalidProductIdentifiers` の警告が伴う場合があります。エラーなしに警告だけが表示される場合は、無視して問題ありません。 `noProductIDsFound` エラーが発生している場合は、以下の手順で解決してください。 ## ステップ 1. Bundle ID を確認する \{#step-2-check-bundle-id\} --- no_index: true --- 1. [App Store Connect](https://appstoreconnect.apple.com/apps) を開きます。アプリを選択し、**General** → **App Information** セクションに進みます。 2. **General Information** サブセクションで **Bundle ID** をコピーします。 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 4. App Store Connect の **App information** ページに戻り、**Apple ID** をコピーします。 5. Adapty ダッシュボードの [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) ページで、**Apple app ID** フィールドにその ID を貼り付けます。 ## ステップ 2. プロダクトを確認する \{#step-2-check-products\} 1. **App Store Connect** を開き、左側のメニューから [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) に移動します。 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テスト対象のプロダクトが **Ready to Submit** になっていることを確認してください。なっていない場合は、[App Store のプロダクト](app-store-products)ページの手順に従ってください。 4. テーブルに表示されているプロダクト ID と、Adapty ダッシュボードの [**Products**](https://app.adapty.io/products) タブに登録されているプロダクト ID を照合してください。ID が一致しない場合は、テーブルからプロダクト ID をコピーして、Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 ## ステップ 3. プロダクトの利用可能地域を確認する \{#step-4-check-product-availability\} 1. **App Store Connect** に戻り、同じ **Subscriptions** セクションを開きます。 2. サブスクリプショングループ名をクリックして、プロダクト一覧を表示します。 3. テスト対象のプロダクトを選択します。 4. **Availability** セクションまでスクロールし、必要な国と地域がすべて一覧に含まれていることを確認してください。 ## ステップ 4. プロダクトの価格を確認する \{#step-5-check-product-prices\} 1. 再び **App Store Connect** の **Monetization** → **Subscriptions** セクションに移動します。 2. サブスクリプショングループ名をクリックします。 3. テスト対象のプロダクトを選択します。 4. **Subscription Pricing** までスクロールし、**Current Pricing for New Subscribers** セクションを展開します。 5. 必要な価格がすべて一覧に含まれていることを確認してください。 ## ステップ 5. アプリの有料ステータス、銀行口座、税務フォームがアクティブであることを確認する \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. [**App Store Connect**](https://appstoreconnect.apple.com/) のホームページで **Business** をクリックします。 2. 会社名を選択します。 3. 下にスクロールして、**Paid Apps Agreement**、**Bank Account**、**Tax forms** がすべて **Active** になっていることを確認します。 以上の手順を実行することで、`InvalidProductIdentifiers` の警告を解消し、プロダクトをストアで公開できるようになります。 ## ステップ 6. プロダクトがスタックしている場合は再作成する \{#step-6-recreate-the-product-if-its-stuck\} ステップ 1〜5 がすべて問題なく通過している場合(`Approved` ステータス、Bundle ID の一致、有効な API キーなど)でも、SDK が `1000 noProductIDsFound` を返し続けることがあります。この場合、プロダクトが Apple のレジストリでスタックしている可能性があります。App Store Connect の UI 上にはプロダクトが存在していても、StoreKit のルックアップパスに公開されていない状態になることがあります。 App Store Connect でプロダクトを削除し、同じプロダクト ID で再作成してください。再作成後、反映されるまで最大 24 時間かかる場合があります。 --- # File: cantMakePayments --- --- title: "Code-1003 cantMakePayment エラーの修正" description: "Adapty でサブスクリプションを管理する際に発生する支払いエラーを解決します。" --- 1003エラー(`cantMakePayments`)は、このデバイスでアプリ内課金ができないことを示しています。 `cantMakePayments`エラーが発生している場合、通常は以下のいずれかの原因が考えられます: - デバイスの制限:このエラーはAdaptyとは無関係です。以下の解決方法を参照してください。 - オブザーバーモードの設定:`makePurchase`メソッドとオブザーバーモードは同時に使用できません。以下のセクションを参照してください。 ## 問題:デバイスの制限 \{#issue-device-restrictions\} | 問題 | 解決方法 | |-----------------------------|---------------------------------------------------------| | スクリーンタイムの制限 | [スクリーンタイム](https://support.apple.com/en-us/102470)でアプリ内課金の制限を無効にする | | アカウントの停止 | Appleサポートに連絡してアカウントの問題を解決する | | 地域の制限 | 対応地域のApp Storeアカウントを使用する | ## 問題:オブザーバーモードとmakePurchaseの併用 \{#issue-using-both-observer-mode-and-makepurchase\} 購入処理に`makePurchase`を使用している場合、オブザーバーモードを使用する必要はありません。[オブザーバーモード](observer-vs-full-mode)が必要なのは、購入ロジックを自分で実装する場合のみです。 したがって、`makePurchase`を使用している場合は、SDK有効化コードからオブザーバーモードの有効化を安全に削除できます。 --- # File: migration-to-ios-sdk-v4 --- --- title: "Adapty iOS SDK を v4.0 に移行する" description: "ペイウォール API をフロー API に置き換えることで Adapty iOS SDK v4.0 (beta) に移行します。Flow Builder と Paywall Builder の両方に対応しています。" --- Adapty iOS SDK 4.0 (beta) ではフローが導入され、それに伴いペイウォール API の名称が変更されました。新しい API は新しい Flow Builder と既存の Paywall Builder の両方に対応しており、Adapty ダッシュボード側での設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId:locale:)` | `Adapty.getFlow(placementId:)` | | `AdaptyUI.getPaywallConfiguration(forPaywall:)` | `AdaptyUI.getFlowConfiguration(forFlow:locale:)` | | `Adapty.getPaywallProducts(paywall:)` | `Adapty.getPaywallProducts(flow:)` | | `Adapty.logShowPaywall(_:)` | `Adapty.logShowFlow(_:)` | | `AdaptyPaywallController` | `AdaptyFlowController` | | `AdaptyPaywallControllerDelegate` | `AdaptyFlowControllerDelegate` | | `AdaptyUI.paywallController(with:delegate:)` | `AdaptyUI.flowController(with:delegate:)` | | `.paywall()` (SwiftUI modifier) | `.flow()` | | `AdaptyPaywallView` | `AdaptyFlowView` | | `didFailRenderingWith:` / `didFailRendering:` | `didReceiveError:` | | `Adapty.updateAttribution(_:source:)` (`source: String`) | `Adapty.updateAttribution(_:source:)` (`source: AdaptyAttributionSource`) | | `Adapty.setIntegrationIdentifier(key:value:)` | `Adapty.setIntegrationIdentifier(_:)` (`AdaptyIntegrationIdentifier`) | ## iOS 最小バージョン \{#minimum-ios-version\} Adapty iOS SDK 4.0 では、最小デプロイメントターゲットが iOS 13.0 から **iOS 15.0** に引き上げられました。アップグレードの前に、プロジェクトの iOS Deployment Target を 15.0 以上に設定してください。 ## インストール:CocoaPods のサポート終了 \{#installation-cocoapods-no-longer-supported\} Adapty iOS SDK 4.0 では CocoaPods のサポートが廃止されました。SDK のインストールには [Swift Package Manager](sdk-installation-ios#install-adapty-sdk) をご利用ください。 プロジェクトで引き続き CocoaPods を使用している場合は、`Podfile` から `Adapty` および `AdaptyUI` の pod を削除し、`pod install` を実行してクリーンアップした後、Xcode の **File → Add Package Dependency** から `https://github.com/adaptyteam/AdaptySDK-iOS.git` を使ってパッケージを追加してください。 ## 削除された API \{#removed-apis\} - **`Adapty.getPaywallProductsWithoutDeterminingOffer(paywall:)`** — 削除されました。すべてのプロダクトにオファー情報が含まれるようになったため、個別の対象資格確認パスは不要になりました。 - **`AdaptyPaywallProductWithoutDeterminingOffer`** — 削除されました。以前このタイプを渡していたコールバック(`didSelectProduct` など)は、今後 `AdaptyPaywallProduct` を渡すようになります。 ## App Store プロモートアプリ内課金の一時的な削除 \{#app-store-promoted-in-app-purchases-temporarily-removed\} StoreKit 2 への移行の一環として、Adapty iOS SDK 4.0 では App Store プロモートアプリ内課金のサポートが削除されました。`shouldAddStorePayment(for:)` デリゲートメソッドおよびそれが受け取る `AdaptyDeferredProduct` 型は、4.0 では使用できません。 :::warning この削除は一時的なものです — プロモートアプリ内課金のサポートは、今後の 4.x リリースで復活する予定です。アプリがプロモートアプリ内課金に依存している場合は、サポートが戻るまで iOS SDK 3.x をご利用ください。 ::: ## ペイウォールの取得 \{#fetching-paywalls\} ### getPaywall + getPaywallConfiguration → getFlow + getFlowConfiguration 返却される型は `AdaptyPaywall` / `AdaptyUI.PaywallConfiguration` から `AdaptyFlow` / `AdaptyUI.FlowConfiguration` に変わります。`locale` パラメータはフェッチ呼び出しから `getFlowConfiguration` に移動します。 ```diff showLineNumbers - let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") - let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall) + let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") + let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "en") ``` ### getPaywallProducts(paywall:) → getPaywallProducts(flow:) `getPaywallProducts` は、`Adapty.getFlow` によって返された `AdaptyFlow` を受け取るようになりました: ```diff showLineNumbers - let products = try await Adapty.getPaywallProducts(paywall: paywall) + let products = try await Adapty.getPaywallProducts(flow: flow) ``` ## ペイウォールの表示を記録する \{#tracking-paywall-views\} ### logShowPaywall(_:) → logShowFlow(_:) `logShowPaywall` は `logShowFlow` にリネームされ、`AdaptyPaywall` の代わりに `AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリアントに対して記録されるため、既存のファネルや A/B テストの指標はダッシュボードの変更なしに引き続き機能します。 ```diff showLineNumbers - try await Adapty.logShowPaywall(paywall) + try await Adapty.logShowFlow(flow) ``` v3と同様に、[Flow Builder](adapty-flow-builder)や[Paywall Builder](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示する際には、このメソッドを呼び出す必要はありません。これらのビューはAdaptyが自動的にトラッキングします。 ## UIKit \{#uikit\} ### AdaptyPaywallController → AdaptyFlowController コントローラーの型とファクトリーメソッドの名前を変更します: ```diff showLineNumbers - let controller = try AdaptyUI.paywallController( - with: paywallConfiguration, - delegate: self - ) + let controller = try AdaptyUI.flowController( + with: flowConfiguration, + delegate: self + ) ``` ### AdaptyPaywallControllerDelegate → AdaptyFlowControllerDelegate プロトコルの名前を変更し、すべてのメソッドシグネチャを更新してください。なお、`didSelectProduct` は削除された `AdaptyPaywallProductWithoutDeterminingOffer` の代わりに `AdaptyPaywallProduct` を受け取るようになりました。 ```diff showLineNumbers - class YourClass: AdaptyPaywallControllerDelegate { + class YourClass: AdaptyFlowControllerDelegate { - func paywallControllerDidAppear(_ controller: AdaptyPaywallController) { } + func flowControllerDidAppear(_ controller: AdaptyFlowController) { } - func paywallControllerDidDisappear(_ controller: AdaptyPaywallController) { } + func flowControllerDidDisappear(_ controller: AdaptyFlowController) { } - func paywallController(_ controller: AdaptyPaywallController, - didPerform action: AdaptyUI.Action) { } + func flowController(_ controller: AdaptyFlowController, + didPerform action: AdaptyUI.Action) { } - func paywallController(_ controller: AdaptyPaywallController, - didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer) { } + func flowController(_ controller: AdaptyFlowController, + didSelectProduct product: AdaptyPaywallProduct) { } - func paywallController(_ controller: AdaptyPaywallController, - didStartPurchase product: AdaptyPaywallProduct) { } + func flowController(_ controller: AdaptyFlowController, + didStartPurchase product: AdaptyPaywallProduct) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishPurchase product: AdaptyPaywallProduct, - purchaseResult: AdaptyPurchaseResult) { } + func flowController(_ controller: AdaptyFlowController, + didFinishPurchase product: AdaptyPaywallProduct, + purchaseResult: AdaptyPurchaseResult) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailPurchase product: AdaptyPaywallProduct, - error: AdaptyError) { } + func flowController(_ controller: AdaptyFlowController, + didFailPurchase product: AdaptyPaywallProduct, + error: AdaptyError) { } - func paywallControllerDidStartRestore(_ controller: AdaptyPaywallController) { } + func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishRestoreWith profile: AdaptyProfile) { } + func flowController(_ controller: AdaptyFlowController, + didFinishRestoreWith profile: AdaptyProfile) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailRestoreWith error: AdaptyError) { } + func flowController(_ controller: AdaptyFlowController, + didFailRestoreWith error: AdaptyError) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailRenderingWith error: AdaptyUIError) { } + func flowController(_ controller: AdaptyFlowController, + didReceiveError error: AdaptyUIError) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailLoadingProductsWith error: AdaptyError) -> Bool { } + func flowController(_ controller: AdaptyFlowController, + didFailLoadingProductsWith error: AdaptyError) -> Bool { } - func paywallController(_ controller: AdaptyPaywallController, - didPartiallyLoadProducts failedIds: [String]) { } + func flowController(_ controller: AdaptyFlowController, + didPartiallyLoadProducts failedIds: [String]) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, - error: AdaptyError?) { } + func flowController(_ controller: AdaptyFlowController, + didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, + error: AdaptyError?) { } } ``` ## SwiftUI \{#swiftui\} ### .paywall() モディファイアを .flow() に変更する \{#paywall-modifier--flow\} モディファイアの名前を変更し、設定パラメータ名を更新してください。 ```diff showLineNumbers @State var flowPresented = false // rename freely — the variable name is your choice var body: some View { Text("Hello, AdaptyUI!") - .paywall( + .flow( isPresented: $flowPresented, - paywallConfiguration: paywallConfiguration, + flowConfiguration: flowConfiguration, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, - didFailRendering: { error in flowPresented = false } + didReceiveError: { error in flowPresented = false } ) } ``` 名前が変更されたコールバックは、`didFailRendering` が対応していたのと同じレンダリングエラーに加え、フロースクリプトの新しいランタイムエラー(`AdaptyUIError` コード `4105` — `.jsException` の JavaScript 例外)にも対応します。既存のハンドラー本体はコードを変更する必要はありません。パラメーターの名前を変更するだけです。 ### AdaptyPaywallView → AdaptyFlowView ビューの名前を変更し、設定パラメーターを更新し、`didSelectProduct` クロージャを更新してください — `AdaptyPaywallProductWithoutDeterminingOffer` が削除され、代わりに `AdaptyPaywallProduct` を受け取るようになりました: ```diff showLineNumbers - AdaptyPaywallView( - paywallConfiguration: paywallConfiguration, - didSelectProduct: { product: AdaptyPaywallProductWithoutDeterminingOffer in /* handle */ }, + AdaptyFlowView( + flowConfiguration: flowConfiguration, + didSelectProduct: { product: AdaptyPaywallProduct in /* handle */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, - didFailRendering: { error in /* handle the error */ } + didReceiveError: { error in /* handle the error */ } ) ``` ## AdaptyUI カスタムアセット \{#adaptyui-custom-assets\} ### AdaptyUICustomVideoAsset 既存のすべての呼び出し箇所に影響する変更が2点あります。 - `.player` が `AVQueuePlayer` の代わりに `AVPlayer` を受け取るようになりました。 - すべてのケースに末尾の `resolution: CGSize?` パラメータが追加されました。現在の動作を維持するには `nil` を渡してください。動画が読み込まれる前にプレイヤーがレイアウトスペースを確保できるよう(アスペクト比 = `width / height`)、実際のピクセルサイズを渡すこともできます。 ```diff showLineNumbers - case file(url: URL, preview: AdaptyUICustomImageAsset?) - case remote(url: URL, preview: AdaptyUICustomImageAsset?) - case player(item: AVPlayerItem, player: AVQueuePlayer, preview: AdaptyUICustomImageAsset?) + case file(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) + case remote(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) + case player(item: AVPlayerItem, player: AVPlayer, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) ``` ## アトリビューションと連携識別子 \{#attribution-and-integration-identifiers\} ### updateAttribution(_:source:) `source` パラメーターの型が `String` から新しい `AdaptyAttributionSource` 型に変更され、以前はネストされていた `AdaptyProfile.AttributionSource` がトップレベルの `AdaptyAttributionSource` に改名されました。定義済みのソースを使用するか、その他のソースには文字列リテラルを渡してください。`AdaptyAttributionSource` は `ExpressibleByStringLiteral` に準拠しているため、既存の文字列リテラルによる呼び出しはそのままコンパイルできます。 ```diff showLineNumbers - try await Adapty.updateAttribution(attribution, source: "adjust") + try await Adapty.updateAttribution(attribution, source: .adjust) ``` 定義済みソース: `.appleAds`、`.adjust`、`.appsflyer`、`.branch`、`.tenjin`。ソースを `String` 変数で保持している場合は、`AdaptyAttributionSource(rawValue: yourSource)` でラップしてください。 ### setIntegrationIdentifier(_:) \{#setintegrationidentifier\} `setIntegrationIdentifier(key:value:)` は、1つ以上の `AdaptyIntegrationIdentifier` 値を受け取る可変長引数メソッドに置き換えられました。生の文字列キーの代わりに、定義済みのファクトリーメソッドを使用してください: ```diff showLineNumbers - try await Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) + try await Adapty.setIntegrationIdentifier(.appsflyerId(uid)) ``` 1回の呼び出しで複数の識別子を設定できます: ```swift showLineNumbers try await Adapty.setIntegrationIdentifier( .appsflyerId(uid), .adjustDeviceId(adid) ) ``` 各古いキー文字列をそのファクトリーメソッドに置き換えます: | v3 キー | v4 ファクトリー | |---|---| | `"adjust_device_id"` | `.adjustDeviceId(_:)` | | `"airbridge_device_id"` | `.airbridgeDeviceId(_:)` | | `"amplitude_user_id"` | `.amplitudeUserId(_:)` | | `"amplitude_device_id"` | `.amplitudeDeviceId(_:)` | | `"appmetrica_device_id"` | `.appmetricaDeviceId(_:)` | | `"appmetrica_profile_id"` | `.appmetricaProfileId(_:)` | | `"appsflyer_id"` | `.appsflyerId(_:)` | | `"branch_id"` | `.branchId(_:)` | | `"facebook_anonymous_id"` | `.facebookAnonymousId(_:)` | | `"firebase_app_instance_id"` | `.firebaseAppInstanceId(_:)` | | `"mixpanel_user_id"` | `.mixpanelUserId(_:)` | | `"one_signal_subscription_id"` | `.oneSignalSubscriptionId(_:)` | | `"one_signal_player_id"` | `.oneSignalPlayerId(_:)` | | `"posthog_distinct_user_id"` | `.posthogDistinctUserId(_:)` | | `"pushwoosh_hwid"` | `.pushwooshHWID(_:)` | | `"tenjin_analytics_installation_id"` | `.tenjinAnalyticsInstallationId(_:)` | --- # File: migration-to-ios-315 --- --- title: "Adapty iOS SDK を v3.15 に移行する" description: "Adapty iOS SDK v3.15 に移行して、パフォーマンスの向上と新しいマネタイズ機能をご利用ください。" --- [オブザーバーモード](observer-vs-full-mode)で[ペイウォールビルダー](adapty-paywall-builder)を使用している場合、iOS SDK 3.15 以降では新しいメソッド `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)` を実装する必要があります。このメソッドにより、リストアロジックをより細かく制御できるようになり、カスタムフローで購入のリストアを処理できます。実装の詳細については、[オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 ```diff showLineNumbers func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } + func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, + onFinishRestore: @escaping () -> Void) { + // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore + } ``` --- # File: migration-to-ios-sdk-34 --- --- title: "Adapty iOS SDK を v3.4 へ移行する" description: "Adapty iOS SDK v3.4 に移行して、パフォーマンスの向上と新しいマネタイズ機能を活用しましょう。" --- Adapty SDK 3.4.0 はメジャーリリースであり、お客様側での移行手順が必要な改善が含まれています。 ## Adapty SDK のアクティベーションを更新する \{#update-adapty-sdk-activation\} ```diff showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") - Adapty.activate(with: configurationBuilder) { error in + Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` **フォールバックペイウォールファイルを更新する** 新しい SDK バージョンとの互換性を確保するために、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新されたフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換え](ios-use-fallback-paywalls)ます。 ```diff showLineNumbers @main struct SampleApp: App { init() { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") Task { - try await Adapty.activate(with: configurationBuilder) + try await Adapty.activate(with: configurationBuilder.build()) } } var body: some Scene { WindowGroup { ContentView() } } } ``` **フォールバックペイウォールファイルを更新する** 新しい SDK バージョンとの互換性を確保するために、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新されたフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換え](ios-use-fallback-paywalls)ます。 --- # File: migration-to-ios330 --- --- title: "Adapty iOS SDK を v3.3 に移行する" description: "パフォーマンス向上と新しいマネタイゼーション機能のために Adapty iOS SDK v3.3 に移行します。" --- Adapty SDK 3.3.0 はメジャーリリースであり、いくつかの改善が加えられています。ただし、一部の移行手順が必要になる場合があります。 1. `Adapty.Configuration` を `AdaptyConfiguration` にリネームする。 2. `getViewConfiguration` メソッドを `getPaywallConfiguration` にリネームする。 3. SwiftUI から `didCancelPurchase` と `paywall` パラメータを削除し、`viewConfiguration` パラメータを `paywallConfiguration` にリネームする。 4. `AdaptyDelegate` メソッドから `defermentCompletion` パラメータを削除して、App Store からのプロモーション用アプリ内課金の処理方法を更新する。 5. `getProductsIntroductoryOfferEligibility` メソッドを削除する。 6. Adjust、AirBridge、Amplitude、AppMetrica、Appsflyer、Branch、Facebook Ads、Firebase と Google Analytics、Mixpanel、OneSignal、Pushwoosh のインテグレーション設定を更新する。 7. オブザーバーモードの実装を更新する。
## Adapty.Configuration を AdaptyConfiguration にリネームする \{#rename-adaptyconfiguration-to-adaptyconfiguration\} 次のように Adapty iOS SDK の有効化コードを更新してください: ```diff showLineNumbers // In your AppDelegate class: let configurationBuilder = - Adapty.Configuration + AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) .with(customerUserId: "YOUR_USER_ID") .with(idfaCollectionDisabled: false) .with(ipAddressCollectionDisabled: false) Adapty.activate(with: configurationBuilder) { error in // handle the error } ``` ```diff showLineNumbers @main struct SampleApp: App { init() let configurationBuilder = - Adapty.Configuration + AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) // optional .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional Task { try await Adapty.activate(with: configurationBuilder) } } var body: some Scene { WindowGroup { ContentView() } } } ``` ## getViewConfiguration メソッドを getPaywallConfiguration にリネームする \{#rename-getviewconfiguration-method-to-getpaywallconfiguration\} ペイウォールの `viewConfiguration` を取得するメソッド名を次のように更新してください: ```diff showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { - let paywallConfiguration = try await AdaptyUI.getViewConfiguration( + let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall ) // use loaded configuration } catch { // handle the error } ``` メソッドの詳細については、[ペイウォールビルダーで作成したペイウォールのビュー設定を取得する](get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をご覧ください。 ## SwiftUI のパラメータを変更する \{#change-parameters-in-swiftui\} SwiftUI に以下の変更が加えられています: 1. `didCancelPurchase` パラメータが削除されました。代わりに `didFinishPurchase` を使用してください。 2. `.paywall()` メソッドはペイウォールオブジェクトを受け付けなくなりました。 3. `paywallConfiguration` パラメータが `viewConfiguration` パラメータに置き換わりました。 次のようにコードを更新してください: ```diff showLineNumbers @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, - paywall: , - viewConfiguration: , + paywallConfiguration: , didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, - didFinishPurchase: { product, profile in paywallPresented = false }, + didFinishPurchase: { product, purchaseResult in /* handle the result*/ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } - didCancelPurchase: { product in /* handle the result*/} ) } ``` ## App Store からのプロモーション用アプリ内課金の処理を更新する \{#update-handling-of-promotional-in-app-purchases-from-app-store\} 以下の例のように `AdaptyDelegate` メソッドから `defermentCompletion` パラメータを削除して、App Store からのプロモーション用アプリ内課金の処理方法を更新してください: ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from the 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## getProductsIntroductoryOfferEligibility メソッドを削除する \{#remove-getproductsintroductoryoffereligibility-method\} Adapty iOS SDK 3.3.0 より前は、ユーザーが対象かどうかに関わらず、プロダクトオブジェクトには常にオファーが含まれていました。そのため、オファーを使用する前に資格を手動で確認する必要がありました。 現在は、ユーザーが対象の場合にのみプロダクトオブジェクトにオファーが含まれます。つまり、資格を確認する必要はなくなりました。オファーが存在する場合、そのユーザーは対象です。 対象外のユーザーのオファーを確認したい場合は、`sk1Product` および `sk2Product` を参照してください。 ## サードパーティインテグレーション SDK の設定を更新する \{#update-third-party-integration-sdk-configuration\} Adapty iOS SDK 3.3.0 から、`updateAttribution` メソッドの公開 API が更新されました。以前は `[AnyHashable: Any]` 辞書を受け付けており、各サービスのアトリビューションオブジェクトをそのまま渡すことができました。現在は `[String: any Sendable]` が必要なため、渡す前にアトリビューションオブジェクトを変換する必要があります。 Adapty iOS SDK 3.3.0 以降でインテグレーションが正常に動作するよう、以下のセクションに従って各インテグレーションの SDK 設定を更新してください。 ### Adjust 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Adjust インテグレーションの SDK 設定](adjust#connect-your-app-to-adjust)をご確認ください。 ```diff showLineNumbers class AdjustModuleImplementation { - func updateAdjustAttribution() { - Adjust.attribution { attribution in - guard let attributionDictionary = attribution?.dictionary()?.toSendableDict() else { return } - - Adjust.adid { adid in - guard let adid else { return } - - Adapty.updateAttribution(attributionDictionary, source: .adjust, networkUserId: adid) { error in - // handle the error - } - } - } - } + func updateAdjustAdid() { + Adjust.adid { adid in + guard let adid else { return } + + Adapty.setIntegrationIdentifier(key: "adjust_device_id", value: adid) + } + } + + func updateAdjustAttribution() { + Adjust.attribution { attribution in + guard let attribution = attribution?.dictionary() else { + return + } + + Adapty.updateAttribution(attribution, source: "adjust") + } + } } ``` ```diff showLineNumbers class YourAdjustDelegateImplementation { // Find your implementation of AdjustDelegate // and update adjustAttributionChanged method: func adjustAttributionChanged(_ attribution: ADJAttribution?) { - if let attribution = attribution?.dictionary()?.toSendableDict() { - Adapty.updateAttribution(attribution, source: .adjust) + if let attribution = attribution?.dictionary() { + Adapty.updateAttribution(attribution, source: "adjust") } } } ``` ### AirBridge 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AirBridge インテグレーションの SDK 設定](airbridge#connect-your-app-to-airbridge)をご確認ください。 ```diff showLineNumbers import AirBridge - let builder = AdaptyProfileParameters.Builder() - .with(airbridgeDeviceId: AirBridge.deviceUUID()) - - Adapty.updateProfile(params: builder.build()) + do { + try await Adapty.setIntegrationIdentifier( + key: "airbridge_device_id", + value: AirBridge.deviceUUID() + ) + } catch { + // handle the error + } ``` ### Amplitude 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Amplitude インテグレーションの SDK 設定](amplitude#sdk-configuration)をご確認ください。 ```diff showLineNumbers import Amplitude - let builder = AdaptyProfileParameters.Builder() - .with(amplitudeUserId: Amplitude.instance().userId) - .with(amplitudeDeviceId: Amplitude.instance().deviceId) - - Adapty.updateProfile(params: builder.build()) + do { + try await Adapty.setIntegrationIdentifier( + key: "amplitude_user_id", + value: Amplitude.instance().userId + ) + try await Adapty.setIntegrationIdentifier( + key: "amplitude_device_id", + value: Amplitude.instance().deviceId + ) + } catch { + // handle the error + } ``` ### AppMetrica 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppMetrica インテグレーションの SDK 設定](appmetrica#sdk-configuration)をご確認ください。 ```diff showLineNumbers import AppMetricaCore - if let deviceID = AppMetrica.deviceID { - let builder = AdaptyProfileParameters.Builder() - .with(appmetricaDeviceId: deviceID) - .with(appmetricaProfileId: "YOUR_ADAPTY_CUSTOMER_USER_ID") - - Adapty.updateProfile(params: builder.build()) - } + if let deviceID = AppMetrica.deviceID { + do { + try await Adapty.setIntegrationIdentifier( + key: "appmetrica_device_id", + value: deviceID + ) + try await Adapty.setIntegrationIdentifier( + key: "appmetrica_profile_id", + value: "YOUR_ADAPTY_CUSTOMER_USER_ID" + ) + } catch { + // handle the error + } + } ``` ### AppsFlyer 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppsFlyer インテグレーションの SDK 設定](appsflyer#connect-your-app-to-appsflyer)をご確認ください。 ```diff showLineNumbers class YourAppsFlyerLibDelegateImplementation { // Find your implementation of AppsFlyerLibDelegate // and update onConversionDataSuccess method: func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) { let uid = AppsFlyerLib.shared().getAppsFlyerUID() - Adapty.updateAttribution( - conversionInfo.toSendableDict(), - source: .appsflyer, - networkUserId: uid - ) + Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) + Adapty.updateAttribution(conversionInfo, source: "appsflyer") } } ``` ### Branch 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Branch インテグレーションの SDK 設定](branch#connect-your-app-to-branch)をご確認ください。 ```diff showLineNumbers class YourBranchImplementation { func initializeBranch() { // Pass the attribution you receive from the initializing method of Branch iOS SDK to Adapty. Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in - if let data = data?.toSendableDict() { - Adapty.updateAttribution(data, source: .branch) - } + if let data { + Adapty.updateAttribution(data, source: "branch") + } } } } ``` ### Facebook Ads 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Facebook Ads インテグレーションの SDK 設定](facebook-ads#connect-your-app-to-facebook-ads)をご確認ください。 ```diff showLineNumbers import FacebookCore - let builder = AdaptyProfileParameters.Builder() - .with(facebookAnonymousId: AppEvents.shared.anonymousID) - - do { - try Adapty.updateProfile(params: builder.build()) - } catch { - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "facebook_anonymous_id", + value: AppEvents.shared.anonymousID + ) + } catch { + // handle the error + } ``` ### Firebase と Google Analytics 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Firebase と Google Analytics インテグレーションの SDK 設定](firebase-and-google-analytics)をご確認ください。 ```diff showLineNumbers import FirebaseCore import FirebaseAnalytics FirebaseApp.configure() - if let appInstanceId = Analytics.appInstanceID() { - let builder = AdaptyProfileParameters.Builder() - .with(firebaseAppInstanceId: appInstanceId) - Adapty.updateProfile(params: builder.build()) { error in - // handle error - } - } + if let appInstanceId = Analytics.appInstanceID() { + do { + try await Adapty.setIntegrationIdentifier( + key: "firebase_app_instance_id", + value: appInstanceId + ) + } catch { + // handle the error + } + } ``` ### Mixpanel 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Mixpanel インテグレーションの SDK 設定](mixpanel#sdk-configuration)をご確認ください。 ```diff showLineNumbers import Mixpanel - let builder = AdaptyProfileParameters.Builder() - .with(mixpanelUserId: Mixpanel.mainInstance().distinctId) - - do { - try await Adapty.updateProfile(params: builder.build()) - } catch { - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "mixpanel_user_id", + value: Mixpanel.mainInstance().distinctId + ) + } catch { + // handle the error + } ``` ### OneSignal 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[OneSignal インテグレーションの SDK 設定](onesignal#sdk-configuration)をご確認ください。 ```diff showLineNumbers // PlayerID (pre-v5 OneSignal SDK) // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { - let params = AdaptyProfileParameters.Builder() - .with(oneSignalPlayerId: playerId) - .build() - - Adapty.updateProfile(params:params) { error in - // check error - } + Task { + try await Adapty.setIntegrationIdentifier( + key: "one_signal_player_id", + value: playerId + ) + } } } // SubscriptionID (v5+ OneSignal SDK) OneSignal.Notifications.requestPermission({ accepted in - let id = OneSignal.User.pushSubscription.id - - let builder = AdaptyProfileParameters.Builder() - .with(oneSignalSubscriptionId: id) - - Adapty.updateProfile(params: builder.build()) + Task { + try await Adapty.setIntegrationIdentifier( + key: "one_signal_subscription_id", + value: OneSignal.User.pushSubscription.id + ) + } }, fallbackToSettings: true) ``` ### Pushwoosh 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Pushwoosh インテグレーションの SDK 設定](pushwoosh#sdk-configuration)をご確認ください。 ```diff showLineNumbers - let params = AdaptyProfileParameters.Builder() - .with(pushwooshHWID: Pushwoosh.sharedInstance().getHWID()) - .build() - - Adapty.updateProfile(params: params) { error in - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "pushwoosh_hwid", + value: Pushwoosh.sharedInstance().getHWID() + ) + } catch { + // handle the error + } ``` ## オブザーバーモードの実装を更新する \{#update-observer-mode-implementation\} ペイウォールとトランザクションを紐付ける方法を更新してください。以前は `setVariationId` メソッドを使用して `variationId` を割り当てていました。現在は、新しい `reportTransaction` メソッドを使用してトランザクションを記録する際に `variationId` を直接含めることができます。最終的なコード例については、[オブザーバーモードでペイウォールを購入トランザクションに関連付ける](report-transactions-observer-mode)をご確認ください。 :::warning `reportTransaction` メソッドを使用してトランザクションを必ず記録してください。この手順を省略すると、Adapty はトランザクションを認識できず、アクセスレベルの付与、アナリティクスへの反映、インテグレーションへの送信が行われません。この手順は必須です! ::: ```diff showLineNumbers - let variationId = paywall.variationId - - // There are two overloads: for StoreKit 1 and StoreKit 2 - Adapty.setVariationId(variationId, forPurchasedTransaction: transaction) { error in - if error == nil { - // successful binding - } - } + do { + // every time when calling transaction.finish() + try await Adapty.reportTransaction(transaction, withVariationId: ) + } catch { + // handle the error + } ``` --- # File: migration-to-ios-sdk-v3 --- --- title: "Adapty iOS SDK を v3.0 に移行する" description: "パフォーマンスの向上と新しいマネタイズ機能のために、Adapty iOS SDK v3.0 に移行しましょう。" --- Adapty SDK v3.0 では、新しい [Adapty ペイウォールビルダー](adapty-paywall-builder)をサポートしています。これはペイウォールをノーコードで作成できる使いやすいツールの最新バージョンです。高い柔軟性と豊富なデザイン機能により、ペイウォールの効果と収益性をさらに高めることができます。 :::info AdaptyUI ライブラリは非推奨となり、現在は AdaptySDK の一部として含まれています。 ::: ## Swift Package Manager で Adapty SDK v3.x を再インストールする \{#reinstall-adapty-sdk-v3x-via-swift-package-manager\} 1. AdaptyUI SDK のパッケージ依存関係をプロジェクトから削除してください。今後は不要です。 2. すでに追加済みであっても、Adapty SDK の依存関係を再追加する必要があります。Xcode で **File** -> **Add Package Dependency...** を開いてください。パッケージ依存関係の追加方法は Xcode のバージョンによって異なる場合があります。必要に応じて Xcode のドキュメントをご参照ください。 3. リポジトリ URL `https://github.com/adaptyteam/AdaptySDK-iOS.git` を入力してください。 4. バージョンを選択し、**Add package** ボタンをクリックしてください。 5. 必要なモジュールを選択してください: 1. **Adapty** は必須モジュールです。 2. **AdaptyUI** は [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なオプションモジュールです。 6. Xcode がプロジェクトにパッケージ依存関係を追加します。インポートするには、**Choose Package Products** ウィンドウで **Add package** ボタンを再度クリックしてください。パッケージが **Packages** リストに表示されます。 ## CocoaPods で Adapty SDK v3.x を再インストールする \{#reinstall-adapty-sdk-v3x-via-cocoapods\} 1. `Podfile` に Adapty を追加してください。必要なモジュールを選択してください: 1. **Adapty** は必須モジュールです。 2. **AdaptyUI** は [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なオプションモジュールです。 2. ```shell showLineNumbers title="Podfile" pod 'Adapty', '~> 3.2.0' pod 'AdaptyUI', '~> 3.2.0' # optional module needed only for Paywall Builder ``` 3. 次を実行してください: ```sh showLineNumbers title="Shell" pod install ``` これにより、アプリ用の `.xcworkspace` ファイルが作成されます。以後のアプリ開発にはこのファイルを使用してください。 Adapty および AdaptyUI SDK モジュールを有効化してください。v3.0 以前は AdaptyUI を有効化していませんでしたが、**AdaptyUI の有効化を追加**することを忘れないでください。パラメーターに変更はないため、そのまま使用してください。 ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .Builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) .with(customerUserId: "YOUR_USER_ID") .with(idfaCollectionDisabled: false) .with(ipAddressCollectionDisabled: false) Adapty.activate(with: configurationBuilder) { error in // handle the error } // Only if you are going to use AdaptyUI AdaptyUI.activate() ``` ```swift title="" showLineNumbers @main struct SampleApp: App { init() let configurationBuilder = AdaptyConfiguration .Builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) // optional .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional Adapty.activate(with: configurationBuilder) { error in // handle the error } // Only if you are going to use AdaptyUI AdaptyUI.activate() } var body: some Scene { WindowGroup { ContentView() } } } ``` --- # End of Documentation _Generated on: 2026-07-01T16:29:19.445Z_ _Successfully processed: 44/44 files_