# FLUTTER - Adapty Documentation (Full Content) This file contains the complete content of all documentation pages for this platform. Locale: ja Generated on: 2026-07-24T13:00:57.638Z Total files: 44 --- # File: sdk-installation-flutter --- --- title: "Flutter SDK のインストールと設定" description: "Flutter でサブスクリプションアプリに Adapty SDK をインストールする手順を解説したガイドです。" --- Adapty SDK には、Flutter アプリへのシームレスな統合を実現する 2 つの主要モジュールが含まれています。 - **Core Adapty**: これはAdaptyがアプリ内で正常に動作するために必要な基本SDKです。 - **AdaptyUI**: [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合に必要なモジュールです。ペイウォールビルダーは、コードなしでクロスプラットフォームのペイウォールを簡単に作成できる使いやすいツールです。 :::tip Adapty SDKをモバイルアプリに統合する実際の例を確認したいですか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示した[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)をぜひご覧ください。 ::: ## 必要条件 \{#requirements\} Adapty SDK は iOS 13.0+ をサポートしていますが、ペイウォールビルダーで作成したペイウォールを正しく動作させるには iOS 15.0+ が必要です。 Adapty Flutter SDK 4.0 — [フロービルダー](adapty-flow-builder)サポートを追加 — の最低要件は **iOS 15.0+**、**Xcode 26+**、**Flutter 3.32.0+**(Dart 3.8.0+)に引き上げられました。インストールの詳細については、以下の [Adapty SDK 4.0](#adapty-sdk-40-swift-package-manager) を参照してください。 :::info Adapty は Google Play Billing Library 8.x までに対応しています。デフォルトでは Adapty は Google Play Billing Library v7.0.0 で動作しますが、より新しいバージョンを使用したい場合は、手動で[依存関係を追加](https://developer.android.com/google/play/billing/integrate#dependency)できます。 ::: :::info SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ::: ## Adapty SDK のインストール \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Flutter.svg?style=flat&logo=flutter)](https://github.com/adaptyteam/AdaptySDK-Flutter/releases) :::important 以下の手順では最新の安定版 SDK(3.x)をインストールします。[フロービルダー](adapty-flow-builder)に必要で[クイックスタート](flutter-quickstart-paywalls)で使用される v4 が必要な場合は、代わりに下の [Adapty SDK 4.0: Swift Package Manager](#adapty-sdk-40-swift-package-manager) の手順に従ってください。 ::: 1. `pubspec.yaml` ファイルに Adapty を追加します: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: ^ ``` 2. 以下のコマンドを実行して依存関係をインストールします: ```bash showLineNumbers title="Terminal" flutter pub get ``` 3. アプリケーションに Adapty SDK をインポートします: ```dart showLineNumbers title="main.dart" import 'package:adapty_flutter/adapty_flutter.dart'; ``` ### Adapty SDK 4.0: Swift Package Manager Adapty Flutter SDK 4.0([フロービルダー](adapty-flow-builder)のサポートを追加)を `pubspec.yaml` に追加します: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: 4.0.0 ``` v4 以降、ネイティブ iOS SDK は CocoaPods での配布を終了し、**Swift Package Manager** のみを通じて提供されます([CocoaPods のスペックリポジトリは 2026 年 12 月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/))。Flutter 3.32〜3.43 をご利用の場合は、Swift Package Manager のサポートを一度有効にしてください: ```bash showLineNumbers title="Terminal" flutter config --enable-swift-package-manager ``` Flutter 3.44 以降では Swift Package Manager がデフォルトで有効になっているため、追加の操作は不要です。 v4 の API 変更については、[移行ガイド](migration-to-flutter-sdk-v4)をご覧ください。 ## Adapty SDKのAdaptyモジュールを有効化する \{#activate-adapty-module-of-adapty-sdk\} アプリのコードでAdapty SDKを有効化します。 :::note Adapty SDKは、アプリ内で一度だけ有効化すれば十分です。 ::: **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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 ```dart showLineNumbers title="main.dart" void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State { @override void initState() { _initializeAdapty(); super.initState(); } Future _initializeAdapty() async { try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY'), ); } catch (e) { // handle the error } } Widget build(BuildContext context) { return Text("Hello"); } } ``` :::important `activate` の処理が完了してから、他の Adapty SDK メソッドを呼び出してください。完全な呼び出し順序については、[Flutter SDK の呼び出し順序](flutter-sdk-call-order)を参照してください。 ::: 次に、アプリにペイウォールを設定します。 - [Adapty Paywall Builder](adapty-paywall-builder) を使用する場合は、まず下の [AdaptyUI モジュールを有効化する](#activate-adaptyui-module-of-adapty-sdk)手順を実行してから、[ペイウォールビルダーのクイックスタート](flutter-quickstart-paywalls)に進んでください。 - 独自のペイウォール UI を構築する場合は、[カスタムペイウォールのクイックスタート](flutter-quickstart-manual)を参照してください。 ## AdaptyUI モジュールの有効化 \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する予定があり、[AdaptyUI モジュールをインストール済み](sdk-installation-flutter#install-adapty-sdk)の場合は、AdaptyUI も有効化する必要があります。 :::note AdaptyUI が有効化されているかどうかに関わらず、AdaptyUI 関連の依存関係はアプリにリンクされます。 ::: :::important コード内では、AdaptyUI を有効化する前に、必ずコアの Adapty モジュールを先に有効化してください。 ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withActivateUI(true), // This automatically activates AdaptyUI ); ``` ## オプションの設定 \{#optional-setup\} ### ログ \{#logging\} #### ログシステムを設定する \{#set-up-the-logging-system\} Adapty はエラーやその他の重要な情報をログに記録し、何が起きているかを把握できるようにします。以下のログレベルが利用可能です: | レベル | 説明 | | :----------------------- | :------------------------------------------------------------------------------------------------------------------------ | | `AdaptyLogLevel.error` | エラーのみがログに記録されます | | `AdaptyLogLevel.warn` | エラーと、重大なエラーは引き起こさないものの注意が必要なSDKからのメッセージがログに記録されます。 | | `AdaptyLogLevel.info` | エラー、警告、さまざまな情報メッセージがログに記録されます。デフォルト値 | | `AdaptyLogLevel.verbose` | 関数呼び出しやAPIクエリなど、デバッグ時に役立つ可能性のある追加情報がログに記録されます。 | | `AdaptyLogLevel.debug` | デバッグ情報がログに記録されます。 | Adaptyを設定する前に、アプリでログレベルを設定できます: ```dart showLineNumbers title="main.dart" // Set log level before activation. // 'verbose' is recommended for development and the first production release await Adapty().setLogLevel(AdaptyLogLevel.verbose); // Or set it during configuration await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withLogLevel(AdaptyLogLevel.verbose), ); ``` ### データポリシー \{#data-policies\} Adapty はユーザーの個人データを明示的に送信しない限り保存しませんが、ストアや国のガイドラインに準拠するために追加のデータセキュリティポリシーを実装できます。 #### IPアドレスの収集と共有を無効にする \{#disable-ip-address-collection-and-sharing\} Adapty モジュールを有効化する際に、`ipAddressCollectionDisabled` を `true` に設定すると、ユーザーのIPアドレスの収集と共有を無効にできます。デフォルト値は `false` です。 IPベースの機能がアプリに必要ない場合に、ユーザーのプライバシー保護、GDPRやCCPAなどの地域のデータ保護規制への準拠、または不要なデータ収集の削減を目的として、このパラメータを使用できます。 ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withIpAddressCollectionDisabled(true), ); ``` #### 広告IDの収集と共有を無効にする \{#disable-advertising-id-collection-and-sharing\} Adaptyモジュールを有効化する際、広告識別子の収集を無効にするには、`appleIdfaCollectionDisabled`(iOS)または`googleAdvertisingIdCollectionDisabled`(Android)を`true`に設定してください。デフォルト値は`false`です。 App Store/Play Storeのポリシーへの準拠、App Tracking Transparencyプロンプトの表示回避、または広告IDに基づくアトリビューションや分析がアプリに不要な場合は、このパラメータを使用してください。 ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withAppleIdfaCollectionDisabled(true) // iOS ..withGoogleAdvertisingIdCollectionDisabled(true), // Android ); ``` #### AdaptyUI のメディアキャッシュ設定 \{#set-up-media-cache-configuration-for-adaptyui\} このモジュールは Adapty SDK と共に自動的に有効化されます。ペイウォールビルダーを使用せず、AdaptyUI モジュールを無効化したい場合は、有効化時に `withActivateUI(false)` を渡してください。 デフォルトでは、AdaptyUI はメディア(画像や動画など)をキャッシュしてパフォーマンスを向上させ、ネットワークの使用量を削減します。カスタム設定を指定することで、キャッシュの設定をカスタマイズできます。 `withMediaCacheConfiguration` を使用して、デフォルトのキャッシュ制限を上書きできます。これはオプションです。このメソッドを呼び出さない場合、デフォルト値が使用されます(ディスクサイズ 100MB、メモリ数制限なし)。ただし、設定オブジェクトを作成する場合、すべてのパラメータが必須です。 ```dart showLineNumbers title="main.dart" final mediaCacheConfig = AdaptyUIMediaCacheConfiguration( memoryStorageTotalCostLimit: 200 * 1024 * 1024, // 200 MB memoryStorageCountLimit: 2147483647, // max int value diskStorageSizeLimit: 200 * 1024 * 1024, // 200 MB ); await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withMediaCacheConfiguration(mediaCacheConfig), ); ``` **パラメーター:** | パラメーター | 必須/任意 | 説明 | |-------------------------|----------|-----------------------------------------------------------------------------| | memoryStorageTotalCostLimit | required | メモリ上のキャッシュサイズの合計(バイト単位)。デフォルトは100 MBです。 | | memoryStorageCountLimit | required | メモリストレージのアイテム数の上限。デフォルトはint型の最大値です。 | | diskStorageSizeLimit | required | ディスク上のファイルサイズの上限(バイト単位)。デフォルトは100 MBです。 | ### Androidでローカルアクセスレベルを有効にする \{#enable-local-access-levels-android\} デフォルトでは、[ローカルアクセスレベル](local-access-levels)はiOSで有効、Androidで無効になっています。Androidでも有効にするには、`withGoogleLocalAccessLevelAllowed`を`true`に設定してください。 ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withGoogleLocalAccessLevelAllowed(true), ); ``` ### バックアップから復元時のデータクリア \{#clear-data-on-backup-restore\} `appleClearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検知し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールなど、ローカルに保存されているSDKデータをすべて削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withAppleClearDataOnBackup(true) // default – false ); ``` ## トラブルシューティング \{#troubleshooting\} #### Android バックアップルール(Auto Backup の設定) \{#android-backup-rules-auto-backup-configuration\} 一部のSDK(Adaptyを含む)には、独自のAndroid Auto Backup設定が含まれています。バックアップルールを定義する複数のSDKを使用している場合、Androidのマニフェストマージャーが `android:fullBackupContent`、`android:dataExtractionRules`、または `android:allowBackup` に関するエラーで失敗することがあります。 よくあるエラーの症状: `Manifest merger failed: Attribute application@dataExtractionRules value=(@xml/your_data_extraction_rules) is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)` :::note これらの変更は、Androidプラットフォームのディレクトリ(通常はプロジェクトの `android/` フォルダー内)で行う必要があります。 ::: この問題を解決するには、以下が必要です: - バックアップ関連の属性に対して、アプリの値を使用するようマニフェストマージャーに指示する。 - AdaptyのルールとほかのSDKのルールをマージしたバックアップルールファイルを作成する。 #### 1. マニフェストに `tools` 名前空間を追加する \{#1-add-the-tools-namespace-to-your-manifest\} `AndroidManifest.xml` ファイルのルートの `` タグに tools が含まれていることを確認してください: ```xml ... ``` #### 2. `` でバックアップ属性を上書きする \{#2-override-backup-attributes-in-application\} 同じ `AndroidManifest.xml` ファイルで、`` タグを更新して、アプリが最終的な値を提供し、マニフェストマージャーにライブラリの値を置き換えるよう指示します: ```xml ... ``` いずれかのSDKが `android:allowBackup` も設定している場合は、`tools:replace` に含めてください: ```xml tools:replace="android:allowBackup,android:fullBackupContent,android:dataExtractionRules" ``` #### 3. マージしたバックアップルールファイルを作成する \{#3-create-merged-backup-rules-files\} AndroidプロジェクトのAdaptyのルールとほかのSDKのルールを組み合わせた `res/xml/` ディレクトリにXMLファイルを作成します。AndroidはOSのバージョンによって異なるバックアップルール形式を使用するため、両方のファイルを作成することで、アプリがサポートするすべてのAndroidバージョンとの互換性が確保されます。 :::note 以下の例では、サンプルのサードパーティSDKとしてAppsFlyerを使用しています。アプリで使用しているほかのSDKのルールに置き換えるか、追加してください。 ::: **Android 12以降**(新しいデータ抽出ルール形式を使用): ```xml title="sample_data_extraction_rules.xml" ``` **Android 11以前**(従来のフルバックアップコンテンツ形式を使用): ```xml title="sample_backup_rules.xml" #### Android で別のアプリから戻ったときに購入が失敗する \{#purchases-fail-after-returning-from-another-app-in-android\} 購入フローを開始する Activity が非デフォルトの `launchMode` を使用している場合、ユーザーが Google Play、銀行アプリ、またはブラウザから戻ったときに Android がその Activity を誤って再作成または再利用することがあります。これにより、購入結果が失われたり、キャンセルされたものとして扱われたりする可能性があります。 購入が正しく機能するようにするには、購入フローを開始する Activity に `standard` または `singleTop` のみを使用し、それ以外のモードは避けてください。 `AndroidManifest.xml` で、購入フローを開始するアクティビティの `launchMode` が `standard` または `singleTop` に設定されていることを確認してください: ```xml ``` #### Podfile の SWIFT_VERSION オーバーライドによる Swift 6 ビルドエラー \{#swift-6-build-errors-caused-by-podfile-swift-version-override\} Flutter アプリを iOS 向けにビルドする際、Adapty の pod ターゲットで Swift 6 のコンパイルエラーが発生することがあります。よくある症状としては、`AdaptyUIBuilderLogic` での `@Sendable` の不一致、Adapty 型の `Sendable` 準拠の欠如、またはアクター分離エラーなどが挙げられます。 Adapty の Pod は `s.swift_version = '6.0'` を宣言しており、ビルドに Swift 6 が必要です。あなた自身のアプリコードは Swift 5 のままでかまいません。Adapty の Pod ターゲット(`Adapty`、`AdaptyUI`、`AdaptyUIBuilder`、`AdaptyLogger`、`AdaptyPlugin`)のみが Swift 6 でビルドされる必要があります。 最もよくある原因は、`ios/Podfile` の `post_install` フックがすべての Pod ターゲットの `SWIFT_VERSION` を上書きしていることです。 ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` **修正方法**: Adapty の pod ターゲットをオーバーライドの対象から除外してください。 ```ruby showLineNumbers title="ios/Podfile" post_install do |installer| installer.pods_project.targets.each do |target| next if %w[Adapty AdaptyUI AdaptyUIBuilder AdaptyLogger AdaptyPlugin].include?(target.name) target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '5.9' end end end ``` 次に `ios/` ディレクトリで `pod install` を実行し、再ビルドしてください。 確認するには、`ios/Pods/Pods.xcodeproj` を開き、`Adapty` pod ターゲットを選択して **Build Settings** → **Swift Language Version** を確認します。**Swift 6** と表示されていれば正常です。 --- # File: flutter-quickstart-paywalls --- --- title: "Flutter SDK で Flow Builder を使って購入を有効にする" description: "Adapty Flow Builder を使ったアプリ内課金の有効化に関するクイックスタートガイド。" --- アプリ内課金を有効にするには、次の3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**フロー**](adapty-flow-builder) – ノーコードのフロービルダーで作成した、プロダクトをユーザーに提示するための画面シーケンス。SDK では `getFlow` で取得します。自前のコードで UI を構築したい場合は、ペイウォールをご利用ください — [ペイウォールを手動で実装する](flutter-quickstart-manual)をご覧ください。 - [**プレースメント**](placements) – アプリ内でフローを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでフローをプレースメントに紐付け、コード内ではプレースメント ID で取得します。これにより、A/B テストの実施やユーザーごとに異なるフローの表示が簡単に行えます。 Adaptyでは、アプリ内課金を有効にする方法を3つ提供しています。アプリの要件に応じていずれかを選択してください: | 実装方法 | 複雑さ | 使用タイミング | |------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Adapty Flow Builder | ✅ 簡単 | [ノーコードビルダーで購入可能な完全なフローを作成](quickstart-paywalls)します。Adapty が自動的にレンダリングし、複雑な購入フロー、レシート検証、サブスクリプション管理をすべて裏側で処理します。 | | 手動で作成したペイウォール | 🟡 中程度 | アプリのコードでペイウォール UI を実装しつつ、プロダクトラインナップの柔軟性を維持するために Adapty からフローオブジェクトを取得します。[ガイド](flutter-quickstart-manual)を参照してください。 | | オブザーバーモード | 🔴 難しい | 独自の購入処理基盤がすでにあり、そのまま使い続けたい場合に使用します。なお、オブザーバーモードには Adapty での制限があります。[記事](observer-vs-full-mode)を参照してください。 | :::important **以下の手順では、Adapty Flow Builder で作成したフローの実装方法を説明します。** ペイウォールのUIを独自に構築したい場合は、[ペイウォールを手動で実装する](flutter-quickstart-manual)をご覧ください。 ::: Adapty Flow Builder で作成したフローをアプリに表示するには、以下の3つだけ行えばOKです。 1. **フローを取得する**: Adapty からフローを取得します。 2. **表示する(購入処理はAdaptyが自動で行います)**: アプリにビューを表示します。 3. **ボタン操作を処理する**: ユーザーのタップ操作に対するアプリの反応を定義します。たとえば、リンクを開いたり、ボタンがタップされたときにフローを閉じたりします。 ## 始める前に \{#before-you-start\} 始める前に、以下の手順を完了してください: 1. Adapty ダッシュボードでアプリを [App Store](initial_ios) および/または [Google Play](initial-android) に接続する。 2. Adapty で[プロダクトを作成する](create-product)。 3. [フローを作成してプロダクトを追加する](create-paywall)。 4. [プレースメントを作成してフローを追加する](create-placement)。 5. アプリのコードに [Adapty SDK をインストールして有効化する](sdk-installation-flutter)。このガイドでは Adapty Flutter SDK v4 の API を使用します。 :::tip これらのステップを最も素早く完了するには、[クイックスタートガイド](quickstart)に従うか、[Developer CLI](developer-cli-quickstart)を使用してペイウォールとプレースメントを作成してください。 ::: ## 1. フローを取得する \{#1-get-the-flow\} フローはダッシュボードで設定したプレースメントに紐付けられています。プレースメントを使うと、オーディエンスごとに異なるフローを表示したり、[A/B テスト](ab-tests)を実施したりできます。 Adapty フロービルダーで作成したフローを取得するには、次の手順を行います。 1. `getFlow` メソッドを使って[プレースメント](placements) ID から `flow` オブジェクトを取得し、`hasViewConfiguration` プロパティを確認してビルダーで作成されたフローかどうかを判別します。 2. `createFlowView` メソッドを使ってフロービューを作成します。ビューにはフローを表示するために必要な UI 要素とスタイル情報が含まれています。 :::important ビュー設定を取得するには、ビルダーで **Show on device** トグルをオンにする必要があります。オンにしていない場合、ビュー設定が空になり、フローが表示されません。 ::: ```dart showLineNumbers try { // the requested flow final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); final view = await AdaptyUI().createFlowView( flow: flow, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ## 2. フローを表示する \{#display-the-flow\} フローのビューが用意できたら、あとは数行追加するだけで表示できます。 フローを表示するには、`createFlowView` メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか表示できません。閉じた後はメモリから解放されます。再度フローを表示する必要がある場合は、`createFlowView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 ```dart showLineNumbers title="Flutter" try { await view.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::tip フローの表示方法の詳細については、[ガイド](flutter-present-paywalls)を参照してください。 ::: ## 3. ボタンアクションの処理 \{#handle-button-actions\} ユーザーがフロー内のボタンをクリックすると、Flutter SDK は購入・復元・画面を閉じる・URL を開くなどの操作を自動的に処理します。ただし、カスタムまたは事前定義された ID を持つボタンについては、コード側でアクションを処理する必要があります。 フロー画面上のプロセスを制御・監視するには、`AdaptyUIFlowsEventsObserver` のメソッドを実装し、画面を表示する前にオブザーバーを設定してください。ユーザーが何らかのアクションを実行すると `flowViewDidPerformAction` が呼び出されるので、アクション ID に応じてアプリが適切に応答する必要があります。 3つのオブザーバーメソッドが**必須**です:`flowViewDidFinishPurchase`、`flowViewDidFinishRestore`、`flowViewDidReceiveError` — これらがないとクラスはコンパイルエラーになります。 :::tip ボタンの[アクション](flutter-handle-paywall-actions)と[イベント](flutter-handling-events)の処理方法については、ガイドをご覧ください。 ::: ウィジェットではなく、専用の長命なオブジェクトとしてオブザーバーを実装してください。アプリ全体で1つのグローバルなオブザーバースロットが共有されるため、`State` にバインドするとその画面がリークし(SDKが強参照を保持するため)、次の画面が登録された時点でサイレントに上書きされてしまいます。`extends` を使うことでSDKのデフォルト動作も継承されるため、必須の3つのメソッドに加え、必要なコールバックだけをオーバーライドすれば十分です。 ```dart showLineNumbers title="Flutter" // A dedicated, long-lived handler for flow events. // It does NOT live inside a Widget/State, so it never leaks and is never // silently replaced when screens are pushed or popped. class FlowEventsHandler extends AdaptyUIFlowsEventsObserver { // A single, app-wide instance — same idiom as Adapty() and AdaptyUI(). static final FlowEventsHandler _instance = FlowEventsHandler._(); factory FlowEventsHandler() => _instance; FlowEventsHandler._(); // This method is called when user performs an action on the flow UI. // Overriding it replaces the default behavior (dismiss on close, open URLs), // so keep those cases if you want to preserve it. @override void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): // close the flow on the Android back button view.dismiss(); break; case OpenUrlAction(:final url, :final openIn): AdaptyUI().openUrl(url, openIn: openIn); break; default: break; } } // Required: decide what happens after a purchase finishes @override void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { if (purchaseResult is! AdaptyPurchaseResultUserCancelled) { view.dismiss(); } } // Required: dismiss the flow once a restore succeeds @override void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { view.dismiss(); } // Required: handle rendering and other view errors @override void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { print('Flow error: $error'); view.dismiss(); } } ``` ハンドラーは、フローが表示される前のアプリ起動時に **一度だけ** 登録してください: ```dart showLineNumbers title="Flutter" AdaptyUI().setFlowsEventsObserver(FlowEventsHandler()); ``` ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールはアプリに表示する準備が整いました。[App Store サンドボックス](test-purchases-in-sandbox)または[Google Play Store](testing-on-android)でテスト購入を試して、ペイウォールからテスト購入が完了できることを確認してください。 次に、[ユーザーのアクセスレベルを確認](flutter-check-subscription-status)して、適切なユーザーにペイウォールを表示したり有料機能へのアクセスを付与したりできるようにする必要があります。 ## 完全なコード例 \{#full-example\} 以下に、これらのすべてのステップをアプリに統合した場合の完全なサンプルコードを示します。 ```dart void main() { // Register a single, long-lived observer once, before any flow is shown. // It is intentionally a plain object (NOT a Widget/State): its lifetime is the // whole app, so it never leaks and is never silently replaced when screens are // pushed or popped. AdaptyUI().setFlowsEventsObserver(FlowEventsHandler()); runApp(MaterialApp(home: FlowScreen())); } /// A dedicated handler for AdaptyUI flow events. /// /// It `extends` [AdaptyUIFlowsEventsObserver] (rather than being implemented /// by a `State`), which gives you two things for free: /// * the SDK's sensible defaults for optional callbacks, so besides the three /// required methods you only override what you actually care about; /// * a lifecycle that is independent of the widget tree — there is no strong /// reference back into a `Widget`, so nothing leaks and there is nothing to /// unregister. /// /// Every callback receives the [AdaptyUIFlowView] it relates to, so handling /// flow actions never requires a `BuildContext` or widget state. class FlowEventsHandler extends AdaptyUIFlowsEventsObserver { // A single, app-wide instance — same idiom as Adapty() and AdaptyUI(). static final FlowEventsHandler _instance = FlowEventsHandler._(); factory FlowEventsHandler() => _instance; FlowEventsHandler._(); // Called when the user performs an action on the flow UI. @override void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): // close the flow on the Android back button view.dismiss(); break; case OpenUrlAction(:final url, :final openIn): // Open the URL natively, honoring the dashboard browser setting. AdaptyUI().openUrl(url, openIn: openIn); break; default: break; } } // Required: decide what happens after a purchase finishes. @override void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { if (purchaseResult is! AdaptyPurchaseResultUserCancelled) { view.dismiss(); } } // Required: dismiss the flow once a restore succeeds. @override void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { view.dismiss(); } // Required: handle rendering and other view errors. @override void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { print('Flow error: $error'); view.dismiss(); } } class FlowScreen extends StatefulWidget { const FlowScreen({super.key}); @override State createState() => _FlowScreenState(); } class _FlowScreenState extends State { @override void initState() { super.initState(); _showFlowIfNeeded(); } Future _showFlowIfNeeded() async { try { final flow = await Adapty().getFlow( placementId: 'YOUR_PLACEMENT_ID', ); if (!flow.hasViewConfiguration) return; final view = await AdaptyUI().createFlowView(flow: flow); await view.present(); } catch (_) { // Handle any errors (network, SDK issues, etc.) } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Adapty Flow Example')), body: Center( // Add a button to re-trigger the flow for testing purposes. child: ElevatedButton( onPressed: _showFlowIfNeeded, child: const Text('Show Flow'), ), ), ); } } ``` --- # File: flutter-check-subscription-status --- --- title: "Flutter SDKでサブスクリプションステータスを確認する" description: "AdaptyでFlutterアプリのサブスクリプションステータスを確認する方法を学びましょう。" --- 有料コンテンツへのアクセスやペイウォールの表示を判断するには、プロファイルの[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態を取得して、ペイウォールを表示するか有料機能へのアクセスを許可するかを判断する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ユーザーにペイウォールを表示するか有料コンテンツを見せるかを判断する際には、プロファイルの[アクセスレベル](access-level)を確認します。方法は2つあります。 - アプリ起動時など、最新のプロファイルデータをすぐに取得したい場合や強制更新したい場合は `getProfile` を呼び出す。 - **プロファイルの自動更新**を設定して、サブスクリプションステータスが変わるたびにローカルコピーを自動的に更新する。 ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得する最もシンプルな方法は、`getProfile` メソッドを使ってプロファイルにアクセスすることです。 ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### サブスクリプションの更新を受け取る \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取るには: 1. `Adapty().didUpdateProfileStream.listen()` を使用してプロファイルの変更を監視します。ユーザーのサブスクリプションステータスが変わると、Adapty は自動的にこのメソッドを呼び出します。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存しておくと、追加のネットワークリクエストを行わずにアプリ全体で利用できます。 ```dart class SubscriptionManager { AdaptyProfile? _currentProfile; SubscriptionManager() { // Listen for profile updates Adapty().didUpdateProfileStream.listen((profile) { _currentProfile = profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() bool hasAccess() { return _currentProfile?.accessLevels['premium']?.isActive ?? false; } } ``` :::note Adapty はアプリ起動時にプロファイル更新ストリームリスナーを自動的に呼び出し、デバイスがオフラインでもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールロジックの連携 \{#connect-profile-with-paywall-logic\} ペイウォールの表示や有料機能へのアクセス付与をすぐに判断する必要がある場合、ユーザーのプロファイルを直接確認できます。この方法は、アプリの起動時、プレミアムセクションへの入場時、特定のコンテンツを表示する前など、さまざまなシナリオで役立ちます。 ```dart Future _checkAccessLevel() async { try { final profile = await Adapty().getProfile(); return profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive ?? false; } catch (e) { print('Error checking access level: $e'); return false; // Show paywall if access check fails } } Future _initializePaywall() async { await _loadPaywall(); final hasAccess = await _checkAccessLevel(); if (!hasAccess) { // Show paywall if no access } } ``` ## 次のステップ \{#next-steps\} サブスクリプションステータスの追跡方法がわかったので、次は[ユーザープロファイルの操作](flutter-quickstart-identify)について学び、ユーザーが購入済みのコンテンツにアクセスできるようにしましょう。 --- # File: flutter-quickstart-identify --- --- title: "Flutter SDKでのユーザー識別" description: "Flutterでのアプリサブスクリプションの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から購入が自動的に同期されます。 匿名ユーザーの場合、インストールのたびに新しいプロファイルが作成されますが、Adaptyのアナリティクスで[新しいインストールとして扱われる条件を設定](general#4-installs-definition-for-analytics)できるため、問題ありません。 匿名ユーザーの場合、**デバイスID**でインストールをカウントする必要があります。この場合、再インストールを含め、デバイスへのアプリのインストールそれぞれが1回のインストールとしてカウントされます。 ## 識別済みユーザー \{#identified-users\} ユーザーを識別するには2つの方法があります: - [**ログイン・サインアップ時:**](#during-loginsignup) アプリ起動後にユーザーがサインインする場合は、認証時に`identify()`をカスタマーユーザーIDと共に呼び出します。 - [**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`が発生するか、匿名プロファイルに対して処理が行われます。詳しくは[Flutter SDKの呼び出し順序](flutter-sdk-call-order)を参照してください。 ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### SDK有効化時 \{#during-the-sdk-activation\} SDKを有効化する時点でカスタマーユーザーIDがわかっている場合は、`identify`を別途呼び出す代わりに、`activate`メソッドに渡すことができます。 カスタマーユーザーIDがわかっていても有効化後に設定する場合、有効化時にAdaptyが新しい匿名プロファイルを作成し、`identify`を呼び出した後にのみ既存のプロファイルへ切り替わります。 既存のカスタマーユーザーID(以前に使用したもの)でも新しいものでも渡すことができます。新しいIDを渡すと、有効化時に作成された新しいプロファイルがそのカスタマーユーザーIDに自動的に紐づけられます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスのダッシュボードに影響しません。インストールはデバイスIDに基づいてカウントされるためです。 デバイスIDはストアからデバイスへのアプリの1回のインストールを表し、アプリを再インストールした場合にのみ再生成されます。 初回インストールか再インストールかに関係なく、また既存のカスタマーユーザーIDを使用するかどうかにも依存しません。 プロファイルの作成(SDK有効化時またはログアウト時)、ログイン、またはアプリの再インストールなしのアップグレードでは、追加のインストールイベントは生成されません。 デバイスではなく一意のユーザーを基準にインストールをカウントしたい場合は、**App settings**に移動して[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```dart showLineNumbers" try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID) // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. ); } catch (e) { // handle the error } ``` ### ユーザーのログアウト \{#log-users-out\} ユーザーをログアウトさせるボタンがある場合は、`logout`メソッドを使用します。 :::important ユーザーをログアウトすると、そのユーザーに対して新しい匿名プロファイルが作成されます。 ::: ```dart showLineNumbers try { await Adapty().logout(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` :::info ユーザーをアプリに再度ログインさせるには、`identify`メソッドを使用してください。 ::: ### ログインなしで購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリにログインする前後の両方で購入できる場合、ログイン後もアクセスが維持されるよう対応する必要があります: 1. ログアウト中のユーザーが購入を行うと、AdaptyはそれをユーザーのAnonymous Profile IDに紐づけます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルへの切り替えを行います。 - 新しいカスタマーユーザーIDの場合(例:登録前に購入が行われた場合)、Adaptyは現在のプロファイルにカスタマーユーザーIDを割り当てるため、購入履歴がすべて維持されます。 - 既存のカスタマーユーザーIDの場合(そのカスタマーユーザーIDがすでにプロファイルに紐づいている場合)、プロファイル切り替え後に実際のアクセスレベルを取得する必要があります。識別直後に[`getProfile`](flutter-check-subscription-status)を呼び出すか、[プロファイルの更新を購読](flutter-check-subscription-status)してデータが自動的に同期されるようにしてください。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内決済のロジックを実装できました!アプリのマネタイズが成功することを願っています! Adaptyをさらに活用するために、以下のトピックを探索してみてください: - [**テスト**](troubleshooting-test-purchases):すべてが期待通りに動作することを確認する - [**オンボーディング**](flutter-onboardings):オンボーディングでユーザーを引き付けてリテンションを向上させる - [**インテグレーション**](configuration):マーケティングアトリビューションや分析サービスとワンラインで連携する - [**カスタムプロファイル属性の設定**](flutter-setting-user-attributes):ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/Bテストの実施や異なるユーザーへの異なるペイウォール表示を可能にする --- # File: adapty-sdk-integration-skill-flutter --- --- title: "SDK統合スキルを使ってFlutterアプリにAdaptyを導入する" description: "adapty-sdk-integrationスキルを使って、AIコーディングツールでFlutterアプリにAdapty SDKをエンドツーエンドで統合します。" --- :::important このスキルはベータ版です。処理が止まったり予期しない動作をした場合は、[ステップバイステップの統合ガイド](adapty-cursor-flutter)を参照してください。AIツールが各ステップを正しいドキュメントに沿って進められるよう案内しています。 ::: [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 またはその他のツール** — [skills CLI](https://skills.sh) を使用してください(この方法でインストールしたスキルは自動更新されません): ``` npx skills add adaptyteam/adapty-sdk-integration-skill ``` または、リポジトリをクローンして `skills/adapty-sdk-integration/` をお使いのツールのスキルディレクトリにコピーしてください。 インストール後、プロジェクトでスキルを実行します: ``` /adapty-sdk-integration ``` スキルがいくつかのセットアップに関する質問をした後、ダッシュボードのセットアップ、SDK のインストール、ペイウォール、検証の手順を案内します。 --- # File: adapty-cursor-flutter --- --- title: "AIアシスタントを使ってAdaptyをFlutterアプリに統合する" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使ってAdaptyをFlutterアプリに統合するステップバイステップガイド。" --- このガイドでは、AIコーディングツールを使ってAdaptyをFlutterアプリにステップバイステップで統合する方法を説明します。適切な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** に移動します。FlutterアプリがiOSとAndroidの両方を対象としている場合は、App StoreとGoogle Playの両方を接続してください。購入機能を動作させるために必要です。 [ストアを接続する](integrate-payments) 2. **Public SDKキーをコピーする**: Adapty ダッシュボードで **App settings → General** に移動し、**API keys** セクションを確認します。コードでは、このキーをAdapty設定に渡します。 3. **プロダクトを1つ以上作成する**: Adapty ダッシュボードで **Products** ページに移動します。コードでプロダクトを直接参照することはなく、Adaptyはペイウォールごしにプロダクトをデリバリーします。 [プロダクトを追加する](quickstart-products) 4. **ペイウォールとプレースメントを作成する**: Adapty ダッシュボードで **Paywalls** ページにペイウォールを作成し、**Placements** ページでプレースメントに割り当てます。コードでは、プレースメントIDを `Adapty().getPaywall()` に渡す文字列として使います。 [ペイウォールを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**: Adapty ダッシュボードの **Products** ページでプロダクトごとに設定します。コードでは `profile.accessLevels['premium']?.isActive` でチェックする文字列です。デフォルトの `premium` アクセスレベルはほとんどのアプリで使えます。プロダクトによって利用できる機能が異なる場合(たとえば `basic` プランと `pro` プラン)は、コーディングを始める前に[追加のアクセスレベルを作成](assigning-access-level-to-a-product)してください。 :::tip この5つが揃えばコードを書く準備は完了です。LLMに「Public SDKキーはX、プレースメントIDはY」と伝えることで、正確な初期化とペイウォール取得コードを生成してもらえます。 ::: ### 準備ができたら設定するもの \{#set-up-when-ready\} これらはコーディングを始めるために必須ではありませんが、統合が進むにつれて必要になります。 - **A/Bテスト**: **Placements** ページで設定します。コードの変更は不要です。 [A/Bテスト](ab-tests) - **追加のペイウォールとプレースメント**: 異なるプレースメントIDで `getPaywall` の呼び出しを追加します。 - **アナリティクス統合**: **Integrations** ページで設定します。統合によって手順が異なります。[アナリティクス統合](analytics-integration)および[アトリビューション統合](attribution-integration)を参照してください。 ## AdaptyドキュメントをLLMに渡す \{#feed-adapty-docs-to-your-llm\} ### Context7を使う(推奨) \{#use-context7-recommended\} [Context7](https://context7.com)は、LLMに最新のAdaptyドキュメントへの直接アクセスを提供するMCPサーバーです。質問内容に応じて適切なドキュメントをLLMが自動的に取得するため、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 Flutter SDK ``` :::warning Context7を使えばドキュメントリンクを手動でペーストする必要はなくなりますが、実装の順序は重要です。すべてが正しく動作するよう、以下の[実装ウォークスルー](#implementation-walkthrough)をステップごとに進めてください。 ::: ### プレーンテキストのドキュメントを使う \{#use-plain-text-docs\} AdaptyのドキュメントはプレーンテキストのMarkdownとして取得できます。URLの末尾に `.md` を追加するか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例: [adapty-cursor-flutter.md](https://adapty.io/docs/ja/adapty-cursor-flutter.md) 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステージには「LLMに送る」ブロックがあり、ペーストできる `.md` リンクが含まれています。 まとめて多くのドキュメントが必要な場合は、以下の[インデックスファイルとプラットフォーム別サブセット](#plain-text-doc-index-files)を参照してください。 ## 実装ウォークスルー \{#implementation-walkthrough\} このガイドの残りの部分では、実装の順序でAdaptyの統合を進めます。各ステージには、LLMに送るドキュメント、完了時に確認できること、よくある問題が含まれています。 ### 統合の計画を立てる \{#plan-your-integration\} コードを書き始める前に、LLMにプロジェクトを分析させて実装計画を作成してもらいましょう。AIツールに計画モード(CursorやClaude Codeのプランモードなど)がある場合は活用してください。コードを書く前にLLMがプロジェクト構造とAdaptyドキュメントの両方を読めます。 購入に使うアプローチをLLMに伝えてください。これにより、参照するガイドが変わります。 - [**Adapty ペイウォールビルダー**](adapty-paywall-builder): Adaptyのノーコードビルダーでペイウォールを作成し、SDKが自動的にレンダリングします。 - [**手動作成のペイウォール**](flutter-making-purchases): 独自のペイウォールUIをコードで構築しつつ、プロダクトの取得と購入処理にAdaptyを使います。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラをそのまま使い、アナリティクスと統合にのみAdaptyを使います。 どれを選べばよいかわからない場合は、[クイックスタートの比較表](flutter-quickstart-paywalls)を参照してください。 ### SDKのインストールと設定 \{#install-and-configure-the-sdk\} `flutter pub add` でAdapty SDKの依存関係を追加し、Public SDKキーで有効化します。これが基盤となり、ここなしには何も動きません。 **ガイド:** [Adapty SDKのインストールと設定](sdk-installation-flutter) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-flutter.md ``` :::tip[チェックポイント] - **期待される結果:** アプリがiOSとAndroidの両方でビルド・起動する。デバッグコンソールにAdaptyのアクティベーションログが表示される。 - **注意点:** 「Public API key is missing」→ プレースホルダーをApp settingsの実際のキーに置き換えたか確認する。 ::: ### ペイウォールの表示と購入の処理 \{#show-paywalls-and-handle-purchases\} プレースメントIDでペイウォールを取得し、表示して、購入イベントを処理します。必要なガイドは購入の処理方法によって異なります。 進める中でサンドボックスでの購入テストを都度行ってください。最後まで待たないようにしましょう。設定手順は[サンドボックスで購入テストする](test-purchases-in-sandbox)を参照してください。 **ガイド:** - [ペイウォールを使って購入を有効にする(クイックスタート)](flutter-quickstart-paywalls) - [ペイウォールビルダーのペイウォールと設定を取得する](flutter-get-pb-paywalls) - [ペイウォールを表示する](flutter-present-paywalls) - [ペイウォールイベントを処理する](flutter-handling-events) - [ボタンアクションに応答する](flutter-handle-paywall-actions) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/flutter-quickstart-paywalls.md - https://adapty.io/docs/ja/flutter-get-pb-paywalls.md - https://adapty.io/docs/ja/flutter-present-paywalls.md - https://adapty.io/docs/ja/flutter-handling-events.md - https://adapty.io/docs/ja/flutter-handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される結果:** 設定したプロダクトでペイウォールが表示される。プロダクトをタップするとサンドボックス購入ダイアログが表示される。 - **注意点:** ペイウォールが空または `getPaywall` エラー → プレースメントIDがダッシュボードと完全に一致しているか、プレースメントにオーディエンスが割り当てられているか確認する。 ::: **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](flutter-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products-flutter) - [リモートコンフィグで設計したペイウォールをレンダリングする](present-remote-config-paywalls-flutter) - [購入を行う](flutter-making-purchases) - [購入を復元する](flutter-restore-purchase) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/flutter-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products-flutter.md - https://adapty.io/docs/ja/present-remote-config-paywalls-flutter.md - https://adapty.io/docs/ja/flutter-making-purchases.md - https://adapty.io/docs/ja/flutter-restore-purchase.md ``` :::tip[チェックポイント] - **期待される結果:** カスタムペイウォールにAdaptyから取得したプロダクトが表示される。プロダクトをタップするとサンドボックス購入ダイアログが表示される。 - **注意点:** プロダクト配列が空 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、プレースメントにオーディエンスがあるか確認する。 ::: **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードを実装する](implement-observer-mode-flutter) - [オブザーバーモードでトランザクションを報告する](report-transactions-observer-mode-flutter) 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-flutter.md - https://adapty.io/docs/ja/report-transactions-observer-mode-flutter.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローでサンドボックス購入を行うと、Adapty ダッシュボードの **Event Feed** にトランザクションが表示される。 - **注意点:** イベントが表示されない → Adaptyへのトランザクション報告が行われているか、両ストアでサーバー通知が設定されているか確認する。 ::: ### サブスクリプションステータスを確認する \{#check-subscription-status\} 購入後、ユーザープロファイルのアクティブなアクセスレベルを確認してプレミアムコンテンツを制限します。 **ガイド:** [サブスクリプションステータスを確認する](flutter-check-subscription-status) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/flutter-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックス購入後、`profile.accessLevels['premium']?.isActive` が `true` を返す。 - **注意点:** 購入後に `accessLevels` が空 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているか確認する。 ::: ### ユーザーを識別する \{#identify-users\} アプリのユーザーアカウントをAdaptyプロファイルに紐付けて、デバイスをまたいで購入が維持されるようにします。 :::important アプリに認証機能がない場合はこのステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](flutter-quickstart-identify) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/flutter-quickstart-identify.md ``` :::tip[チェックポイント] - **期待される結果:** `Adapty().identify()` を呼び出した後、ダッシュボードの **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 settings → iOS SDK** でApp Store Server Notificationsを設定し、**App settings → Android SDK** でGoogle Play Real-Time Developer Notificationsを設定する。 ::: ## プレーンテキストのドキュメントインデックスファイル \{#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つのファイルに統合したものです。非常に大きいため、全体像が必要な場合のみ使用してください。 - Flutter専用の [`flutter-llms.txt`](https://adapty.io/docs/ja/flutter-llms.txt) と [`flutter-llms-full.txt`](https://adapty.io/docs/ja/flutter-llms-full.txt): サイト全体よりもトークンを節約できるプラットフォーム別サブセットです。 --- # File: flutter-get-pb-paywalls --- --- title: "フローとペイウォールの取得 - Flutter" description: "Flutter アプリで Adapty からフローとペイウォールを取得する方法。" --- [フローまたはペイウォールビルダーのペイウォールを設計](adapty-paywall-builder)したら、モバイルアプリに表示できます。最初のステップは、以下に説明するように、プレースメントに関連付けられたフローまたはペイウォールとそのビュー設定を取得することです。 このトピックはフローおよびペイウォールビルダーでカスタマイズされたペイウォールに関するものです。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォール用のペイウォールとプロダクトの取得](fetch-paywalls-and-products-flutter)トピックを参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリにフローとペイウォールを表示する前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フロー/ペイウォールを組み込む](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-flutter) をインストールする。
## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} Flow Builder または Paywall Builder でフローやペイウォールを作成した場合、それをユーザーに表示するためのレンダリングコードをモバイルアプリに書く必要はありません。フローやペイウォールには、表示する内容と表示方法がすべて含まれています。ただし、プレースメントを通じてその ID を取得し、ビュー設定を取得したうえで、モバイルアプリ内で表示する必要があります。 フローまたはペイウォールをできるだけ早めに取得し、表示する前に[ビュー](flutter-get-pb-paywalls#fetch-the-view-configuration)を作成しておきましょう。`createFlowView` メソッドはビューの設定を読み込み、画像のダウンロードとキャッシュをバックグラウンドで開始します。早めに呼び出すほど、ダウンロードが完了するまでの時間を確保できます。フローまたはペイウォールを表示する頃には、設定と画像がすでにキャッシュされて表示可能な状態になっています。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します。 ```dart showLineNumbers try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow/paywall } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

ただし、ユーザーが不安定なインターネット環境を利用していると考えられる場合は、`.returnCacheDataElseLoad` を使用することを検討してください。キャッシュが存在する場合はそちらを返す方式です。この場合、ユーザーが最新データを受け取れないことがありますが、通信状況が不安定でも高速に読み込めます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても安全です。

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

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

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

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

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

| レスポンスパラメータ: | パラメーター | 説明 | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | フローの識別子(`instanceIdentity`、`variationId`)、名前、プレースメント、ペイウォールのバリアント(`paywalls`)、リモートコンフィグ(`remoteConfigs`)を含む `AdaptyFlow` オブジェクト。 | ## ビューの設定を取得する \{#fetch-the-view-configuration\} :::important ビルダーで **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビューの設定を取得できません。 ::: プレースメントが **Flow Builder** または **Paywall Builder** で設計されている場合、Adapty が UI をレンダリングします — 取得したフローの `hasViewConfiguration` プロパティが `true` になります。`createFlowView` でビューを作成し、[フローまたはペイウォールを表示](flutter-present-paywalls)してください。プレースメントがビルダー UI のないカスタムペイウォール(`hasViewConfiguration` が `false`)の場合は、代わりに[リモートコンフィグペイウォールとして処理](present-remote-config-paywalls-flutter)してください。 :::warning `createFlowView` メソッドの結果は一度しか表示できません。再度表示する必要がある場合は、`createFlowView` メソッドを新たに呼び出してください。 ::: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView(flow: flow); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | 必須 | 対象のフロー/ペイウォールのビューを取得するための `AdaptyFlow` オブジェクト。 | | **customTags** | 任意 | カスタムタグとその解決済みの値のマップを定義します。カスタムタグはコンテンツ内のプレースホルダーとして機能し、フロー/ペイウォール内でパーソナライズされたコンテンツを提供するために特定の文字列に動的に置き換えられます。詳細については、[ペイウォールビルダーのカスタムタグ](custom-tags-in-paywall-builder)を参照してください。 | | **preloadProducts** | 任意 | 画面上のプロダクト表示タイミングを最適化するために有効にします。`true` の場合、AdaptyUI は必要なプロダクトを自動的に取得します。デフォルト: `false`。 | | **loadTimeout** | 任意 | ビュー設定の読み込み時間を制限する `Duration`。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが使用されます。 | :::note 複数の言語を使用している場合は、[フローのローカリゼーション](add-paywall-locale-in-adapty-paywall-builder)の追加方法と、ロケールコードの正しい使い方を[こちら](flutter-localizations-and-locale-codes)でご確認ください。 ::: ビューを取得したら、[フロー/ペイウォールを表示](flutter-present-paywalls)してください。 ## デフォルトオーディエンスのフローまたはペイウォールを取得して高速化する \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、フローやペイウォールはほぼ即座に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が不安定な場合は、取得に想定より時間がかかることがあります。そのような状況では、何も表示しないよりも、デフォルトのフローやペイウォールを表示してスムーズなユーザー体験を確保したい場合があるでしょう。 これに対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けのフローまたはペイウォールを取得します。ただし、推奨されるアプローチは [フロー/ペイウォールの取得](#fetch-flowpaywall) セクションで詳しく説明されている `getFlow` メソッドでフローまたはペイウォールを取得することであることを、ぜひ理解しておいてください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンをサポートするペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないペイウォールに遭遇する可能性を受け入れるかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになり、国、マーケティングアトリビューション、独自のカスタム属性に基づくパーソナライズされたターゲティングが失われます。 これらのデメリットを許容してでもフローやペイウォールの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-flowpaywall)で説明した `getFlow` を使用してください。 ::: ```dart showLineNumbers try { final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow/paywall } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値を使用してください。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

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

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

| ## アセットのカスタマイズ \{#customize-assets\} フロー/ペイウォールの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、`hero_image` と `hero_video` という定義済みIDがあります。カスタムアセットバンドルでは、これらのIDを使って対象の要素を指定し、その動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、以下のようなことができます。 - 特定のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 Here's an example of how you can provide custom assets via a simple dictionary: ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createFlowView( flow: flow, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note アセットが見つからない場合、フロー/ペイウォールはデフォルトの外観にフォールバックします。 ::: ## カスタムタイマーの設定 \{#set-up-developer-defined-timers\} モバイルアプリでカスタムタイマーを使用するには、`customTimers` マップを `createFlowView` メソッドに渡します。マップの各キーはタイマー ID で、その値はタイマーの終了時刻を定義する `DateTime` オブジェクトです。以下に例を示します: ```dart showLineNumbers try { final view = await AdaptyUI().createFlowView( flow: flow, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2027, 1, 1), // New Year 2027 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`customTimers` マップにより、アプリは各タイマーを正しい値で動的に更新します。例えば: - `CUSTOM_TIMER_NY`: 元日など、タイマーの終了時刻までの残り時間。 - `CUSTOM_TIMER_6H`: ユーザーがフローを開いてから始まった 6 時間の残り時間。
[Adapty ダッシュボードのペイウォールビルダー](adapty-paywall-builder)でペイウォールのビジュアル部分をデザインしたら、モバイルアプリに表示できます。まず、プレースメントに関連付けられたペイウォールとそのビュー設定を取得する必要があります。詳細は以下をご覧ください。 :::warning 新しいペイウォールビルダーは Flutter SDK バージョン 3.3.0 以上が必要です。 ::: ペイウォールビルダーでカスタマイズしたペイウォールについての説明です。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォールのペイウォールとプロダクトを取得する](fetch-paywalls-and-products-flutter)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでペイウォールの表示を開始する前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[ペイウォールを作成してプロダクトを追加](create-paywall)する。 3. Adapty ダッシュボードで[プレースメントを作成してペイウォールを追加](create-placement)する。 4. モバイルアプリに [Adapty SDK](sdk-installation-flutter) をインストールする。
## ペイウォールビルダーで作成したペイウォールを取得する \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーを使用してペイウォールをデザイン](adapty-paywall-builder)した場合、モバイルアプリのコードでそのペイウォールをレンダリングしてユーザーに表示する処理を個別に実装する必要はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてペイウォールのIDを取得し、ビュー設定を取得したうえで、モバイルアプリ内に表示する必要があります。 最適なパフォーマンスを確保するには、ペイウォールと[ビュー設定](flutter-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得し、ユーザーに表示する前に画像をダウンロードする十分な時間を確保することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します: ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en"); // the requested paywall } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

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

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

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

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

Android の場合: 拡張関数(例: `5.seconds`、`.seconds` は `import com.adapty.utils.seconds` から)を使用して `TimeInterval` を作成するか、`TimeInterval.seconds(5)` を使用できます。制限を設けない場合は `TimeInterval.INFINITE` を使用してください。

| レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクト ID のリスト、ペイウォール識別子、リモートコンフィグ、およびその他のプロパティを含む [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーの **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、`ViewConfiguration` が含まれているかどうかを確認してください。これはペイウォールビルダーで作成されたことを示します。この情報をもとに、ペイウォールの表示方法を決定してください。`ViewConfiguration` が存在する場合はペイウォールビルダーのペイウォールとして扱い、存在しない場合は[リモートコンフィグのペイウォールとして処理してください](present-remote-config-paywalls-flutter)。 ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ビューを取得したら、[ペイウォールを表示](flutter-present-paywalls)してください。 ## デフォルトオーディエンス向けのペイウォールを取得して表示を高速化する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ瞬時に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのネット接続が遅い場合は、取得に予想以上の時間がかかることがあります。そのような状況では、ペイウォールを何も表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を保つほうが望ましいでしょう。 これに対処するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンスのペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](flutter-get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)セクションを参照してください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)で異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがペイウォールを表示できないという問題を受け入れるか、どちらかを選択する必要があります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを受け入れてでもペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` を使用してください。 ::: ```dart showLineNumbers try { final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` :::note `getPaywallForDefaultAudience` メソッドは Flutter SDK バージョン 3.2.0 以降で利用可能です。 ::: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **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 Flutter SDK をバージョン 3.8.0 以上にアップデートしてください。 ::: カスタムアセットをシンプルなディクショナリ形式で提供する例を以下に示します。 ```dart final customAssets = { // Show a local image using a custom ID 'custom_image': AdaptyCustomAsset.localImageAsset( assetId: 'assets/images/image_name.png', ), // Show a local video with a preview image 'hero_video': AdaptyCustomAsset.localVideoAsset( assetId: 'assets/videos/custom_video.mp4', ), }; try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customAssets: customAssets, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの外観にフォールバックします。 ::: ## カスタムタイマーの設定 \{#set-up-developer-defined-timers\} モバイルアプリでカスタムタイマーを使用するには、`createPaywallView` メソッドに `customTimers` マップを渡します。マップの各キーはタイマーIDで、その値はタイマーの終了時刻を定義する `DateTime` オブジェクトです。以下に例を示します。 ```dart showLineNumbers try { final view = await AdaptyUI().createPaywallView( paywall: paywall, customTimers: { 'CUSTOM_TIMER_6H': DateTime.now().add(const Duration(seconds: 3600 * 6)), 'CUSTOM_TIMER_NY': DateTime(2025, 1, 1), // New Year 2025 }, ); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`customTimers` マップにより、アプリは各タイマーを正しい値で動的に更新します。例: - `CUSTOM_TIMER_NY`: 元旦など、タイマーの終了時刻までの残り時間。 - `CUSTOM_TIMER_6H`: ユーザーがペイウォールを開いてから始まった6時間のうち、残りの時間。
--- # File: flutter-present-paywalls --- --- title: "フローとペイウォールの表示 - Flutter" description: "Adapty のマネタイズ機能を使って Flutter アプリでフローとペイウォールを表示する方法を説明します。" --- Flow Builder またはペイウォールビルダーを使ってフローやペイウォールをデザインした場合、モバイルアプリのコードでレンダリングしてユーザーに表示する処理を自分で実装する必要はありません。フローやペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このガイドはフローおよびペイウォールビルダーのペイウォールを対象としています。**リモートコンフィグのペイウォール**を表示する場合は、[リモートコンフィグで設計したペイウォールのレンダリング](present-remote-config-paywalls-flutter)を参照してください。 ::: Adapty Flutter SDK では、フローとペイウォールを表示する方法が2つあります。 - **スタンドアロン画面** - **埋め込みウィジェット** ## スタンドアロン画面として表示する \{#present-as-standalone-screen\} フローまたはペイウォールをスタンドアロン画面として表示するには、[`createFlowView`](flutter-get-pb-paywalls#fetch-the-view-configuration) メソッドで作成した `view` に対して `view.present()` メソッドを使用します。各 `view` は一度しか表示できません。非表示にすると、その `view` はメモリから解放されます。再度フローまたはペイウォールを表示する必要がある場合は、`createFlowView` を再度呼び出して新しい `view` インスタンスを作成してください。 ```dart showLineNumbers title="Flutter" try { await view.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### フローまたはペイウォールを閉じる \{#dismiss-the-flow-or-paywall\} フローまたはペイウォールをプログラムで閉じる必要がある場合は、`dismiss()` メソッドを使用します。 ```dart showLineNumbers title="Flutter" try { await view.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::note ビューを閉じると、そのビューはメモリから解放されます。一度閉じたビューは再表示できません。代わりに `createFlowView` で新しいビューを作成してください。 ::: ### ダイアログを表示する \{#show-dialog\} Android でフローまたはペイウォールビューが表示されているときは、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートがビューの後ろに表示されるため、ユーザーから見えなくなります。このメソッドを使用すると、すべてのプラットフォームでフローまたはペイウォールの上に正しくダイアログが表示されます。 ```dart showLineNumbers title="Flutter" try { final action = await view.showDialog( title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', ); if (action == AdaptyUIDialogActionType.secondary) { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (e) { // handle error } ``` ### iOSプレゼンテーションスタイルの設定 \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのフローまたはペイウォールの表示スタイルを設定できます。このパラメータには `AdaptyUIIOSPresentationStyle.fullScreen`(デフォルト)または `AdaptyUIIOSPresentationStyle.pageSheet` を指定できます。 ```dart showLineNumbers try { await view.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## ウィジェット階層への埋め込み \{#embed-in-widget-hierarchy\} フローやペイウォールを既存のウィジェットツリー内に埋め込むには、`AdaptyUIFlowPlatformView` ウィジェットを Flutter のウィジェット階層に直接配置します。 ```dart showLineNumbers title="Flutter" AdaptyUIFlowPlatformView( flow: flow, // The flow object you fetched onDidAppear: (view) { }, onDidDisappear: (view) { }, onDidPerformAction: (view, action) { }, onDidSelectProduct: (view, productId) { }, onDidStartPurchase: (view, product) { }, onDidFinishPurchase: (view, product, purchaseResult) { }, onDidFailPurchase: (view, product, error) { }, onDidStartRestore: (view) { }, onDidFinishRestore: (view, profile) { }, onDidFailRestore: (view, error) { }, onDidReceiveError: (view, error) { }, onDidFailLoadingProducts: (view, error) { }, onDidFinishWebPaymentNavigation: (view, product, error) { }, ) ``` :::note Android のプラットフォームビューを機能させるには、`MainActivity` が `FlutterFragmentActivity` を継承していることを確認してください: ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: ペイウォールビルダーでペイウォールをカスタマイズした場合、モバイルアプリのコード側でレンダリングの処理を実装しなくても、ユーザーに表示できます。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このガイドは、SDK v3.2.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。ペイウォールの表示方法は、異なるバージョンのペイウォールビルダーで設計されたペイウォールやリモートコンフィグペイウォールによって異なります。 - **リモートコンフィグペイウォール**の表示については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls-flutter)を参照してください。 ::: Adapty Flutter SDK では、ペイウォールの表示方法が2つあります: - **スタンドアロン画面** - **埋め込みウィジェット** ## スタンドアロン画面として表示する \{#present-as-standalone-screen\} ペイウォールをスタンドアロン画面として表示するには、[`createPaywallView`](flutter-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。再度ペイウォールを表示する必要がある場合は、`createPaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用すると、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```dart showLineNumbers title="Flutter" try { await view.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### ペイウォールを閉じる \{#dismiss-the-paywall\} ペイウォールをプログラムで閉じる必要がある場合は、`dismiss()` メソッドを使用してください: ```dart showLineNumbers title="Flutter" try { await view.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### ダイアログを表示する \{#show-dialog\} Android でペイウォールビューが表示されている場合は、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートがペイウォールビューの背後に表示されるため、ユーザーには見えません。このメソッドを使用することで、すべてのプラットフォームでペイウォールの前面にダイアログが正しく表示されます。 ```dart showLineNumbers title="Flutter" try { final action = await view.showDialog( title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', ); if (action == AdaptyUIDialogActionType.secondary) { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (e) { // handle error } ``` ### iOS のプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOS でのペイウォールの表示スタイルを設定できます。このパラメーターには `AdaptyUIIOSPresentationStyle.fullScreen`(デフォルト)または `AdaptyUIIOSPresentationStyle.pageSheet` を指定できます。 ```dart showLineNumbers try { await view.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## ウィジェット階層への埋め込み \{#embed-in-widget-hierarchy\} ペイウォールを既存のウィジェットツリーに埋め込むには、`AdaptyUIPaywallPlatformView` ウィジェットを Flutter のウィジェット階層に直接配置します。 ```dart showLineNumbers title="Flutter" AdaptyUIPaywallPlatformView( paywall: paywall, // The paywall object you fetched onDidAppear: (view) { }, onDidDisappear: (view) { }, onDidPerformAction: (view, action) { }, onDidSelectProduct: (view, productId) { }, onDidStartPurchase: (view, product) { }, onDidFinishPurchase: (view, product, purchaseResult) { }, onDidFailPurchase: (view, product, error) { }, onDidStartRestore: (view) { }, onDidFinishRestore: (view, profile) { }, onDidFailRestore: (view, error) { }, onDidFailRendering: (view, error) { }, onDidFailLoadingProducts: (view, error) { }, onDidFinishWebPaymentNavigation: (view, product, error) { }, ) ``` :::note Android のプラットフォームビューを機能させるには、`MainActivity` が `FlutterFragmentActivity` を継承していることを確認してください: ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: --- # File: flutter-handle-paywall-actions --- --- title: "Flutter SDKでボタンアクションに応答する" description: "AdaptyのFlutterでペイウォールのボタンアクションを処理し、アプリの収益化を改善します。" --- Adaptyビルダーを使ってフローやペイウォールを構築している場合、ボタンを正しく設定することが重要です: 1. [ビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションをアプリのコードで処理します。 このガイドでは、コード内でカスタムアクションおよび既存アクションを処理する方法を説明します。 :::warning **ビューを閉じる操作とURLを開く操作は、** デフォルトの `flowViewDidPerformAction` 実装によって**自動的に処理され**、購入と復元はSDK自体が処理します。ログインや別のフローを開くといった他のボタンアクションについては、アプリコード側で適切なレスポンスを実装する必要があります。なお、購入と復元の*完了*に対する応答は、必須のオブザーバーコールバックで行います。詳細は[フロー&ペイウォールイベントの処理](flutter-handling-events)を参照してください。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローまたはペイウォールを閉じるボタンを追加するには、ビルダーでボタンを追加し、**Close** アクションを割り当てます。コードは不要です。デフォルトの `flowViewDidPerformAction` 実装は、`CloseAction` を受け取るとビューを閉じます。 :::info Android の **Back** ボタンは、デフォルトではビューを閉じなくなりました。`flowViewDidPerformAction` に `AndroidSystemBackAction` として渡されるので、バックボタンでフローやペイウォールを閉じたい場合は自分で処理してください。 ::: カスタム動作が必要な場合は `flowViewDidPerformAction` をオーバーライドしてください。たとえば、v3 のように Android のシステムバックボタンでもビューを閉じる場合は次のようにします: ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): view.dismiss(); break; case OpenUrlAction(:final url, :final openIn): AdaptyUI().openUrl(url, openIn: openIn); break; default: break; } } ``` :::warning `flowViewDidPerformAction` をオーバーライドすると、デフォルトの実装が完全に置き換えられます。デフォルトの閉じる動作とURL開く動作を維持したい場合は、`CloseAction` と `OpenUrlAction` のケースをそのまま残してください。 ::: ## フローとペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: リンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには、ビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 コードは不要です。デフォルトの `flowViewDidPerformAction` 実装は、`AdaptyUI().openUrl` を使ってURLをネイティブに開き、ダッシュボードのアプリ内ブラウザ/外部ブラウザの設定に従います。 ほとんどのケースではデフォルトの動作で十分です。自分でURLを開きたい場合は、ハンドラーをオーバーライドしてください。 ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): view.dismiss(); break; case OpenUrlAction(url: final url): // Open the URL in whatever way fits your app break; default: break; } } ``` ## アプリへのログイン \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには: 1. ビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコードに、ユーザーを識別する `login` アクションのハンドラーを実装します。 ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'login'): // Navigate to your login screen in whatever way fits your app break; default: break; } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ビルダーでボタンを追加し、**Custom** アクションを割り当て、IDを設定します。 2. アプリのコードに、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます: ```dart void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'openNewPaywall'): // Display another flow or paywall break; default: break; } } ``` ペイウォールビルダーを使ってペイウォールを構築する場合、ボタンを適切に設定することが重要です: 1. [ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよびあらかじめ用意されたアクションをコード内で処理する方法を説明します。 :::warning **購入と復元のみが自動的に処理されます。** ペイウォールを閉じる、リンクを開くなど、その他のボタンアクションはすべてアプリのコード内で適切な処理を実装する必要があります。 ::: ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、`CloseAction` および `AndroidSystemBackAction` アクションのハンドラーを実装します。 :::info Flutter SDK では、`CloseAction` および `AndroidSystemBackAction` アクションはデフォルトでペイウォールを閉じる動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じると別のペイウォールが開くようにすることも可能です。 ::: ```dart void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case const CloseAction(): case const AndroidSystemBackAction(): view.dismiss(); break; default: break; } } ``` ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションが設定されたボタンと同じ方法で処理してください。 ::: ペイウォールにリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 ```dart // You have to install url_launcher plugin in order to handle urls: // https://pub.dev/packages/url_launcher void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case OpenUrlAction(url: final url): final Uri uri = Uri.parse(url); launchUrl(uri, mode: LaunchMode.inAppBrowserView); break; default: break; } } ``` ## アプリへのログイン \{#log-into-the-app\} ユーザーがアプリにログインするためのボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコードで、ユーザーを識別する `login` アクションのハンドラーを実装します。 ```dart void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'login'): // Navigate to your login screen in whatever way fits your app break; default: break; } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} 他のアクションを処理するボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当て、IDを設定します。 2. アプリのコードで、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入のセットがある場合、別のペイウォールを表示するボタンを追加できます: ```dart void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { switch (action) { case CustomAction(action: 'openNewPaywall'): // 別のペイウォールを表示する break; default: break; } } ``` --- # File: flutter-handling-events --- --- title: "Flutter - フロー & ペイウォールイベントの処理" description: "Adapty を使って Flutter でサブスクリプション関連のイベントを処理し、ユーザーの操作を効果的に追跡する方法を解説します。" --- :::important このガイドでは、購入・復元・プロダクト選択・レンダリングのイベント処理について説明します。ビューを閉じる処理とリンクを開く処理は、デフォルトの `flowViewDidPerformAction` 実装によって行われます。これらをオーバーライドしたり、カスタムボタンアクションを処理したりする方法については、[ボタンアクションの処理に関するガイド](flutter-handle-paywall-actions)をご覧ください。 ::: ビルダーで設定したフローやペイウォールは、購入や復元のために追加のコードは不要です。ただし、アプリが応答できるイベントがいくつか生成されます。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や、フローまたはペイウォール上での購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご確認ください。 モバイルアプリ内でフローまたはペイウォール画面上の処理を制御・監視するには、`AdaptyUIFlowsEventsObserver` のメソッドを実装し、画面を表示する前にオブザーバーを設定してください。 ```dart showLineNumbers title="Flutter" AdaptyUI().setFlowsEventsObserver(this); ``` 3つのオブザーバーメソッドは**必須**です — `flowViewDidFinishPurchase`、`flowViewDidFinishRestore`、`flowViewDidReceiveError` がないとクラスがコンパイルされません。その他のメソッドはすべて任意です。設定済みのオブザーバーを解除するには、`setFlowsEventsObserver` に `null` を渡してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: 以下のイベント例では、各オブジェクトで使用できるプロパティをコメント内の例示値とともに示しています。 ### ユーザー生成イベント \{#user-generated-events\} #### 画面表示 \{#view-appeared\} このメソッドは、フローまたはペイウォールのビューが画面に表示されたときに呼び出されます。 :::note iOS では、ユーザーがペイウォール内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップし、アプリ内ブラウザでウェブペイウォールが開いたときにも呼び出されます。 ::: ```dart showLineNumbers title="Flutter" void flowViewDidAppear(AdaptyUIFlowView view) { } ``` #### 画面非表示 \{#view-disappeared\} このメソッドは、フローまたはペイウォールのビューが画面から消えたときに呼び出されます。 :::note iOSでは、ペイウォールのアプリ内ブラウザから開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えた場合にも呼び出されます。 ::: ```dart showLineNumbers title="Flutter" void flowViewDidDisappear(AdaptyUIFlowView view) { } ``` #### プロダクトの選択 \{#product-selection\} ユーザーまたはシステムによってプロダクトが選択された場合、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) { } ```
イベントの例(クリックして展開) ```dart void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ```
#### 購入の開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { } ```
イベントの例(クリックして展開) ```dart void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' product.localizedTitle; // 'Premium Monthly' product.localizedDescription; // 'Premium subscription for 1 month' product.price.amount; // 9.99 (double) product.price.currencyCode; // 'USD' product.price.localizedString; // '$9.99' } ```
#### 購入完了 \{#finished-purchase\} このメソッドは**必須**です。購入が成功したとき、ユーザーが購入をキャンセルしたとき、または購入が保留中と判断されたときに呼び出されます。 ```dart showLineNumbers title="Flutter" void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // successful purchase break; case AdaptyPurchaseResultPending(): // purchase is pending break; case AdaptyPurchaseResultUserCancelled(): // user cancelled the purchase break; default: break; } } ```
イベントの例(クリックして展開) ```dart void flowViewDidFinishPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) break; case AdaptyPurchaseResultPending(): // no additional data break; case AdaptyPurchaseResultUserCancelled(): // no additional data break; } } ```
:::info v3 とは異なり、このメソッドにはデフォルトの動作がありません。購入が成功しても画面は自動的に閉じられません。次の動作は自分で決める必要があります。フローを続けるか、`view.dismiss()` を呼び出してください。画面を閉じる方法については、[ボタンアクションへの対応](flutter-handle-paywall-actions)を参照してください。 ::: #### ウェブ決済ナビゲーションの完了 \{#finished-web-payment-navigation\} このメソッドは、特定のプロダクトに対して[ウェブペイウォール](web-paywall)を開こうとした後に呼び出されます。ナビゲーションの成功・失敗に関わらず、両方のケースで呼び出されます。 ```dart showLineNumbers title="Flutter" void flowViewDidFinishWebPaymentNavigation(AdaptyUIFlowView view, AdaptyPaywallProduct? product, AdaptyError? error) { } ``` **パラメーター:** | パラメーター | 説明 | |:------------|:---------------------------------------------------------------------------------------------------| | **product** | ウェブペイウォールが開かれた `AdaptyPaywallProduct`。`null` の場合があります。 | | **error** | ウェブペイウォールのナビゲーションに失敗した場合は `AdaptyError` オブジェクト。成功した場合は `null`。 | #### 購入失敗 \{#failed-purchase\} このメソッドは、購入が失敗した場合(例:決済エラーやネットワークエラー)に呼び出されます。ユーザーが自らキャンセルした場合や保留中のトランザクションには**呼び出されません**—それらは`flowViewDidFinishPurchase`で処理されます: ```dart showLineNumbers title="Flutter" void flowViewDidFailPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product, AdaptyError error) { } ``` #### 復元の開始 \{#started-restore\} ユーザーが復元プロセスを開始した場合、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void flowViewDidStartRestore(AdaptyUIFlowView view) { } ``` #### 復元の成功 \{#successful-restore\} このメソッドは**必須**です。購入の復元が成功した場合に呼び出されます: ```dart showLineNumbers title="Flutter" void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { } ```
イベントの例(クリックして展開) ```dart void flowViewDidFinishRestore(AdaptyUIFlowView view, AdaptyProfile profile) { // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) profile.subscriptions['premium_monthly']?.isActive; // true profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) } ```
ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることをお勧めします。確認方法については [サブスクリプションステータス](flutter-listen-subscription-changes) を、画面を閉じる方法については [ボタン操作への対応](flutter-handle-paywall-actions) を参照してください。 #### リストアの失敗 \{#failed-restore\} 購入のリストアに失敗した場合、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void flowViewDidFailRestore(AdaptyUIFlowView view, AdaptyError error) { } ``` ### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクト配列を渡さなかった場合、AdaptyUI はサーバーから必要なオブジェクトを自動的に取得します。この処理が失敗した場合、AdaptyUI は次のメソッドを呼び出してエラーを通知します。 ```dart showLineNumbers title="Flutter" void flowViewDidFailLoadingProducts(AdaptyUIFlowView view, AdaptyError error) { } ``` #### ビューのエラー \{#view-errors\} このメソッドは**必須**です。v3 の `paywallViewDidFailRendering` メソッドの代替となります。インターフェースのレンダリング中に発生したエラーやその他のビューエラーは、このメソッドを呼び出すことで報告されます。実装後の画面の閉じ方はご自身で決定できますが、このようなエラー時にはビューを閉じることをお勧めします。これは、オブザーバーが設定されていない場合の SDK 組み込みのデフォルト動作でもあります: ```dart showLineNumbers title="Flutter" void flowViewDidReceiveError(AdaptyUIFlowView view, AdaptyError error) { // log the error and dismiss the broken view view.dismiss(); } ``` 通常、レンダリングエラーは発生しないため、もし遭遇した場合はご連絡ください。 ### アナリティクスイベント \{#analytics-events\} オプションの `flowViewDidReceiveAnalyticEvent` メソッドは、フローからのカスタムアナリティクスイベント用に予約されています。現時点ではフローからこのコードへのイベント送信は行われないため、実装は不要です。 ### オブザーバーモードで購入を処理する \{#handle-purchases-in-observer-mode\} SDKを[オブザーバーモード](implement-observer-mode-flutter)で有効化し、Adaptyがレンダリングするフローやペイウォールを表示している場合、SDKは代わりに購入処理を行いません。ユーザーが購入ボタンまたは復元ボタンをタップすると、SDKは代わりに`AdaptyUIObserverModeResolver`を呼び出します。詳細なセットアップ手順については、[オブザーバーモードでフローを表示する](flutter-present-flows-in-observer-mode)を参照してください。 ### システムリクエストの処理 \{#handle-system-requests\} `AdaptyUISystemRequestsHandler`(`AdaptyUI().setSystemRequestsHandler(...)` で登録)は、フローからのシステムリクエスト(プッシュ通知やカメラアクセスなどのOS権限プロンプト、App Storeレビューリクエスト)のために予約されています。現時点ではフローがこれらのリクエストをトリガーすることはないため、ハンドラーを登録する必要はありません。 `handlePermission` はクラスの必須メソッドです。独自のコードでパーミッションをリクエストし、`AdaptyUIPermissionResult.granted()` または `AdaptyUIPermissionResult.denied()` を返してください。`handleAppReviewRequest` は任意です。
:::important このガイドでは、購入・復元・プロダクト選択・ペイウォールレンダリングのイベント処理について説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の実装も必要です。詳細は[ボタンアクションの処理に関するガイド](flutter-handle-paywall-actions)をご参照ください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定されたペイウォールは、購入や復元のために追加のコードは不要です。ただし、アプリが応答できるいくつかのイベントが生成されます。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上での購入関連アクションの通知が含まれます。これらのイベントへの応答方法については、以下をご覧ください。 :::warning このガイドは、Adapty SDK v3.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。 ::: ペイウォール画面で発生するプロセスを制御または監視するには、`AdaptyUIPaywallsEventsObserver` のメソッドを実装し、画面を表示する前にオブザーバーを設定してください。 ```dart showLineNumbers title="Flutter" AdaptyUI().setPaywallsEventsObserver(this); ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: 以下のイベントの例では、各オブジェクトで利用可能なプロパティと、コメント内の説明用の値を示しています。 ### ユーザー生成イベント \{#user-generated-events\} #### ペイウォールが表示された \{#paywall-appeared\} このメソッドは、ペイウォールビューが画面に表示されたときに呼び出されます。 :::note iOS では、ユーザーがペイウォール内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップしてインアプリブラウザでウェブペイウォールが開いた場合にも呼び出されます。 ::: ```dart showLineNumbers title="Flutter" void paywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### ペイウォールが非表示になった \{#paywall-disappeared\} このメソッドは、ペイウォールビューが画面から閉じられたときに呼び出されます。 :::note iOSでは、ペイウォール内のアプリ内ブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えたときにも呼び出されます。 ::: ```dart showLineNumbers title="Flutter" void paywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### プロダクトの選択 \{#product-selection\} ユーザーまたはシステムによってプロダクトが購入のために選択されると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) { } ```
イベントの例(クリックして展開) ```dart void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ```
#### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { } ```
イベントの例(クリックして展開) ```dart void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' product.localizedTitle; // 'Premium Monthly' product.localizedDescription; // 'Premium subscription for 1 month' product.price.amount; // 9.99 (double) product.price.currencyCode; // 'USD' product.price.localizedString; // '$9.99' } ```
#### 購入完了 \{#finished-purchase\} この方法は、購入が成功した場合、ユーザーが購入をキャンセルした場合、または購入が保留中と判断された場合に呼び出されます。 ```dart showLineNumbers title="Flutter" void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // successful purchase break; case AdaptyPurchaseResultPending(): // purchase is pending break; case AdaptyPurchaseResultUserCancelled(): // user cancelled the purchase break; default: break; } } ```
イベントの例(クリックして展開) ```dart void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchaseResult) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) break; case AdaptyPurchaseResultPending(): // no additional data break; case AdaptyPurchaseResultUserCancelled(): // no additional data break; } } ```
このような場合はスクリーンを閉じることをおすすめします。ペイウォール画面を閉じる方法については、[ボタンアクションへの対応](flutter-handle-paywall-actions)を参照してください。 #### ウェブ決済ナビゲーションの完了 \{#finished-web-payment-navigation\} このメソッドは、特定のプロダクトに対して[ウェブペイウォール](web-paywall)を開こうとした後に呼び出されます。ナビゲーションの成功・失敗いずれの場合も対象となります。 ```dart showLineNumbers title="Flutter" void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct? product, AdaptyError? error) { } ``` **パラメーター:** | パラメーター | 説明 | |:------------|:---------------------------------------------------------------------------------------------------| | **product** | ウェブペイウォールが開かれた `AdaptyPaywallProduct`。`null` の場合があります。 | | **error** | ウェブペイウォールのナビゲーションに失敗した場合は `AdaptyError` オブジェクト。成功した場合は `null`。 |
イベント例(クリックして展開) ```dart void paywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct? product, AdaptyError? error) { // product — AdaptyPaywallProduct?: product?.vendorProductId; // 'premium_monthly' if (error == null) { // navigation succeeded } else { // error — AdaptyError: error.code; // AdaptyErrorCode.networkFailed (2005) error.message; // 'Network request failed' error.detail; // platform-specific underlying error, or null } } ```
#### 購入失敗 \{#failed-purchase\} このメソッドは、支払いの問題やネットワークエラーなどにより購入が失敗した場合に呼び出されます。ユーザーが自発的にキャンセルした場合やペンディング中のトランザクションには**呼び出されません**。それらは `paywallViewDidFinishPurchase` で処理されます: ```dart showLineNumbers title="Flutter" void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } ```
イベントの例(クリックして展開) ```dart void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { // product — AdaptyPaywallProduct: product.vendorProductId; // 'premium_monthly' // error — AdaptyError: error.code; // AdaptyErrorCode.productPurchaseFailed (1006) error.message; // 'Product purchase failed.' error.detail; // platform-specific underlying error, or null } ```
#### 復元の開始 \{#started-restore\} ユーザーが復元プロセスを開始すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### 復元成功 \{#successful-restore\} 購入の復元が成功すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { } ```
イベント例(クリックして展開) ```dart void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { // profile — AdaptyProfile: profile.accessLevels['premium']?.isActive; // true profile.accessLevels['premium']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) profile.subscriptions['premium_monthly']?.isActive; // true profile.subscriptions['premium_monthly']?.expiresAt; // DateTime(2027, 2, 15, 10, 30) } ```
ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることを推奨します。確認方法については [サブスクリプションのステータス](flutter-listen-subscription-changes) を、ペイウォール画面を閉じる方法については [ボタン操作への対応](flutter-handle-paywall-actions) を参照してください。 #### 復元の失敗 \{#failed-restore\} 購入の復元に失敗した場合、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { } ```
イベントの例(クリックして展開) ```dart void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { // error — AdaptyError: error.code; // AdaptyErrorCode.receiveRestoredTransactionsFailed (1011) error.message; // 'Error occurred in the process of restoring purchases.' error.detail; // platform-specific underlying error, or null } ```
### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクト配列を渡さなかった場合、AdaptyUIはサーバーから必要なオブジェクトを自動的に取得します。この処理が失敗した場合、AdaptyUIは以下のメソッドを呼び出してエラーを通知します: ```dart showLineNumbers title="Flutter" void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { } ```
イベント例(クリックして展開) ```dart void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { // error — AdaptyError: error.code; // AdaptyErrorCode.productRequestFailed (1002) error.message; // 'Unable to fetch available In-App Purchase products at the moment.' error.detail; // platform-specific underlying error, or null } ```
#### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生した場合、このメソッドを呼び出すことでエラーが報告されます。デフォルトでは(v3.15.2以降)、レンダリングエラーが発生するとペイウォールは自動的に閉じられますが、必要に応じてこの動作をオーバーライドできます。 ```dart showLineNumbers title="Flutter" void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { // Default behavior: view.dismiss() // Override with custom logic if needed, for example: // - Log the error // - Show an error message to the user } ```
イベントの例(クリックして展開) ```dart void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { // error — AdaptyError: error.code; // AdaptyErrorCode.jsException (4105) error.message; // 'An exception was thrown from JS during AdaptyUI flow execution.' error.detail; // platform-specific underlying error, or null // Default behavior: view.dismiss() } ```
通常の状況では、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひご連絡ください。
--- # File: flutter-use-fallback-paywalls --- --- title: "Flutter - フォールバックペイウォールを使用する" description: "ユーザーがオフラインのときや Adapty サーバーが利用できないときの対処方法" --- :::warning フォールバックペイウォールは Flutter SDK v2.11 以降でサポートされています。 ::: スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} 1. フォールバック設定ファイルをプロジェクトルートの `assets` ディレクトリに追加します。 2. 対象のペイウォールまたはオンボーディングを取得する**前に** `.setFallback` メソッドを呼び出します。 ```dart showLineNumbers title="Flutter" final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; try { await Adapty().setFallback(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` パラメーター: | パラメーター | 説明 | | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **assetId** | フォールバック設定ファイルへのパス。 | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: flutter-localizations-and-locale-codes --- --- title: "Flutter SDKでローカリゼーションとロケールコードを使用する" description: "アプリのローカリゼーションとロケールコードを管理して、グローバルなユーザーにリーチしましょう。" --- ## これが重要な理由 \{#why-this-is-important\} ロケールコードは、Adapty がフローのローカライズを選択する際や、カスタムペイウォールのリモートコンフィグを読み取る際に使用されます。 ロケールコードはプラットフォームによって異なる場合があり複雑なため、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 がユーザーのロケールに合う地域化を探す際、以下の処理が行われます。 1. ロケール文字列を小文字に変換し、アンダースコア(`_`)をすべてハイフン(`-`)に置き換えます 2. ロケールコードが完全に一致する地域化を検索します 3. 一致する地域化が見つからない場合、最初のハイフンより前の部分文字列(`pt-br` に対する `pt` など)を取り出し、一致する地域化を検索します 4. それでも一致する地域化が見つからない場合、デフォルトの `en` 地域化を返します このため、`'pt_BR'`、`pt-BR`、`pt-br` はすべて同じ地域化に解決されます。 ## ローカライズの実装 \{#implementing-localizations\} SDK v4 では、フローを取得する際にロケールコードを渡す必要はありません。 - **フロービルダーおよびペイウォールビルダーのペイウォール**: Adapty はデバイス設定とビルダーで設定したローカライズをもとに、自動的にローカライズを解決します。`createFlowView` でフローをレンダリングするだけで、ロケールコードは不要です。 - **カスタム(リモートコンフィグ)ペイウォール**: `getFlow` は設定されたすべてのローカライズを `flow.remoteConfigs` に返します。各エントリには `locale` コードとコンフィグの内容(`data` 文字列、またはパース済みの `dictionary`)が含まれています。ユーザーに合ったエントリを選択し、独自のフォールバック処理を実装してください。 ```dart showLineNumbers final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); final config = flow.remoteConfigs.firstWhereOrNull((c) => c.locale == 'en') ?? flow.remoteConfig; // the first remote config, if present // read your values from config?.dictionary ``` 上記のロケールコードマッチングルールは、各リモートコンフィグに保存されている `locale` コードを Adapty がどのように正規化するかを説明しています。 ## これが重要な理由 \{#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 を呼び出す際に、そのキーの値を取り出して渡します。 ```dart showLineNumbers // 1. Modify your app_en.arb, app_es.arb, app_pt_br.arb files /* app_en.arb */ "adapty_paywalls_locale": "en", /* app_es.arb */ "adapty_paywalls_locale": "es", /* app_pt_br.arb */ "adapty_paywalls_locale": "pt-br", // 2. Extract and use the locale code final locale = AppLocalizations.of(context)!.adapty_paywalls_locale; // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` この方法により、アプリの各ユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。 ## ローカリゼーションの別の実装方法 \{#implementing-localizations-the-other-way\} ロケールコードをすべてのローカリゼーションに明示的に定義しなくても、同様の(ただし完全に同じではない)結果を得ることができます。その場合、プラットフォームが提供する別のオブジェクトからロケールコードを取得する方法が考えられます。例えば次のようにします。 ```dart showLineNumbers final locale = Localizations.localeOf(context).languageCode; // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` ただし、この方法はいくつかの理由からお勧めしません。 1. iOSでは、優先言語と現在のロケールは同一ではありません。ローカライズが正しく選択されるようにするには、ローカライズされた文字列ファイルを使用する推奨のアプローチを利用してAppleのロジックにそのまま任せるか、独自に再実装する必要があります。 2. Adaptyのサーバーが実際に何を受け取るかを予測するのは困難です。たとえばiOSでは、デバイスから `ar_OM@numbers='latn'` のようなロケールを取得してサーバーに送信することがあります。この場合、期待していた `ar-om` ローカライズではなく、`ar` が返されることになり、予期しない動作となる可能性があります。 万が一このアプローチを採用する場合は、関連するすべてのユースケースを網羅していることを確認してください。 --- # File: flutter-web-paywall --- --- title: "Flutter SDKでウェブペイウォールを実装する" description: "App Storeの手数料や審査なしに支払いを受け取るためのウェブペイウォールを設定します。" --- :::important 始める前に、[ダッシュボードでウェブペイウォールを設定済み](web-paywall)であること、およびAdapty SDK バージョン3.6.1以降がインストールされていることを確認してください。 ::: 自作のペイウォールを使用している場合は、SDK のメソッドを使ってウェブペイウォールを処理する必要があります。`.openWebPaywall` メソッドは次の処理を行います。 1. 固有の URL を生成し、Adapty が特定のユーザーに表示されたペイウォールと、そのユーザーがリダイレクトされたウェブページを紐付けられるようにします。 2. ユーザーがアプリに戻ったタイミングを検知し、短い間隔で `.getProfile` をリクエストして、プロファイルのアクセス権が更新されたかどうかを確認します。 これにより、支払いが成功してアクセス権が更新されると、サブスクリプションはほぼ即座にアプリ内で有効化されます。 ```dart showLineNumbers title="Flutter" try { await Adapty().openWebPaywall(product: ); // The web paywall will be opened } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle other errors } ``` :::note `openWebPaywall` メソッドには2つのバージョンがあります: 1. `openWebPaywall(product)` — ペイウォールをもとに URL を生成し、プロダクトデータも URL に付加します。 2. `openWebPaywall(paywall)` — ペイウォールをもとに URL を生成しますが、プロダクトデータは URL に付加しません。Adapty ペイウォールのプロダクトとウェブペイウォールのプロダクトが異なる場合に使用してください。 SDK v4 では、`paywall` パラメータは `AdaptyFlowPaywall`(取得したフローのペイウォールバリアント)を受け取ります。インデックスアクセスする前に `flow.paywalls` が空でないことを確認してください(例:`flow.paywalls[0]`)。 ::: #### エラーの処理 \{#handle-errors\} | エラー | 説明 | 推奨対応 | |-----------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | ペイウォールにウェブ購入 URL が設定されていません | Adapty ダッシュボードでペイウォールが正しく設定されているか確認してください | | AdaptyError.productWithoutPurchaseUrl | プロダクトにウェブ購入 URL がありません | Adapty ダッシュボードでプロダクトの設定を確認してください | | AdaptyError.failedOpeningWebPaywallUrl | ブラウザで URL を開けませんでした | デバイスの設定を確認するか、別の購入方法を提供してください | | AdaptyError.failedDecodingWebPaywallUrl | URL のパラメーターを正しくエンコードできませんでした | URL パラメーターが有効かつ正しい形式であることを確認してください | ## ウェブペイウォールをアプリ内ブラウザで開く \{#open-web-paywalls-in-an-in-app-browser\} :::important アプリ内ブラウザでのウェブペイウォールの表示は、Adapty SDK v3.15 以降でサポートされています。 ::: デフォルトでは、ウェブペイウォールは外部ブラウザで開かれます。 シームレスなユーザー体験を提供するために、ウェブペイウォールをアプリ内ブラウザで開くことができます。これにより、ウェブ購入ページがアプリ内に表示され、ユーザーはアプリを切り替えることなく取引を完了できます。 これを有効にするには、`in` パラメータを `.inAppBrowser` に設定します。 ```dart showLineNumbers try { await Adapty().openWebPaywall( product: , openIn: AdaptyWebPresentation.inAppBrowser, ); // The web paywall will be opened in the in-app browser } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle other errors } ``` --- # File: flutter-troubleshoot-paywall-builder --- --- title: "Flutter SDKでのペイウォールビルダーのトラブルシューティング" description: "Flutter SDKでのペイウォールビルダーのトラブルシューティング" --- このガイドでは、Flutter SDK で Adapty ペイウォールビルダーを使用して作成したペイウォールを利用する際によくある問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: `createPaywallView` メソッドがペイウォール設定の取得に失敗する。 **原因**: ペイウォールビルダーでデバイス表示が有効になっていない。 **解決策**: ペイウォールビルダーの **Show on device** トグルを有効にしてください。 ## ペイウォールのビュー数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールのビュー数が想定の2倍になっている。 **原因**: ペイウォールビルダーまたはフローのビルダーを使用している場合に `logShowFlow`(Flutter SDK v4以降)/ `logShowPaywall` を呼び出すと、ビュー数が重複してしまいます。これらのツールで構築したフローやペイウォールでは、アナリティクスが自動的に計測されるため、このメソッドを呼び出す必要はありません。 **解決策**: ペイウォールビルダーまたはフローのビルダーを使用している場合は、コード内で `logShowFlow`(Flutter SDK v4以降)/ `logShowPaywall` を呼び出していないことを確認してください。 ## その他の問題 \{#other-issues\} **問題**: 上記では取り上げていないペイウォールビルダー関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](flutter-sdk-migration-guides)を参照し、SDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: flutter-present-flows-in-observer-mode --- --- title: "FlutterのSDKでObserverモードのフローを表示する" description: "FlutterアプリでObserverモードのフローとペイウォールビルダーのペイウォールを表示しながら、独自のコードで購入処理を行います。" --- ビルダーを使ってフローやペイウォールをカスタマイズした場合、モバイルアプリのコード内でそれをレンダリングしてユーザーに表示する方法を気にする必要はありません。そのようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このセクションは[オブザーバーモード](observer-vs-full-mode)専用の説明です。オブザーバーモードで作業していない場合は、[フローとペイウォールの表示](flutter-present-paywalls)のトピックを参照してください。 ::: :::info この機能を利用するには Adapty Flutter SDK 4.0 以降が必要です。以前はネイティブの iOS および Android SDK でのみ利用可能でした。アップグレードするには[移行ガイド](migration-to-flutter-sdk-v4)をご参照ください。 :::
フローの表示を始める前に(クリックして展開) 1. Adapty と [App Store](initial_ios) および [Google Play](initial-android) の初期連携を設定します。 2. Adapty SDK をインストールして設定します。`observerMode` パラメータを `true` に設定してください。詳しくは [Flutter SDK インストールガイド](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk) を参照してください。 3. Adapty ダッシュボードで [プロダクトを作成](create-product) します。 4. [ビルダーでフローまたはペイウォールを設定](create-paywall) し、プロダクトを割り当てます。 5. [プレースメントを作成し、フローまたはペイウォールを割り当てます](create-placement)。 6. モバイルアプリのコードで [フローとその設定を取得します](flutter-get-pb-paywalls)。
オブザーバーモードでは、SDKが代わりに購入処理を行いません。ユーザーがAdaptyのフローやペイウォール上で購入ボタンまたは復元ボタンをタップすると、SDKはあなたの`AdaptyUIObserverModeResolver`を呼び出します。購入や復元の処理は、そこで独自のコードを使って行ってください。 1. `AdaptyUIObserverModeResolver`を実装します: ```dart showLineNumbers title="Flutter" class MyObserverModeResolver extends AdaptyUIObserverModeResolver { @override void observerModeDidInitiatePurchase( AdaptyUIFlowView view, AdaptyPaywallProduct product, void Function() onStartPurchase, void Function() onFinishPurchase, ) { onStartPurchase(); // the view shows its loading indicator // make the purchase with your own code, then: onFinishPurchase(); // the view hides the loading indicator } @override void observerModeDidInitiateRestore( AdaptyUIFlowView view, void Function() onStartRestore, void Function() onFinishRestore, ) { onStartRestore(); // restore purchases with your own code, then: onFinishRestore(); } } ``` `observerModeDidInitiatePurchase` メソッドはユーザーが購入を開始したことを、`observerModeDidInitiateRestore` はユーザーがリストアを開始したことをそれぞれ通知します。これらに応じて、カスタムの購入またはリストアフローを起動してください。 また、購入またはリストアの処理状況を AdaptyUI に通知するために、以下のコールバックを呼び出すことを忘れないでください。これは、ローダーの表示など、フローを正常に動作させるために必要です。 | コールバック | 説明 | | :----------------- | :------------------------------------------------------------------------------- | | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | | onStartRestore() | 復元が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishRestore() | 復元が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | 2. スクリーンを表示する前にリゾルバーを登録してください: ```dart showLineNumbers title="Flutter" AdaptyUI().setObserverModeResolver(MyObserverModeResolver()); ``` 3. 通常どおりフロービューを作成して表示してください: [フローを取得してビューを作成し](flutter-get-pb-paywalls)、その後[表示します](flutter-present-paywalls)。追加のパラメーターは不要です — リゾルバーを登録すれば、Adapty がレンダリングするすべてのフローおよびペイウォールの購入・復元がそこを通じて処理されます。 :::warning [トランザクションを報告してペイウォールと関連付ける](report-transactions-observer-mode-flutter)ことを忘れないでください。これを行わないと、Adaptyはトランザクションを認識できず、購入元のペイウォールを特定できません。 ::: --- # File: flutter-quickstart-manual --- --- title: "Flutter SDKのカスタムペイウォールで購入を有効にする" description: "Adapty SDKをFlutterのカスタムペイウォールに統合して、アプリ内課金を有効にします。" --- このガイドでは、カスタムペイウォールへのAdapty統合方法を説明します。ペイウォールの実装を完全にコントロールしながら、Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を担当します。このガイドはAdapty Flutter SDK v4のAPIを使用しています。v3をお使いの場合は、対応するメソッド名について[マイグレーションガイド](migration-to-flutter-sdk-v4)をご参照ください。 :::important **このガイドは、カスタムペイウォールを実装する開発者向けです。** 最も簡単に購入機能を有効にしたい場合は、[Adapty ペイウォールビルダー](flutter-quickstart-paywalls)をご利用ください。ペイウォールビルダーを使えば、ノーコードのビジュアルエディターでペイウォールを作成でき、購入ロジックはすべて Adapty が自動で処理します。また、アプリを再公開することなく異なるデザインをテストできます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトの設定 \{#set-up-products\} アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセスなど) - [**ペイウォール**](paywalls) – どのプロダクトを提示するかを定義する設定。Adapty ではペイウォールを通じてのみプロダクトを取得できます。この設計により、アプリのコードを変更せずにプロダクト・価格・オファーを更新できます。SDK v4 では、プレースメントのペイウォールのバリアントは **flow** オブジェクトで管理されます。flow を取得してプロダクトを参照します。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所やタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでプレースメントにペイウォールを設定し、コードからプレースメント ID で呼び出します。これにより A/B テストの実施や、ユーザーごとに異なるペイウォールの表示が簡単に行えます。 これらのコンセプトは、カスタムペイウォールを使用する場合でも必ず理解しておいてください。基本的に、これらはアプリで販売するプロダクトを管理するための仕組みです。 カスタムペイウォールを実装するには、**ペイウォール**を作成して**プレースメント**に追加する必要があります。この設定によって、プロダクトを取得できるようになります。ダッシュボードでの操作手順については、[こちら](quickstart)のクイックスタートガイドをご覧ください。 ### ユーザーを管理する \{#manage-users\} バックエンド認証の有無に関わらず、どちらの方法でも利用できます。 ただし、Adapty SDK は匿名ユーザーと識別済みユーザーを異なる方法で扱います。詳細を理解し、ユーザーを適切に管理するために、[識別クイックスタートガイド](flutter-quickstart-identify) をご覧ください。 ## ステップ 1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、次の手順を実行します。 1. [プレースメント](placements) ID を `getFlow` メソッドに渡して、`flow` オブジェクトを取得します。 2. `getPaywallProducts` メソッドを使用して、このフローのプロダクト配列を取得します。 ```dart showLineNumbers Future loadPaywall() async { try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); final products = await Adapty().getPaywallProducts(flow: flow); // Use products to build your custom paywall UI } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } } ``` ## ステップ 2. 購入を受け付ける \{#step-2-accept-purchases\} カスタムペイウォールでユーザーがプロダクトをタップしたら、選択したプロダクトを引数として `makePurchase` メソッドを呼び出してください。これにより購入フローが処理され、更新されたプロファイルが返されます。 ```dart showLineNumbers Future purchaseProduct(AdaptyPaywallProduct product) async { try { final purchaseResult = await Adapty().makePurchase(product: product); switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): // Purchase successful, profile updated break; case AdaptyPurchaseResultUserCancelled(): // User canceled the purchase break; case AdaptyPurchaseResultPending(): // Purchase is pending (e.g., user will pay offline with cash) break; } } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } } ``` ## ステップ3. 購入を復元する \{#step-3-restore-purchases\} アプリストアでは、サブスクリプションを提供するすべてのアプリに、ユーザーが購入を復元できる手段を設けることを義務付けています。 ユーザーが復元ボタンをタップしたときに `restorePurchases` メソッドを呼び出してください。これにより購入履歴が Adapty と同期され、更新されたプロファイルが返されます。 ```dart showLineNumbers Future restorePurchases() async { try { final profile = await Adapty().restorePurchases(); // Restore successful, profile updated } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } } ``` ## ステップ 4. サブスクリプションのステータスを確認する \{#step-4-check-the-subscription-status\} 購入やリストアの後、[アクセスレベル](access-level)を確認して、ペイウォールを表示するか有料機能を解放するかを決定します。`makePurchase` メソッドと `restorePurchases` メソッドはすでに更新されたプロファイルを返しますが、アプリの他の場所で現在のステータスが必要な場合は、`getProfile` メソッドを使用してください。 ```dart showLineNumbers Future hasPremiumAccess() async { try { final profile = await Adapty().getProfile(); return profile.accessLevels['premium']?.isActive ?? false; } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } return false; } ``` サブスクリプションステータスの確認方法やリアルタイム更新のリスニングなど、詳細については[サブスクリプションステータスの確認](flutter-check-subscription-status)をご覧ください。 ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備ができました。[App Store サンドボックス](test-purchases-in-sandbox)または [Google Play Store](testing-on-android) でテスト購入を行い、ペイウォールからテスト購入を完了できることを確認してください。本番環境に近い実装例を確認したい場合は、サンプルアプリの [PurchasesObserver](https://github.com/adaptyteam/AdaptySDK-Flutter/blob/master/example/lib/purchase_observer.dart) をご覧ください。エラーハンドリング、UI オブザーバー、包括的な SDK インテグレーションを含む購入処理の実装例が確認できます。 --- # File: fetch-paywalls-and-products-flutter --- --- title: "Flutter SDK のリモートコンフィグペイウォールでペイウォールとプロダクトを取得する" description: "Adapty Flutter SDK でペイウォールとプロダクトを取得し、ユーザーの収益化を強化します。" --- リモートコンフィグとカスタムペイウォールを表示する前に、それらに関する情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。フローおよびペイウォールビルダーでカスタマイズされたペイウォールの取得については、[フローとペイウォールを取得する](flutter-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでペイウォールとプロダクトの取得を開始する前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. [ペイウォールを作成し、プロダクトをペイウォールに組み込む](create-paywall)(Adapty ダッシュボード) 3. [プレースメントを作成し、ペイウォールをプレースメントに組み込む](create-placement)(Adapty ダッシュボード) 4. [Adapty SDK をインストールする](sdk-installation-flutter)(モバイルアプリ)
## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)は App Store と Google Play 両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームのプロダクトはペイウォールに統合され、モバイルアプリの特定のプレースメントで表示できるようになります。 プロダクトを表示するには、`getFlow` メソッドを使って[プレースメント](placements)の一つから `AdaptyFlow` を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードすべきIDはプレースメントIDのみです。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。ペイウォールが今日2つのプロダクトを返し、明日3つ返す場合、コードを変更せずにすべてを表示できなければなりません。 ::: ```dart showLineNumbers try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

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

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

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

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

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

なお、このメソッドは内部で複数のリクエストを行う場合があるため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトするケースがまれにあります。

| :::note v4 では、`getFlow` は `locale` パラメーターを受け取りません。カスタムペイウォールの場合、利用可能なすべてのローカライズがフローのリモートコンフィグ(`flow.remoteConfigs`)として返されるので、ユーザーのデバイスまたはアプリ設定に合ったものを選択してください。詳しくは[ローカライズとロケールコード](flutter-localizations-and-locale-codes)をご覧ください。 ::: レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | フローの識別子(`instanceIdentity`、`variationId`)、名前、プレースメント、ペイウォールのバリアント(`paywalls`)、リモートコンフィグ(`remoteConfigs`)を含む `AdaptyFlow` オブジェクト。 | ## プロダクトの取得 \{#fetch-products\} フローを取得したら、それに対応するプロダクトの配列を取得できます。 ```dart showLineNumbers try { final products = await Adapty().getPaywallProducts(flow: flow); // the requested products array } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティが含まれます。 | 独自のペイウォールデザインを実装する際、[`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) オブジェクトの以下のプロパティが必要になることがあります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントをご参照ください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。なお、ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **Price** | ローカライズされた価格を表示するには、`product.price.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づきます。`product.price.amount` を使用すると数値として価格を取得することもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには、`product.price.currencySymbol` を使用します。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.subscription?.localizedPeriod` を使用します。このローカライズはデバイスのロケールに基づきます。サブスクリプション期間をプログラムで取得するには、`product.subscription?.period` を使用します。ここから `unit` 列挙型にアクセスして、長さ(day、week、month、year、または unknown)を取得できます。`numberOfUnits` の値は期間ユニット数を返します。例えば、四半期サブスクリプションの場合、unit プロパティには `AdaptyPeriodUnit.month`、numberOfUnits プロパティには `3` が設定されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかどうかをバッジなどで表示するには、`product.subscription?.offer?.phases` プロパティを確認してください。これはリストで、フリートライアルフェーズと初回価格フェーズの最大2つの割引フェーズを含めることができます。各フェーズオブジェクトには以下の便利なプロパティがあります:
• `paymentMode`:`AdaptyPaymentMode.freeTrial`、`AdaptyPaymentMode.payAsYouGo`、`AdaptyPaymentMode.payUpFront`、`AdaptyPaymentMode.unknown` の値を持つ列挙型です。フリートライアルは `AdaptyPaymentMode.freeTrial` タイプになります。
• `price`:割引価格を数値で表します。フリートライアルの場合は `0` になります。
• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列です。例えば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。
• `subscriptionPeriod`:オファー期間の個別の詳細をこのプロパティで取得することもできます。オファーに対しても前のセクションで説明したのと同じ方法で機能します。
• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間です。 | ## デフォルトオーディエンスフローによるフロー取得の高速化 \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ瞬時に取得されるため、この処理を高速化することを特に気にする必要はありません。ただし、オーディエンスやプレースメントの数が多く、ユーザーのインターネット接続が不安定な場合、フローの取得に予想以上の時間がかかることがあります。そのような状況では、何も表示しないよりも、デフォルトのフローを表示してスムーズなユーザー体験を確保したい場合があるでしょう。 これに対処するために、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けフローを取得します。ただし、推奨されるアプローチは `getFlow` メソッドを使用してフローを取得することであり、詳細は上記の[フロー情報の取得](fetch-paywalls-and-products-flutter#fetch-flow-information)セクションをご覧ください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在(レガシー)バージョンに対応したペイウォールを設計するか、現在(レガシー)バージョンのユーザーがレンダリングされないペイウォールに遭遇することを受け入れるかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを表示することになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを受け入れてフローの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-flutter#fetch-flow-information)で説明した `getFlow` を引き続き使用してください。 ::: ```dart showLineNumbers try { final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); // the requested flow } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

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

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

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

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

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

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

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

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

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

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

|
--- # File: present-remote-config-paywalls-flutter --- --- title: "Flutter SDKでリモートコンフィグでデザインされたペイウォールを表示する" description: "Adapty Flutter SDKでリモートコンフィグペイウォールを表示し、ユーザー体験をパーソナライズする方法を紹介します。" --- リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコード上でレンダリングを実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、ペイウォールのビューをどのように表示するかはあなた次第です。リモートコンフィグ経由で設定されたカスタムペイウォールを表示するために、リモート設定を取得するメソッドを提供しています。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} v4 では、フローに `remoteConfigs` リストが含まれています。設定されたローカライゼーションごとに 1 つのリモートコンフィグが用意されています。ユーザーのロケールに合ったエントリを選択し、必要な値を取り出してください。適切なローカライゼーションの選び方については、[ローカライゼーションとロケールコード](flutter-localizations-and-locale-codes) を参照してください。 ```dart showLineNumbers try { final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); // one entry per configured localization; fall back to the first one final config = flow.remoteConfigs.firstWhereOrNull((c) => c.locale == 'en') ?? flow.remoteConfig; final String? headerText = config?.dictionary?['header_text'] as String?; } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` 必要な値をすべて取得したら、それらをレンダリングして視覚的に魅力的なページに組み立てます。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、デバイスを問わずシームレスで使いやすい体験を提供してください。 :::warning 以下で説明するペイウォール表示イベントを必ず記録してください。これにより、Adapty アナリティクスがファネルや A/B テストの情報を収集できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入を行う際は、ペイウォールのプロダクトを引数として `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実行](flutter-making-purchases)をご覧ください。 また、[フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](flutter-use-fallback-paywalls)をおすすめします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーへ表示され、そのような状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adaptyはペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはお客様が記録する必要があります。ペイウォールがいつ表示されるかを把握しているのはお客様自身だからです。 ペイウォールの表示イベントを記録するには、`.logShowFlow(flow: flow)` を呼び出すだけです。これにより、ファネルやA/B テストのペイウォール指標に反映されます。 :::important [ビルダー](adapty-paywall-builder) で作成したフローやペイウォールを表示している場合は、`.logShowFlow(flow: flow)` を呼び出す必要はありません。 ::: ```dart showLineNumbers try { await Adapty().logShowFlow(flow: flow); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :---------- | :------- |:----------------------------------------------------------------------| | **flow** | 必須 | `AdaptyFlow` オブジェクト。 | リモートコンフィグを使ってペイウォールをカスタマイズした場合は、ユーザーに表示するためのレンダリングをアプリのコードで実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、ペイウォールの見た目をどうするかはすべて自分で決められます。リモートコンフィグを取得するメソッドを用意しているので、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(placementId: "YOUR_PLACEMENT_ID"); final String? headerText = paywall.remoteConfig?.dictionary?['header_text'] as String?; } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` 必要な値をすべて取得したら、次はそれらをレンダリングして視覚的に魅力的なページに組み立てましょう。さまざまなモバイル端末の画面サイズや向きに対応したデザインにすることで、どのデバイスでもシームレスで使いやすい体験を提供できます。 :::warning 以下で説明するペイウォール表示イベントを必ず記録してください。これにより、Adapty アナリティクスがファネルおよび A/B テスト用の情報を収集できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入を行う際は、ペイウォールのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実装](flutter-making-purchases)を参照してください。 また、[フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](flutter-use-fallback-paywalls)もお勧めします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーに表示され、こうした状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス計測をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見たタイミングをあなた自身しか把握できないため、手動での記録が必要です。 ペイウォールの表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。これによりファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder) で作成したペイウォールを表示している場合、`.logShowPaywall(paywall)` の呼び出しは不要です。 ::: ```dart showLineNumbers try { final result = await Adapty().logShowPaywall(paywall: paywall); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :---------- | :------- |:----------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) オブジェクト。 | --- # File: flutter-making-purchases --- --- title: "Flutter 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)を使用していますか?** 購入は自動的に処理されるため、この手順はスキップできます。 **ステップバイステップのガイドをお探しですか?** フルコンテキストでのエンドツーエンドの実装手順については、[クイックスタートガイド](flutter-implement-paywalls-manually)をご確認ください。 ::: ```dart showLineNumbers try { final purchaseResult = await Adapty().makePurchase(product: product); switch (purchaseResult) { case AdaptyPurchaseResultSuccess(profile: final profile): if (profile.accessLevels['premium']?.isActive ?? false) { // Grant access to the paid features } break; case AdaptyPurchaseResultPending(): break; case AdaptyPurchaseResultUserCancelled(): break; default: break; } } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywallProduct-class.html) オブジェクト。 | レスポンスパラメーター: | パラメータ | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

リクエストが成功した場合、レスポンスにはこのオブジェクトが含まれます。[AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) オブジェクトは、アプリ内のユーザーのアクセスレベル、サブスクリプション、および買い切り購入に関する包括的な情報を提供します。

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

| :::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 により非推奨とされています。 ::: ## 購入時にサブスクリプションを変更する \{#change-subscription-when-making-a-purchase\} ユーザーが現在のサブスクリプションを更新するのではなく、新しいサブスクリプションを選択した場合の動作は、アプリストアによって異なります。 - App Store の場合、サブスクリプションはサブスクリプショングループ内で自動的に更新されます。ユーザーがすでに別のグループのサブスクリプションを持っている状態で、あるグループのサブスクリプションを購入した場合、両方のサブスクリプションが同時にアクティブになります。 - Google Play の場合、サブスクリプションは自動的に更新されません。以下で説明するように、モバイルアプリのコードで切り替えを管理する必要があります。 Androidでサブスクリプションを別のものに切り替えるには、追加パラメータを指定して `.makePurchase()` メソッドを呼び出します。 ```dart showLineNumbers try { final subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( 'OLD_PRODUCT_ID', AdaptyAndroidSubscriptionUpdateReplacementMode.immediateWithTimeProration, ); final result = await Adapty().makePurchase( product: product, parameters: AdaptyPurchaseParameters( subscriptionUpdateParams: subscriptionUpdateParams, ), ); // successful cross-grade } on AdaptyError catch (adaptyError) { // Handle the error } catch (e) { // Handle the error } ``` 追加のリクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :--------------------------- | :------- |:--------------------------------------------------------------------------------------------------------| | **parameters** | required | `subscriptionUpdateParams` フィールドに [`AdaptyAndroidSubscriptionUpdateParameters`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyAndroidSubscriptionUpdateParameters-class.html) オブジェクトを設定した `AdaptyPurchaseParameters` オブジェクト。 | Googleデベロッパードキュメントで、サブスクリプションと置き換えモードについて詳しく確認できます: - [置き換えモードについて](https://developer.android.com/google/play/billing/subscriptions#replacement-modes) - [置き換えモードに関するGoogleの推奨事項](https://developer.android.com/google/play/billing/subscriptions#replacement-recommendations) - 置き換えモード [`CHARGE_PRORATED_PRICE`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#CHARGE_PRORATED_PRICE())。注意: このメソッドはサブスクリプションのアップグレードにのみ使用できます。ダウングレードはサポートされていません。 - 置き換えモード [`DEFERRED`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode#DEFERRED())。注意: 実際のサブスクリプション変更は、現在のサブスクリプションの請求期間が終了したときにのみ行われます。 ## iOS でオファーコードを使用する \{#redeem-offer-codes-in-ios\}
オファーコードについて オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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\} :::warning Appleは2026年3月にアプリ内課金向けのプロモコードを廃止しました。オファーコードはより多くの機能(適格性の設定、有効期限、四半期あたり最大100万コード)を備えた後継機能です。アプリ内課金にプロモコードを使用していた場合は、App Store Connectでオファーコードに移行してください。 ::: レガシープロモコード(アプリのバージョンごとに最大100件)は、サブスクリプションへの無料アクセスを付与していました。オファーコードとは異なり、Appleはプロモコードのトランザクションに割引情報を含めず、レシートには通常価格が記載されていました。そのため、Adaptyはこれらのトランザクションを通常価格で記録し、Adaptyアナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。
アプリ内でコード引き換えシートを表示するには: ```dart showLineNumbers try { await Adapty().presentCodeRedemptionSheet(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` :::danger 弊社の観測によると、一部のアプリではオファーコード引き換えシートが正常に動作しない場合があります。ユーザーを直接 App Store にリダイレクトすることをおすすめします。 これを行うには、次の形式のURLを開く必要があります: `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: ### プリペイドプランの管理(Android) \{#manage-prepaid-plans-android\} アプリのユーザーが[プリペイドプラン](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans)(例:数ヶ月分の非更新型サブスクリプションを一括購入)を利用できる場合、プリペイドプランの[保留中のトランザクション](https://developer.android.com/google/play/billing/subscriptions#pending)を有効にすることができます。 ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withGoogleEnablePendingPrepaidPlans(true), ); ``` --- # File: flutter-restore-purchase --- --- title: "Flutter SDKでモバイルアプリの購入を復元する" description: "Adaptゆのアプリ内課金復元方法を学び、シームレスなユーザーエクスペリエンスを確保しましょう。" --- 復元購入は iOS と Android の両方でサポートされている機能で、サブスクリプションやアプリ内課金など、以前に購入したコンテンツへのアクセスを再度課金されることなく取り戻すことができます。この機能は、アプリをアンインストールして再インストールしたユーザーや、新しいデバイスに乗り換えたユーザーが、再度支払うことなく以前に購入したコンテンツにアクセスしたい場合に特に便利です。 :::note [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールでは、追加のコードなしに購入が自動的に復元されます。該当する場合は、このステップをスキップしてください。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしていない場合、購入を復元するには `.restorePurchases()` メソッドを呼び出します。 ```dart showLineNumbers try { final profile = await Adapty().restorePurchases(); if (profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive ?? false) { // successful access restore } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` レスポンスパラメーター: | パラメータ | 説明 | |---------|-----------| | **Profile** |

[`AdaptyProfile`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) オブジェクト。このモデルには、アクセスレベル、サブスクリプション、非サブスクリプション購入に関する情報が含まれています。

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

| :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: implement-observer-mode-flutter --- --- title: "Flutter SDKにObserverモードを実装する" description: "Flutter SDKでAdaptyのオブザーバーモードを実装して、ユーザーのサブスクリプションイベントを追跡する方法を説明します。" --- すでに独自の購入インフラを持っており、Adapty への完全移行をすぐには行えない場合は、[オブザーバーモード](observer-vs-full-mode)を検討してください。基本的な使い方として、オブザーバーモードは高度なアナリティクスや、アトリビューション・アナリティクスシステムとのシームレスな連携を提供します。 これがニーズに合っている場合は、以下の手順に従ってください: 1. Adapty SDK を設定する際に `observerMode` パラメータを `true` に設定してオンにします。[Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk) のセットアップ手順に従ってください。 2. 既存の購入インフラから Adapty へ[トランザクションを報告](report-transactions-observer-mode-flutter)します。 ## オブザーバーモードの設定 \{#observer-mode-setup\} 購入処理やサブスクリプションのステータス管理を自前で行い、サブスクリプションイベントの送信とアナリティクスにのみ Adapty を使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作する場合、Adapty SDK はトランザクションをクローズしません。トランザクションの処理は必ずご自身で行ってください。 ::: ```dart showLineNumbers title="main.dart" await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') ..withObserverMode(true) // Enable observer mode ..withLogLevel(AdaptyLogLevel.verbose), ); ``` パラメーター: | パラメータ | 説明 | | --------------------------- | ------------------------------------------------------------ | | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御するboolean値。デフォルト値は`false`です。 | ## Observer ModeでAdaptyのペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} ペイウォールやA/Bテスト機能も利用したい場合は、Observerモードで追加の設定が必要です。上記の手順に加えて、以下の対応が必要です。 1. [リモートコンフィグペイウォール](present-remote-config-paywalls-flutter)の場合は、通常どおりペイウォールを表示します。 3. 購入トランザクションに[ペイウォールを紐付ける](report-transactions-observer-mode-flutter)。 :::tip SDK v4では、ObserverモードでAdaptyがレンダリングするフローやペイウォールを表示することもできます。ユーザーが対応するボタンをタップしたときに、独自のコードで購入または復元を行うために`AdaptyUIObserverModeResolver`を登録してください。詳しくは[Observerモードでのフローの表示](flutter-present-flows-in-observer-mode)をご覧ください。 ::: --- # File: report-transactions-observer-mode-flutter --- --- title: "Flutter SDKでオブザーバーモードのトランザクションを報告する" description: "Adaptyオブザーバーモードで購入トランザクションを報告し、ユーザーインサイトと収益トラッキングをFlutter SDKで行います。" --- Observer モードでは、Adapty SDK は既存の購入システムを通じて行われた購入を単独で追跡することができません。アプリストアからのトランザクションをご自身で報告する必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前**にこの設定を必ず行ってください。 Adapty がトランザクションを認識できるよう、`reportTransaction` を使用して各トランザクションを明示的に報告してください。 :::warning **トランザクションのレポートをスキップしないでください!** `reportTransaction` を呼び出さないと、Adapty はトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adapty のペイウォールを使用している場合は、トランザクションをレポートする際に `variationId` を含めてください。これにより、購入がトリガーされたペイウォールに紐付けられ、正確なペイウォール分析が保証されます。 ```dart showLineNumbers try { // every time when calling transaction.finish() await Adapty().reportTransaction( "YOUR_TRANSACTION_ID", variationId: "PAYWALL_VARIATION_ID", // optional ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | 必須 |
  • iOS の場合: トランザクションの識別子。
  • Android の場合: 購入の文字列識別子 `purchase.getOrderId`。ここで、purchase は billing ライブラリの [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。
| | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) オブジェクトの `variationId` プロパティを使用して取得できます。 |
オブザーバーモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡することができません。アプリストアのトランザクションを報告するか、復元する必要があります。アナリティクスのエラーを避けるために、アプリをリリースする**前**にこの設定を完了することが重要です。 両方のプラットフォームで `reportTransaction` を使用して各トランザクションを明示的に報告し、AndroidではAdaptyがそれを認識できるよう追加の手順として `restorePurchases` を使用してください。 :::warning **トランザクションの報告と購入のリストアを省略しないでください!** これらのメソッドを呼び出さないと、Adapty はトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adapty のペイウォールを使用している場合は、トランザクションを報告する際に `variationId` を含めてください。これにより、購入がそのペイウォールと紐付けられ、ペイウォールのアナリティクスが正確に記録されます。 ```dart showLineNumbers // every time when calling transaction.finish() if (Platform.isAndroid) { try { await Adapty().restorePurchases(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } } try { // every time when calling transaction.finish() await Adapty().reportTransaction( "YOUR_TRANSACTION_ID", variationId: "PAYWALL_VARIATION_ID", // optional ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | -------- | ------------------------------------------------------------ | | transactionId | 必須 |
  • iOS、StoreKit 1 の場合:[SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction) オブジェクト。
  • iOS、StoreKit 2 の場合:[Transaction](https://developer.apple.com/documentation/storekit/transaction) オブジェクト。
  • Android の場合:String 識別子(purchase は billing library の [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスで、その purchase.getOrderId)。
| | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) オブジェクトの `variationId` プロパティから取得できます。 |
**トランザクションのレポート** - バージョン3.1.x以前は、App Storeのトランザクションを自動的に検知するため、手動でのレポートは不要です。 - バージョン3.2はオブザーバーモードをサポートしていません。 **トランザクションのレポート** `restorePurchases`を使って、[モバイルコードでの購入のリストア](flutter-restore-purchase)ページで説明しているように、Observer ModeでAdaptyにトランザクションを報告してください。 :::warning **トランザクションの報告を省略しないでください!** `restorePurchases`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: **ペイウォールとトランザクションの紐付け** Adapty SDKは購入のソースを判別できません。これはあなた自身が処理を行っているためです。そのため、オブザーバーモードでペイウォールやA/Bテストを使用する場合は、アプリストアからのトランザクションをモバイルアプリのコード内で対応するペイウォールに紐付ける必要があります。これはアプリをリリースする前に正しく設定しておくことが重要で、設定を誤るとアナリティクスにエラーが生じます。 ```dart final transactionId = transaction.transactionIdentifier final variationId = paywall.variationId try { await Adapty().setVariationId('transactionId', variationId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ```
--- # File: flutter-troubleshoot-purchases --- --- title: "Flutter SDKでの購入のトラブルシューティング" description: "Flutter SDKでの購入のトラブルシューティング" --- このガイドでは、Flutter SDKで手動購入を実装する際によく発生する問題の解決方法を説明します。 ## makePurchaseは正常に呼び出されたが、プロファイルが更新されない \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **問題**: `makePurchase` メソッドが正常に完了したにもかかわらず、ユーザーのプロファイルとサブスクリプションのステータスがAdaptyで更新されません。 **原因**: これは通常、Google Play ストアのセットアップが不完全またはコンフィグレーションに問題があることを示しています。 **解決策**: [Google Playのセットアップ手順](initial-android)をすべて完了していることを確認してください。 ## makePurchaseが2回呼び出される \{#makepurchase-is-invoked-twice\} **問題**: 同じ購入に対して `makePurchase` メソッドが複数回呼び出されています。 **原因**: これは通常、UIの状態管理の問題やユーザーの素早い操作によって購入フローが複数回トリガーされたときに発生します。 **解決策**: [Google Playのセットアップ手順](initial-android)をすべて完了していることを確認してください。 ## オブザーバーモードでのAdaptyError.cantMakePayments \{#adaptyerrorcantmakepayments-in-observer-mode\} **問題**: オブザーバーモードで `makePurchase` を使用すると `AdaptyError.cantMakePayments` が発生します。 **原因**: オブザーバーモードでは、Adaptyの `makePurchase` メソッドを使用するのではなく、購入処理をご自身で行う必要があります。 **解決策**: 購入に `makePurchase` を使用している場合は、オブザーバーモードをオフにしてください。`makePurchase` を使用するか、オブザーバーモードで購入を自分で処理するか、どちらか一方を選ぶ必要があります。詳細については、[オブザーバーモードの実装](implement-observer-mode-flutter)を参照してください。 ## Adaptyエラー: (code: 103, message: Play Market request failed on purchases updated: responseCode=3, debugMessage=Billing Unavailable, detail: null) \{#adapty-error-code-103-message-play-market-request-failed-on-purchases-updated-responsecode3-debugmessagebilling-unavailable-detail-null\} **問題**: Google Play ストアからbilling unavailableエラーが返されています。 **原因**: このエラーはAdaptyとは無関係です。デバイスで課金が利用できないことを示すGoogle Play課金ライブラリのエラーです。 **解決策**: このエラーはAdaptyとは無関係です。Play Storeのドキュメントで詳細を確認できます: [Handle BillingResult response codes](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers。 ## makePurchasesCompletionHandlersが見つからない \{#not-found-makepurchasescompletionhandlers\} **問題**: `makePurchasesCompletionHandlers` が見つからないという問題が発生しています。 **原因**: これは通常、サンドボックステストの問題に関連しています。 **解決策**: 新しいサンドボックスユーザーを作成して再試行してください。サンドボックス関連の購入完了ハンドラーの問題はこれで解決することが多いです。 ## その他の問題 \{#other-issues\} **問題**: 上記で説明していないその他の購入関連の問題が発生しています。 **解決策**: 必要に応じて、[移行ガイド](flutter-sdk-migration-guides)を使用してSDKを最新バージョンに移行してください。新しいSDKバージョンでは多くの問題が解決されています。 --- # File: flutter-identifying-users --- --- title: "Flutter SDK でユーザーを識別する" description: "Adapty でユーザーを識別して、パーソナライズされたサブスクリプション体験を向上させましょう。" --- Adapty はすべてのユーザーに対して内部プロファイル ID を作成します。ただし、独自の認証システムがある場合は、独自の Customer User ID を設定する必要があります。[Profiles](profiles-crm) セクションで Customer User ID によってユーザーを検索でき、また[サーバーサイド API](getting-started-with-server-side-api) でも使用でき、すべてのインテグレーションに送信されます。 ### 設定時に Customer User ID を設定する \{#setting-customer-user-id-on-configuration\} 設定時にユーザー ID がある場合は、`.activate()` メソッドの `customerUserId` パラメータとして渡すだけです: ```dart showLineNumbers title="Dart" try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID) ); } catch (e) { // handle the error } ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 設定後に Customer User ID を設定する \{#setting-customer-user-id-after-configuration\} SDK の設定時にユーザー ID がない場合は、`.identify()` メソッドを使っていつでも後から設定できます。このメソッドが最もよく使われるケースは、登録または認証後に匿名ユーザーから認証済みユーザーに切り替わるときです。 ```dart showLineNumbers try { await Adapty().identify(customerUserId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` リクエストパラメータ: - **Customer User ID**(必須):文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信 ユーザーが再度ログインするなど、一部のケースでは Adapty のサーバーにはすでにそのユーザーの情報があります。このような場合、Adapty SDK は自動的に新しいユーザーとして動作するよう切り替わります。カスタム属性やサードパーティネットワークからのアトリビューションなど、匿名ユーザーに渡したデータがある場合は、識別されたユーザーに対してそのデータを再送信する必要があります。 また、新しいユーザーのデータが異なる可能性があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得する必要があることにも注意してください。 ::: ### ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()` メソッドを呼び出すことで、いつでもユーザーをログアウトできます: ```dart showLineNumbers try { await Adapty().logout(); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` その後、`.identify()` メソッドを使ってユーザーをログインできます。 ## `appAccountToken` を設定する(iOS) \{#assign-appaccounttoken-ios\} [`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` と一緒に渡す必要があります。 トークンのみを渡した場合、トランザクションに含まれません。 ::: ```dart showLineNumbers // During configuration: try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID, iosAppAccountToken: "YOUR_APP_ACCOUNT_TOKEN") ); } catch (e) { // handle the error } // Or when identifying users try { await Adapty().identify(customerUserId, iosAppAccountToken: "YOUR_APP_ACCOUNT_TOKEN"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### 難読化されたアカウント ID を設定する(Android) \{#set-obfuscated-account-ids-android\} Google Play では、ユーザーのプライバシーとセキュリティを強化するために、特定のユースケースで難読化されたアカウント ID が必要です。これらの ID により、Google Play はユーザー情報を匿名に保ちながら購入を識別できます。これは不正防止や分析において特に重要です。 アプリが機密性の高いユーザーデータを扱う場合、または特定のプライバシー規制に準拠する必要がある場合は、これらの ID を設定する必要があるかもしれません。難読化された ID により、Google Play は実際のユーザー識別子を公開せずに購入を追跡できます。 ```dart showLineNumbers // During configuration: try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') ..withCustomerUserId(YOUR_CUSTOMER_USER_ID, androidObfuscatedAccountId: "OBFUSCATED_ACCOUNT_ID") ); } catch (e) { // handle the error } // Or when identifying users try { await Adapty().identify(customerUserId, androidObfuscatedAccountId: "OBFUSCATED_ACCOUNT_ID"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ## デバイスをまたいでユーザーを識別する \{#detect-users-across-devices\} 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: flutter-setting-user-attributes --- --- title: "Flutter SDKでユーザー属性を設定する" description: "Adaptyでユーザー属性を設定し、より正確なオーディエンスセグメンテーションを実現する方法を学びましょう。" --- メールアドレスや電話番号などのオプション属性をアプリのユーザーに設定できます。設定した属性は、ユーザー[セグメント](segments)の作成やCRMでの閲覧に活用できます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します: ```dart showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setEmail("email@email.com") ..setPhoneNumber("+18888888888") ..setFirstName('John') ..setLastName('Appleseed') ..setGender(AdaptyProfileGender.other) ..setBirthday(DateTime(1970, 1, 3)); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` `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\} カスタム属性を独自に設定できます。通常はアプリの使用状況に関連するもので、たとえばフィットネスアプリなら週あたりのエクササイズ回数、語学学習アプリならユーザーの習熟度レベルなどが該当します。カスタム属性はセグメントで活用してターゲットを絞ったペイウォールやオファーを作成したり、アナリティクスでどのプロダクト指標が収益に最も影響するかを分析したりするのに役立ちます。 ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..setCustomStringAttribute('value1', 'key1') ..setCustomDoubleAttribute(1.0, 'key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` 既存のキーを削除するには、`.withRemoved(customAttributeForKey:)` メソッドを使用してください: ```dart showLineNumbers try { final builder = AdaptyProfileParametersBuilder() ..removeCustomAttribute('key1') ..removeCustomAttribute('key2'); await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` すでに設定されているカスタム属性を確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning `customAttributes` の値は最新でない可能性があることに注意してください。ユーザー属性はいつでも異なるデバイスから送信されるため、最後の同期以降にサーバー上の属性が変更されている場合があります。 ::: ### 制限事項 \{#limits\} - ユーザーあたり最大30件のカスタム属性 - キー名は最大30文字。キー名には英数字と次の文字を使用できます: `_` `-` `.` - 値は50文字以内の文字列または浮動小数点数。 --- # File: flutter-listen-subscription-changes --- --- title: "Flutter SDKでサブスクリプションステータスを確認する" description: "Adaptyでユーザーのサブスクリプションステータスをトラッキングおよび管理し、Flutterアプリのカスタマーリテンションを向上させましょう。" --- Adaptyを使えば、サブスクリプションのステータス管理が簡単になります。コードにプロダクトIDを手動で埋め込む必要はありません。アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプション状態を手軽に把握できます。
サブスクリプションステータスを確認する前に(クリックして展開) - iOSの場合、[App Store Server Notifications](enable-app-store-server-notifications)を設定してください - Androidの場合、[リアルタイム デベロッパー通知(RTDN)](enable-real-time-developer-notifications-rtdn)を設定してください
## アクセスレベルとAdaptyProfileオブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは[AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html)オブジェクトのプロパティです。アプリ起動時(例えば[ユーザーを識別する](flutter-identifying-users#setting-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更があるたびに更新することをお勧めします。こうすることで、プロファイルオブジェクトを繰り返しリクエストすることなく利用できます。 プロファイルの更新通知を受け取るには、以下の[プロファイルの更新(アクセスレベルを含む)をリッスンする](flutter-listen-subscription-changes)セクションで説明されているように、プロファイルの変更をリッスンしてください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()` メソッドを使用してください: ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` レスポンスのパラメーター: | パラメーター | 説明 | | --------- | ------------------------------------------------------------ | | Profile |

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

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

| `.getProfile()` メソッドを使用すると、アクセスレベルのステータスを取得できるユーザープロファイルを取得できます。アプリごとに複数のアクセスレベルを設定することも可能です。例えば、ニュースアプリで異なるトピックのサブスクリプションを独立して販売する場合、"sports" や "science" といったアクセスレベルを作成できます。ただし、ほとんどの場合はアクセスレベルが1つあれば十分なので、デフォルトの "premium" アクセスレベルをそのまま使えます。 デフォルトの "premium" アクセスレベルを確認する例を以下に示します: ```dart showLineNumbers try { final profile = await Adapty().getProfile(); if (profile?.accessLevels['premium']?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` ### サブスクリプションステータス更新のリッスン \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adaptyはイベントを発火します。 Adaptyからメッセージを受け取るには、追加の設定が必要です。 ```dart showLineNumbers Adapty().didUpdateProfileStream.listen((profile) { // handle any changes to subscription state }); ``` Adaptyはアプリ起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDK に実装されたキャッシュは、プロファイルのサブスクリプションステータスを保存します。つまり、サーバーが利用できない場合でも、キャッシュされたデータにアクセスしてプロファイルのサブスクリプションステータスに関する情報を取得できます。 ただし、キャッシュへの直接データリクエストはできません。SDKは1分ごとに定期的にサーバーへ問い合わせを行い、プロファイルに関する更新や変更がないかを確認します。新しいトランザクションやその他の更新など変更があった場合は、キャッシュデータに反映され、サーバーとの同期が維持されます。 --- # File: flutter-deal-with-att --- --- title: "Flutter SDK での ATT の処理" description: "Flutter で Adapty を使い始めて、サブスクリプションの設定と管理を効率化しましょう。" --- アプリが AppTrackingTransparency フレームワークを使用しており、ユーザーにアプリのトラッキング認可リクエストを表示する場合は、[認可ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/)を Adapty に送信する必要があります。 ```dart showLineNumbers final builder = AdaptyProfileParametersBuilder() ..setAppTrackingTransparencyStatus(AdaptyIOSAppTrackingTransparencyStatus.authorized); try { await Adapty().updateProfile(builder.build()); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle unknown error } ``` :::warning この値は変更されたときにできるだけ早く送信することを強くおすすめします。そうすることで、設定済みのインテグレーションにデータがタイムリーに送信されます。 ::: --- # File: kids-mode-flutter --- --- title: "Flutter SDKのキッズモード" description: "AppleとGoogleのポリシーに準拠するためにキッズモードを簡単に有効化。Flutter SDKではIDFA、GAID、広告データを収集しません。" --- Flutterアプリが子ども向けの場合、[Apple](https://developer.apple.com/kids/)および[Google](https://support.google.com/googleplay/android-developer/answer/9893335)のポリシーに従う必要があります。Adapty SDKを使用している場合、いくつかの簡単な手順でこれらのポリシーに準拠するよう設定し、アプリストアの審査を通過できます。 ## 何が必要ですか? \{#whats-required\} 以下の情報収集を無効にするよう、Adapty SDK を設定する必要があります。 - [IDFA(広告識別子)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers)(iOS) - [Android 広告 ID(AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248)(Android) - [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(iOS)、GAID/AAID(Android)、および IP アドレスの収集を無効にしてください。 **Android: SDK の設定を更新する** ```dart showLineNumbers title="Dart" try { await Adapty().activate( configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') // highlight-start ..withGoogleAdvertisingIdCollectionDisabled(true) // set to `true` ..withIpAddressCollectionDisabled(true), // set to `true` // highlight-end ); } catch (e) { // handle the error } ``` **iOS: SDK v4 でキッズモードを有効にする** :::important SDK v4 では、ネイティブ iOS SDK は Swift Package Manager からインストールされ、キッズモードは `KidsMode` Swift パッケージトレイトを通じて有効化されます。このトレイトにより、IDFA、AdSupport、AppTrackingTransparency に関するコードがすべてコンパイルから除外されます。これには **Xcode 26** 以降が必要です。 ::: SDK v4 では、`pubspec.yaml` で `adapty_flutter` の代わりに `adapty_flutter_kids` パッケージを使用してください。これはプラグインのキッズモード版であり、公開 API もバージョンも同じです。唯一の違いは、ネイティブ iOS SDK が `KidsMode` トレイトでビルドされている点です: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter_kids: 4.0.0 ``` Dart のコードはそのままで、インポートを新しいパッケージ名に更新するだけです: ```dart showLineNumbers title="Dart" ``` **iOS: CocoaPods を使用してキッズモードを有効にする(SDK v3)** 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: flutter-get-onboardings --- --- title: "Flutter SDK でオンボーディングを取得する" description: "Adapty の Flutter でオンボーディングを取得する方法を学びます。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や機能改善は行われません。代わりに[フロー](flutter-get-pb-paywalls)を使用してください。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存がないというメリットがあります。はじめるには[フローとペイウォールの取得](flutter-get-pb-paywalls)および[フローとペイウォールの表示](flutter-present-paywalls)を参照してください。 ::: Adapty ダッシュボードのビルダーで[オンボーディングのビジュアルデザインを作成した](design-onboarding)後、Flutter アプリに表示できます。この処理の最初のステップは、以下に説明するように、プレースメントに関連付けられたオンボーディングとそのビュー設定を取得することです。 始める前に、以下を確認してください。 1. [Adapty Flutter SDK](sdk-installation-flutter) バージョン 3.8.0 以上をインストールしていること。 2. [オンボーディングを作成](create-onboarding)していること。 3. オンボーディングを[プレースメント](placements)に追加していること。 ## オンボーディングの取得 \{#fetch-onboarding\} [オンボーディング](onboardings)をノーコードビルダーで作成すると、アプリが取得・表示する必要のあるコンテナとして保存されます。このコンテナはエクスペリエンス全体を管理します。表示されるコンテンツ、その見せ方、クイズの回答やフォーム入力などのユーザー操作の処理方法がすべてここで制御されます。また、コンテナは分析イベントを自動的に追跡するため、別途ビュートラッキングを実装する必要はありません。 パフォーマンスを最大化するために、ユーザーに表示する前に画像のダウンロードが完了するよう、オンボーディングの設定はできるだけ早めに取得してください。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```dart showLineNumbers try { final onboarding = await Adapty().getOnboarding(placementId: "YOUR_PLACEMENT_ID"); } on AdaptyError catch (e) { //handle error } catch (e) { //handle error } ``` 次に、`createOnboardingView` メソッドを呼び出して、表示するビューを取得します。 :::warning `createOnboardingView` メソッドの戻り値は一度しか使用できません。再度使用する必要がある場合は、`createOnboardingView` メソッドを新たに呼び出してください。再生成せずに2回呼び出すと、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```dart showLineNumbers try { final onboardingView = await Adapty().createOnboardingView(onboarding: onboarding); } on AdaptyError catch (e) { //handle error } catch (e) { //handle error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値を使用します。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

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

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

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

| レスポンスパラメーター: | パラメータ | 説明 | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | [`AdaptyOnboarding`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyOnboarding-class.html) オブジェクト。オンボーディングの識別子と設定、リモートコンフィグ、およびその他のプロパティを含みます。 | ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ瞬時にフェッチされるため、このプロセスの高速化を気にする必要はありません。ただし、オーディエンスやオンボーディングの数が多く、ユーザーのインターネット接続が遅い場合、オンボーディングのフェッチに想定より時間がかかることがあります。そのような場合は、オンボーディングをまったく表示しないよりも、デフォルトのオンボーディングを表示してスムーズなユーザー体験を確保したいところです。 この問題を解決するには、`getOnboardingForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンス向けのオンボーディングを取得します。ただし、推奨されるアプローチは [オンボーディングの取得](#fetch-onboarding) セクションで説明している `getOnboarding` メソッドでオンボーディングを取得することである点を必ず理解しておいてください。 :::warning `getOnboardingForDefaultAudience` の代わりに `getOnboarding` の使用を検討してください。前者には重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のある設計が必要になるか、古いバージョンが正しく表示されないことを許容しなければなりません。 - **パーソナライズなし**: 「すべてのユーザー」オーディエンス向けのコンテンツのみ表示され、国・アトリビューション・カスタム属性などによるターゲティングは利用できません。 これらのデメリットよりも高速なフェッチが優先される場合は、以下のように `getOnboardingForDefaultAudience` を使用してください。それ以外の場合は、[上記](#fetch-onboarding)で説明している `getOnboarding` を使用してください。 ::: ```dart showLineNumbers try { final onboarding = await Adapty().getOnboardingForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle unknown error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |-----------------|-----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

| --- # File: flutter-present-onboardings --- --- title: "Flutter SDKでオンボーディングを表示する" description: "オンボーディングを効果的に表示してコンバージョンを高める方法を学びましょう。" --- :::warning **オンボーディングは SDK v4 で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに [フロー](flutter-get-pb-paywalls) を使用してください。オンボーディングが WebView 内で動作するのとは異なり、フローはデバイス上でネイティブにレンダリングされるため、スムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、そして WebView ランタイムへの依存がありません。開始するには [フローとペイウォールの取得](flutter-get-pb-paywalls) および [フローとペイウォールの表示](flutter-present-paywalls) を参照してください。 ::: ビルダーを使用してオンボーディングをカスタマイズした場合、Flutterアプリのコードでレンダリングする必要はありません。そのようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [Adapty Flutter SDK](sdk-installation-flutter) 3.8.0以降をインストールしていること。 2. [オンボーディングを作成](create-onboarding)していること。 3. オンボーディングを[プレースメント](placements)に追加していること。 Adapty Flutter SDKには、オンボーディングを表示する方法が2つあります: - **スタンドアロン画面** - **埋め込みウィジェット** ## スタンドアロンスクリーンとして表示する \{#present-as-standalone-screen\} オンボーディングをスタンドアロンスクリーンとして表示するには、`createOnboardingView` メソッドで作成した `onboardingView` に対して `onboardingView.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。オンボーディングを再度表示する必要がある場合は、`createOnboardingView` をもう一度呼び出して新しい `onboardingView` インスタンスを作成してください。 :::warning 同じ `onboardingView` を再作成せずに再利用すると、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```dart showLineNumbers title="Flutter" try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### オンボーディングを閉じる \{#dismiss-the-onboarding\} プログラムでオンボーディングを閉じる必要がある場合は、`dismiss()` メソッドを使用します: ```dart showLineNumbers title="Flutter" try { await onboardingView.dismiss(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### iOS の表示スタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのオンボーディングの表示方法を設定できます。このパラメータには `AdaptyUIIOSPresentationStyle.fullScreen`(デフォルト)または `AdaptyUIIOSPresentationStyle.pageSheet` を指定できます。 ```dart showLineNumbers try { await onboardingView.present(iosPresentationStyle: AdaptyUIIOSPresentationStyle.pageSheet); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ## ウィジェット階層への埋め込み \{#embed-in-widget-hierarchy\} 既存のウィジェットツリーにオンボーディングを埋め込むには、Flutterのウィジェット階層に`AdaptyUIOnboardingPlatformView`ウィジェットを直接使用します。 ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, // The onboarding object you fetched onDidFinishLoading: (meta) { }, onDidFailWithError: (error) { }, onCloseAction: (meta, actionId) { }, onPaywallAction: (meta, actionId) { }, onCustomAction: (meta, actionId) { }, onStateUpdatedAction: (meta, elementId, params) { }, onAnalyticsEvent: (meta, event) { }, ) ``` :::note Android のプラットフォームビューを動作させるには、`MainActivity` が `FlutterFragmentActivity` を継承していることを確認してください: ```kotlin showLineNumbers title="Kotlin" class MainActivity : FlutterFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } } ``` ::: ## オンボーディング中のローダー \{#loader-during-onboarding\} オンボーディングを表示する際、スプラッシュ画面とオンボーディングの間に、基盤となるビューの初期化中に短いローディング画面が表示されることがあります。これはニーズに応じてさまざまな方法で対処できます。 #### onDidFinishLoading を使用したスプラッシュ画面の制御 \{#control-splash-screen-using-ondidfinishloading\} :::note このアプローチは、オンボーディングをウィジェットとして埋め込む場合にのみ使用できます。スタンドアロン画面として表示する場合は使用できません。 ::: 推奨されるクロスプラットフォームのアプローチは、オンボーディングが完全に読み込まれるまでスプラッシュスクリーンやカスタムオーバーレイを表示したままにしておき、その後手動で非表示にすることです。 埋め込みウィジェットを使用する場合は、その上に独自のウィジェットをオーバーレイし、`onDidFinishLoading` が発火したタイミングでオーバーレイを非表示にします: ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, onDidFinishLoading: (meta) { // Hide your custom splash screen or overlay here }, // ... other callbacks ) ``` ### ネイティブローダーをカスタマイズする \{#customize-native-loader\} :::important このアプローチはプラットフォーム固有であり、ネイティブ UI コードのメンテナンスが必要です。アプリで既に別のネイティブレイヤーをメンテナンスしている場合を除き、推奨しません。 ::: デフォルトのローダー自体をカスタマイズしたい場合は、プラットフォーム固有のレイアウトに置き換えることができます。このアプローチでは、Android と iOS それぞれに個別の実装が必要です: - **iOS**: Xcode プロジェクトに `AdaptyOnboardingPlaceholderView.xib` を追加する - **Android**: `res/layout` に `adapty_onboarding_placeholder_view.xml` を作成し、プレースホルダーを定義する ## オンボーディング内リンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディング内リンクの開き方のカスタマイズは、Adapty SDK v3.15.1 以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、ユーザーがアプリを切り替えることなく Web ページを閲覧できるシームレスな体験が提供されます。 外部ブラウザでリンクを開くように変更したい場合は、`externalUrlsPresentation` パラメータを `AdaptyWebPresentation.externalBrowser` に設定することでこの動作をカスタマイズできます。 ```dart showLineNumbers title="Flutter" final onboardingView = await AdaptyUI().createOnboardingView( onboarding: onboarding, externalUrlsPresentation: AdaptyWebPresentation.externalBrowser, // default – AdaptyWebPresentation.inAppBrowser ); try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, externalUrlsPresentation: AdaptyWebPresentation.externalBrowser, // default – AdaptyWebPresentation.inAppBrowser onDidFinishLoading: (meta) { }, onDidFailWithError: (error) { }, onCloseAction: (meta, actionId) { }, onPaywallAction: (meta, actionId) { }, onCustomAction: (meta, actionId) { }, onStateUpdatedAction: (meta, elementId, params) { }, onAnalyticsEvent: (meta, event) { }, ) ``` ## セーフエリアのパディングを無効にする(Android) \{#disable-safe-area-paddings-android\} デフォルトでは、Androidデバイスにおいて、オンボーディングビューはステータスバーやナビゲーションバーなどのシステムUI要素を避けるため、セーフエリアのパディングを自動的に適用します。ただし、この動作を無効にしてレイアウトを完全に制御したい場合は、アプリにboolean型のリソースを追加することで対応できます。 1. `android/app/src/main/res/values` に移動します。`bools.xml` ファイルが存在しない場合は、新規作成してください。 2. 以下のリソースを追加します。 ```xml false ``` 変更はアプリ内のすべてのオンボーディングにグローバルに適用されます。 --- # File: flutter-handling-onboarding-events --- --- title: "Flutter SDK でのオンボーディングイベントの処理" description: "Adapty を使って Flutter でオンボーディング関連のイベントを処理します。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](flutter-get-pb-paywalls)を使用してください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存がありません。まずは[フローとペイウォールの取得](flutter-get-pb-paywalls)と[フローとペイウォールの表示](flutter-present-paywalls)をご覧ください。 ::: ビルダーで設定されたオンボーディングは、アプリが応答できるイベントを生成します。これらのイベントの処理方法は、どのプレゼンテーション方式を使用しているかによって異なります。 - **フルスクリーン表示**:すべてのオンボーディングビューのイベントを処理するグローバルイベントオブザーバーの設定が必要です - **埋め込みウィジェット**:ウィジェット内のインラインコールバックパラメーターを通じてイベントを処理します 開始する前に、以下を確認してください。 1. [Adapty Flutter SDK](sdk-installation-flutter) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## フルスクリーン表示のイベント \{#full-screen-presentation-events\} ### イベントオブザーバーの設定 \{#set-up-event-observer\} フルスクリーンオンボーディングのイベントを処理するには、`AdaptyUIOnboardingsEventsObserver`を実装して、表示前に設定します: ```dart showLineNumbers title="Flutter" AdaptyUI().setOnboardingsEventsObserver(this); try { await onboardingView.present(); } on AdaptyError catch (e) { // handle the error } catch (e) { // handle the error } ``` ### イベントを処理する \{#handle-events\} 以下のメソッドをオブザーバーに実装してください: ```dart showLineNumbers title="Flutter" void onboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, ) { // Onboarding finished loading } void onboardingViewDidFailWithError( AdaptyUIOnboardingView view, AdaptyError error, ) { // Handle loading errors } void onboardingViewOnCloseAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Handle close action view.dismiss(); } void onboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Dismiss onboarding before presenting paywall view.dismiss().then((_) { _openPaywall(actionId); }); } void onboardingViewOnCustomAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Handle custom actions } void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Handle user input updates } void onboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent event, ) { // Track analytics events } ``` ## 埋め込みウィジェットのイベント \{#embedded-widget-events\} `AdaptyUIOnboardingPlatformView` を使用する場合、ウィジェット内のインラインコールバックパラメータを通じてイベントを直接処理できます。イベントはウィジェットのコールバックとグローバルオブザーバーの両方に送信されますが、グローバルオブザーバーの設定は任意です。 ```dart showLineNumbers title="Flutter" AdaptyUIOnboardingPlatformView( onboarding: onboarding, onDidFinishLoading: (meta) { // Onboarding finished loading }, onDidFailWithError: (error) { // Handle loading errors }, onCloseAction: (meta, actionId) { // Handle close action }, onPaywallAction: (meta, actionId) { _openPaywall(actionId); }, onCustomAction: (meta, actionId) { // Handle custom actions }, onStateUpdatedAction: (meta, elementId, params) { // Handle user input updates }, onAnalyticsEvent: (meta, event) { // Track analytics events }, ) ``` ## イベントの種類 \{#event-types\} 以下のセクションでは、使用しているプレゼンテーション方式に関わらず処理できる各種イベントについて説明します。 ### カスタムアクションの処理 \{#handle-custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。 ユーザーがカスタムボタン(**Login** や **Allow notifications** など)をタップすると、デリゲートメソッド `onboardingController` が `.custom(id:)` ケースでトリガーされ、`actionId` パラメーターにはビルダーで設定した **Action ID** が渡されます。このIDをコード内で使用して、カスタムアクションとして処理できます。IDは「allowNotifications」のように自由に設定できます。 ```dart // Full-screen presentation void onboardingViewOnCustomAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { switch (actionId) { case 'login': _login(); break; case 'allow_notifications': _allowNotifications(); break; } } // Embedded widget onCustomAction: (meta, actionId) { _handleCustomAction(actionId); } ```
イベント例(クリックして展開) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
### オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、次のイベントがトリガーされます。 ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, ) { print('Onboarding loaded: ${meta.onboardingId}'); } // Embedded widget onDidFinishLoading: (meta) { print('Onboarding loaded: ${meta.onboardingId}'); } ```
イベントの例(クリックして展開) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
### オンボーディングを閉じる \{#closing-onboarding\} ユーザーが **Close** アクションが割り当てられたボタンをタップすると、オンボーディングは閉じられたとみなされます。 :::important ユーザーがオンボーディングを閉じたときの動作は、ご自身で管理する必要があります。たとえば、オンボーディング自体の表示を停止する処理が必要です。 ::: ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewOnCloseAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { await view.dismiss(); } // Embedded widget onCloseAction: (meta, actionId) { Navigator.of(context).pop(); } ```
イベント例(クリックして展開) ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
### ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。ペイウォールが閉じた後に別のペイウォールを開きたい場合は、もっとシンプルな方法があります。クローズアクションを処理して、イベントデータに依存せずにペイウォールを開いてください。 ::: オンボーディングでペイウォールをシームレスに扱うには、アクションIDをペイウォールのプレースメントIDと同じにするのがベストです。 :::note iOSでは、ペイウォールまたはオンボーディングの1つのビューのみが画面上に同時に表示できます。オンボーディングの上にペイウォールを表示した場合、バックグラウンドのオンボーディングをプログラムで操作することはできません。オンボーディングを閉じようとすると、代わりにペイウォールが閉じられ、オンボーディングが残ったままになります。これを避けるため、ペイウォールを表示する前に必ずオンボーディングのビューを閉じてください。 ::: ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String actionId, ) { // Dismiss onboarding before presenting paywall view.dismiss().then((_) { _openPaywall(actionId); }); } Future _openPaywall(String actionId) async { // Implement your paywall opening logic here } // Embedded widget onPaywallAction: (meta, actionId) { _openPaywall(actionId); } ```
イベントの例(クリックして展開) ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ```
### ナビゲーションの追跡 \{#tracking-navigation\} オンボーディングフロー中にさまざまなナビゲーション関連イベントが発生すると、アナリティクスイベントを受け取ります。 ```dart showLineNumbers title="Flutter" // Full-screen presentation void onboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent event, ) { trackEvent(event.type, meta.onboardingId); } // Embedded widget onAnalyticsEvent: (meta, event) { trackEvent(event.type, meta.onboardingId); } ``` `event` オブジェクトは以下のいずれかのタイプになります。 | タイプ | 説明 | |------------|-------------| | `onboardingStarted` | オンボーディングが読み込まれたとき | | `screenPresented` | 任意の画面が表示されたとき | | `screenCompleted` | 画面が完了したとき。オプションの `elementId`(完了した要素の識別子)とオプションの `reply`(ユーザーからの回答)を含みます。ユーザーが画面を離れるための操作を行ったときにトリガーされます。 | | `secondScreenPresented` | 2番目の画面が表示されたとき | | `userEmailCollected` | 入力フィールドでユーザーのメールアドレスが収集されたときにトリガーされます | | `onboardingCompleted` | ユーザーが `final` IDを持つ画面に到達したときにトリガーされます。このイベントが必要な場合は、[最後の画面に `final` IDを割り当ててください](design-onboarding)。 | | `unknown` | 認識されないイベントタイプに対して使用されます。`name`(不明なイベントの名前)と `meta`(追加のメタデータ)を含みます | 各イベントには以下の`meta`情報が含まれます: | フィールド | 説明 | |------------|-------------| | `onboardingId` | オンボーディングフローの一意識別子 | | `screenClientId` | 現在のスクリーンの識別子 | | `screenIndex` | フロー内での現在のスクリーンの位置 | | `screensTotal` | フロー内のスクリーンの合計数 |
イベントの例(クリックして展開) ```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: flutter-onboarding-input --- --- title: "Flutter SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用して、FlutterアプリでオンボーディングのデータをAdapty SDKで保存・活用する方法をご紹介します。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や機能改善は行われません。代わりに[フロー](flutter-get-pb-paywalls)をご利用ください。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存がないといったメリットがあります。まずは[フローとペイウォールの取得](flutter-get-pb-paywalls)および[フローとペイウォールの表示](flutter-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力すると、`onStateUpdatedAction` メソッドが呼び出されます。フィールドタイプをコード内で保存または処理できます。 例: ```dart // Full-screen presentation void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Process data } // Embedded widget onStateUpdatedAction: (meta, elementId, params) { // Process data } ``` アクションのフォーマットについては[こちら](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyUIOnboardingPlatformView/onStateUpdatedAction.html)を参照してください。
各 params タイプのプロパティの形状(クリックして展開) ```dart void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // elementId は String です: elementId; // 'preference_selector' // meta — AdaptyUIOnboardingMeta: meta.onboardingId; // 'onboarding_123' meta.screenClientId; // 'preferences_screen' meta.screenIndex; // 1 meta.screensTotal; // 3 // params は AdaptyOnboardingsStateUpdatedParams のサブクラスのいずれかです: switch (params) { case AdaptyOnboardingsSelectParams(:final id, :final value, :final label): // 単一の選択肢 id; // 'option_1' value; // 'premium' label; // 'Premium Plan' break; case AdaptyOnboardingsMultiSelectParams(:final params): // 選択された選択肢のリスト。各要素は AdaptyOnboardingsSelectParams params; // [(id: 'interest_1', value: 'sports', label: 'Sports'), (id: 'interest_2', value: 'music', label: 'Music')] break; case AdaptyOnboardingsInputParams(:final input): switch (input) { case AdaptyOnboardingsTextInput(:final value): value; // 'John Doe' break; case AdaptyOnboardingsEmailInput(:final value): value; // 'user@example.com' break; case AdaptyOnboardingsNumberInput(:final value): value; // 25.0 (double 型) break; } break; case AdaptyOnboardingsDatePickerParams(:final day, :final month, :final year): day; // 15 month; // 6 year; // 1990 break; } } ```
## ユースケース \{#use-cases\} ### ユーザープロファイルをデータで補完する \{#enrich-user-profiles-with-data\} 入力されたデータをユーザープロファイルにすぐに紐付けて、同じ情報を二度聞かないようにするには、アクションを処理する際に入力データで[ユーザープロファイルを更新](flutter-setting-user-attributes)する必要があります。 たとえば、`name` という ID のテキストフィールドでユーザーに名前を入力してもらい、その値をユーザーの名 (first name) として設定したい場合や、`email` フィールドでメールアドレスを入力してもらいたい場合、アプリのコードは次のようになります。 ```dart showLineNumbers // Full-screen presentation void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Store user preferences or responses if (params is AdaptyOnboardingsInputParams) { final builder = AdaptyProfileParametersBuilder(); // Map elementId to appropriate profile field switch (elementId) { case 'name': if (params.input is AdaptyOnboardingsTextInput) { builder.setFirstName((params.input as AdaptyOnboardingsTextInput).value); } break; case 'email': if (params.input is AdaptyOnboardingsEmailInput) { builder.setEmail((params.input as AdaptyOnboardingsEmailInput).value); } break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } // Embedded widget onStateUpdatedAction: (meta, elementId, params) { // Store user preferences or responses if (params is AdaptyOnboardingsInputParams) { final builder = AdaptyProfileParametersBuilder(); // Map elementId to appropriate profile field switch (elementId) { case 'name': if (params.input is AdaptyOnboardingsTextInput) { builder.setFirstName((params.input as AdaptyOnboardingsTextInput).value); } break; case 'email': if (params.input is AdaptyOnboardingsEmailInput) { builder.setEmail((params.input as AdaptyOnboardingsEmailInput).value); } break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } ``` ### 回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングでクイズを使用することで、ユーザーがオンボーディングを完了した後に表示するペイウォールをカスタマイズすることもできます。 たとえば、スポーツの経験についてユーザーに質問し、異なるユーザーグループに異なるCTAやプロダクトを表示することができます。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、選択肢に意味のあるIDを割り当てます。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](flutter-setting-user-attributes)します。 ```dart showLineNumbers // Full-screen presentation void onboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, String elementId, AdaptyOnboardingsStateUpdatedParams params, ) { // Handle quiz responses and set custom attributes if (params is AdaptyOnboardingsSelectParams) { final builder = AdaptyProfileParametersBuilder(); // Map quiz responses to custom attributes switch (elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.setCustomStringAttribute(params.value, 'experience'); break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } // Embedded widget onStateUpdatedAction: (meta, elementId, params) { // Handle quiz responses and set custom attributes if (params is AdaptyOnboardingsSelectParams) { final builder = AdaptyProfileParametersBuilder(); // Map quiz responses to custom attributes switch (elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.setCustomStringAttribute(params.value, 'experience'); break; } // Update profile Adapty().updateProfile(builder.build()).catchError((error) { // handle the error }); } } ``` 3. [セグメントを作成](segments)します(カスタム属性の値ごとに)。 4. [プレースメント](placements)を作成し、作成した各セグメントに[オーディエンス](audience)を追加します。 5. アプリのコードで、そのプレースメントの[ペイウォールを表示](flutter-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[このボタンのアクションへの応答](flutter-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: flutter-sdk-call-order --- --- title: "Flutter SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的な#2002エラーを防ぎましょう。" --- `Adapty().activate()` の完了前に他のAdapty SDKメソッドを呼び出してはいけません。`activate()` が解決するまで、SDKは何の状態も持ちません。`activate()` の前または並行して発行された呼び出しはすべて [`#2002 notActivated`](error-handling-on-flutter-react-native-unity#custom-network-codes) で失敗します。 アプリがユーザーを認証していて、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `Adapty().identify()` を呼び出してください。`identify` が完了するまで、ユーザー操作に関するメソッドは呼び出さないでください。`identify` と競合する呼び出しは、[`#3006 profileWasChanged`](error-handling-on-flutter-react-native-unity#custom-network-codes) エラーで失敗するか、アクティベーション時に作成された匿名プロファイルに対して実行されてしまいます。この場合、アトリビューション・`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と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(configuration: ...)` に `withCustomerUserId` を設定 | アプリ起動時、ステップ 1 の後。カスタマーユーザー ID がある場合 | 推奨。匿名プロファイルは作成されない。 | | 2b | `Adapty().activate(configuration: ...)` に `withCustomerUserId` を設定しない | アプリ起動時、ステップ 1 の後。カスタマーユーザー ID がない場合(または収集しない場合) | Adapty が匿名プロファイルを作成する。 | | 3 | 各 MMP に対して `Adapty().setIntegrationIdentifier(key: ..., value: ...)` を呼び出す | ステップ 2 の後、ユーザーアクション呼び出しの前 | MMP の ID を正しいプロファイルに紐付けるために必須。 | | 4 | `await Adapty().identify(customerUserId)` | ステップ 3 の後(MMP がない場合はステップ 2 の後)、ステップ 5 の前。パス 2b で認証を行う場合のみ | 必ず `await` を使用する。`identify` 中に並行して呼び出すと `#3006 profileWasChanged` が発生する。 | | 5 | `getPaywall`(SDK v4 では `getFlow`)、`getPaywallProducts`、`restorePurchases`、`makePurchase`、`updateAttribution`、`updateProfile` | `identify` を呼び出す場合はステップ 4 の後、それ以外はステップ 3 の後(MMP がない場合はステップ 2 の後) | これらの呼び出しには安定したプロファイルが必要。 | :::important これらのステップをスキップすると、復帰ユーザーのプレミアムアクセスが失われたり、プロファイルに `appsflyer_id` が設定されなかったり、間違ったオーディエンスに対してペイウォールが返されたりする原因になります。 ::: ## Web2app およびウェブファネル経由のインストール \{#web2app-and-web-funnel-installs\} ユーザーがウェブのチェックアウト(Stripe、Paddle)で購入してからネイティブアプリをインストールする場合、デバイス上で最初に `activate()` を呼び出すと新しい匿名プロファイルが作成されます。このプロファイルはウェブのプロファイルとは紐付けられません。アプリ起動前に(認証フローやインストールリファラーから)customer user ID を解決できる場合は、`activate()` に直接渡してください。そうでない場合、`identify("YOUR_USER_ID")` を呼び出してから `restorePurchases` を実行するまで、ウェブでの購入はデバイス上で表示されません。 各ウェブチェックアウトで送信するメタデータについては以下をご覧ください。 - [Stripe](stripe) - [Paddle](paddle) --- # File: flutter-optimize-paywall-fetching --- --- title: "Flutter SDKでのペイウォール取得を最適化する" description: "Adaptyのペイウォールを確実に取得する:Flutterにおけるタイミングとキャッシュとフォールバックパターンの解説。" --- Flutter でのペイウォール取得を信頼性の高いものにするには、3つのことを実現する必要があります:高速な表示、オーディエンスにターゲティングされたペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバックです。以下のルールでは、これを実現するためのタイミング、キャッシュ、フォールバックパターンについて説明します。 :::tip 以下のルールは、`Adapty().activate()` および `Adapty().identify()` がすでに完了していることを前提としています。詳しくは [Flutter SDK の呼び出し順序](flutter-sdk-call-order) をご覧ください。 ::: 以下のアドバイスは v3 のメソッド名を使用しています。SDK v4 では、`getPaywall` が `getFlow` に、フェッチポリシーの型が `AdaptyFlowFetchPolicy` にそれぞれ名称変更されていますが、すべてのルールはそのまま適用されます。 ## ルールと注意点 \{#rules-and-pitfalls\} | すること | しないこと | 理由 | |---|---|---| | これから表示するプレースメントをフェッチする。 | 起動時にすべてのプレースメントを並列でプリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、処理が集中する間にブラックスクリーンが発生する。 | | アトリビューションが解決する時間を確保してから `getPaywall` をフェッチする(たとえば `activate` から 1〜2 秒後、または `didUpdateProfileStream` が発火した後)。 | `runApp` の前の `main()` で `getPaywall` を呼び出す。 | アトリビューションがまだ確定していないため、ペイウォールはデフォルトのオーディエンスで解決され、セグメントや ASA パーソナライゼーションが無効になる。 | | `loadTimeout` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無期限に待機する。 | タイムアウトを設定しないと、通信環境が悪いユーザーはネットワークが解決するまで空白画面を見続けるか、アプリを閉じてしまう。 | プレースメントの選び方については[プレースメント](placements)を、`fetchPolicy`および`loadTimeout`パラメータの詳細については[ペイウォールとプロダクトの取得](fetch-paywalls-and-products-flutter)を参照してください。 ## 接続状況が悪い環境向けのチューニング \{#tune-for-poor-connectivity\} 接続状況が慢性的に悪い市場(農村部、移動中、ルーティングの問題がある地域)向けには: - 最初の取得以外のすべての取得で `fetchPolicy: AdaptyPaywallFetchPolicy.returnCacheDataElseLoad` を設定する。 - Adapty ダッシュボードですべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeout` を3〜5秒に設定し、タイムアウトが発火した場合はフォールバックを受け入れる。 - `getProfile()` にペイウォールの表示を依存させない。`getPaywall` を独立して呼び出すことで、プロファイルの取得が遅くてもUIをブロックしないようにする。 --- # File: flutter-show-aa-targeted-paywall --- --- title: "FlutterSDKで初回起動時にApple Ads向けペイウォールを表示する" description: "Flutterで初回起動時、Apple Adsのアトリビューションを短時間待ってからペイウォールを表示し、タイムアウト時はデフォルトオーディエンスにフォールバックします。AdaptyProfile.appliedAttributionSourcesを使用します。" --- Apple Ads (AA) のアトリビューションは `Adapty().activate()` の後に非同期で届きます。初回起動時はまだ届いていないことが多いため、すぐに `getPaywall` を呼び出すと、Adapty はデフォルトオーディエンスに基づいてリクエストを解決してしまい、Apple Ads ユーザーが AA セグメント向けペイウォールを見逃してしまいます。ペイウォールを表示してから差し替えるのではなく、何も表示する前に AA アトリビューションを少しの間待ちましょう。アトリビューションが短いタイムアウト内に届けばターゲット向けペイウォールを、届かなければデフォルトオーディエンスのペイウォールを表示します。`AdaptyProfile.appliedAttributionSources` を使うと、AA アトリビューションが適用済みかどうかを確認できます。 ## 始める前に \{#before-you-start\} 必要なもの: - Adapty Flutter SDK **3.17.0** 以降。 - AdaptyでアプリのApple Adsが設定済みであること。詳しくは[Apple Ads](apple-search-ads)を参照してください。 ## 仕組み \{#how-it-works\} `Adapty().activate()` を呼び出すと、SDKはバックグラウンドでApple Ads(AA)のアトリビューション情報をAppleに問い合わせ、その結果をAdaptyのバックエンドに転送します。AAがそのプロファイルのアクティブなアトリビューションソースになると、SDKは`didUpdateProfileStream`リスナーに更新済みの`AdaptyProfile`を届けます。このとき、`appliedAttributionSources`リストには`AdaptyAttributionSource.appleAds`が含まれています。 初回起動時には、次の2つのケースを処理する必要があります: 1. **タイムアウト内にアトリビューションが届いた場合。** `getPaywall` を呼び出すと、Adapty が Apple Ads のオーディエンスに対してリクエストを解決し、ターゲットのペイウォールを返します。 2. **先にタイムアウトが経過した場合。** 代わりにデフォルトオーディエンスのペイウォールを表示し、Apple Ads のアトリビューションがないユーザーを待たせないようにしましょう。`getPaywallForDefaultAudience` はセグメント処理を待たずに即座に返します。 `appliedAttributionSources` は空になることがあります。これは次のいずれかを意味します: - このプロファイルに対する Apple Ads のアトリビューションがまだ処理されていない、または - アトリビューション自体が届いていない。 いずれの場合も、`getPaywallForDefaultAudience` は安全に呼び出せます — プロファイルの状態に関わらず、デフォルトオーディエンス向けのペイウォールを返します。 :::important この待機が発生するのは初回起動時のみです。Apple Ads のアトリビューションが一度記録されると、プロファイルに永続的に保存されます。2回目以降の起動では、キャッシュされたプロファイルには既に `appliedAttributionSources` に `AdaptyAttributionSource.appleAds` が含まれているため、アトリビューションのパスはすぐに解決され、`getPaywall` は遅延なく Apple Ads セグメント向けのペイウォールを返します。 ::: ## 実装 \{#implementation\} 初回起動時は `AdaptyAttributionSource.appleAds` を待ち、ハードタイムアウトを設定してください。Apple Ads のアトリビューションが届かなかった場合でも、該当ユーザーにはペイウォールを表示する必要があります。 1. **SDKを有効化する。** [Flutter SDKのインストールと設定](sdk-installation-flutter)を参照してください。 2. **`Adapty().didUpdateProfileStream.listen(…)`でプロファイルの更新を購読する。** リスナーをまだ設定していない場合は、[サブスクリプションの更新をリッスンする](flutter-check-subscription-status#listen-to-subscription-updates)を参照してください。 3. **`appliedAttributionSources`に`AdaptyAttributionSource.appleAds`が現れるのを監視する。** それが現れたら、`getPaywall`でペイウォールを読み込みます — AdaptyはAAセグメント済みのバリアントを返します: ```dart final subscription = Adapty().didUpdateProfileStream.listen((profile) async { if (!profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) return; final paywall = await Adapty().getPaywall(placementId: placementId); // セグメント済みのペイウォールを表示し、サブスクリプションとタイマーをキャンセルする }); ``` `didUpdateProfileStream` はブロードキャストストリームであり、過去のイベントを再生しません。そのため、`getProfile()` を使って現在のプロファイルも一度確認してください。アプリを再起動した場合、保存済みのアトリビューションはすでに適用済みのため、再度イベントは発行されません。 4. **サブスクリプションと並行して3〜5秒のタイマーを起動します。** タイマーが`AdaptyAttributionSource.appleAds`の受信より先に発火した場合は、代わりに`getPaywallForDefaultAudience`を使用してデフォルトオーディエンスのペイウォールを読み込みます。最初に解決した方のペイウォールを表示し、もう一方のパスをキャンセルして、ペイウォールが二重に取得されないようにします。ネットワークリクエストが失敗してもユーザーが行き詰まらないよう、プレースメントに[フォールバックペイウォール](flutter-use-fallback-paywalls)を設定してください。 ## 完全な実装例 \{#complete-example\} 以下の実装では、アトリビューションとタイムアウトを競合させながら、デフォルトオーディエンス向けのペイウォールを並行してプリフェッチし、適切なペイウォールを返します。呼び出し元は単一の関数を待つだけでよく、コールサイトでリスナーやステートフラグを管理する必要はありません。 - アトリビューションが `timeout` 以内に届いた場合、`getPaywall` を通じてセグメント化されたペイウォールを返します。 - `timeout` が先に経過した場合、`getPaywallForDefaultAudience` を通じてプリフェッチ済みのデフォルトオーディエンス向けペイウォールを返します。 ```dart title="apple_ads_paywall.dart" /// Returns the Apple Ads-segmented paywall if attribution is applied within /// [timeout], otherwise the default-audience paywall. Call after Adapty().activate(). Future getPaywallOrDefault({ required String placementId, required Duration timeout, }) { // Prefetch the default-audience paywall right away so the timeout path resolves // without an extra network round-trip. `getPaywallForDefaultAudience` skips the // wait for segmentation data. `..ignore()` keeps an unused prefetch from surfacing // as an unhandled error; the error still reaches the caller if this paywall wins. final defaultPaywall = Adapty().getPaywallForDefaultAudience(placementId: placementId)..ignore(); final completer = Completer(); late final StreamSubscription subscription; late final Timer timer; void resolve(Future paywall) { if (completer.isCompleted) return; timer.cancel(); subscription.cancel(); completer.complete(paywall); } void onProfile(AdaptyProfile profile) { if (profile.appliedAttributionSources.contains(AdaptyAttributionSource.appleAds)) { resolve(Adapty().getPaywall(placementId: placementId)); } } // Attribution path: react to profile updates as attribution is applied. subscription = Adapty().didUpdateProfileStream.listen(onProfile); // The stream is a broadcast stream and doesn't replay, so check the current // profile too — on relaunches attribution is already stored and won't re-emit. Adapty().getProfile().then(onProfile).ignore(); // Timeout path: fall back to the prefetched default-audience paywall. timer = Timer(timeout, () => resolve(defaultPaywall)); return completer.future; } ``` スプラッシュ画面から呼び出し、解決後にペイウォールを表示します: ```dart try { final paywall = await getPaywallOrDefault( placementId: 'YOUR_PLACEMENT_ID', timeout: const Duration(seconds: 5), ); // present the paywall } on AdaptyError catch (adaptyError) { // handle the error or show a fallback paywall } catch (e) { // handle the error } ``` `timeout` を調整して、ペイウォールが表示されるまでユーザーを待たせる時間を設定してください。ほとんどのユーザーはApple Adsのアトリビューションを持っていないため、設定したタイムアウトの全時間を待つことになります。3〜5秒が現実的なバランスです。アトリビューションが来る場合は、通常、アプリ起動から数秒以内に届きます。 アプリがすでに別の目的(例:[サブスクリプションステータスの確認](flutter-check-subscription-status#listen-to-subscription-updates))で `didUpdateProfileStream` をリッスンしている場合、変更する必要はありません。`didUpdateProfileStream` はブロードキャストストリームなので、複数の独立したリスナーが互いに影響を与えることなく使用できます。 --- # File: flutter-test --- --- title: "Flutter SDK でのテストとリリース" description: "AdaptyでFlutterアプリのサブスクリプション状態を確認する方法を説明します。" --- Flutter アプリに Adapty SDK をすでに組み込んでいる場合は、すべてが正しく設定されており、iOS と Android の両プラットフォームで購入が期待どおりに機能することを確認するテストを行いましょう。これには、SDK の統合テストと、Apple のサンドボックス環境および Google Play のテスト環境を使った実際の購入フローのテストが含まれます。 ## アプリをテストする \{#test-your-app\} アプリ内課金の包括的なテストについては、プラットフォーム別のテストガイドを参照してください: [iOS テストガイド](test-purchases-in-sandbox) および [Android テストガイド](testing-on-android)。 ## リリースの準備 \{#prepare-for-release\} アプリをストアに申請する前に、[リリースチェックリスト](release-checklist) に従って以下を確認してください: - ストアの接続とサーバー通知が設定されている - 購入が完了し、Adapty に報告されている - アクセスが正しくアンロックおよび復元される - プライバシーおよびレビュー要件を満たしている --- # File: InvalidProductIdentifiers-flutter --- --- title: "Flutter SDK の Code-1000 noProductIDsFound エラーの修正方法" description: "Adapty でサブスクリプションを管理する際の無効なプロダクト識別子エラーを解決します。" --- 1000 コードエラー `noProductIDsFound` は、ペイウォールでリクエストしたプロダクトが App Store に登録されているにもかかわらず、購入可能な状態ではないことを示します。このエラーには `InvalidProductIdentifiers` 警告が伴う場合があります。エラーなしで警告のみが表示される場合は、無視して問題ありません。 `noProductIDsFound` エラーが発生している場合は、以下の手順で解決してください。 ## ステップ 1. バンドル ID を確認する \{#step-2-check-bundle-id\} 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-3-check-products\} 1. **App Store Connect** を開き、左側のメニューから [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) に移動します。 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テスト対象のプロダクトが **Ready to Submit** になっていることを確認します。 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`、バンドル ID が一致、API キーが有効 — SDK が依然として `1000 noProductIDsFound` を返す場合があります。この場合、プロダクトが Apple のレジストリで詰まっている可能性があります。App Store Connect の UI 上にはプロダクトが存在しているにもかかわらず、StoreKit のルックアップパスに公開されていない状態になることがあります。 App Store Connect でそのプロダクトを削除し、同じプロダクト ID で再作成してください。再作成後、反映されるまで最大 24 時間かかる場合があります。 --- # File: cantMakePayments-flutter --- --- title: "Flutter SDKにおけるコード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-flutter-sdk-v4 --- --- title: "Adapty Flutter SDK を v. 4.0 へ移行する" description: "ペイウォール API をフロー API に置き換えることで Adapty Flutter SDK v4.0 へ移行します。Flow Builder と Paywall Builder の両方に対応しています。" --- Adapty Flutter SDK 4.0 ではフローが導入され、ペイウォール API の名称が変更されました。新しい API は新しい Flow Builder と既存の Paywall Builder の両方に対応しており、Adapty ダッシュボード側の設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty().getPaywall(placementId: id)` | `Adapty().getFlow(placementId: id)` | | `Adapty().getPaywallForDefaultAudience(placementId: id)` | `Adapty().getFlowForDefaultAudience(placementId: id)` | | `Adapty().getPaywallProducts(paywall: paywall)` | `Adapty().getPaywallProducts(flow: flow)` | | `Adapty().logShowPaywall(paywall: paywall)` | `Adapty().logShowFlow(flow: flow)` | | `AdaptyPaywall`(型) | `AdaptyFlow` | | `AdaptyPaywallFetchPolicy`(型) | `AdaptyFlowFetchPolicy` | | `AdaptyUI().createPaywallView(paywall: paywall)` | `AdaptyUI().createFlowView(flow: flow)` | | `AdaptyUIPaywallView`(型) | `AdaptyUIFlowView` | | `AdaptyUIPaywallPlatformView`(ウィジェット) | `AdaptyUIFlowPlatformView` | | `AdaptyUI().presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI().presentFlowView(view)` / `dismissFlowView(view)` | | `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` | | `AdaptyUI().setPaywallsEventsObserver(observer)` | `AdaptyUI().setFlowsEventsObserver(observer)` | | `paywallViewDid*` コールバック | `flowViewDid*` コールバック | | `paywallViewDidFailRendering` | `flowViewDidReceiveError` | `AdaptyPaywallProduct` はそのまま名前が変わりません。プロダクトは引き続きフローに属しており、`getPaywallProducts` は `AdaptyFlow` を受け取るようになりました。フローを取得する際に `locale` を渡す必要はなくなりました。購入とプロファイル関連のAPI(`makePurchase`、`restorePurchases`、`getProfile`、`identify` など)は変更なし、ビューメソッド(`present`、`dismiss`、`showDialog`)も変わりません。一部のデフォルト動作が変更されています。詳しくは[デフォルト動作の変更](#default-behavior-changes)をご覧ください。 ## 最小バージョン \{#minimum-versions\} Adapty Flutter SDK 4.0 では、最小要件が引き上げられました: - **iOS 15.0** — iOS の最小デプロイメントターゲット(iOS 13.0 から引き上げ)。 - **Xcode 26** 以降 — ネイティブ iOS SDK は Swift tools 6.2 を使用します。 - **Flutter 3.32.0**(Dart 3.8.0)以降。 ## インストール \{#installation\} ### パッケージを更新する \{#update-the-package\} インストールするパッケージは、アプリがキッズモードを使用しているかどうかによって異なります。 ほとんどのアプリでは、`pubspec.yaml` の `adapty_flutter` を v4.0 に更新します: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter: 4.0.0 ``` アプリがキッズモードを使用している場合は、代わりに `adapty_flutter_kids` を指定します: ```yaml showLineNumbers title="pubspec.yaml" dependencies: adapty_flutter_kids: 4.0.0 ``` これは**スタンドアロン**パッケージで、IDFAおよび広告トラッキングコードを削除してApp Storeの要件に準拠します。Dartのインポートパスを`package:adapty_flutter_kids/adapty_flutter.dart`に更新してください。それ以外の移行手順は通常パッケージとまったく同じです。 キッズモードでは、Adapty ダッシュボードでIPアドレス収集を無効にする必要があります。詳細なセットアップ手順は[キッズモード](kids-mode-flutter)を参照してください。 ### iOS:ネイティブSDKはSwift Package Manager経由で配布されるようになりました \{#ios-native-sdks-now-come-through-swift-package-manager\} [CocoaPodsのスペックリポジトリは2026年12月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)。そのため、v4からはネイティブiOS SDKの**CocoaPodsによる配布が終了**し、プラグインは**Swift Package Manager**のみを通じて配布されます。 Flutter 3.32〜3.43をお使いの場合は、Swift Package Managerのサポートを一度有効化してください: ```bash flutter config --enable-swift-package-manager ``` Flutter 3.44以降ではSwift Package Managerがデフォルトで有効になっているため、特別な操作は不要です。 ## フローの取得 \{#fetching-flows\} ### getPaywall → getFlow 返り値の型が `AdaptyPaywall` から `AdaptyFlow` に変わり、`locale` を渡す必要がなくなりました — フローをレンダリングする際にローカライズは自動的に解決され、カスタムペイウォールの場合はすべての設定済みロケールが `flow.remoteConfigs` に返されます。 ```diff showLineNumbers - final paywall = await Adapty().getPaywall(placementId: 'YOUR_PLACEMENT_ID', locale: 'en'); + final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); ``` `getPaywallForDefaultAudience` も同様にリネームされています。 ```diff showLineNumbers - final paywall = await Adapty().getPaywallForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID', locale: 'en'); + final flow = await Adapty().getFlowForDefaultAudience(placementId: 'YOUR_PLACEMENT_ID'); ``` フェッチポリシーの型名が `AdaptyPaywallFetchPolicy` から `AdaptyFlowFetchPolicy` に変更されました。オプション(`reloadRevalidatingCacheData`、`returnCacheDataElseLoad`、`returnCacheDataIfNotExpiredElseLoad`)は変更ありません。 ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` は名前はそのままですが、`flow` パラメーターで `AdaptyFlow` を受け取るようになりました: ```diff showLineNumbers - final products = await Adapty().getPaywallProducts(paywall: paywall); + final products = await Adapty().getPaywallProducts(flow: flow); ``` ## データモデル \{#data-model\} `getFlow` は `AdaptyPaywall` の代わりに `AdaptyFlow` を返し、オブジェクトの構造が変わりました。 | v3 `AdaptyPaywall` メンバー | v4 `AdaptyFlow` メンバー | アクション | |---|---|---| | `remoteConfig`(単一、nullable) | `remoteConfigs`(リスト) | フローは設定された言語ごとに1つのリモートコンフィグを持ちます。`remoteConfig` ゲッターは引き続き存在し、最初のエントリを返します。特定の言語を選択するには、`remoteConfigs` を `locale` で検索してください。 | | `productIdentifiers` | `productIdentifiers` | 維持されていますが、フローのすべてのペイウォールバリエーションを横断して収集されるようになりました。バリエーションごとの識別子は `flow.paywalls[i].productIdentifiers` に格納されています。 | | `hasViewConfiguration` | `hasViewConfiguration` | 変更なし。 | | `placementId`(非推奨) | 削除済み | `flow.placement.id` を使用してください。 | | `revision`(非推奨) | 削除済み | `flow.placement.revision` を使用してください。 | | `vendorProductIds`(非推奨) | 削除済み | `productIdentifiers` を使用してください。 | | _(新規)_ | `paywalls`(`AdaptyFlowPaywall` のリスト) | 各エントリはフロー内の1つのペイウォールバリエーションで、独自の `name`、`variationId`、および `productIdentifiers` を持ちます。 | `AdaptyPaywallViewConfiguration` は非公開になりました — ビュー設定は不透明になりました。この型への参照をすべて削除してください。 ## Webペイウォールメソッド \{#web-paywall-methods\} `openWebPaywall` と `createWebPaywallUrl` の名前はそのままですが、`paywall` パラメータは `AdaptyPaywall` の代わりに `AdaptyFlowPaywall`(フローのバリアント)を受け取るようになりました。引き続き `AdaptyPaywallProduct` を渡すこともできます。 ```diff showLineNumbers final flow = await Adapty().getFlow(placementId: 'YOUR_PLACEMENT_ID'); - await Adapty().openWebPaywall(paywall: paywall); + if (flow.paywalls.isNotEmpty) { + await Adapty().openWebPaywall(paywall: flow.paywalls[0]); + } ``` ## フローのビュー数を追跡する \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` は `logShowFlow` に名前が変更され、`AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリアントに対して記録されるため、既存のファネルおよび A/B テストの指標はダッシュボードの変更なしにそのまま機能します。 ```diff showLineNumbers - await Adapty().logShowPaywall(paywall: paywall); + await Adapty().logShowFlow(flow: flow); ``` v3 と同様に、[フロービルダー](adapty-flow-builder) または [ペイウォールビルダー](adapty-paywall-builder) でレンダリングされたフローやペイウォールを表示する際には、このメソッドを呼び出す必要はありません。Adapty がそれらのビューを自動的にトラッキングします。 ## フローの表示 \{#displaying-flows\} ### createPaywallView → createFlowView メソッド名を変更し、`AdaptyFlow` を `flow` パラメータで渡します。その他のパラメータ(`loadTimeout`、`preloadProducts`、`customTags`、`customTimers`、`customAssets`、`productPurchaseParams`)や、ビューのメソッド(`present`、`dismiss`、`showDialog`)は変更ありません: ```diff showLineNumbers - final view = await AdaptyUI().createPaywallView(paywall: paywall); + final view = await AdaptyUI().createFlowView(flow: flow); await view.present(); ``` ### AdaptyUIPaywallView → AdaptyUIFlowView ビュータイプの名前が変更されました。非推奨の `paywallVariationId` プロパティは削除されました — 代わりに `variationId` を使用してください: ```diff showLineNumbers - void flowViewDidAppear(AdaptyUIPaywallView view) { + void flowViewDidAppear(AdaptyUIFlowView view) { ``` ### AdaptyUIPaywallPlatformView → AdaptyUIFlowPlatformView ウィジェットツリーにビューをウィジェットとして埋め込む場合は、名前を変更して `flow` パラメータを渡してください。イベントコールバック(`onDidAppear`、`onDidFinishPurchase` など)は名前がそのまま引き継がれます: ```diff showLineNumbers - AdaptyUIPaywallPlatformView( - paywall: paywall, + AdaptyUIFlowPlatformView( + flow: flow, onDidFinishPurchase: (view, product, purchaseResult) { /* … */ }, ) ``` :::note `createFlowView` で作成したフロービューは使い捨てです。`dismiss()` を呼び出すと、ビューはメモリから解放され、再表示できなくなります。フローをもう一度表示するには、再度 `createFlowView` を呼び出してください。 ::: ## イベントの処理 \{#handling-events\} オブザーバークラスは `AdaptyUIPaywallsEventsObserver` から `AdaptyUIFlowsEventsObserver` へ、登録メソッドは `setPaywallsEventsObserver` から `setFlowsEventsObserver` へ、そしてすべての `paywallViewDid*` コールバックは `flowViewDid*` へとそれぞれリネームされました。 ```diff showLineNumbers - class MyObserver extends AdaptyUIPaywallsEventsObserver { + class MyObserver extends AdaptyUIFlowsEventsObserver { @override - void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) { + void flowViewDidPerformAction(AdaptyUIFlowView view, AdaptyUIAction action) { // … } } - AdaptyUI().setPaywallsEventsObserver(this); + AdaptyUI().setFlowsEventsObserver(this); ``` 次の3つのコールバックは**必須**です — これらがないとオブザーバーはコンパイルエラーになります: - **`flowViewDidFinishPurchase`**: v3 ではオプションで、デフォルトでは購入後にビューが閉じられていました。現在は、フローを続けるか `view.dismiss()` を呼び出すかを自分で決定します。 - **`flowViewDidFinishRestore`**: v3 と同様に必須です。 - **`flowViewDidReceiveError`**: `paywallViewDidFailRendering` を置き換え、その他のビューエラーも受け取るようになりました。 その他の小さな変更点が 2 つあります: - `setFlowsEventsObserver`(および `setOnboardingsEventsObserver`)が `null` を受け付けるようになり、設定済みのオブザーバーを取り外せるようになりました。これにより、SDK がオブザーバーを保持し続けることがなくなります。 - 新しいオプションの `flowViewDidReceiveAnalyticEvent` コールバックは、フローからのカスタム分析イベント用に予約されています。現時点ではフローからこのコールバックがコードに送出されることはないため、実装する必要はありません。 v4 ではオプトインで利用できる新機能も追加されています。 - `AdaptyUI().setObserverModeResolver(...)` と `AdaptyUIObserverModeResolver` — SDKが[オブザーバーモード](implement-observer-mode-flutter)で動作中に、フローから開始された購入やリストアを処理します。以前はネイティブのiOSおよびAndroid SDKでのみ利用可能でした。[オブザーバーモードでフローを表示する](flutter-present-flows-in-observer-mode)を参照してください。 - `AdaptyUI().setSystemRequestsHandler(...)` と `AdaptyUISystemRequestsHandler` — フローからのシステムリクエスト(OSの権限プロンプトやApp Storeのレビューリクエスト)用に予約されています。フローはまだこれらのリクエストをトリガーしないため、ハンドラーを登録する必要はありません。 ## 削除された API \{#removed-apis\} これらのシンボルは 3.x で非推奨となり、v4 では削除されています: ### setFallbackPaywalls → setFallback ```diff showLineNumbers - await Adapty().setFallbackPaywalls(assetId); + await Adapty().setFallback(assetId); ``` ### withIdfaCollectionDisabled → withAppleIdfaCollectionDisabled ```diff showLineNumbers configuration: AdaptyConfiguration(apiKey: 'YOUR_PUBLIC_SDK_KEY') - ..withIdfaCollectionDisabled(true), + ..withAppleIdfaCollectionDisabled(true), ``` ### その他の削除されたメンバー \{#other-removed-members\} - **`AdaptyPurchaseResultSuccess.jwsTransaction`**: `appleJwsTransaction` を使用してください。 - **`AdaptyUIFlowView.paywallVariationId`**: `variationId` を使用してください。 - **`AdaptyUIObserver` と `AdaptyUI().setObserver(...)`**: `AdaptyUIFlowsEventsObserver` と `setFlowsEventsObserver(...)` を使用してください。 ## デフォルト動作の変更 \{#default-behavior-changes\} これらの変更はコンパイルエラーを引き起こしませんが、実行時にテストしてください: - **購入成功時**: v3 では `paywallViewDidFinishPurchase` のデフォルト動作でビューが閉じられていましたが、v4 では `flowViewDidFinishPurchase` が必須となり、デフォルトの動作はありません。ビューを閉じたい場合は自分でその処理を実装してください。 - **Android システムの戻るボタン**: デフォルトではフローを閉じなくなりました。このアクションは `AndroidSystemBackAction` として `flowViewDidPerformAction` に渡されるため、戻るボタンでフローを閉じたい場合はそこで処理してください。 - **URL を開く処理**: `flowViewDidPerformAction` のデフォルト動作が変更され、`CloseAction` 時のビュー閉鎖に加え、`OpenUrlAction` をネイティブに処理する(ダッシュボードで設定されたアプリ内ブラウザまたは外部ブラウザの設定に従う)ようになりました。URL を独自に処理したい場合はコールバックをオーバーライドしてください。 - **ビューのエラー**: `flowViewDidReceiveError` が必須となり、ビューを閉じるかどうかはご自身の実装次第です。v3 でレンダリングエラー時に自動的にビューが閉じられる動作に依存していた場合は、このコールバック内で `view.dismiss()` を呼び出してください。 - **ビューのライフサイクル**: フローまたはオンボーディングのビューを閉じると、そのビューはメモリから解放されます。一度閉じたビューは再表示できないため、新しいビューを作成してください。 ## オンボーディング API の廃止 \{#onboarding-api-deprecation\} レガシーオンボーディング API は v4.0 で廃止され、[Flow Builder](adapty-flow-builder) に移行されました。引き続き動作しますが、`@Deprecated` アノテーションにより IDE が廃止シンボルをフラグとして表示します(ランタイム警告は発生しません)。これらのシンボルは将来のリリースで削除される予定ですので、オンボーディングの Flow Builder への移行を計画してください。 非推奨のシンボル: `getOnboarding`、`getOnboardingForDefaultAudience`、`createOnboardingView`、`presentOnboardingView`、`dismissOnboardingView`、`setOnboardingsEventsObserver`、`AdaptyOnboarding`、`AdaptyUIOnboardingView`、`AdaptyUIOnboardingPlatformView`、`AdaptyUIOnboardingsEventsObserver`、およびオンボーディングの状態・入力・アナリティクスモデル。 --- # File: flutter-migration-guide-310 --- --- title: "Flutter Adapty SDK 3.10.0 への移行ガイド" description: "" --- Adapty SDK 3.10.0 はメジャーリリースであり、いくつかの改善が含まれていますが、移行作業が必要になる場合があります。 1. `makePurchase` メソッドを、個別のパラメーターの代わりに `AdaptyPurchaseParameters` を使用するように更新する。 2. `AdaptyPaywall` モデル内の `vendorProductIds` を `productIdentifiers` に置き換える。 ## makePurchase メソッドの更新 \{#update-makepurchase-method\} `makePurchase` メソッドは、個別の `subscriptionUpdateParams` および `isOfferPersonalized` 引数の代わりに `AdaptyPurchaseParameters` を使用するようになりました。これにより、型の安全性が向上し、将来的に購入パラメーターを拡張しやすくなります。 ```diff showLineNumbers - final purchaseResult = await adapty.makePurchase( - product: product, - subscriptionUpdateParams: subscriptionUpdateParams, - isOfferPersonalized: true, - ); + final parameters = AdaptyPurchaseParametersBuilder() + ..setSubscriptionUpdateParams(subscriptionUpdateParams) + ..setIsOfferPersonalized(true) + ..setObfuscatedAccountId('your-account-id') + ..setObfuscatedProfileId('your-profile-id'); + final purchaseResult = await adapty.makePurchase( + product: product, + parameters: parameters.build(), + ); ``` 追加のパラメーターが不要な場合は、次のようにシンプルに記述できます。 ```dart showLineNumbers final purchaseResult = await adapty.makePurchase( product: product, ); ``` ## AdaptyPaywall モデルの使用方法の更新 \{#update-adaptypaywall-model-usage\} `vendorProductIds` プロパティは非推奨となり、`productIdentifiers` が推奨されるようになりました。新しいプロパティは、単純な文字列の代わりに `AdaptyProductIdentifier` オブジェクトを返すため、プロダクト情報がより構造化されています。 ```diff showLineNumbers - paywall.vendorProductIds.map((vendorId) => - ListTextTile(title: vendorId) - ).toList() + paywall.productIdentifiers.map((productId) => + ListTextTile(title: productId.vendorProductId) + ).toList() ``` `AdaptyProductIdentifier` オブジェクトは `vendorProductId` プロパティを通じてベンダープロダクト ID にアクセスでき、同等の機能を維持しながら将来の拡張に向けてより良い構造を提供します。 ## 後方互換性 \{#backward-compatibility\} どちらの変更も後方互換性を維持しています。 - `makePurchase` の旧パラメーターは非推奨ですが、引き続き機能します - `vendorProductIds` プロパティは非推奨ですが、引き続きアクセス可能です - 既存のコードは動作し続けますが、非推奨の警告が表示されます 新しい API を使用するようにコードを更新することを推奨します。これにより、将来の互換性が確保され、改善された型の安全性と拡張性のメリットを活用できます。 --- # File: flutter-migration-guide-38 --- --- title: "Adapty Flutter SDK を v3.8 へ移行する" description: "Adapty Flutter SDK v3.8 へ移行して、パフォーマンス向上と新しいマネタイズ機能を利用しましょう。" --- Adapty SDK 3.8.0 はメジャーリリースで、いくつかの改善が加えられています。ただし、移行作業が必要になる場合があります。 1. オブザーバークラスとメソッド名を更新する。 2. フォールバックペイウォールのメソッド名を更新する。 3. イベントハンドリングメソッドのビュークラス名を更新する。 ## オブザーバークラスとメソッド名を更新する \{#update-observer-class-and-method-names\} オブザーバークラスとその登録メソッドの名前が変更されました: ```diff showLineNumbers - class MyObserver extends AdaptyUIObserver { + class MyObserver extends AdaptyUIPaywallsEventsObserver { @override void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) { // Handle action } } // Register observer - AdaptyUI().setObserver(this); + AdaptyUI().setPaywallsEventsObserver(this); ``` ## フォールバックペイウォールのメソッド名を更新する \{#update-fallback-paywalls-method-name\} フォールバックペイウォールを設定するメソッドが簡略化されました: ```diff showLineNumbers try { - await Adapty.setFallbackPaywalls(assetId); + await Adapty.setFallback(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ## イベントハンドリングメソッドのビュークラス名を更新する \{#update-view-class-name-in-event-handling-methods\} すべてのイベントハンドリングメソッドで、`AdaptyUIView` の代わりに新しい `AdaptyUIPaywallView` クラスが使用されるようになりました: ```diff showLineNumbers - void paywallViewDidPerformAction(AdaptyUIView view, AdaptyUIAction action) + void paywallViewDidPerformAction(AdaptyUIPaywallView view, AdaptyUIAction action) - void paywallViewDidSelectProduct(AdaptyUIView view, AdaptyPaywallProduct product) + void paywallViewDidSelectProduct(AdaptyUIPaywallView view, AdaptyPaywallProduct product) - void paywallViewDidStartPurchase(AdaptyUIView view, AdaptyPaywallProduct product) + void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) - void paywallViewDidFinishPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyProfile profile) + void paywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyProfile profile) - void paywallViewDidFailPurchase(AdaptyUIView view, AdaptyPaywallProduct product, AdaptyError error) + void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) - void paywallViewDidFinishRestore(AdaptyUIView view, AdaptyProfile profile) + void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) - void paywallViewDidFailRestore(AdaptyUIView view, AdaptyError error) + void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) - void paywallViewDidFailLoadingProducts(AdaptyUIView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) + void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyIOSProductsFetchPolicy? fetchPolicy, AdaptyError error) - void paywallViewDidFailRendering(AdaptyUIView view, AdaptyError error) + void paywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) ``` --- # File: migration-to-flutter-sdk-34 --- --- title: "Adapty Flutter SDK を v3.4 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty Flutter SDK v3.4 に移行します。" --- Adapty SDK 3.4.0 はメジャーリリースであり、お客様側での移行手順が必要な改善が含まれています。 ## フォールバックペイウォールファイルを更新する \{#update-fallback-paywall-files\} 新しい SDK バージョンとの互換性を確保するため、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新されたフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換え](flutter-use-fallback-paywalls)ます。 ## オブザーバーモードの実装を更新する \{#update-implementation-of-observer-mode\} オブザーバーモードを使用している場合は、その実装を更新してください。 以前は、トランザクションを Adapty に報告するために異なるメソッドが使用されていました。新しいバージョンでは、Android と iOS の両方で `reportTransaction` メソッドを一貫して使用する必要があります。このメソッドは各トランザクションを Adapty に明示的に報告し、認識されることを保証します。ペイウォールが使用された場合は、バリエーション ID を渡してトランザクションをペイウォールに紐付けてください。 :::warning **トランザクションの報告をスキップしないでください!** `reportTransaction` を呼び出さない場合、Adapty はトランザクションを認識せず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: ```diff showLineNumbers - // every time when calling transaction.finish() - if (Platform.isAndroid) { - try { - await Adapty().restorePurchases(); - } on AdaptyError catch (adaptyError) { - // handle the error - } catch (e) { - } - } try { // every time when calling transaction.finish() await Adapty().reportTransaction( "YOUR_TRANSACTION_ID", variationId: "PAYWALL_VARIATION_ID", // optional ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` --- # File: migration-to-flutter330 --- --- title: "Adapty Flutter SDK を v3.3 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty Flutter SDK v3.3 に移行します。" --- Adapty SDK 3.3.0 はメジャーリリースであり、いくつかの改善が加えられましたが、移行作業が必要になる場合があります。 1. フォールバックペイウォールを提供するメソッドを更新する。 2. `getProductsIntroductoryOfferEligibility` メソッドを削除する。 3. Adjust、AirBridge、Amplitude、AppMetrica、Appsflyer、Branch、Facebook Ads、Firebase and Google Analytics、Mixpanel、OneSignal、Pushwoosh のインテグレーション設定を更新する。 4. Observer モードの実装を更新する。 ## フォールバックペイウォールを提供するメソッドを更新する \{#update-method-for-providing-fallback-paywalls\} 以前は、メソッドにフォールバックペイウォールを JSON 文字列(`jsonString`)として渡していましたが、現在はローカルのフォールバックファイルへのパス(`assetId`)を渡すように変更されました。 ```diff showLineNumbers import 'dart:async' show Future; import 'dart:io' show Platform; -import 'package:flutter/services.dart' show rootBundle; -final filePath = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; -final jsonString = await rootBundle.loadString(filePath); +final assetId = Platform.isIOS ? 'assets/ios_fallback.json' : 'assets/android_fallback.json'; try { - await adapty.setFallbackPaywalls(jsonString); + await adapty.setFallbackPaywalls(assetId); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` 完全なコード例については、[フォールバックペイウォールを使用する](flutter-use-fallback-paywalls)ページをご覧ください。 ## `getProductsIntroductoryOfferEligibility` メソッドを削除する \{#remove-getproductsintroductoryoffereligibility-method\} Adapty iOS SDK 3.3.0 より前は、ユーザーが適格かどうかに関わらず、プロダクトオブジェクトには常にオファーが含まれていました。そのため、オファーを使用する前に適格性を手動で確認する必要がありました。 現在は、ユーザーが適格な場合にのみプロダクトオブジェクトにオファーが含まれます。つまり、適格性を確認する必要がなくなりました。オファーが存在していれば、ユーザーは適格です。 ## サードパーティインテグレーションの SDK 設定を更新する \{#update-third-party-integration-sdk-configuration\} Adapty Flutter SDK 3.3.0 以降でインテグレーションが正しく動作するよう、以下のセクションに従って各インテグレーションの SDK 設定を更新してください。 ### Adjust 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Adjust インテグレーションの SDK 設定](adjust#connect-your-app-to-adjust)をご覧ください。 ```diff showLineNumbers import 'package:adjust_sdk/adjust.dart'; import 'package:adjust_sdk/adjust_config.dart'; try { final adid = await Adjust.getAdid(); if (adid == null) { // handle the error } + await Adapty().setIntegrationIdentifier( + key: "adjust_device_id", + value: adid, + ); final attributionData = await Adjust.getAttribution(); var attribution = Map(); if (attributionData.trackerToken != null) attribution['trackerToken'] = attributionData.trackerToken!; if (attributionData.trackerName != null) attribution['trackerName'] = attributionData.trackerName!; if (attributionData.network != null) attribution['network'] = attributionData.network!; if (attributionData.adgroup != null) attribution['adgroup'] = attributionData.adgroup!; if (attributionData.creative != null) attribution['creative'] = attributionData.creative!; if (attributionData.clickLabel != null) attribution['clickLabel'] = attributionData.clickLabel!; if (attributionData.costType != null) attribution['costType'] = attributionData.costType!; if (attributionData.costAmount != null) attribution['costAmount'] = attributionData.costAmount!.toString(); if (attributionData.costCurrency != null) attribution['costCurrency'] = attributionData.costCurrency!; if (attributionData.fbInstallReferrer != null) attribution['fbInstallReferrer'] = attributionData.fbInstallReferrer!; - Adapty().updateAttribution( - attribution, - source: AdaptyAttributionSource.adjust, - networkUserId: adid, - ); + await Adapty().updateAttribution(attribution, source: "adjust"); } catch (e) { // handle the error } on AdaptyError catch (adaptyError) { // handle the error } ``` ### AirBridge 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AirBridge インテグレーションの SDK 設定](airbridge#connect-your-app-to-airbridge)をご覧ください。 ```diff showLineNumbers import 'package:airbridge_flutter_sdk/airbridge_flutter_sdk.dart'; final deviceUUID = await Airbridge.state.deviceUUID; try { - final builder = AdaptyProfileParametersBuilder() - ..setAirbridgeDeviceId(deviceUUID); - await Adapty().updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "airbridge_device_id", + value: deviceUUID, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### Amplitude 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Amplitude インテグレーションの SDK 設定](amplitude#sdk-configuration)をご覧ください。 ```diff showLineNumbers import 'package:amplitude_flutter/amplitude.dart'; final Amplitude amplitude = Amplitude.getInstance(instanceName: "YOUR_INSTANCE_NAME"); final deviceId = await amplitude.getDeviceId(); final userId = await amplitude.getUserId(); try { - final builder = AdaptyProfileParametersBuilder() - ..setAmplitudeDeviceId(deviceId) - ..setAmplitudeUserId(userId); - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "amplitude_user_id", + value: userId, + ); + await Adapty().setIntegrationIdentifier( + key: "amplitude_device_id", + value: deviceId, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### AppMetrica 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppMetrica インテグレーションの SDK 設定](appmetrica#sdk-configuration)をご覧ください。 ```diff showLineNumbers import 'package:appmetrica_plugin/appmetrica_plugin.dart'; final deviceId = await AppMetrica.deviceId; if (deviceId != null) { try { - final builder = AdaptyProfileParametersBuilder() - ..setAppmetricaDeviceId(deviceId) - ..setAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID"); - - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "appmetrica_device_id", + value: deviceId, + ); + await Adapty().setIntegrationIdentifier( + key: "appmetrica_profile_id", + value: "YOUR_ADAPTY_CUSTOMER_USER_ID", + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } } ``` ### AppsFlyer 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppsFlyer インテグレーションの SDK 設定](appsflyer#connect-your-app-to-appsflyer)をご覧ください。 ```diff showLineNumbers import 'package:appsflyer_sdk/appsflyer_sdk.dart'; AppsflyerSdk appsflyerSdk = AppsflyerSdk(); appsflyerSdk.onInstallConversionData((data) async { try { final appsFlyerUID = await appsFlyerSdk.getAppsFlyerUID(); - await Adapty().updateAttribution( - data, - source: AdaptyAttributionSource.appsflyer, - networkUserId: appsFlyerUID, - ); + await Adapty().setIntegrationIdentifier( + key: "appsflyer_id", + value: appsFlyerUID, + ); + + await Adapty().updateAttribution(data, source: "appsflyer"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } }); appsflyerSdk.initSdk( registerConversionDataCallback: true, registerOnAppOpenAttributionCallback: true, registerOnDeepLinkingCallback: true, ); ``` ### Branch 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Branch インテグレーションの SDK 設定](branch#connect-your-app-to-branch)をご覧ください。 ```diff showLineNumbers FlutterBranchSdk.initSession().listen((data) async { try { + await Adapty().setIntegrationIdentifier( + key: "branch_id", + value: , + ); - await Adapty().updateAttribution(data, source: AdaptyAttributionSource.branch); + await Adapty().updateAttribution(data, source: "branch"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ); ``` ### Firebase and Google Analytics 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Firebase and Google Analytics インテグレーションの SDK 設定](firebase-and-google-analytics)をご覧ください。 ```diff showLineNumbers final appInstanceId = await FirebaseAnalytics.instance.appInstanceId; try { - final builder = AdaptyProfileParametersBuilder() - ..setFirebaseAppInstanceId(appInstanceId); - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "firebase_app_instance_id", + value: appInstanceId, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### Mixpanel 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Mixpanel インテグレーションの SDK 設定](mixpanel#sdk-configuration)をご覧ください。 ```diff showLineNumbers final mixpanel = await Mixpanel.init("Your Token", trackAutomaticEvents: true); final distinctId = await mixpanel.getDistinctId(); try { - final builder = AdaptyProfileParametersBuilder() - ..setMixpanelUserId(distinctId); - await Adapty().updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "mixpanel_user_id", + value: distinctId, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ### OneSignal 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[OneSignal インテグレーションの SDK 設定](onesignal#sdk-configuration)をご覧ください。 ```diff showLineNumbers OneSignal.shared.setSubscriptionObserver((changes) { final playerId = changes.to.userId; if (playerId != null) { - final builder = - AdaptyProfileParametersBuilder() - ..setOneSignalPlayerId(playerId); - // ..setOneSignalSubscriptionId(playerId); try { - Adapty().updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "one_signal_player_id", + value: playerId, + ); } on AdaptyError catch (adaptyError) { // handle error } catch (e) { // handle error } } }); ``` ### Pushwoosh 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Pushwoosh インテグレーションの SDK 設定](pushwoosh#sdk-configuration)をご覧ください。 ```diff showLineNumbers final hwid = await Pushwoosh.getInstance.getHWID; - final builder = AdaptyProfileParametersBuilder() - ..setPushwooshHWID(hwid); try { - await adapty.updateProfile(builder.build()); + await Adapty().setIntegrationIdentifier( + key: "pushwoosh_hwid", + value: hwid, + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` ## Observer モードの実装を更新する \{#update-observer-mode-implementation\} ペイウォールとトランザクションを紐付ける方法を更新してください。以前は `setVariationId` メソッドを使って `variationId` を割り当てていましたが、現在は新しい `reportTransaction` メソッドでトランザクションを記録する際に `variationId` を直接含めることができます。最終的なコード例については、[Observer モードでペイウォールを購入トランザクションに関連付ける](report-transactions-observer-mode-flutter)をご覧ください。 :::warning `reportTransaction` メソッドを使ってトランザクションを必ず記録してください。この手順を省略すると、Adapty はトランザクションを認識できず、アクセスレベルの付与、アナリティクスへの記録、インテグレーションへの送信がいずれも行われません。この手順は必須です! ::: ```diff showLineNumbers try { - await Adapty().setVariationId("YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID"); + // every time when calling transaction.finish() + await Adapty().reportTransaction( + "YOUR_TRANSACTION_ID", + variationId: "PAYWALL_VARIATION_ID", // optional + ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` --- # File: migration-to-flutter-sdk-v3 --- --- title: "Adapty Flutter SDK v3.0 への移行" description: "より良いパフォーマンスと新しいマネタイズ機能のために、Adapty Flutter SDK v3.0 に移行しましょう。" --- Adapty SDK v3.0 では、ペイウォールを作成するための新しいノーコードツール [Adapty ペイウォールビルダー](adapty-paywall-builder) がサポートされました。最大限の柔軟性と豊富なデザイン機能により、ペイウォールをより効果的かつ収益性の高いものにできます。 :::info AdaptyUI ライブラリは非推奨となり、AdaptySDK の一部として組み込まれました。 ::: ## AdaptyUI SDK の削除 \{#remove-adaptyu-sdk\} 1. AdaptyUI は Adapty SDK のモジュールになったため、`pubspec.yaml` ファイルから `adapty_ui_flutter` を削除してください。 ```diff showLineNumbers dependencies: + adapty_flutter: ^3.2.1 - adapty_flutter: ^2.10.3 - adapty_ui_flutter: ^2.1.3 ``` 2. 以下を実行します。 ```bash showLineNumbers title="Bash" flutter pub get ``` ## Adapty SDK の設定 \{#configure-adapty-sdks\} これまでは、Adapty SDK の設定に `Adapty-Info.plist` および `AndroidManifest.xml` ファイルを使用する必要がありました。 現在は、追加ファイルは不要です。代わりに、アクティベーション時に必要なパラメータをすべて指定できます。 Adapty SDK の設定は、通常アプリのライフサイクル開始時に一度だけ行います。 ### Adapty SDK の Adapty モジュールをアクティベートする \{#activate-adapty-module-of-adapty-sdk\} 1. アプリケーションから AdaptyUI SDK のインポートを次のように削除します。 ```diff showLineNumbers import 'package:adapty_flutter/adapty_flutter.dart'; - import 'package:adapty_ui_flutter/adapty_ui_flutter.dart'; ``` 2. Adapty SDK のアクティベーションを次のように更新します。 ```diff showLineNumbers try { - Adapty().activate(); + await Adapty().activate( + configuration: AdaptyConfiguration(apiKey: 'YOUR_API_KEY') + ..withLogLevel(AdaptyLogLevel.debug) + ..withObserverMode(false) + ..withCustomerUserId(null) + ..withIdfaCollectionDisabled(false) + ..withIpAddressCollectionDisabled(false), + ); } catch (e) { // handle the error } ``` パラメータ: | パラメータ | 必須/任意 | 説明 | | ----------------------------------- | --------- | ------------------------------------------------------------ | | **PUBLIC_SDK_KEY** | 必須 | Adapty のアプリ設定にある **Public SDK key** フィールドで確認できるキーです: [**App settings** -> **General** タブ -> **API keys** セクション](https://app.adapty.io/settings/general) | | **withLogLevel** | 任意 | Adapty はエラーやその他の重要な情報をログに記録し、アプリの動作状況を把握できるようにします。利用可能なレベルは以下のとおりです。
  • error: エラーのみがログに記録されます。
  • warn: エラーと、重大なエラーではないが注意が必要な SDK からのメッセージがログに記録されます。
  • info: エラー、警告、および各モジュールのライフサイクルなどの重要な情報メッセージがログに記録されます。
  • verbose: 関数呼び出し、API クエリなど、デバッグ時に役立つ追加情報がすべてログに記録されます。
| | **withObserverMode** | 任意 |

[オブザーバーモード](observer-vs-full-mode)を制御する真偽値です。購入とサブスクリプションの状態を自分で管理し、サブスクリプションイベントの送信と分析に Adapty を使用する場合は有効にしてください。

デフォルト値は `false` です。

🚧 オブザーバーモードで動作している場合、Adapty SDK はトランザクションをクローズしないため、自前で処理する必要があります。

| | **withCustomerUserId** | 任意 | 自社システムにおけるユーザーの識別子です。サブスクリプションおよび分析イベントに含めて送信し、イベントを正しいプロファイルに紐付けます。[**Profiles and Segments**](https://app.adapty.io/profiles/users) メニューで `customerUserId` によるユーザー検索も可能です。 | | **withIdfaCollectionDisabled** | 任意 |

IDFA の収集と共有を無効にするには `true` を設定します。

ユーザーの IP アドレス共有も無効になります。

デフォルト値は `false` です。

IDFA 収集の詳細については、[Analytics integration](analytics-integration#disable-collection-of-advertising-identifiers) セクションをご参照ください。

| | **withIpAddressCollectionDisabled** | 任意 |

ユーザーの IP アドレスの収集と共有を無効にするには `true` を設定します。

デフォルト値は `false` です。

| ### Adapty SDK の AdaptyUI モジュールをアクティベートする \{#activate-adaptyu-module-of-adapty-sdk\} AdaptyUI モジュールの設定が必要なのは、[ペイウォールビルダー](adapty-paywall-builder)を使用する予定がある場合のみです。 ```dart showLineNumbers title="Dart" try { final mediaCache = AdaptyUIMediaCacheConfiguration( memoryStorageTotalCostLimit: 100 * 1024 * 1024, // 100MB memoryStorageCountLimit: 2147483647, // 2^31 - 1, max int value in Dart diskStorageSizeLimit: 100 * 1024 * 1024, // 100MB ); await AdaptyUI().activate( configuration: AdaptyUIConfiguration(mediaCache: mediaCache), observer: , ); } catch (e) { // handle the error } ``` AdaptyUI の設定はオプションであり、設定なしで AdaptyUI モジュールをアクティベートすることも可能です。ただし、設定を使用する場合はすべてのパラメータが必須となります。 パラメータ: | パラメータ | 必須/任意 | 説明 | | :------------------------------ | :-------- | :----------------------------------------------------------- | | **memoryStorageTotalCostLimit** | 必須 | ストレージの合計コスト上限(バイト単位)。 | | **memoryStorageCountLimit** | 必須 | メモリストレージのアイテム数上限。 | | **diskStorageSizeLimit** | 必須 | ディスク上のストレージファイルサイズ上限(バイト単位)。0 は上限なしを意味します。 | --- # End of Documentation _Generated on: 2026-07-24T13:00:57.659Z_ _Successfully processed: 44/44 files_