# Adapty Documentation (Full Content) > Complete documentation content across all platforms. Locale: ja Generated on: 2026-07-24T13:00:57.864Z --- # ANDROID - 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.583Z Total files: 41 --- # File: sdk-installation-android --- --- title: "Android SDKのインストールと設定" description: "サブスクリプションアプリ向けにAndroidへAdapty SDKをインストールするステップバイステップガイド。" --- Adapty SDK には、モバイルアプリへのシームレスな統合を実現する2つの主要モジュールが含まれています。 - **Core Adapty**: アプリで Adapty を正しく動作させるために必要な、必須の SDK です。 - **AdaptyUI**: コードなしでクロスプラットフォームのペイウォールを簡単に作成できる [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なモジュールです。AdaptyUI はコアモジュールとともに自動的に有効化されます。 :::tip Adapty SDK がモバイルアプリにどのように組み込まれるか、実際の例を見てみませんか?ペイウォールの表示、購入処理など基本的な機能を含むフルセットアップを確認できる[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)をご覧ください。 ::: ## 要件 \{#requirements\} 最低 SDK 要件: `minSdkVersion 21` :::info Adapty は Google Play Billing Library 8.x まで対応しています。デフォルトでは 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\} 依存関係の設定方法を選択してください: - 標準の Gradle:**モジュールレベル**の `build.gradle` に依存関係を追加する - プロジェクトで `.gradle.kts` ファイルを使用している場合は、モジュールレベルの `build.gradle.kts` に依存関係を追加する - バージョンカタログを使用している場合は、`libs.versions.toml` ファイルに依存関係を追加し、`build.gradle.kts` で参照する [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Android.svg?style=flat&logo=android)](https://github.com/adaptyteam/AdaptySDK-Android/releases) ```groovy showLineNumbers dependencies { ... implementation platform('io.adapty:adapty-bom:') implementation 'io.adapty:android-sdk' // Only add this line if you plan to use Paywall Builder implementation 'io.adapty:android-ui' } ``` ```kotlin showLineNumbers dependencies { ... implementation(platform("io.adapty:adapty-bom:")) implementation("io.adapty:android-sdk") // ペイウォールビルダーを使用する場合のみ、この行を追加してください: implementation("io.adapty:android-ui") } ``` ```toml showLineNumbers //libs.versions.toml [versions] .. adaptyBom = "" [libraries] .. adapty-bom = { module = "io.adapty:adapty-bom", version.ref = "adaptyBom" } adapty = { module = "io.adapty:android-sdk" } // Only add this line if you plan to use Paywall Builder: adapty-ui = { module = "io.adapty:android-ui" } //module-level build.gradle.kts dependencies { ... implementation(platform(libs.adapty.bom)) implementation(libs.adapty) // Only add this line if you plan to use Paywall Builder: implementation(libs.adapty.ui) } ``` 依存関係が解決されない場合は、Gradle スクリプトに `mavenCentral()` が含まれていることを確認してください。
追加方法の手順 プロジェクトの `settings.gradle` に `dependencyResolutionManagement` がない場合は、トップレベルの `build.gradle` のリポジトリの末尾に以下を追加してください: ```groovy showLineNumbers title="top-level build.gradle" allprojects { repositories { ... mavenCentral() } } ``` それ以外の場合は、`settings.gradle` の `dependencyResolutionManagement` セクションの `repositories` に以下を追加してください: ```groovy showLineNumbers title="settings.gradle" dependencyResolutionManagement { ... repositories { ... mavenCentral() } } ```
:::important Adapty Android SDK 4.0 はプレリリース版です。Gradle は動的バージョン範囲(`+` や `latest.release` など)でプレリリース版を自動選択しません。そのため、正確なバージョンを明示的に指定する必要があります。`adapty-bom` のバージョンに 4.0 プレリリース版を設定してください。例: `io.adapty:adapty-bom:4.0.0-beta.2`、または `libs.versions.toml` では `adaptyBom = "4.0.0-beta.2"` のように記述します。BOM が対応する `android-sdk` と `android-ui` のバージョンを自動的に解決します。詳しくは [Adapty Android SDK を v4 に移行する](migration-to-android-sdk-v4) をご覧ください。 ::: ## Adapty SDK の Adapty モジュールを有効化する \{#activate-adapty-module-of-adapty-sdk\} ### 基本的なセットアップ \{#basic-setup\} アプリのコードで 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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 ```kotlin showLineNumbers // In your Application class class MyApplication : Application() { override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") .build() ) } } ``` ```java showLineNumbers // In your Application class public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Adapty.activate( getApplicationContext(), new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .build() ); } } ``` :::important 他の Adapty SDK メソッドを呼び出す前に、`Adapty.activate` の完了を待ってください。完全な順序については、[Android SDK の呼び出し順序](android-sdk-call-order)を参照してください。 ::: 次に、アプリにペイウォールを設定します。 - [ペイウォールビルダー](adapty-paywall-builder)を使用している場合は、[ペイウォールビルダーのクイックスタート](android-quickstart-paywalls)に従ってください。 - 独自のペイウォール UI を構築している場合は、[カスタムペイウォールのクイックスタート](android-quickstart-manual)を参照してください。 ## Adapty SDK の AdaptyUI モジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する予定の場合、AdaptyUI モジュールが必要です。コアモジュールを有効化すると自動的に有効化されるため、追加の操作は不要です。 ## Proguard を設定する \{#configure-proguard\} 本番環境でアプリを公開する前に、Proguard の設定に `-keep class com.adapty.** { *; }` を追加してください。 ## オプションの設定 \{#optional-setup\} ### ログ記録 \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty はエラーやその他の重要な情報をログに記録し、何が起きているかを把握できるようにします。以下のログレベルが利用可能です: | レベル | 説明 | | :----------------------- | :------------------------------------------------------------------------------------------------------------------------ | | `AdaptyLogLevel.NONE` | 何もログに記録されません。デフォルト値 | | `AdaptyLogLevel.ERROR` | エラーのみがログに記録されます | | `AdaptyLogLevel.WARN` | エラーと、致命的なエラーではないものの注意が必要なSDKからのメッセージがログに記録されます。 | | `AdaptyLogLevel.INFO` | エラー、警告、および各種情報メッセージがログに記録されます。 | | `AdaptyLogLevel.VERBOSE` | 関数呼び出しやAPIクエリなど、デバッグ時に役立つ可能性のある追加情報がすべてログに記録されます。 | Adapty を設定する前に、アプリでログレベルを設定できます。 ```kotlin showLineNumbers Adapty.logLevel = AdaptyLogLevel.VERBOSE //recommended for development and the first production release ``` ```java showLineNumbers Adapty.setLogLevel(AdaptyLogLevel.VERBOSE); //recommended for development and the first production release ``` #### ログシステムのメッセージをリダイレクトする \{#redirect-the-logging-system-messages\} 何らかの理由で Adapty からのメッセージを自分のシステムに送信したり、ファイルに保存したい場合は、デフォルトの動作を上書きできます。 ```kotlin showLineNumbers Adapty.setLogHandler { level, message -> //handle the log } ``` ```java showLineNumbers Adapty.setLogHandler((level, message) -> { //handle the log }); ``` ### データポリシー \{#data-policies\} Adapty は、明示的に送信しない限りユーザーの個人データを保存しません。ただし、ストアや国のガイドラインに準拠するために、追加のデータセキュリティポリシーを実装することもできます。 #### IPアドレスの収集と共有を無効にする \{#disable-ip-address-collection-and-sharing\} Adapty モジュールを有効化する際に、`ipAddressCollectionDisabled` を `true` に設定することで、ユーザーの IP アドレスの収集と共有を無効にできます。デフォルト値は `false` です。 このパラメータを使用すると、ユーザーのプライバシーを保護したり、地域のデータ保護規制(GDPRやCCPAなど)に準拠したり、IPアドレスベースの機能がアプリに不要な場合に不必要なデータ収集を減らすことができます。 ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withIpAddressCollectionDisabled(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withIpAddressCollectionDisabled(true) .build(); ``` #### 広告 ID(Ad ID)の収集と共有を無効にする \{#disable-advertising-id-ad-id-collection-and-sharing\} Adapty モジュールを有効にする際、`adIdCollectionDisabled` を `true` に設定すると、ユーザーの[広告 ID](https://support.google.com/googleplay/android-developer/answer/6048248) の収集を無効にできます。デフォルト値は `false` です。 このパラメータは、Play Storeポリシーへの準拠、広告ID権限プロンプトの表示回避、またはアプリが広告IDを使用したアトリビューションや分析を必要としない場合に使用してください。 ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withAdIdCollectionDisabled(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withAdIdCollectionDisabled(true) .build(); ``` #### AdaptyUI のメディアキャッシュ設定をカスタマイズする \{#set-up-media-cache-configuration-for-adaptyui\} デフォルトでは、AdaptyUI はパフォーマンス向上とネットワーク使用量削減のためにメディア(画像や動画など)をキャッシュします。カスタム設定を指定することで、キャッシュの動作を変更できます。 `AdaptyUI.configureMediaCache` を使用して、デフォルトのキャッシュサイズと有効期間を上書きできます。これはオプションです。このメソッドを呼び出さない場合、デフォルト値(ディスクサイズ 100MB、有効期間 7 日)が使用されます。 ```kotlin showLineNumbers val cacheConfig = MediaCacheConfiguration.Builder() .overrideDiskStorageSizeLimit(200L * 1024 * 1024) // 200 MB .overrideDiskCacheValidityTime(3.days) .build() AdaptyUI.configureMediaCache(cacheConfig) ``` ```java showLineNumbers MediaCacheConfiguration cacheConfig = new MediaCacheConfiguration.Builder() .overrideDiskStorageSizeLimit(200L * 1024 * 1024) // 200 MB .overrideDiskCacheValidityTime(TimeInterval.days(3)) .build(); AdaptyUI.configureMediaCache(cacheConfig); ``` **パラメーター:** | パラメーター | 必須/任意 | 説明 | |-------------------------|----------|-----------------------------------------------------------------------------| | diskStorageSizeLimit | 任意 | ディスク上のキャッシュの合計サイズ(バイト単位)。デフォルトは 100 MB です。 | | diskCacheValidityTime | 任意 | キャッシュされたファイルが有効とみなされる期間。デフォルトは 7 日間です。 | :::tip ランタイムで `AdaptyUI.clearMediaCache(strategy)` を使用してメディアキャッシュをクリアできます。`strategy` には `CLEAR_ALL` または `CLEAR_EXPIRED_ONLY` を指定できます。 ::: ### 難読化されたアカウントIDの設定 \{#set-obfuscated-account-ids\} Google Playでは、ユーザーのプライバシーとセキュリティを強化するために、特定のユースケースで難読化されたアカウントIDが必要です。これらのIDはGoogle Playが購入を識別するのに役立ちながら、ユーザー情報を匿名に保ちます。特に不正防止や分析において重要です。 アプリが機密性の高いユーザーデータを扱う場合、または特定のプライバシー規制への準拠が求められる場合は、これらのIDを設定する必要があります。難読化されたIDを使用することで、Google Playは実際のユーザー識別子を公開することなく購入を追跡できます。 ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObfuscatedAccountId("YOUR_OBFUSCATED_ACCOUNT_ID") .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObfuscatedAccountId("YOUR_OBFUSCATED_ACCOUNT_ID") .build(); ``` ### カスタムプロセスでAdaptyを実行する \{#run-adapty-in-a-custom-process\} デフォルトでは、Adaptyはアプリのメインプロセスでのみ動作します。 アプリが複数のプロセスを使用している場合、Adaptyの初期化は1回だけ行ってください。複数回初期化すると、予期しない動作が発生する可能性があります。 別のプロセスでAdaptyを実行する必要がある場合は、設定で指定してください: ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withProcessName(":custom") .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withProcessName(":custom") .build(); ``` この値を設定せずに別のプロセスで Adapty を有効化しようとすると、SDK は警告をログに記録して有効化をスキップします。 ### ローカルアクセスレベルを有効にする \{#enable-local-access-levels\} デフォルトでは、Android での[ローカルアクセスレベル](local-access-levels)は無効になっています。有効にするには、`withLocalAccessLevelAllowed` を `true` に設定してください: ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withLocalAccessLevelAllowed(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withLocalAccessLevelAllowed(true) .build(); ``` ## トラブルシューティング \{#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/sample_data_extraction_rules) is also present at [com.other.sdk:library:1.0.0] value=(@xml/other_sdk_data_extraction_rules)` これを解決するには、以下の対応が必要です。 - マニフェストマージャーに、バックアップ関連の属性にはアプリの値を使用するよう指示する。 - AdaptyやほかのSDKのバックアップルールを、単一のXMLファイル(Android 12以降の場合はファイルのペア)にまとめる。 #### 1. マニフェストに `tools` 名前空間を追加する \{#1-add-the-tools-namespace-to-your-manifest\} まだ追加していない場合は、ルートの `` タグに `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\} `app/src/main/res/xml/` 配下に、Adapty のルールと他の SDK のルールを組み合わせた 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" ``` この設定により: - Adaptyのバックアップ除外設定(`AdaptySDKPrefs.xml`)が保持されます。 - 他のSDKの除外設定(例:`appsflyer-data`)も適用されます。 - マニフェストマージャーはアプリの設定を使用し、バックアップ属性の競合によるエラーが発生しなくなります。 #### 別のアプリから戻った後に購入が失敗する \{#purchases-fail-after-returning-from-another-app\} 購入フローを開始する Activity が非デフォルトの `launchMode` を使用している場合、ユーザーが Google Play、銀行アプリ、またはブラウザから戻ったときに Android が Activity を誤って再生成または再利用することがあります。これにより、購入結果が失われたり、キャンセルとして扱われたりする可能性があります。 購入が正しく機能するようにするには、購入フローを開始する Activity に `standard` または `singleTop` の起動モードのみを使用し、それ以外のモードは避けてください。 `AndroidManifest.xml` で、購入フローを開始する Activity が `standard` または `singleTop` に設定されていることを確認してください: ```xml ``` --- # File: android-quickstart-paywalls --- --- title: "Android SDKでFlow Builderを使ったアプリ内課金の有効化" description: "Adapty Flow Builderを使ったアプリ内課金の設定クイックスタートガイド。" --- アプリ内課金を有効化するには、3つの重要なコンセプトを理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**フロー**](adapty-flow-builder) – プロダクトをユーザーに提示するための画面シーケンスで、ノーコードのフロービルダーで作成します。SDK は `getFlow` を使って取得します。独自のコードでUIを構築したい場合はペイウォールを使ってください — [ペイウォールを手動で実装する](android-quickstart-manual)をご覧ください。 - [**プレースメント**](placements) – アプリ内でフローを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでフローをプレースメントに紐付けておき、コード内でプレースメント ID を使ってリクエストします。これにより、A/B テストの実行や、ユーザーごとに異なるフローの表示が簡単に行えます。 Adapty では、アプリで購入機能を有効にする方法を3つ提供しています。アプリの要件に応じていずれかを選択してください。 | 実装方法 | 複雑さ | 使用場面 | |---|---|---| | Adapty フロービルダー | ✅ 簡単 | [ノーコードビルダーで購入可能な完全なフローを作成します](quickstart-paywalls)。Adapty が自動的にレンダリングし、購入フロー・レシート検証・サブスクリプション管理をすべて裏側で処理します。 | | 手動作成のペイウォール | 🟡 中程度 | アプリのコードでペイウォール UI を実装しますが、プロダクト提供の柔軟性を保つために Adapty からフローオブジェクトを取得します。[ガイド](android-quickstart-manual)を参照してください。 | | オブザーバーモード | 🔴 難しい | すでに独自の購入処理インフラがあり、それを引き続き使用したい場合に選択します。オブザーバーモードには Adapty における制限があります。[記事](observer-vs-full-mode)を参照してください。 | :::important **以下の手順では、Adapty Flow Builder で作成したフローの実装方法を説明します。** ペイウォールの UI を自分でビルドしたい場合は、[ペイウォールを手動で実装する](android-quickstart-manual)をご覧ください。 ::: Adapty Flow Builder で作成したフローをアプリに表示するには、以下の手順だけで対応できます。 1. **フローを取得する**: Adapty からフローを取得します。 2. **表示する(購入処理は Adapty が担当)**: アプリにビューを表示します。 3. **ボタンアクションを処理する**: ユーザーの操作に対するアプリの反応を設定します。たとえば、リンクを開いたり、ユーザーがボタンをタップしたときにフローを閉じたりします。 ## 始める前に \{#before-you-start\} 始める前に、以下の手順を完了してください: 1. Adapty ダッシュボードで[アプリを Google Play に接続する](initial-android)。 2. Adapty で[プロダクトを作成する](create-product)。 3. [フローを作成してプロダクトを追加する](create-paywall)。 4. [プレースメントを作成してフローを追加する](create-placement)。 5. アプリのコードに[Adapty SDK をインストールして有効化する](sdk-installation-android)。このガイドでは Adapty Android 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` オブジェクトを取得し、ビュー設定が含まれているか確認します。 2. `getFlowConfiguration` メソッドを使ってビュー設定を取得します。ビュー設定には、フローを表示するために必要な UI 要素とスタイリング情報が含まれています。 :::important ビュー設定を取得するには、Flow Builder の **Show on device** トグルをオンにする必要があります。オンにしないと、空のビュー設定が返され、フローが表示されません。 ::: ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> if (result is AdaptyResult.Success) { val flow = result.value if (!flow.hasViewConfiguration) { return@getFlow } AdaptyUI.getFlowConfiguration(flow) { configResult -> if (configResult is AdaptyResult.Success) { val flowConfiguration = configResult.value } } } } ``` ```java showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); if (!flow.hasViewConfiguration()) { return; } AdaptyUI.getFlowConfiguration(flow, configResult -> { if (configResult instanceof AdaptyResult.Success) { AdaptyUI.FlowConfiguration flowConfiguration = ((AdaptyResult.Success) configResult).getValue(); // 読み込んだ設定を使用する } }); } }); ``` ## 2. フローを表示する \{#display-the-flow\} フローの設定が完了したら、数行追加するだけでフローを表示できます。 デバイス画面にビジュアルフローを表示するには、まず設定を行う必要があります。そのためには、`AdaptyUI.getFlowView()` メソッドを呼び出すか、`AdaptyFlowView` を直接作成してください: ```kotlin showLineNumbers val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, null, // products = null means auto-fetch eventListener, ) ``` ```kotlin showLineNumbers val flowView = AdaptyFlowView(activity) // or retrieve it from xml ... with(flowView) { showFlow( flowConfiguration, null, // products = null means auto-fetch eventListener, ) } ``` ```java showLineNumbers AdaptyFlowView flowView = AdaptyUI.getFlowView( activity, flowConfiguration, null, // products = null means auto-fetch eventListener ); ``` ```java showLineNumbers AdaptyFlowView flowView = new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml ... flowView.showFlow(flowConfiguration, products, eventListener); ``` ```xml showLineNumbers ``` ビューが正常に作成されたら、ビュー階層に追加してデバイスの画面に表示できます。 :::tip フローの表示方法の詳細については、[ガイド](android-present-paywalls)をご覧ください。 ::: ## 3. ボタンのアクションを処理する \{#handle-button-actions\} ユーザーがフロー内のボタンをタップすると、Android SDK は購入、リストア、フローのクローズ、リンクの開封を自動的に処理します。 ただし、カスタムIDまたは事前定義済みIDを持つボタンは、コード上でアクションを処理する必要があります。また、デフォルトの動作を上書きしたい場合もあるでしょう。 たとえば、以下はクローズボタンのデフォルト動作です。コードに追加する必要はありませんが、必要な場合にどのように実装するかを確認できます。 :::tip ボタンの[アクション](android-handle-paywall-actions)と[イベント](android-handling-events)の処理方法については、ガイドをご覧ください。 ::: ```kotlin showLineNumbers title="Kotlin" override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior } } ``` ```java showLineNumbers @Override public void onActionPerformed(@NonNull AdaptyUI.Action action, @NonNull Context context) { if (action instanceof AdaptyUI.Action.Close) { if (context instanceof Activity) { ((Activity) context).onBackPressed(); } } } ``` ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備が整いました。[Google Play Storeでのテスト購入](testing-on-android)を行い、ペイウォールからテスト購入を完了できることを確認してください。 次に、適切なユーザーにペイウォールを表示したり有料機能へのアクセスを付与したりするために、[ユーザーのアクセスレベルを確認する](android-check-subscription-status)必要があります。 ## 完全な例 \{#full-example\} これらのすべてのステップをアプリに統合する方法を示します。 ```kotlin showLineNumbers title="Kotlin" class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Adapty.getFlow("YOUR_PLACEMENT_ID") { flowResult -> if (flowResult is AdaptyResult.Success) { val flow = flowResult.value if (!flow.hasViewConfiguration) { // Use custom logic return@getFlow } AdaptyUI.getFlowConfiguration(flow) { configResult -> if (configResult is AdaptyResult.Success) { val flowConfiguration = configResult.value val flowView = AdaptyUI.getFlowView( this, flowConfiguration, null, // products = null means auto-fetch object : AdaptyFlowDefaultEventListener() { override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.Close -> { (context as? Activity)?.onBackPressed() } } } } ) setContentView(flowView) } } } } } } ``` ```java showLineNumbers public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Adapty.getFlow("YOUR_PLACEMENT_ID", flowResult -> { if (flowResult instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) flowResult).getValue(); if (!flow.hasViewConfiguration()) { // Use custom logic return; } AdaptyUI.getFlowConfiguration(flow, configResult -> { if (configResult instanceof AdaptyResult.Success) { AdaptyUI.FlowConfiguration flowConfiguration = ((AdaptyResult.Success) configResult).getValue(); AdaptyFlowView flowView = AdaptyUI.getFlowView( this, flowConfiguration, null, // products = null means auto-fetch new AdaptyFlowDefaultEventListener() { @Override public void onActionPerformed(@NonNull AdaptyUI.Action action, @NonNull Context context) { if (action instanceof AdaptyUI.Action.Close) { if (context instanceof Activity) { ((Activity) context).onBackPressed(); } } } } ); setContentView(flowView); } }); } }); } } ``` --- # File: android-check-subscription-status --- --- title: "Android SDKでサブスクリプションステータスを確認する" description: "AdaptyでAndroidアプリのサブスクリプションステータスを確認する方法を学びましょう。" --- 有料コンテンツへのアクセス許可やペイウォールの表示を判断するには、プロファイル内の[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態にアクセスして、ペイウォールを表示するか有料機能へのアクセスを許可するかを決める方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ペイウォールを表示するか有料コンテンツを見せるかを判断するとき、プロファイルの[アクセスレベル](access-level)を確認します。方法は2つあります: - 最新のプロファイルデータがすぐに必要な場合(アプリ起動時など)や強制更新したい場合は、`getProfile` を呼び出す。 - **プロファイルの自動更新**を設定して、サブスクリプションステータスが変わるたびに自動でリフレッシュされるローカルコピーを保持する。 ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得する最もシンプルな方法は、`getProfile` メソッドを使ってプロファイルにアクセスすることです: ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); // check the access } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` ### サブスクリプション更新を監視する \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取るには: 1. `Adapty.setOnProfileUpdatedListener()` を使ってプロファイルの変更を監視する。ユーザーのサブスクリプションステータスが変わると、Adaptyが自動でこのメソッドを呼び出します。 2. このメソッドが呼び出されたら更新されたプロファイルデータを保存し、追加のネットワークリクエストなしにアプリ全体で利用できるようにする。 ```kotlin class SubscriptionManager { private var currentProfile: AdaptyProfile? = null init { // Listen for profile updates Adapty.setOnProfileUpdatedListener { profile -> currentProfile = profile // Update UI, unlock content, etc. } } // Use stored profile instead of calling getProfile() fun hasAccess(): Boolean { return currentProfile?.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true } } ``` ```java public class SubscriptionManager { private AdaptyProfile currentProfile; public SubscriptionManager() { // Listen for profile updates Adapty.setOnProfileUpdatedListener(profile -> { this.currentProfile = profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() public boolean hasAccess() { if (currentProfile == null) { return false; } AdaptyAccessLevel premiumAccess = currentProfile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); return premiumAccess != null && premiumAccess.isActive(); } } ``` :::note Adaptyはアプリ起動時にプロファイル更新リスナーを自動で呼び出し、デバイスがオフラインでもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールのロジックを連携させる \{#connect-profile-with-paywall-logic\} ペイウォールの表示や有料機能へのアクセス許可をすぐに判断する必要がある場合、ユーザーのプロファイルを直接確認できます。このアプローチは、アプリ起動時、プレミアムセクションへの遷移時、特定コンテンツの表示前など、さまざまなシナリオで役立ちます。 ```kotlin private fun initializePaywall() { loadPaywall { paywallView -> checkAccessLevel { result -> when (result) { is AdaptyResult.Success -> { if (!result.value && paywallView != null) { setContentView(paywallView) // Show paywall if no access } } is AdaptyResult.Error -> { if (paywallView != null) { setContentView(paywallView) // Show paywall if access check fails } } } } } } private fun checkAccessLevel(callback: ResultCallback) { Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val hasAccess = result.value.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true callback.onResult(AdaptyResult.Success(hasAccess)) } is AdaptyResult.Error -> { callback.onResult(AdaptyResult.Error(result.error)) } } } } ``` ```java private void initializePaywall() { loadPaywall(paywallView -> { checkAccessLevel(result -> { if (result instanceof AdaptyResult.Success) { boolean hasAccess = ((AdaptyResult.Success) result).getValue(); if (!hasAccess && paywallView != null) { setContentView(paywallView); // Show paywall if no access } } else if (result instanceof AdaptyResult.Error) { if (paywallView != null) { setContentView(paywallView); // Show paywall if access check fails } } }); }); } private void checkAccessLevel(ResultCallback callback) { Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); AdaptyAccessLevel premiumAccess = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); boolean hasAccess = premiumAccess != null && premiumAccess.isActive(); callback.onResult(AdaptyResult.success(hasAccess)); } else if (result instanceof AdaptyResult.Error) { callback.onResult(AdaptyResult.error(((AdaptyResult.Error) result).getError())); } }); } ``` ## 次のステップ \{#next-steps\} サブスクリプションステータスの確認方法を習得したら、次は[ユーザープロファイルの操作](android-quickstart-identify)を学び、ユーザーが購入済みのコンテンツにアクセスできるようにしましょう。 --- # File: android-quickstart-identify --- --- title: "Android SDKでのユーザー識別" description: "Androidアプリにおける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) ユーザーがアプリ起動後にサインインする場合、認証時にカスタマーユーザーIDを指定して`identify()`を呼び出します。 - [**SDK有効化時:**](#during-the-sdk-activation) アプリ起動時にすでにカスタマーユーザーIDが保存されている場合、`activate()`を呼び出す際に一緒に送信します。 :::important デフォルトでは、Adaptyが別のカスタマーユーザーIDに現在関連付けられているカスタマーユーザーIDからの購入を受け取った場合、アクセスレベルは共有され、両方のプロファイルが有料アクセスを持ちます。この設定を変更して、有料アクセスを一方のプロファイルから別のプロファイルに移行したり、共有を完全に無効にしたりすることができます。詳細は[こちらの記事](general#6-sharing-paid-access-between-user-accounts)をご覧ください。 ::: ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(例:ログインまたはサインアップ後)、`identify`メソッドを使用してカスタマーユーザーIDを設定します。 - このカスタマーユーザーIDを**まだ使用したことがない場合**、Adaptyは自動的に現在のプロファイルにリンクします。 - このカスタマーユーザーIDを**以前にユーザーの識別に使用したことがある場合**、Adaptyはそのカスタマーユーザーに紐づくプロファイルに切り替えます。 :::important カスタマーユーザーIDは各ユーザーに対して一意である必要があります。パラメータの値をハードコードすると、すべてのユーザーが同一人物とみなされます。 ::: 他のSDKメソッドを呼び出す前に、`identify`の完了コールバックが呼ばれるまで待機してください。同時に呼び出すと、識別済みプロファイルではなく匿名プロファイルに処理が紐づく場合があります。詳細は[Android SDKの呼び出し順序](android-sdk-call-order)をご覧ください。 ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` ### SDK有効化時 \{#during-the-sdk-activation\} SDKを有効化する時点でカスタマーユーザーIDが分かっている場合、`identify`を別途呼び出す代わりに、`activate`メソッドに含めて送信できます。 カスタマーユーザーIDが分かっていても有効化後に設定する場合、有効化時にAdaptyは新しい匿名プロファイルを作成し、`identify`を呼び出した後にのみ既存のプロファイルに切り替えます。 既存のカスタマーユーザーID(以前に使用したもの)でも新しいものでも渡すことができます。新しいカスタマーユーザーIDを渡した場合、有効化時に作成された新しいプロファイルが自動的にそのカスタマーユーザーIDにリンクされます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスのダッシュボードに影響しません。インストールはデバイスIDに基づいてカウントされるためです。 デバイスIDはストアからの端末へのアプリの単一インストールを表し、アプリを再インストールした場合にのみ再生成されます。 初回インストールか再インストールか、または既存のカスタマーユーザーIDが使用されているかどうかは関係ありません。 プロファイルの作成(SDKの有効化またはログアウト時)、ログイン、アプリの再インストールを伴わないアップグレードでは、追加のインストールイベントは発生しません。 デバイスではなく一意のユーザーに基づいてインストールをカウントしたい場合は、**App settings**から[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. .build(); ``` ### ユーザーのログアウト \{#log-users-out\} ユーザーをログアウトさせるボタンがある場合は、`logout`メソッドを使用してください。 :::important ユーザーをログアウトすると、そのユーザー用に新しい匿名プロファイルが作成されます。 ::: ```kotlin showLineNumbers Adapty.logout { error -> if (error == null) { // successful logout } } ``` ```java showLineNumbers Adapty.logout(error -> { if (error == null) { // successful logout } }); ``` :::info ユーザーをアプリに再ログインさせるには、`identify`メソッドを使用してください。 ::: ### ログインなしでの購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリへのログイン前後どちらでも購入できる場合、ログイン後もアクセスが維持されるようにする必要があります。 1. ログアウト状態のユーザーが購入を行うと、Adaptyはその購入を匿名プロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルへの切り替えを行います。 - 新しいカスタマーユーザーIDの場合(例:登録前に購入が行われた場合)、Adaptyは現在のプロファイルにカスタマーユーザーIDを割り当てるため、すべての購入履歴が維持されます。 - 既存のカスタマーユーザーIDの場合(そのカスタマーユーザーIDがすでにプロファイルにリンクされている場合)、プロファイル切り替え後に実際のアクセスレベルを取得する必要があります。識別後すぐに[`getProfile`](android-check-subscription-status)を呼び出すか、[プロファイルの更新をリッスン](android-check-subscription-status)してデータが自動的に同期されるようにすることができます。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内課金のロジックを実装できました!アプリのマネタイズが順調に進むことを願っています! Adaptyをさらに活用するために、以下のトピックもご覧ください。 - [**テスト**](troubleshooting-test-purchases): すべてが期待通りに動作することを確認する - [**オンボーディング**](android-onboardings): オンボーディングでユーザーを引き付け、リテンションを高める - [**インテグレーション**](configuration): マーケティングアトリビューションや分析サービスとたった1行のコードで連携する - [**カスタムプロファイル属性の設定**](android-setting-user-attributes): ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/Bテストを実施したり、ユーザーごとに異なるペイウォールを表示したりする --- # File: adapty-sdk-integration-skill-android --- --- title: "SDKインテグレーションスキルを使ってAdaptyをAndroidアプリに統合する" description: "adapty-sdk-integrationスキルを使って、AIコーディングツールでAdapty SDKをAndroidアプリにエンドツーエンドで統合しましょう。" --- :::important このスキルはベータ版です。処理が止まったり予期しない動作をした場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor-android)をご利用ください。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-android --- --- title: "AIを使ってAndroidアプリにAdaptyを統合する" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使って、AndroidアプリにAdaptyをステップバイステップで統合するガイド。" --- このガイドでは、AIコーディングツールを使って、AdaptyをAndroidアプリへ段階的に統合していきます。適切な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** へ移動します。購入機能を動かすには必須です。 [Google Playを接続する](integrate-payments) 2. **Public SDKキーをコピーする**: Adapty ダッシュボードで **App settings → General** へ移動し、**API keys** セクションを確認します。コード内では、Adaptyの設定ビルダーに渡す文字列として使用します。 3. **プロダクトを1つ以上作成する**: Adapty ダッシュボードの **Products** ページへ移動します。プロダクトはコード内で直接参照しません — Adatyはペイウォールを通じてプロダクトを届けます。 [プロダクトを追加する](quickstart-products) 4. **ペイウォールとプレースメントを作成する**: Adapty ダッシュボードで **Paywalls** ページにペイウォールを作成し、**Placements** ページでプレースメントに割り当てます。コード内では、`Adapty.getPaywall("YOUR_PLACEMENT_ID")` に渡す文字列がプレースメントIDです。 [ペイウォールを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**: Adapty ダッシュボードで **Products** ページのプロダクトごとに設定します。コード内では `profile.accessLevels["premium"]?.isActive` でチェックする文字列です。デフォルトの `premium` アクセスレベルはほとんどのアプリで機能します。プロダクトによって(例:`basic` プランと `pro` プランなど)ユーザーがアクセスできる機能が異なる場合は、コーディングを始める前に[アクセスレベルを追加作成](assigning-access-level-to-a-product)してください。 :::tip 以上の5つが揃ったら、コードを書く準備完了です。「Public SDKキーはX、プレースメントIDはY」とLLMに伝えると、正しい初期化コードとペイウォール取得コードを生成してもらえます。 ::: ### 準備ができたら設定するもの \{#set-up-when-ready\} コーディング開始に必須ではありませんが、統合が進んだ段階で必要になります。 - **A/Bテスト**: **Placements** ページで設定します。コードの変更は不要です。 [A/Bテスト](ab-tests) - **追加のペイウォールとプレースメント**: 異なるプレースメントIDで `getPaywall` 呼び出しを追加します。 - **アナリティクス連携**: **Integrations** ページで設定します。連携先によって手順が異なります。[アナリティクス連携](analytics-integration)・[アトリビューション連携](attribution-integration)を参照してください。 ## LLMにAdaptyドキュメントを渡す \{#feed-adapty-docs-to-your-llm\} ### Context7を使う(推奨) \{#use-context7-recommended\} [Context7](https://context7.com) は、LLMに最新のAdaptyドキュメントへの直接アクセスを提供するMCPサーバーです。質問内容に基づいて適切なドキュメントを自動的に取得するため、URLを手動で貼り付ける必要がありません。 Context7は **Cursor**、**Claude Code**、**Windsurf**、その他MCP対応ツールで動作します。セットアップするには以下を実行してください: ``` npx ctx7 setup ``` エディタを自動検出してContext7サーバーを設定します。手動セットアップの方法は [Context7 GitHubリポジトリ](https://github.com/upstash/context7)をご覧ください。 設定完了後、プロンプトでAdaptyライブラリを参照できます: ``` Use the adaptyteam/adapty-docs library to look up how to install the Android SDK ``` :::warning Context7を使えばドキュメントのリンクを手動で貼り付ける必要はなくなりますが、実装の順序は重要です。すべてが正しく動作するよう、以下の[実装ウォークスルー](#implementation-walkthrough)をステップごとに進めてください。 ::: ### プレーンテキストドキュメントを使う \{#use-plain-text-docs\} AdaptyのドキュメントはプレーンテキストのMarkdownとして取得できます。URLの末尾に `.md` を追加するか、記事タイトル下の **Copy for LLM** をクリックしてください。例:[adapty-cursor-android.md](https://adapty.io/docs/ja/adapty-cursor-android.md) 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステップには、貼り付けるための `.md` リンクが入った「LLMへ送るプロンプト」ブロックがあります。 まとめて多くのドキュメントを取得する場合は、以下の[インデックスファイルとプラットフォーム別サブセット](#plain-text-doc-index-files)を参照してください。 ## 実装ウォークスルー \{#implementation-walkthrough\} ここからは、実装順にAdaptyの統合を進めます。各ステージには、LLMに送るドキュメント、完了時に確認すべき内容、よくある問題が含まれています。 ### 統合計画を立てる \{#plan-your-integration\} コードを書き始める前に、LLMにプロジェクトを分析させ、実装計画を作成してもらいましょう。AIツールに計画モード(CursorやClaude Codeのプランモードなど)がある場合は、LLMがコードを書く前にプロジェクト構造とAdaptyドキュメントの両方を読めるよう活用してください。 購入に使うアプローチをLLMに伝えてください — これにより、参照すべきガイドが変わります。 - [**Adaptyペイウォールビルダー**](adapty-paywall-builder): Adaptのノーコードビルダーでペイウォールを作成し、SDKが自動でレンダリングします。 - [**手動作成のペイウォール**](android-making-purchases): 自分でペイウォールUIをコードで構築しつつ、プロダクトの取得と購入処理はAdaptyを使います。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラを維持したまま、アナリティクスと連携にのみAdaptyを使います。 どれを選べばいいかわからない場合は、[クイックスタートの比較表](android-quickstart-paywalls)をご覧ください。 ### SDKのインストールと設定 \{#install-and-configure-the-sdk\} Android StudioでGradleを使ってAdapty SDKの依存関係を追加し、Public SDKキーで有効化します。これが基盤となるため、他の機能はすべてこのステップが完了しないと動きません。 **ガイド:** [Adapty SDKのインストールと設定](sdk-installation-android) LLMへ送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-android.md ``` :::tip[チェックポイント] - **期待される結果:** アプリがビルド・実行され、LogcatにAdaptyのアクティベーションログが表示される。 - **注意点:** 「Public API key is missing」エラーが出た場合 → プレースホルダーをApp settingsで確認した実際のキーに置き換えたか確認してください。 ::: ### ペイウォールの表示と購入処理 \{#show-paywalls-and-handle-purchases\} プレースメントIDでペイウォールを取得し、表示して、購入イベントを処理します。必要なガイドは購入処理の方法によって異なります。 進めながらサンドボックスで各購入をテストしてください。最後まで待たないようにしましょう。セットアップ方法は[サンドボックスでの購入テスト](test-purchases-in-sandbox)をご覧ください。 **ガイド:** - [ペイウォールを使って購入を有効にする(クイックスタート)](android-quickstart-paywalls) - [ペイウォールビルダーのペイウォールと設定の取得](android-get-pb-paywalls) - [ペイウォールの表示](android-present-paywalls) - [ペイウォールイベントの処理](android-handling-events) - [ボタンアクションへの対応](android-handle-paywall-actions) LLMへ送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/android-quickstart-paywalls.md - https://adapty.io/docs/ja/android-get-pb-paywalls.md - https://adapty.io/docs/ja/android-present-paywalls.md - https://adapty.io/docs/ja/android-handling-events.md - https://adapty.io/docs/ja/android-handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される結果:** 設定したプロダクトとともにペイウォールが表示され、プロダクトをタップするとサンドボックスの購入ダイアログが起動する。 - **注意点:** ペイウォールが空、または `getPaywall` エラーが出る場合 → プレースメントIDがダッシュボードと完全に一致しているか、プレースメントにオーディエンスが割り当てられているかを確認してください。 ::: **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](android-quickstart-manual) - [ペイウォールとプロダクトの取得](fetch-paywalls-and-products-android) - [リモートコンフィグで設計したペイウォールのレンダリング](present-remote-config-paywalls-android) - [購入処理](android-making-purchases) - [購入の復元](android-restore-purchase) LLMへ送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/android-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products-android.md - https://adapty.io/docs/ja/present-remote-config-paywalls-android.md - https://adapty.io/docs/ja/android-making-purchases.md - https://adapty.io/docs/ja/android-restore-purchase.md ``` :::tip[チェックポイント] - **期待される結果:** カスタムペイウォールにAdaptyから取得したプロダクトが表示され、プロダクトをタップするとサンドボックスの購入ダイアログが起動する。 - **注意点:** プロダクト配列が空の場合 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、プレースメントにオーディエンスがあるかを確認してください。 ::: **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードの実装](implement-observer-mode-android) - [オブザーバーモードでのトランザクション報告](report-transactions-observer-mode-android) 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-android.md - https://adapty.io/docs/ja/report-transactions-observer-mode-android.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローでサンドボックス購入を行った後、Adapty ダッシュボードの **Event Feed** にトランザクションが表示される。 - **注意点:** イベントが表示されない場合 → Adaptyへのトランザクション報告が設定されているか、Google Play リアルタイム デベロッパー通知が設定されているかを確認してください。 ::: ### サブスクリプションのステータス確認 \{#check-subscription-status\} 購入後、ユーザープロファイルでアクティブなアクセスレベルを確認し、プレミアムコンテンツへのアクセスを制御します。 **ガイド:** [サブスクリプションのステータス確認](android-check-subscription-status) LLMへ送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/android-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックスで購入後、`profile.accessLevels["premium"]?.isActive` が `true` を返す。 - **注意点:** 購入後に `accessLevels` が空の場合 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているかを確認してください。 ::: ### ユーザーの識別 \{#identify-users\} アプリのユーザーアカウントとAdaptyプロファイルを紐付けることで、デバイスをまたいで購入情報が維持されます。 :::important アプリに認証機能がない場合はこのステップをスキップしてください。 ::: **ガイド:** [ユーザーの識別](android-quickstart-identify) LLMへ送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/android-quickstart-identify.md ``` :::tip[チェックポイント] - **期待される結果:** `Adapty.identify("your-user-id")` を呼び出した後、ダッシュボードの **Profiles** セクションにカスタムユーザーIDが表示される。 - **注意点:** アクティベーション後・ペイウォール取得前に `identify` を呼び出すことで、匿名プロファイルへのアトリビューションを防げます。 ::: ### リリース準備 \{#prepare-for-release\} サンドボックスでの統合確認が完了したら、リリースチェックリストに沿ってプロダクション対応を確認しましょう。 **ガイド:** [リリースチェックリスト](release-checklist) LLMへ送るプロンプト: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ja/release-checklist.md ``` :::tip[チェックポイント] - **期待される結果:** チェックリストの全項目を確認済み:ストア接続、サーバー通知、購入フロー、アクセスレベルの確認、プライバシー要件。 - **注意点:** Google Play リアルタイム デベロッパー通知が未設定の場合 → **App settings → Android SDK** で設定してください。設定しないとダッシュボードにイベントが表示されません。 ::: ## プレーンテキストドキュメントのインデックスファイル \{#plain-text-doc-index-files\} 個別ページを超えた幅広いコンテキストをLLMに提供したい場合は、Adaptyドキュメント全体をまとめたインデックスファイルを用意しています: - [`llms.txt`](https://adapty.io/docs/ja/llms.txt): すべてのページを `.md` リンク付きで一覧表示。LLMがウェブサイトにアクセスしやすくするための[新興標準](https://llmstxt.org/)です。一部のAIエージェント(ChatGPTなど)では、`llms.txt` をダウンロードしてチャットにファイルとしてアップロードする必要があります。 - [`llms-full.txt`](https://adapty.io/docs/ja/llms-full.txt): Adaptyドキュメントサイト全体を1つのファイルにまとめたもの。非常に大きなファイルのため、全体像が必要なときのみ使用してください。 - Android専用の [`android-llms.txt`](https://adapty.io/docs/ja/android-llms.txt) と [`android-llms-full.txt`](https://adapty.io/docs/ja/android-llms-full.txt): サイト全体と比べてトークン数を節約できるプラットフォーム別サブセットです。 --- # File: android-get-pb-paywalls --- --- title: "フローとペイウォールの取得 - Android" description: "AdaptyからAndroidアプリでフローとペイウォールを取得します。" --- [フロー、またはペイウォールビルダーのペイウォールをデザインした](adapty-paywall-builder)後、それをモバイルアプリに表示できます。最初のステップは、プレースメントに関連付けられたフローまたはペイウォールと、そのビュー設定を以下の手順で取得することです。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでフローを表示する前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成してプロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成してフロー/ペイウォールを組み込む](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-android) をインストールする。
## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} フローまたはペイウォールをフロービルダーやペイウォールビルダーで作成した場合、モバイルアプリのコードでレンダリングしてユーザーに表示する処理を自分で実装する必要はありません。このようなフローまたはペイウォールには、表示するコンテンツと表示方法の両方が含まれています。ただし、プレースメントを通じてIDを取得し、ビュー設定を取得した上で、モバイルアプリ内で表示する必要があります。 最適なパフォーマンスを確保するために、フローまたはペイウォールとその[ビュー設定](android-get-pb-paywalls#fetch-the-view-configuration)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します: ```kotlin showLineNumbers ... Adapty.getFlow("YOUR_PLACEMENT_ID", loadTimeout = 10.seconds) { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow/paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers ... Adapty.getFlow("YOUR_PLACEMENT_ID", TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow/paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **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.seconds(5)` を使って `TimeInterval` を作成できます。制限なしにするには `TimeInterval.INFINITE` を使用してください。

| レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------- | | Flow | プレースメント、識別子(`id`、`variationId`)、名前、リモートコンフィグ、およびフローにビュー設定が含まれているかどうかを示す `hasViewConfiguration` フラグを含む `AdaptyFlow` オブジェクト。プリロード、カスタム UI、またはプログラムによるチェックのために実際のプロダクトを取得するには、`getPaywallProducts(flow)` を呼び出してください。 | ## ビュー設定の取得 \{#fetch-the-view-configuration\} フローまたはペイウォールを取得したら、`flow.hasViewConfiguration` を使ってビュー設定が含まれているかどうかを確認します。このフラグは、Adapty ダッシュボードでプレースメントがどのように設計されているかを示します。 - **`true`** — プレースメントが **Flow Builder**(フロー)または **Paywall Builder**(ペイウォール)でデザインされています。Adapty が UI をレンダリングします。以下の手順に進み、ビュー設定を取得して[フローまたはペイウォールを表示](android-present-paywalls)してください。 - **`false`** — プレースメントはビルダー UI を持たないカスタムペイウォールです。[リモートコンフィグペイウォールとして処理してください](present-remote-config-paywalls-android)。 :::important Flow Builder で **Show on device** トグルを必ず有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: `getFlowConfiguration` メソッドを使用して、ビュー設定を読み込みます。 ```kotlin showLineNumbers if (!flow.hasViewConfiguration) { // use your custom logic return } AdaptyUI.getFlowConfiguration(flow, loadTimeout = 10.seconds) { result -> when(result) { is AdaptyResult.Success -> { val flowConfiguration = result.value // use loaded configuration } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` | パラメーター | 必須/任意 | 説明 | | :-------------- | :------------- | :----------------------------------------------------------- | | **flow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | | **locale** |

任意

デフォルト: デバイスのロケール

| [ローカライゼーション](add-paywall-locale-in-adapty-paywall-builder)の識別子。`-` で区切られた1つまたは2つのサブタグを持つ言語コードとして指定します(例: `en`、`pt-br`)。[ローカライゼーションとロケールコード](android-localizations-and-locale-codes)を参照してください。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。この処理は内部的に複数のリクエストで構成される場合があるため、`loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがまれにあります。 |
`getFlowConfiguration` メソッドを使用して、ビュー設定を読み込みます。 ```java showLineNumbers if (!flow.hasViewConfiguration()) { // use your custom logic return; } AdaptyUI.getFlowConfiguration(flow, TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyUI.FlowConfiguration flowConfiguration = ((AdaptyResult.Success) result).getValue(); // use loaded configuration } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | パラメーター | 必須/任意 | 説明 | | :-------------- | :------------- | :----------------------------------------------------------- | | **flow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | | **locale** |

任意

デフォルト: デバイスのロケール

| [ローカライゼーション](add-paywall-locale-in-adapty-paywall-builder)の識別子。`-` で区切られた1つまたは2つのサブタグを含む言語コードで指定します(例: `en`、`pt-br`)。詳細は [ローカライゼーションとロケールコード](android-localizations-and-locale-codes) を参照してください。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅くタイムアウトすることがあります。 |
:::note 複数の言語を使用している場合は、[ビルダーのローカライゼーション](add-paywall-locale-in-adapty-paywall-builder)の追加方法と、ロケールコードの正しい使用方法を[こちら](android-localizations-and-locale-codes)でご確認ください。 ::: 読み込みが完了したら、[フローまたはペイウォールを表示](android-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` を使用してください。 ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

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

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

| ## アセットのカスタマイズ \{#customize-assets\} フローやペイウォールの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、定義済みのID(`hero_image` と `hero_video`)があります。カスタムアセットバンドルでは、これらのIDを使って要素を指定し、その動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定する](custom-media)必要があります。 例えば、次のようなことができます: - 特定のユーザーに異なる画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 Here's an example of how you can provide custom assets via a simple dictionary: ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, ) ``` :::note アセットが見つからない場合、フローはデフォルトの外観にフォールバックします。 ::: 動画の場合、オプションで `resolution` を渡すことで、動画の読み込み前にレイアウトスペースを確保し、アスペクト比(`width / height`)を設定できます: ```kotlin showLineNumbers AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), resolution = AdaptyCustomVideoAsset.Resolution(width = 1080, height = 1920), ) ```
[Adapty ダッシュボード](adapty-paywall-builder)の新しいペイウォールビルダーで[ペイウォールのビジュアル部分をデザイン](adapty-paywall-builder)したら、それをモバイルアプリに表示できます。このプロセスの最初のステップは、プレースメントに紐づいたペイウォールとそのビュー設定を取得することです。詳細は以下をご覧ください。 :::warning 新しいペイウォールビルダーは Android SDK バージョン 3.0 以上で動作します。 ::: Paywall Builderでカスタマイズされたペイウォールについての説明です。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォール用のペイウォールとプロダクトの取得](fetch-paywalls-and-products-android)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでペイウォールの表示を始める前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加する](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加する](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-android) をインストールする。
## ペイウォールビルダーで作成したペイウォールを取得する \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーでペイウォールを作成した](adapty-paywall-builder)場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングを実装する必要はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてペイウォールの ID を取得し、ビュー設定を行ったうえで、モバイルアプリに表示する必要があります。 最適なパフォーマンスを確保するには、ペイウォールとその[ビュー設定](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します: ```kotlin showLineNumbers ... Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en", loadTimeout = 10.seconds) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers ... Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値を使用します。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

Adapty SDK はペイウォールをローカルに2層で保存します。1つ目は上述の定期更新されるキャッシュ、2つ目は[フォールバックペイウォール](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://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーで **Show on device** トグルを必ず有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、`ViewConfiguration` が含まれているかどうかを確認してください。これが含まれている場合、そのペイウォールはペイウォールビルダーで作成されたことを示します。`ViewConfiguration` が存在する場合はペイウォールビルダーのペイウォールとして処理し、存在しない場合は[リモートコンフィグのペイウォールとして処理](present-remote-config-paywalls)してください。 `getViewConfiguration` メソッドを使用して、ビュー設定を読み込みます。 ```kotlin showLineNumbers if (!paywall.hasViewConfiguration) { // use your custom logic return } AdaptyUI.getViewConfiguration(paywall, loadTimeout = 10.seconds) { result -> when(result) { is AdaptyResult.Success -> { val viewConfiguration = result.value // use loaded configuration } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` | パラメーター | 必須/任意 | 説明 | | :-------------- | :------------- | :----------------------------------------------------------- | | **paywall** | 必須 | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。なお、このメソッドは内部で複数のリクエストで構成されることがあるため、まれに `loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。 | ビューの設定を読み込むには、`getViewConfiguration` メソッドを使用します。 ```java showLineNumbers if (!paywall.hasViewConfiguration()) { // use your custom logic return; } AdaptyUI.getViewConfiguration(paywall, TimeInterval.seconds(10), result -> { if (result instanceof AdaptyResult.Success) { AdaptyUI.LocalizedViewConfiguration viewConfiguration = ((AdaptyResult.Success) result).getValue(); // use loaded configuration } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | 必須 | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。なお、このメソッドは内部で複数のリクエストを実行する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。 | :::note 複数の言語を使用している場合は、[ペイウォールビルダーのローカライゼーション](add-paywall-locale-in-adapty-paywall-builder)の追加方法と、ロケールコードの正しい使い方[こちら](android-localizations-and-locale-codes)を参照してください。 ::: 読み込みが完了したら、[ペイウォールを表示](android-present-paywalls)してください。 ## デフォルトオーディエンス向けペイウォールを素早く取得する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ瞬時に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、スムーズなユーザー体験を確保するためにデフォルトのペイウォールを表示したい場合があるでしょう。 これに対処するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドによるペイウォールの取得であることを理解しておくことが重要です。詳細は上記の[ペイウォール情報の取得](#fetch-paywall-designed-with-paywall-builder)セクションをご参照ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがペイウォールを正常に表示できない問題を受け入れるかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになり、国、マーケティングのアトリビューション、独自のカスタム属性に基づくパーソナライズされたターゲティングができなくなります。 ペイウォールの取得速度を優先してこれらのデメリットを許容できる場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` を使用してください。 ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` :::note `getPaywallForDefaultAudience` メソッドは Android SDK 2.11.3 以降で利用可能です。 ::: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

| ## アセットのカスタマイズ \{#customize-assets\} ペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、あらかじめ定義されたID(`hero_image` と `hero_video`)があります。カスタムアセットバンドルでは、これらのIDを使って要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定する](custom-media)必要があります。 たとえば、次のようなことができます: - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty Android SDK をバージョン 3.7.0 以上にアップデートしてください。 ::: カスタムアセットをシンプルな辞書で提供する方法の例を示します。 ```kotlin showLineNumbers val customAssets = AdaptyCustomAssets.of( "hero_image" to AdaptyCustomImageAsset.remote( url = "https://example.com/image.jpg", preview = AdaptyCustomImageAsset.file( FileLocation.fromAsset("images/hero_image_preview.png"), ) ), "hero_video" to AdaptyCustomVideoAsset.file( FileLocation.fromResId(requireContext(), R.raw.custom_video), preview = AdaptyCustomImageAsset.file( FileLocation.fromResId(requireContext(), R.drawable.video_preview), ), ), ) val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, customAssets, ) ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの外観にフォールバックします。 :::
--- # File: android-present-paywalls --- --- title: "フローとペイウォールの表示 - Android" description: "Androidアプリでフローとペイウォールをユーザーに表示します。" --- フローまたはペイウォールを作成した場合、それをユーザーに表示するためにモバイルアプリのコードでレンダリングを実装する必要はありません。フローやペイウォールには、表示するコンテンツとその表示方法の両方が含まれています。 :::warning このガイドでは、Adapty がレンダリングするフローと**新しいペイウォールビルダーのペイウォール**について説明します。リモートコンフィグのペイウォールや [Observer モード](observer-vs-full-mode) の場合は、手順が異なります。 - **リモートコンフィグペイウォール**の表示については、[リモートコンフィグで設計したペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。 - **オブザーバーモードのペイウォール**の表示については、[Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](android-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 ::: 以下で使用する `flowConfiguration` オブジェクトの取得方法については、[フローとペイウォールの取得](android-get-pb-paywalls)を参照してください。 デバイス画面にビジュアルフローを表示するには、まず設定が必要です。`AdaptyUI.getFlowView()` メソッドを呼び出すか、`AdaptyFlowView` を直接作成してください: ```kotlin showLineNumbers val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, ) ``` ```kotlin showLineNumbers val flowView = AdaptyFlowView(activity) // or retrieve it from xml ... with(flowView) { showFlow( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, ) } ``` ```java showLineNumbers AdaptyFlowView flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver ); ``` ```java showLineNumbers AdaptyFlowView flowView = new AdaptyFlowView(activity); //add to the view hierarchy if needed, or you receive it from xml ... flowView.showFlow(flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver); ``` ```xml showLineNumbers ``` ビューの作成が完了したら、ビュー階層に追加してデバイスの画面に表示できます。 `AdaptyFlowView` を `AdaptyUI.getFlowView()` 以外の方法で取得した場合は、`.showFlow()` メソッドを別途呼び出す必要があります。 デバイス画面にビジュアルフローを表示するには、まず設定が必要です。以下のコンポーザブル関数を使用してください: ```kotlin showLineNumbers AdaptyFlowScreen( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, ) ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :---------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **flowConfiguration** | 必須 | フローのビジュアル詳細を含む `AdaptyUI.FlowConfiguration` オブジェクトを指定します。`AdaptyUI.getFlowConfiguration(flow)` メソッドを使って読み込んでください。詳細は [ビュー設定の取得](android-get-pb-paywalls#fetch-the-view-configuration) をご参照ください。 | | **products** | 任意 | 画面上のプロダクトの表示タイミングを最適化するために `AdaptyPaywallProduct` の配列を指定します。`null` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **eventListener** | 任意 | フローイベントを監視するために `AdaptyFlowEventListener` を指定します。使いやすさの観点から `AdaptyFlowDefaultEventListener` を拡張することを推奨します。詳細は [フロー & ペイウォールイベントの処理](android-handling-events) をご参照ください。 | | **insets** | 任意 |

インセットは、タップ可能な要素がシステムバーの裏に隠れないようにするためのフロー周囲のスペースです。

デフォルト: `Unspecified`。この場合、Adapty が自動的にインセットを調整します。エッジツーエッジのフローでは適切に機能します。

フローがエッジツーエッジでない場合は、カスタムインセットを設定することを検討してください。設定方法については、以下の [フローインセットの変更](android-present-paywalls#change-flow-insets) セクションをご参照ください。

| | **customAssets** | 任意 | `AdaptyCustomAssets` オブジェクトを渡すことで、実行時にフローやペイウォール内の画像や動画を置き換えられます。詳細は [アセットのカスタマイズ](android-get-pb-paywalls#customize-assets) をご参照ください。 | | **tagResolver** | 任意 | フローのテキスト内のカスタムタグを解決するには `AdaptyUiTagResolver` を使用します。このリゾルバーはタグパラメータを受け取り、対応する文字列に解決します。詳細はペイウォールビルダーのカスタムタグのトピックをご参照ください。 | | **timerResolver** | 任意 | カスタムタイマー機能を使用する場合は、ここにリゾルバーを渡してください。 | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## フローのインセットを変更する \{#change-flow-insets\} インセットとは、フローの周囲の余白のことで、タップ可能な要素がシステムバーの後ろに隠れないようにするためのものです。デフォルトでは Adapty がインセットを自動的に調整するため、エッジツーエッジのフローでも問題なく機能します。 フローがエッジツーエッジでない場合は、カスタムインセットを設定することをお勧めします。 - ステータスバーとナビゲーションバーのどちらも `AdaptyFlowView` と重ならない場合は、`AdaptyFlowInsets.None` を使用してください。 - フローが上部のステータスバーとは重なるが下部とは重ならないといった複雑な設定の場合は、以下の例のように `bottomInset` のみを `0` に設定できます。 ```kotlin showLineNumbers //create extension function fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) ViewCompat.setOnApplyWindowInsetsListener(this, null) action(systemBarInsets) insets } } //and then use it with the view flowView.onReceiveSystemBarsInsets { insets -> val flowInsets = AdaptyFlowInsets.vertical(insets.top, 0) flowView.showFlow( flowConfiguration, products, eventListener, flowInsets, customAssets, tagResolver, timerResolver, ) } ``` ```java showLineNumbers ... ViewCompat.setOnApplyWindowInsetsListener(flowView, (view, insets) -> { Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); ViewCompat.setOnApplyWindowInsetsListener(flowView, null); AdaptyFlowInsets flowInsets = AdaptyFlowInsets.vertical(systemBarInsets.top, 0); flowView.showFlow(flowConfiguration, products, eventListener, flowInsets); return insets; }); ``` ## 開発者定義タイマーを使用する \{#use-developer-defined-timer\} モバイルアプリで開発者定義タイマーを使用するには、`timerResolver` オブジェクトを作成します。これは、カスタムタイマーとフローのレンダリング時に置き換えられる文字列値をペアにした辞書またはマップです。以下に例を示します。 ```kotlin showLineNumbers ... val customTimers = mapOf( "CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025 ) val timerResolver = AdaptyUiTimerResolver { timerId -> customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } ) } ``` ```java showLineNumbers ... Map customTimers = new HashMap<>(); customTimers.put( "CUSTOM_TIMER_NY", new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime() ); AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() { @NonNull @Override public Date timerEndAtDate(@NonNull String timerId) { Date date = customTimers.get(timerId); return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */ } }; ``` この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリは正しい値(例:New Year's Day などのタイマー終了時刻から現在時刻を引いて計算した `13d 09h 03m 34s`)でタイマーを動的に更新します。 ## カスタムタグを使用する \{#use-custom-tags\} モバイルアプリでカスタムタグを使用するには、`tagResolver` オブジェクト(カスタムタグと、フロー描画時にそれらを置き換える文字列値のペアを持つ辞書またはマップ)を作成します。以下に例を示します。 ```kotlin showLineNumbers val customTags = mapOf("USERNAME" to "John") val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] } ``` ```java showLineNumbers Map customTags = new HashMap<>(); customTags.put("USERNAME", "John"); AdaptyUiTagResolver tagResolver = customTags::get; ``` この例では、`USERNAME` は Adapty ダッシュボードで `` として入力したカスタムタグです。`tagResolver` により、アプリはこのカスタムタグを `John` などの指定した値に動的に置き換えます。 `tagResolver` はフローを表示する直前に作成・設定することをおすすめします。準備ができたら、フローの表示に使用する AdaptyUI メソッドに渡してください。 ## フローの読み込みインジケーターの色を変更する \{#change-flow-loading-indicator-color\} 次の方法で、読み込みインジケーターのデフォルトカラーをオーバーライドできます。 ```xml showLineNumbers title = "XML" ```
ペイウォールビルダーを使ってペイウォールをカスタマイズした場合、モバイルアプリのコード内でそのペイウォールをレンダリングしてユーザーに表示する処理は不要です。このようなペイウォールには、表示するコンテンツと表示方法の両方が含まれています。 :::warning このガイドは、SDK v3.0 が必要な**新しいペイウォールビルダーのペイウォール**専用です。ペイウォールの表示方法は、異なるバージョンのペイウォールビルダーで設計されたペイウォール、リモートコンフィグペイウォール、および[オブザーバーモード](observer-vs-full-mode)によって異なります。 - **リモートコンフィグペイウォール**の表示については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。 - **オブザーバーモードのペイウォール**の表示については、[Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](android-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 ::: 以下で使用する `viewConfiguration` オブジェクトの取得方法については、[ペイウォールビルダーのペイウォールと設定の取得](android-get-pb-paywalls)を参照してください。 デバイス画面にビジュアルペイウォールを表示するには、まず設定を行う必要があります。`AdaptyUI.getPaywallView()` メソッドを呼び出すか、`AdaptyPaywallView` を直接作成してください。 ```kotlin showLineNumbers val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver, ) ``` ```kotlin showLineNumbers val paywallView = AdaptyPaywallView(activity) // or retrieve it from xml ... with(paywallView) { showPaywall( viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver, ) } ``` ```java showLineNumbers AdaptyPaywallView paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver ); ``` ```java showLineNumbers AdaptyPaywallView paywallView = new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml ... paywallView.showPaywall(viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver); ``` ```xml showLineNumbers ``` ビューが正常に作成されたら、それをビュー階層に追加してデバイスの画面に表示できます。 `AdaptyPaywallView` を `AdaptyUI.getPaywallView()` を呼び出す以外の方法で取得した場合は、`.showPaywall()` メソッドも呼び出す必要があります。 デバイス画面にペイウォールのビジュアルを表示するには、まず設定が必要です。次のコンポーザブル関数を使用してください: ```kotlin showLineNumbers AdaptyPaywallScreen( viewConfiguration, products, eventListener, insets, personalizedOfferResolver, tagResolver, timerResolver, ) ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | | :---------------------------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **viewConfiguration** | 必須 | ペイウォールのビジュアル情報を含む `AdaptyUI.LocalizedViewConfiguration` オブジェクトを指定します。取得には `Adapty.getViewConfiguration(paywall)` メソッドを使用してください。詳しくは [ペイウォールのビジュアル設定の取得](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) をご覧ください。 | | **products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` の配列を指定します。`null` を渡した場合、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **eventListener** | 任意 | ペイウォールのイベントを監視するために `AdaptyUiEventListener` を指定します。使いやすさの観点から、`AdaptyUiDefaultEventListener` を継承することを推奨します。詳しくは [ペイウォールイベントの処理](android-handling-events) をご覧ください。 | | **insets** | 任意 |

インセットは、タップ可能な要素がシステムバーの後ろに隠れないようにするためのペイウォール周囲のスペースです。

デフォルト値は `UNSPECIFIED` で、Adapty がインセットを自動調整します。これはエッジツーエッジのペイウォールに最適です。

ペイウォールがエッジツーエッジでない場合は、カスタムインセットを設定することをお勧めします。設定方法については、以下の [ペイウォールインセットの変更](android-present-paywalls#change-paywall-insets) セクションをご覧ください。

| | **personalizedOfferResolver** | 任意 | パーソナライズされた価格表示([詳細](https://developer.android.com/google/play/billing/integrate#personalized-price))を示すには、`AdaptyUiPersonalizedOfferResolver` を実装し、`AdaptyPaywallProduct` に対してその価格がパーソナライズされている場合は `true`、そうでない場合は `false` を返す独自のロジックを渡します。 | | **tagResolver** | 任意 | ペイウォールテキスト内のカスタムタグを解決するには `AdaptyUiTagResolver` を使用します。このリゾルバはタグパラメータを受け取り、対応する文字列に変換します。詳しくはペイウォールビルダーのカスタムタグのトピックをご覧ください。 | | **timerResolver** | 任意 | カスタムタイマー機能を使用する場合は、ここにリゾルバを渡してください。 | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## ペイウォールのインセットを変更する \{#change-paywall-insets\} インセットとは、システムバーの裏側にタップ可能な要素が隠れないようにするための、ペイウォール周囲のスペースのことです。デフォルトでは、Adapty がインセットを自動的に調整します。これはエッジツーエッジのペイウォールではうまく機能します。 ペイウォールがエッジツーエッジでない場合は、カスタムインセットを設定することをお勧めします。 - ステータスバーとナビゲーションバーの両方が`AdaptyPaywallView`と重ならない場合は、`AdaptyPaywallInsets.NONE`を使用してください。 - ペイウォールが上部のステータスバーとは重なるが下部とは重ならないといったカスタム設定の場合は、以下の例のように`bottomInset`のみを`0`に設定できます。 ```kotlin showLineNumbers //create extension function fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) ViewCompat.setOnApplyWindowInsetsListener(this, null) action(systemBarInsets) insets } } //and then use it with the view paywallView.onReceiveSystemBarsInsets { insets -> val paywallInsets = AdaptyPaywallInsets.vertical(insets.top, 0) paywallView.showPaywall( viewConfiguration, products, eventListener, paywallInsets, personalizedOfferResolver, tagResolver, timerResolver, ) } ``` ```java showLineNumbers ... ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> { Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); ViewCompat.setOnApplyWindowInsetsListener(paywallView, null); AdaptyPaywallInsets paywallInsets = AdaptyPaywallInsets.of(systemBarInsets.top, 0); paywallView.showPaywall(paywall, products, viewConfiguration, paywallInsets, productTitleResolver); return insets; }); ``` ## 開発者定義タイマーを使用する \{#use-developer-defined-timer\} モバイルアプリで開発者定義タイマーを使用するには、`timerResolver` オブジェクトを作成します。これは、カスタムタイマーとペイウォールのレンダリング時に置き換えられる文字列値をペアにした辞書またはマップです。以下に例を示します: ```kotlin showLineNumbers ... val customTimers = mapOf( "CUSTOM_TIMER_NY" to Calendar.getInstance(TimeZone.getDefault()).apply { set(2025, 0, 1) }.time, // New Year 2025 ) val timerResolver = AdaptyUiTimerResolver { timerId -> customTimers.getOrElse(timerId, { Date(System.currentTimeMillis() + 3600 * 1000L) /* in 1 hour */ } ) } ``` ```java showLineNumbers ... Map customTimers = new HashMap<>(); customTimers.put( "CUSTOM_TIMER_NY", new Calendar.Builder().setTimeZone(TimeZone.getDefault()).setDate(2025, 0, 1).build().getTime() ); AdaptyUiTimerResolver timerResolver = new AdaptyUiTimerResolver() { @NonNull @Override public Date timerEndAtDate(@NonNull String timerId) { Date date = customTimers.get(timerId); return date != null ? date : new Date(System.currentTimeMillis() + 3600 * 1000L); /* in 1 hour */ } }; ``` この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリはタイマーを正しい値(例:`13d 09h 03m 34s`、元旦などのタイマー終了時刻から現在時刻を引いた値)で動的に更新できます。 ## カスタムタグを使う \{#use-custom-tags\} モバイルアプリでカスタムタグを使用するには、`tagResolver` オブジェクト(カスタムタグとペイウォール表示時に置換される文字列値を対応付けるディクショナリまたはマップ)を作成します。以下に例を示します。 ```kotlin showLineNumbers val customTags = mapOf("USERNAME" to "John") val tagResolver = AdaptyUiTagResolver { tag -> customTags[tag] } ``` ```java showLineNumbers Map customTags = new HashMap<>(); customTags.put("USERNAME", "John"); AdaptyUiTagResolver tagResolver = customTags::get; ``` この例では、`USERNAME` は Adapty ダッシュボードで `` として入力したカスタムタグです。`tagResolver` によって、アプリがこのカスタムタグを `John` のような指定した値に動的に置き換えます。 `tagResolver` はペイウォールを表示する直前に作成・設定することをおすすめします。準備ができたら、ペイウォールを表示するために使用する AdaptyUI メソッドに渡してください。 ## ローディングインジケーターの色を変更する \{#change-paywall-loading-indicator-color\} ローディングインジケーターのデフォルト色は、以下の方法で上書きできます。 ```xml showLineNumbers title = "XML" ```
--- # File: android-handle-paywall-actions --- --- title: "フローアクションへの応答 - Android" description: "AndroidアプリでフローやペイウォールのボタンアクションをHandleする方法。" --- Adapty フロービルダーまたはペイウォールビルダーを使ってフローやペイウォールを構築している場合、ボタンを適切に設定することが重要です: 1. [ビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションをアプリのコードで処理する処理を実装します。 このガイドでは、カスタムアクションと既存アクションをコードで処理する方法を説明します。 :::warning **購入、復元、フロー/ペイウォールのクローズ、URL の開封のみ自動で処理されます。** その他すべてのボタンアクションは、アプリのコードで適切なレスポンス実装が必要です。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローまたはペイウォールを閉じるボタンを追加するには、次の手順を行います。 1. ビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで `close` アクションのハンドラーを実装します。 :::info Android SDK では、`close` アクションはデフォルトでフローまたはペイウォールを閉じる動作をします。ただし、必要に応じてコードでこの動作をオーバーライドできます。たとえば、あるフローを閉じたときに別のフローを開くといった処理が可能です。 ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior } } ``` ## フローとペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: フローやペイウォールからリンクを開くボタン(例:**Terms of use** や **Privacy policy**)を追加するには: 1. ビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info Android SDKでは、`openUrl`アクションはデフォルトでURLを開きます。ただし、必要に応じてコード内でこの動作をオーバーライドできます。 ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.OpenUrl -> { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(action.url)) // default behavior context.startActivity(intent) } } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} ボタンを追加して任意のアクションを処理するには、次の手順に従います: 1. ビルダーでボタンを追加し、**Custom** アクションを割り当て、IDを設定します。 2. アプリのコードで、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.Custom -> { if (action.customId == "openNewPaywall") { // Display another flow or paywall } } } } ``` ペイウォールビルダーを使ってペイウォールを作成する場合、ボタンを適切に設定することが重要です: 1. [ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクションIDを作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよび既存アクションをコードで処理する方法を説明します。 :::warning **購入、復元、ペイウォールのクローズ、URLの開封は自動的に処理されます。** それ以外のすべてのボタンアクションは、アプリのコードで適切な処理を実装する必要があります。 ::: ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info Android SDK では、`close` アクションはデフォルトでペイウォールを閉じる動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じたときに別のペイウォールを開くといった処理が可能です。 ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Close -> (context as? Activity)?.onBackPressed() // default behavior } } ``` ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションが設定されたボタンと同じ方法で処理してください。 ::: ペイウォールにリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. アプリのコードに、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info Android SDK では、`openUrl` アクションはデフォルトで URL を開く動作をトリガーします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。 ::: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.OpenUrl -> { val intent = Intent(Intent.ACTION_VIEW, Uri.parse(action.url)) // default behavior context.startActivity(intent) } } } ``` ## アプリへのログイン \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコード内で、ユーザーを識別する `login` アクションのハンドラーを実装します。 ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { AdaptyUI.Action.Login -> { val intent = Intent(context, LoginActivity::class.java) context.startActivity(intent) } } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} ほかのアクションを処理するボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当て、ID を設定します。 2. アプリのコードで、作成したアクション ID に対応するハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のペイウォールを表示するボタンを追加できます: ```kotlin override fun onActionPerformed(action: AdaptyUI.Action, context: Context) { when (action) { is AdaptyUI.Action.Custom -> { if (action.customId == "openNewPaywall") { // Display another paywall } } } } ``` --- # File: android-handling-events --- --- title: "フローとペイウォールのイベント処理 - Android" description: "Androidアプリでフローおよびペイウォールのイベントを処理する方法を説明します。" --- :::important このガイドでは、購入・復元・プロダクト選択・フロー表示に関するイベント処理について説明します。ボタンの処理(フローを閉じる、リンクを開くなど)も別途実装する必要があります。詳しくは[ボタンアクションの処理に関するガイド](android-handle-paywall-actions)をご覧ください。 ::: [Flow Builder](adapty-flow-builder)や[Paywall Builder](adapty-paywall-builder)で設定したフローやペイウォールは、購入や復元のための追加コードは不要です。ただし、アプリが応答できるイベントが発生します。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や購入関連アクションの通知が含まれます。これらのイベントへの応答方法については、以下をご覧ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: 購入画面で行われるプロセスを制御・監視する必要がある場合は、`AdaptyFlowEventListener` のメソッドを実装してください。 デフォルトの動作をそのまま使いたい場合は、`AdaptyFlowDefaultEventListener` を継承して、変更したいメソッドのみをオーバーライドできます。 以下は `AdaptyFlowDefaultEventListener` のデフォルト動作です。 ### ユーザー生成イベント \{#user-generated-events\} #### プロダクトの選択 \{#product-selection\} プロダクトが(ユーザーまたはシステムによって)購入のために選択されると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onProductSelected( product: AdaptyPaywallProduct, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseStarted( product: AdaptyPaywallProduct, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
このメソッドはObserverモードでは呼び出されません。詳細は [Android - ObserverモードでペイウォールビルダーのペイウォールをPresent する](android-present-paywall-builder-paywalls-in-observer-mode) を参照してください。 #### 購入成功、キャンセル、または保留中 \{#successful-canceled-or-pending-purchase\} 購入が成功すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFinished( purchaseResult: AdaptyPurchaseResult, product: AdaptyPaywallProduct, context: Context, ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) context.getActivityOrNull()?.onBackPressed() } ```
イベント例(クリックして展開) ```javascript // Successful purchase { "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // Cancelled purchase { "purchaseResult": { "type": "UserCanceled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // Pending purchase { "purchaseResult": { "type": "Pending" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
このケースではスクリーンを閉じることをお勧めします。 このメソッドはオブザーバーモードでは呼び出されません。詳細は [Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](android-present-paywall-builder-paywalls-in-observer-mode) をご参照ください。 #### 購入失敗 \{#failed-purchase\} 購入がエラーにより失敗した場合、このメソッドが呼び出されます。Google Play Billing のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、およびシステムエラーが対象です。なお、ユーザーによるキャンセルはキャンセル結果を伴う `onPurchaseFinished` をトリガーし、保留中の支払いはこのメソッドをトリガーしません。 ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFailure( error: AdaptyError, product: AdaptyPaywallProduct, context: Context, ) {} ```
イベント例(クリックして展開) ```javascript { "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
このメソッドはオブザーバーモードでは呼び出されません。詳細については、[Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](android-present-paywall-builder-paywalls-in-observer-mode)トピックを参照してください。 #### ウェブ決済ナビゲーションの完了 \{#finished-web-payment-navigation\} このメソッドは、特定のプロダクトの[ウェブペイウォール](web-paywall)を開こうとした後に呼び出されます。ナビゲーションの成功・失敗にかかわらず呼び出されます。 ```kotlin showLineNumbers title="Kotlin" public override fun onFinishWebPaymentNavigation( product: AdaptyPaywallProduct?, error: AdaptyError?, context: Context, ) {} ``` **パラメーター:** | パラメーター | 説明 | |:------------|:-----| | **product** | ウェブペイウォールが開かれた `AdaptyPaywallProduct`。`null` の場合があります。 | | **error** | ウェブペイウォールのナビゲーションに失敗した場合は `AdaptyError` オブジェクト、成功した場合は `null`。 |
イベントの例(クリックして展開) ```javascript // Successful navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "web_navigation_failed", "message": "Failed to open web paywall", "details": { "underlyingError": "Browser unavailable" } } } ```
#### 購入の復元成功 \{#successful-restore\} 購入の復元が成功すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreSuccess( profile: AdaptyProfile, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ```
ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることを推奨します。確認方法については、[サブスクリプションの状態](android-listen-subscription-changes) を参照してください。 #### 復元の失敗 \{#failed-restore\} `Adapty.restorePurchases()` が失敗した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreFailure( error: AdaptyError, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
#### サブスクリプションのアップグレード \{#upgrade-subscription\} ユーザーが既存のサブスクリプションがアクティブな状態で新しいサブスクリプションを購入しようとした場合、このメソッドをオーバーライドして新しい購入の処理方法を制御できます。次の2つのオプションがあります: 1. **現在のサブスクリプションを新しいものに置き換える:** ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback, ): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived( AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) .build() ) return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` 2. **両方のサブスクリプションを維持する**(新しいものを別途追加する): ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyFlowEventListener.PurchaseParamsCallback, ): AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty) return AdaptyFlowEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` :::note このメソッドをオーバーライドしない場合、デフォルトの動作では両方のサブスクリプションがアクティブな状態を維持します(`AdaptyPurchaseParameters.Empty`を使用した場合と同じ動作です)。 ::: 必要に応じて、追加の購入パラメーターを設定することもできます: ```kotlin AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription .withOfferPersonalized(true) // optional - if using personalized pricing .build() ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_yearly", "localizedTitle": "Premium Yearly", "localizedDescription": "Premium subscription for 1 year", "localizedPrice": "$99.99", "price": 99.99, "currencyCode": "USD" }, "subscriptionUpdateParams": { "replacementMode": "with_time_proration" } } ```
### データ取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクトを渡さない場合、AdaptyUI は必要なオブジェクトをサーバーから自動的に取得します。この操作が失敗した場合、AdaptyUI は次のメソッドを呼び出してエラーを報告します。 ```kotlin showLineNumbers title="Kotlin" public override fun onLoadingProductsFailure( error: AdaptyError, context: Context, ): Boolean = false ```
イベントの例(クリックして展開) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
`true` を返すと、AdaptyUI は 2 秒後にリクエストを再試行します。 #### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生した場合、次のメソッドを呼び出して報告されます: ```kotlin showLineNumbers title="Kotlin" public override fun onError( error: AdaptyError, context: Context, ) {} ```
イベント例(クリックして展開) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render flow interface", "details": { "underlyingError": "Invalid flow configuration" } } } ```
通常、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひご連絡ください。 ### ナビゲーション \{#navigation\} #### システムの戻るボタン \{#system-back-button\} デフォルトでは、フローはシステムの戻るボタンやバックジェスチャーでは閉じられません。ユーザーは、ビルダーで設定した **Close** ボタンや `on_device_back` アクションなど、あなたが定義したパスを通じてフローを離れます。システムの戻るボタンでフローを閉じられるようにしたい場合は、`onBackPressed` をオーバーライドして `false` を返し、ホストのアクティビティまたはフラグメントがその押下を処理できるようにしてください: ```kotlin showLineNumbers title="Kotlin" public override fun onBackPressed(context: Context): Boolean { return false // let the host handle the back press (e.g. finish the activity or pop the fragment) } ``` このコールバックは、現在の画面に `on_device_back` アクションが設定されていない場合にのみ呼び出されます。アクションが設定されている場合は、そちらが優先されて内部で処理されます。`true` を返すとそのプレスを消費し(デフォルトの動作)、`false` を返すとホスト側の戻る処理が実行されます。 ### 予約済みイベント \{#reserved-events\} `AdaptyFlowEventListener` には、フローがまだ使用していない機能向けにいくつかのコールバックが宣言されています。これらを実装する必要はありません。`AdaptyFlowDefaultEventListener` がすでにno-opのデフォルト実装を提供しています。 | メソッド | 説明 | |:-------|:------------| | **onAnalyticEvent** | フローからのカスタム分析イベント用に予約されています。フローはまだこれらをコードに送信しないため、実装は不要です。 | | **onShowAppRate** | フローからのアプリレビューリクエスト用に予約されています。フローはまだアプリレビューリクエストをトリガーしないため、実装は不要です。 | | **onShowRequestPermission** | フローからのシステム権限リクエスト(プッシュ通知やカメラアクセスなど)用に予約されています。フローはまだ権限リクエストをトリガーしないため、実装は不要です。 |
:::important このガイドでは、購入・復元・プロダクト選択・ペイウォールレンダリングのイベント処理について説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の処理も実装する必要があります。詳細は[ボタンアクションの処理に関するガイド](android-handle-paywall-actions)を参照してください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定したペイウォールは、購入や復元のために追加のコードを書く必要はありません。ただし、アプリが対応できるイベントをいくつか生成します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。 :::warning このガイドは、Adapty SDK v3.0以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。 ::: :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: 購入画面で発生するプロセスを制御・監視したい場合は、`AdaptyUiEventListener` のメソッドを実装してください。 一部のケースでデフォルトの動作をそのまま使いたい場合は、`AdaptyUiDefaultEventListener` を継承し、変更したいメソッドだけをオーバーライドできます。 以下は `AdaptyUiDefaultEventListener` のデフォルト実装です。 ### ユーザーが生成するイベント \{#user-generated-events\} #### プロダクトの選択 \{#product-selection\} ユーザーまたはシステムによってプロダクトが購入のために選択されると、次のメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onProductSelected( product: AdaptyPaywallProduct, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
#### 購入の開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseStarted( product: AdaptyPaywallProduct, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
このメソッドはオブザーバーモードでは呼び出されません。詳細は [Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](android-present-paywall-builder-paywalls-in-observer-mode) を参照してください。 #### 購入の成功・キャンセル・保留 \{#successful-canceled-or-pending-purchase\} 購入が成功した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFinished( purchaseResult: AdaptyPurchaseResult, product: AdaptyPaywallProduct, context: Context, ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) context.getActivityOrNull()?.onBackPressed() } ```
イベントの例(クリックして展開) ```javascript // Successful purchase { "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // Cancelled purchase { "purchaseResult": { "type": "UserCanceled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // Pending purchase { "purchaseResult": { "type": "Pending" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
その場合はスクリーンを閉じることを推奨します。 このメソッドはObserverモードでは呼び出されません。詳細は[Android - ObserverモードでのペイウォールビルダーペイウォールをPresent](android-present-paywall-builder-paywalls-in-observer-mode)トピックを参照してください。 #### 購入失敗 \{#failed-purchase\} 購入がエラーにより失敗した場合、このメソッドが呼び出されます。これには、Google Play Billing のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、およびシステムエラーが含まれます。なお、ユーザーがキャンセルした場合はキャンセル結果とともに `onPurchaseFinished` がトリガーされ、保留中の支払いはこのメソッドをトリガーしません。 ```kotlin showLineNumbers title="Kotlin" public override fun onPurchaseFailure( error: AdaptyError, product: AdaptyPaywallProduct, context: Context, ) {} ```
イベント例(クリックして展開) ```javascript { "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ```
このメソッドはオブザーバーモードでは呼び出されません。詳細については、[Android - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](android-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 #### ウェブ決済ナビゲーションの完了 \{#finished-web-payment-navigation\} このメソッドは、特定のプロダクトの[ウェブペイウォール](web-paywall)を開こうとした後に呼び出されます。ナビゲーションの成功・失敗に関わらず呼び出されます。 ```kotlin showLineNumbers title="Kotlin" public override fun onFinishWebPaymentNavigation( product: AdaptyPaywallProduct?, error: AdaptyError?, context: Context, ) {} ``` **パラメーター:** | パラメーター | 説明 | |:------------|:--------------------------------------------------------------------------------------------| | **product** | ウェブペイウォールが開かれた `AdaptyPaywallProduct`。`null` の場合があります。 | | **error** | ウェブペイウォールのナビゲーションに失敗した場合は `AdaptyError` オブジェクト、成功した場合は `null`。 |
イベントの例(クリックして展開) ```javascript // Successful navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "web_navigation_failed", "message": "Failed to open web paywall", "details": { "underlyingError": "Browser unavailable" } } } ```
#### 購入のリストア成功 \{#successful-restore\} 購入のリストアが成功した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreSuccess( profile: AdaptyProfile, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ```
ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることをお勧めします。確認方法については、[サブスクリプションのステータス](android-listen-subscription-changes) をご覧ください。 #### 復元の失敗 \{#failed-restore\} `Adapty.restorePurchases()` が失敗した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" public override fun onRestoreFailure( error: AdaptyError, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ```
#### サブスクリプションのアップグレード \{#upgrade-subscription\} ユーザーが既存のサブスクリプションがアクティブな状態で新しいサブスクリプションを購入しようとした場合、このメソッドをオーバーライドすることで新しい購入の処理方法を制御できます。2つのオプションがあります: 1. **現在のサブスクリプションを新しいものに置き換える:** ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived( AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) .build() ) return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` 2. **両方のサブスクリプションを保持する**(新しいものを別途追加する): ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty) return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` :::note このメソッドをオーバーライドしない場合、デフォルトの動作では両方のサブスクリプションがアクティブに保たれます(`AdaptyPurchaseParameters.Empty` を使用した場合と同等です)。 ::: 追加の購入パラメータが必要な場合は、以下のように設定できます: ```kotlin AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) // optional - for replacing current subscription .withOfferPersonalized(true) // optional - if using personalized pricing .build() ``` 別のサブスクリプションがまだアクティブな状態で新しいサブスクリプションが購入された場合、現在のものを新しいものに置き換えるにはこのメソッドをオーバーライドしてください。アクティブなサブスクリプションをそのまま維持し、新しいものを別途追加する場合は、`onSubscriptionUpdateParamsReceived(null)` を呼び出してください。 ```kotlin showLineNumbers title="Kotlin" public override fun onAwaitingSubscriptionUpdateParams( product: AdaptyPaywallProduct, context: Context, onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback, ) { onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...)) } ```
イベント例(クリックして展開) ```javascript { "product": { "vendorProductId": "premium_yearly", "localizedTitle": "Premium Yearly", "localizedDescription": "Premium subscription for 1 year", "localizedPrice": "$99.99", "price": 99.99, "currencyCode": "USD" }, "subscriptionUpdateParams": { "replacementMode": "with_time_proration" } } ```
### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクトを渡さない場合、AdaptyUI は必要なオブジェクトをサーバーから自動的に取得します。この操作が失敗した場合、AdaptyUI は以下のメソッドを呼び出してエラーを報告します: ```kotlin showLineNumbers title="Kotlin" public override fun onLoadingProductsFailure( error: AdaptyError, context: Context, ): Boolean = false ```
イベント例(クリックして展開) ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ```
`true` を返すと、AdaptyUI は 2 秒後にリクエストを再試行します。 #### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生した場合、このメソッドが呼び出されてエラーが通知されます: ```kotlin showLineNumbers title="Kotlin" public override fun onRenderingError( error: AdaptyError, context: Context, ) {} ```
イベントの例(クリックして展開) ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ```
通常、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひご連絡ください。
--- # File: android-use-fallback-paywalls --- --- title: "Android - フォールバックペイウォールを使用する" description: "ユーザーがオフラインのとき、またはAdaptyサーバーが利用できないときのケースを処理します。" --- :::warning フォールバックペイウォールは Android SDK v2.11 以降でサポートされています。 ::: スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} 1. フォールバック設定ファイルを Android プロジェクトの `assets` または `res/raw` ディレクトリに移動します。 2. 対象のフロー、ペイウォール、またはオンボーディングを取得する**前に** `.setFallback` メソッドを呼び出します。 ```kotlin showLineNumbers //if you put the 'android_fallback.json' file to the 'assets' directory val location = FileLocation.fromAsset("android_fallback.json") //or `FileLocation.fromAsset("/android_fallback.json")` if you placed it in a child folder of 'assets') //if you put the 'android_fallback.json' file to the 'res/raw' directory val location = FileLocation.fromResId(context, R.raw.android_fallback) //you can also pass a file URI val fileUri: Uri = //get Uri for the file with fallback paywalls val location = FileLocation.fromFileUri(fileUri) //pass the file location Adapty.setFallback(location, callback) ``` ```java showLineNumbers //if you put the 'android_fallback.json' file to the 'assets' directory FileLocation location = FileLocation.fromAsset("android_fallback.json"); //or `FileLocation.fromAsset("/android_fallback.json");` if you placed it in a child folder of 'assets') //if you put the 'android_fallback.json' file to the 'res/raw' directory FileLocation location = FileLocation.fromResId(context, R.raw.android_fallback); //you can also pass a file URI Uri fileUri = //get Uri for the file with fallback paywalls FileLocation location = FileLocation.fromFileUri(fileUri); //pass the file location Adapty.setFallback(location, callback); ``` | パラメータ | 説明 | | :----------- | :----------------------------------------------------------- | | **location** | フォールバック設定ファイルの [FileLocation](https://android.adapty.io/adapty/com.adapty.utils/-file-location/-companion/) オブジェクト | --- # File: android-localizations-and-locale-codes --- --- title: "Android SDKでローカライゼーションとロケールコードを使用する" description: "アプリのローカライゼーションとロケールコードを管理して、グローバルなユーザーにリーチしましょう(Android)。" --- ## なぜこれが重要なのか \{#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 を呼び出す際にそのキーの値を取得します: ```kotlin showLineNumbers // 1. Modify your strings.xml files /* strings.xml - Spanish */ es /* strings.xml - Portuguese (Brazil) */ pt-br // 2. Extract and use the locale code val localeCode = context.getString(R.string.adapty_paywalls_locale) // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` この方法により、アプリのすべてのユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。 ## ローカライゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} すべてのローカライゼーションに対してロケールコードを明示的に定義しなくても、似た結果(ただし完全に同一ではありません)を得ることができます。それは、プラットフォームが提供する他のオブジェクトからロケールコードを抽出する方法です: ```kotlin showLineNumbers val locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) context.resources.configuration.locales[0] else context.resources.configuration.locale val localeCode = locale.toLanguageTag() // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` この方法は、Adapty のサーバーが受け取る内容を正確に予測することが難しいため、推奨していません。 それでもこの方法を使用する場合は、関連するすべてのユースケースに対応していることを確認してください。 --- # File: android-web-paywall --- --- title: "Android SDKでウェブペイウォールを実装する" description: "ウェブペイウォールを設定して、Playストアの手数料や審査なしで収益を得ましょう。" --- :::important 始める前に、[ダッシュボードでウェブペイウォールを設定](web-paywall)し、Adapty SDK バージョン 3.15 以降をインストールしていることを確認してください。 ::: ## ウェブペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールを使用している場合は、SDKメソッドを使ってウェブペイウォールを処理する必要があります。`.openWebPaywall` メソッドは以下を行います: 1. 固有のURLを生成し、特定のユーザーに表示されたペイウォールと、そのユーザーがリダイレクトされるウェブページをAdaptyが紐付けられるようにします。 2. ユーザーがアプリに戻るタイミングを追跡し、プロファイルのアクセス権が更新されたかどうかを確認するために、短い間隔で`.getProfile`をリクエストします。 これにより、支払いが成功してアクセス権が更新された場合、サブスクリプションはほぼ即座にアプリ内で有効になります。 :::note ユーザーがアプリに戻った後、プロファイルの更新を反映するためにUIを更新してください。AdaptyはプロファイルのUpdateイベントを受信して処理します。 ::: ```kotlin showLineNumbers Adapty.openWebPaywall( activity = activity, product = product, ) { error -> if (error == null) { // the web paywall was opened successfully } else { // handle the error } } ``` :::note `openWebPaywall` メソッドには2つのバージョンがあります: 1. `openWebPaywall(product)` — ペイウォールに基づいてURLを生成し、プロダクトデータもURLに追加します。 2. `openWebPaywall(paywall)` — ペイウォールに基づいてURLを生成しますが、プロダクトデータはURLに追加しません。Adaptyペイウォール内のプロダクトとウェブペイウォールのプロダクトが異なる場合に使用してください。 ::: ## アプリ内ブラウザでウェブペイウォールを開く \{#open-web-paywalls-in-an-in-app-browser\} デフォルトでは、ウェブペイウォールは外部ブラウザで開きます。 シームレスなユーザー体験を提供するために、アプリ内ブラウザでウェブペイウォールを開くことができます。これにより、アプリを切り替えることなく、アプリケーション内でウェブ購入ページを表示してトランザクションを完了できます。 これを有効にするには、`presentation` パラメータを `AdaptyWebPresentation.InAppBrowser` に設定します: ```kotlin showLineNumbers Adapty.openWebPaywall( activity = activity, product = product, presentation = AdaptyWebPresentation.InAppBrowser, ) { error -> if (error == null) { // the web paywall was opened successfully } else { // handle the error val adaptyError = error } } ``` --- # File: android-troubleshoot-paywall-builder --- --- title: "Android SDKのペイウォールビルダーのトラブルシューティング" description: "Android SDKのペイウォールビルダーのトラブルシューティング" --- このガイドでは、Android SDKでAdapty ペイウォールビルダーを使用して作成したペイウォールを利用する際によくある問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: `getViewConfiguration` メソッドがペイウォール設定の取得に失敗する。 **原因**: ペイウォールビルダーで、デバイスへの表示が有効になっていない。 **解決策**: ペイウォールビルダーで **Show on device** トグルを有効にする。 ## ペイウォールのビュー数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールのビュー数が期待値の2倍になっている。 **原因**: ペイウォールビルダーまたはフローBuilder を使用しているにもかかわらず、コード内で `logShowFlow`(Android SDK v4以降)/ `logShowPaywall` を呼び出している可能性があります。これらのツールで作成したフローやペイウォールでは、アナリティクスが自動的に計測されるため、このメソッドを使用する必要はありません。 **解決策**: ペイウォールビルダーまたはフローBuilderを使用している場合は、コード内で `logShowFlow`(Android SDK v4以降)/ `logShowPaywall` を呼び出していないことを確認してください。 ## その他の問題 \{#other-issues\} **問題**: 上記で取り上げていないペイウォールビルダー関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](android-sdk-migration-guides)を参照し、SDKを最新バージョンへ移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: android-quickstart-manual --- --- title: "Android SDKのカスタムペイウォールで購入を有効にする" description: "Adapty SDKをAndroidカスタムペイウォールに統合してアプリ内課金を有効にする方法。" --- このガイドでは、Adaptyをカスタムペイウォールに統合する方法を説明します。ペイウォールの実装を完全にコントロールしながら、Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を行います。 :::important **このガイドは、カスタムペイウォールを実装している開発者向けです。** 課金を有効にする最も簡単な方法をお探しであれば、[Adapty Flow Builder](android-quickstart-paywalls) をご利用ください。Flow Builder を使うと、ノーコードのビジュアルエディターでフローを作成でき、すべての購入ロジックは Adapty が自動的に処理します。また、アプリを再公開することなく、さまざまなデザインをテストすることができます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトを設定する \{#set-up-products\} アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセスなど) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定。Adapty では、プロダクトを取得するにはペイウォールを使う必要がありますが、この設計のおかげでアプリのコードを変更せずにプロダクト、価格、オファーを変更できます。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでプレースメントにペイウォールを設定しておき、コード内でプレースメント ID を指定してリクエストします。これにより、A/B テストの実施や、ユーザーごとに異なるペイウォールの表示が簡単に行えます。 これらのコンセプトは、カスタムペイウォールを使用する場合でも理解しておく必要があります。基本的には、アプリで販売するプロダクトを管理するための仕組みです。 カスタムペイウォールを実装するには、**ペイウォール**を作成し、**プレースメント**に追加する必要があります。この設定によって、プロダクトを取得できるようになります。ダッシュボードでの操作については、[こちら](quickstart)のクイックスタートガイドを参照してください。 ### ユーザーの管理 \{#manage-users\} バックエンド認証の有無にかかわらず利用できます。 ただし、Adapty SDKは匿名ユーザーと識別済みユーザーを異なる方法で処理します。詳細を理解し、ユーザーを適切に扱うために、[識別クイックスタートガイド](android-quickstart-identify)をお読みください。 ## ステップ 1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、次の手順が必要です。 1. `getFlow` メソッドに[プレースメント](placements) ID を渡して `flow` オブジェクトを取得する。 2. `getPaywallProducts` メソッドを使って、このフローのプロダクト配列を取得する。 ```kotlin showLineNumbers fun loadPaywall() { Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value Adapty.getPaywallProducts(flow) { productResult -> when (productResult) { is AdaptyResult.Success -> { val products = productResult.value // Use products to build your custom paywall UI } is AdaptyResult.Error -> { val error = productResult.error // Handle the error } } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } } ``` ```java showLineNumbers public void loadPaywall() { Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); Adapty.getPaywallProducts(flow, productResult -> { if (productResult instanceof AdaptyResult.Success) { List products = ((AdaptyResult.Success>) productResult).getValue(); // カスタムペイウォールUIの構築にproductsを使用する } else if (productResult instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) productResult).getError(); // エラーを処理する } }); } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // エラーを処理する } }); } ``` ## ステップ 2. 購入を処理する \{#step-2-accept-purchases\} カスタムペイウォールでユーザーがプロダクトをタップしたら、選択したプロダクトで `makePurchase` メソッドを呼び出します。これにより購入フローが処理され、更新されたプロファイルが返されます。 ```kotlin showLineNumbers fun purchaseProduct(activity: Activity, product: AdaptyPaywallProduct) { Adapty.makePurchase(activity, product) { result -> when (result) { is AdaptyResult.Success -> { when (val purchaseResult = result.value) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // Purchase successful, profile updated } is AdaptyPurchaseResult.UserCanceled -> { // User canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Purchase is pending (e.g., user will pay offline with cash) } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } } ``` ```java showLineNumbers public void purchaseProduct(Activity activity, AdaptyPaywallProduct product) { Adapty.makePurchase(activity, product, null, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue(); if (purchaseResult instanceof AdaptyPurchaseResult.Success) { AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile(); // 購入成功、プロファイルが更新されました } else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) { // ユーザーが購入をキャンセルしました } else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) { // 購入が保留中です(例:ユーザーが現金でオフライン支払いを行う場合) } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // エラーを処理します } }); } ``` ## ステップ 3. 購入を復元する \{#step-3-restore-purchases\} Google Play などのアプリストアでは、サブスクリプションを提供するすべてのアプリに対して、ユーザーが購入を復元できる方法を用意することを求めています。 ユーザーが復元ボタンをタップしたときに `restorePurchases` メソッドを呼び出してください。これにより、購入履歴が Adapty と同期され、更新されたプロファイルが返されます。 ```kotlin showLineNumbers fun restorePurchases() { Adapty.restorePurchases { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // Restore successful, profile updated } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } } ``` ```java showLineNumbers public void restorePurchases() { Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); // 復元成功、プロファイル更新済み } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // エラーを処理する } }); } ``` ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備が整いました。[Google Play ストアでの購入テスト](testing-on-android)を行い、ペイウォールからテスト購入を完了できることを確認してください。本番環境に対応した実装の例については、サンプルアプリの [ProductListFragment.kt](https://github.com/adaptyteam/AdaptySDK-Android/blob/master/app/src/main/java/com/adapty/example/ProductListFragment.kt) をご覧ください。エラーハンドリング、UI フィードバック、サブスクリプション管理を含む購入処理の実装例が確認できます。 次に、[ユーザーが購入を完了したかどうかを確認](android-check-subscription-status)して、ペイウォールを表示するか有料機能へのアクセスを付与するかを判断します。 --- # File: fetch-paywalls-and-products-android --- --- title: "Android SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "AdaptyのAndroid SDKでペイウォールとプロダクトを取得してユーザーの収益化を強化しましょう。" --- リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。**Flow Builder** や **Paywall Builder** でカスタマイズされたフローやペイウォールの取得については、[フローとペイウォールの取得](android-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 :::
モバイルアプリでフローとプロダクトの取得を始める前に(クリックして展開) 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[フローまたはペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに [Adapty SDK をインストールする](sdk-installation-android)。
## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)は App Store と Google Play 両方のプロダクトを組み合わせたものとして機能します。これらのクロスプラットフォームプロダクトはフローやペイウォールに統合され、モバイルアプリの特定のプレースメント内で表示できるようになります。 プロダクトを表示するには、`getFlow` メソッドを使っていずれかの[プレースメント](placements)から `AdaptyFlow` を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードするIDはプレースメントIDのみにしてください。フローはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。今日2つのプロダクトを返すフローが明日3つを返しても、コードを変更せずにすべてを表示できるようにしてください。 ::: ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 || **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

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

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

Adapty SDK はフローとペイウォールを 2 つの層に保存します。1 つ目は上述の定期更新キャッシュ、2 つ目は[フォールバックペイウォール](android-use-fallback-paywalls)です。また、フローとペイウォールの高速取得のために CDN を使用しており、CDN に到達できない場合に備えた独立したフォールバックサーバーも用意しています。

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

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

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

| プロダクトIDをハードコードしないでください!フローはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特別オファー(無料トライアルなど)は随時変更される可能性があります。コードがこれらのシナリオに対応できるようにしてください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはその2つのプロダクトを表示する必要があります。しかし、後で3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できる必要があります。ハードコードする必要があるのはプレースメントIDだけです。 レスポンスのパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | プレースメント、識別子(`id`、`variationId`)、名前、設定済みロケールごとのエントリを含む `remoteConfigs` 配列、および `hasViewConfiguration` フラグを持つ `AdaptyFlow` オブジェクトです。フローのプロダクトを取得するには、`getPaywallProducts(flow)` を呼び出してください。 | :::note v4 では、`locale` パラメータは `getFlow` から移動し、`getFlowConfiguration`(AdaptyUI でレンダリングする場合のみ使用)に渡すようになりました。カスタムペイウォールの場合、利用可能なすべてのロケールが `flow.remoteConfigs` にまとめて返されるため、ユーザーのデバイスやアプリの設定に合ったロケールを選択してください。 ::: ## プロダクトを取得する \{#fetch-products\} フローを取得したら、それに対応するプロダクト配列を取得できます: ```kotlin showLineNumbers Adapty.getPaywallProducts(flow) { result -> when (result) { is AdaptyResult.Success -> { val products = result.value // the requested products } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallProducts(flow, result -> { if (result instanceof AdaptyResult.Success) { List products = ((AdaptyResult.Success>) result).getValue(); // the requested products } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティが含まれます。 | 独自のフロー設計を実装する際、[`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) オブジェクトから以下のプロパティにアクセスする必要があります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細についてはリンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **Price** | ローカライズされた価格を表示するには、`product.price.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づいています。また、`product.price.amount` を使って価格を数値として取得することもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには、`product.price.currencySymbol` を使用します。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.subscriptionDetails?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づいています。サブスクリプション期間をプログラムで取得するには、`product.subscriptionDetails?.subscriptionPeriod` を使用します。そこから `unit` 列挙型にアクセスして長さ(DAY、WEEK、MONTH、YEAR、UNKNOWN)を取得できます。`numberOfUnits` の値で期間の単位数を取得できます。たとえば、四半期サブスクリプションの場合、unit プロパティには `MONTH`、numberOfUnits プロパティには `3` が返されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかどうかをバッジなどで示すには、`product.subscriptionDetails?.introductoryOfferPhases` プロパティを確認してください。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには次の便利なプロパティがあります:
• `paymentMode`:`FREE_TRIAL`、`PAY_AS_YOU_GO`、`PAY_UPFRONT`、`UNKNOWN` の値を持つ列挙型。無料トライアルは `FREE_TRIAL` タイプになります。
• `price`:割引価格の数値。無料トライアルの場合は `0` になります。
• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列。例えば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。
• `subscriptionPeriod`:オファー期間の個別の詳細をこのプロパティで取得することもできます。オファーに対しても前のセクションで説明したのと同じように機能します。
• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## デフォルトオーディエンスのフローでフロー取得を高速化する \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ即座に取得されるため、この処理を高速化することを特別に意識する必要はありません。ただし、オーディエンスやプレースメントの数が多く、ユーザーのインターネット接続が不安定な場合は、フローの取得に想定以上の時間がかかることがあります。そのような状況では、何も表示しないよりもスムーズなユーザー体験を提供するために、デフォルトフローを表示したい場合があるかもしれません。 これに対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、**All Users** オーディエンス向けに指定されたプレースメントのフローを取得します。ただし、推奨されるアプローチは `getFlow` メソッドでフローを取得することであり、詳細は上記の [フロー情報の取得](fetch-paywalls-and-products-android#fetch-flow-information) セクションを参照してください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)に対して異なるフローを表示する必要がある場合、課題が生じる可能性があります。現行(レガシー)バージョンに対応したフローを設計するか、現行(レガシー)バージョンのユーザーがフローを正しく表示できない問題を許容するかのどちらかを選ぶことになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同一のフローを表示することになるため、国・マーケティングアトリビューション・独自のカスタム属性に基づくパーソナライズされたターゲティングが利用できなくなります。 これらのデメリットを受け入れてでも高速なフロー取得の恩恵を受けたい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-android#fetch-flow-information)で説明した `getFlow` を引き続き使用してください。 ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value // the requested flow } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); // the requested flow } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 || **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` |

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

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

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

|
リモートコンフィグとカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズされたペイウォールの取得方法については、[ペイウォールビルダーのペイウォールと設定の取得](android-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-android)(モバイルアプリ)。
## ペイウォール情報の取得 \{#fetch-paywall-information\} Adapty では、[プロダクト](product)はApp StoreとGoogle Playの両方からのプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはペイウォールに統合されており、モバイルアプリの特定のプレースメント内に表示できます。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)のいずれかから[ペイウォール](paywalls)を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードしてよいのはプレースメントIDのみです。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更に動的に対応する必要があります。今日ペイウォールが2つのプロダクトを返し、明日3つを返しても、コードを変更せずにすべて表示できるようにしてください。 ::: ```kotlin showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

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

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

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

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

| プロダクト ID をハードコードしないでください!ペイウォールはリモートで設定されるため、利用可能なプロダクト、プロダクト数、特別オファー(無料トライアルなど)は随時変更される場合があります。こうしたシナリオにコードで対応できるようにしてください。 たとえば、最初に 2 つのプロダクトを取得した場合はそれらを表示し、後から 3 つ取得した場合はコードを変更せずに 3 つすべてを表示できるようにする必要があります。ハードコードする必要があるのは、プレースメント ID だけです。 レスポンスパラメータ: | パラメータ | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクト ID のリスト、ペイウォール識別子、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) オブジェクト。 | ## プロダクトを取得する \{#fetch-products\} ペイウォールを取得したら、それに対応するプロダクト配列を取得できます: ```kotlin showLineNumbers Adapty.getPaywallProducts(paywall) { result -> when (result) { is AdaptyResult.Success -> { val products = result.value // the requested products } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallProducts(paywall, result -> { if (result instanceof AdaptyResult.Success) { List products = ((AdaptyResult.Success>) result).getValue(); // the requested products } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他いくつかのプロパティが含まれます。 | 独自のペイウォールデザインを実装する場合、[`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) オブジェクトの以下のプロパティが必要になることが多いです。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティについては、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **タイトル** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づきます。 | | **価格** | ローカライズされた価格を表示するには、`product.price.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づきます。`product.price.amount` を使って価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.price.currencySymbol` を使用します。 | | **サブスクリプション期間** | 期間(週、月、年など)を表示するには、`product.subscriptionDetails?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づきます。プログラムでサブスクリプション期間を取得するには、`product.subscriptionDetails?.subscriptionPeriod` を使用します。そこから `unit` 列挙型にアクセスして長さを取得できます(DAY、WEEK、MONTH、YEAR、UNKNOWN)。`numberOfUnits` の値で期間の単位数が得られます。たとえば四半期サブスクリプションの場合、unit プロパティに `MONTH`、numberOfUnits プロパティに `3` が表示されます。 | | **初回オファー** | サブスクリプションに初回オファーが含まれていることを示すバッジなどのインジケーターを表示するには、`product.subscriptionDetails?.introductoryOfferPhases` プロパティを確認します。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下の便利なプロパティがあります:
• `paymentMode`:`FREE_TRIAL`、`PAY_AS_YOU_GO`、`PAY_UPFRONT`、`UNKNOWN` の値を持つ列挙型。無料トライアルは `FREE_TRIAL` タイプです。
• `price`:数値としての割引価格。無料トライアルの場合は `0` になります。
• `localizedNumberOfPeriods`:オファーの長さをデバイスのロケールでローカライズした文字列。たとえば3日間のトライアルオファーの場合、このフィールドに `3 days` と表示されます。
• `subscriptionPeriod`:オファー期間の個別の詳細をこのプロパティで取得することもできます。オファーに対しても前のセクションで説明したのと同じように機能します。
• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## デフォルトオーディエンスのペイウォールでフェッチを高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールのフェッチはほぼ瞬時に完了するため、この処理を高速化することを特に意識する必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合は、ペイウォールのフェッチに想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したい場合があるでしょう。 これを解決するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](fetch-paywalls-and-products-android#fetch-paywall-information)セクションをご参照ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがペイウォールの未表示という問題に直面することを許容するかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになり、国・マーケティングアトリビューション・独自のカスタム属性に基づいたパーソナライズされたターゲティングができなくなります。 ペイウォールの取得速度を優先してこれらの制約を受け入れる場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-android#fetch-paywall-information)で説明した `getPaywall` を使用してください。 ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // the requested paywall } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); // the requested paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` :::note `getPaywallForDefaultAudience` メソッドは Android SDK バージョン 2.11.3 以降で使用できます。 ::: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

|
--- # File: present-remote-config-paywalls-android --- --- title: "Android SDKでリモートコンフィグによるペイウォールをレンダリングする" description: "Adapty Android SDKでリモートコンフィグペイウォールを表示し、ユーザー体験をパーソナライズする方法を説明します。" --- リモートコンフィグを使ってペイウォールをカスタマイズした場合は、ユーザーに表示するためのレンダリングをアプリのコードで実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、またペイウォールの見た目をどうするかはあなた次第です。Adapty はリモートコンフィグを取得するメソッドを提供しており、カスタムペイウォールを自由に表示できます。 ## フローのリモートコンフィグを取得して表示する \{#get-flow-remote-config-and-present-it\} v4 では、フローは `remoteConfigs` 配列に設定済みロケールごとに 1 つの `AdaptyRemoteConfig` エントリを持ちます。ユーザーの設定に合ったロケールを選択し、必要な値を読み取ってください。 ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val flow = result.value val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() val headerText = config?.dataMap?.get("header_text") as? String } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyFlow flow = ((AdaptyResult.Success) result).getValue(); AdaptyRemoteConfig config = null; for (AdaptyRemoteConfig remoteConfig : flow.getRemoteConfigs()) { if ("en".equals(remoteConfig.getLocale())) { config = remoteConfig; break; } } if (config == null && !flow.getRemoteConfigs().isEmpty()) { config = flow.getRemoteConfigs().get(0); } if (config != null && config.getDataMap().get("header_text") instanceof String) { String headerText = (String) config.getDataMap().get("header_text"); } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` 必要な値をすべて取得したら、次はそれらをレンダリングして視覚的に魅力的なページに組み立てましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、デバイスを問わずシームレスで使いやすい体験を提供してください。 :::warning Adapty アナリティクスがファネルや A/B テストの情報を収集できるように、以下で説明する[ペイウォール表示イベントの記録](present-remote-config-paywalls-android#track-paywall-view-events)を必ず行ってください。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入を行う際は、フローからプロダクトを渡して `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実装](android-making-purchases)をご覧ください。 [フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](android-use-fallback-paywalls)をお勧めします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーに表示され、そのような状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントをトラッキングする \{#track-paywall-view-events\} Adapty はフローやペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、表示イベントのログ記録はユーザー側で行う必要があります。ユーザーがフローを見るタイミングを把握できるのは開発者だけだからです。 表示イベントをログに記録するには、`.logShowFlow(flow)` を呼び出すだけです。ファネルや A/B テストの指標にすぐ反映されます。 :::important [フローBuilder](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示する場合、`.logShowFlow(flow)`を呼び出す必要はありません。その場合、Adaptyは自動的にビューをトラッキングします。 ::: ```kotlin showLineNumbers Adapty.logShowFlow(flow) ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :---------- | :-------- |:------------------------------------------------------------------------------------------| | **flow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリングをアプリのコード内で実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、ペイウォールに含める内容や表示方法はすべて自由に決められます。リモートコンフィグで設定したカスタムペイウォールを表示できるよう、リモートコンフィグを取得するメソッドを提供しています。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```kotlin showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value val headerText = paywall.remoteConfig?.dataMap?.get("header_text") as? String } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success) result).getValue(); AdaptyPaywall.RemoteConfig remoteConfig = paywall.getRemoteConfig(); if (remoteConfig != null) { if (remoteConfig.getDataMap().get("header_text") instanceof String) { String headerText = (String) remoteConfig.getDataMap().get("header_text"); } } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` この時点で、必要な値をすべて取得したら、それらをレンダリングして視覚的に魅力的なページに組み立てましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、デバイスを問わずシームレスで使いやすい体験を提供してください。 :::warning 後述のとおり、[ペイウォールの表示イベントを必ず記録](present-remote-config-paywalls-android#track-paywall-view-events)してください。これにより、Adapty アナリティクスがファネルおよび A/B テスト用の情報を収集できるようになります。 ::: ペイウォールの表示が完了したら、購入フローのセットアップに進みます。ユーザーが購入を行う際は、ペイウォールのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入処理](android-making-purchases)をご覧ください。 [フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](android-use-fallback-paywalls)をおすすめします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーへ表示され、こうした状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス計測をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザー自身が記録する必要があります。ペイウォールがいつ表示されるかを把握しているのはあなただけだからです。 ペイウォールの表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。記録されたデータは、ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールを表示している場合は、`.logShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```kotlin showLineNumbers Adapty.logShowPaywall(paywall) ``` リクエストパラメータ: | パラメータ | 必須/任意 | 説明 | | :---------- | :------- |:------------------------------------------------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) オブジェクト。 | --- # File: android-making-purchases --- --- title: "Android 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)をお使いですか?** 購入は自動的に処理されるため、このステップはスキップできます。 **ステップバイステップのガイドをお探しですか?** 全体のコンテキストを含む実装手順については、[クイックスタートガイド](android-implement-paywalls-manually)をご確認ください。 ::: ```kotlin showLineNumbers Adapty.makePurchase(activity, product, null) { result -> when (result) { is AdaptyResult.Success -> { when (val purchaseResult = result.value) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // Grant access to the paid features } } is AdaptyPurchaseResult.UserCanceled -> { // Handle the case where the user canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Handle deferred purchases (e.g., the user will pay offline with cash) } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } ``` ```java showLineNumbers Adapty.makePurchase(activity, product, null, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue(); if (purchaseResult instanceof AdaptyPurchaseResult.Success) { AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile(); AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); if (premium != null && premium.isActive()) { // Grant access to the paid features } } else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) { // Handle the case where the user canceled the purchase } else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) { // Handle deferred purchases (e.g., the user will pay offline with cash) } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); ``` リクエストパラメータ: | パラメータ | 必須 | 説明 | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall-product/) オブジェクト。 | レスポンスパラメータ: | パラメータ | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** |

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

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

| :::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\} ユーザーが現在のサブスクリプションを更新する代わりに新しいサブスクリプションを選択した場合、その動作はアプリストアによって異なります。Google Play では、サブスクリプションは自動的に更新されません。以下に説明するように、モバイルアプリのコードで切り替えを管理する必要があります。 Android でサブスクリプションを別のものに変更するには、追加パラメータを指定して `.makePurchase()` メソッドを呼び出します: ```kotlin showLineNumbers Adapty.makePurchase( activity, product, AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(subscriptionUpdateParams) .build() ) { result -> when (result) { is AdaptyResult.Success -> { when (val purchaseResult = result.value) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // successful cross-grade } is AdaptyPurchaseResult.UserCanceled -> { // user canceled the purchase flow } is AdaptyPurchaseResult.Pending -> { // the purchase has not been finished yet, e.g. user will pay offline by cash } } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } ``` 追加リクエストパラメータ: | パラメータ | 必須 | 説明 | | :--------------------------- | :------- | :----------------------------------------------------------- | | **subscriptionUpdateParams** | 必須 | [`AdaptySubscriptionUpdateParameters`](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/) オブジェクト。 | ```java showLineNumbers Adapty.makePurchase( activity, product, new AdaptyPurchaseParameters.Builder() .withSubscriptionUpdateParams(subscriptionUpdateParams) .build(), result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchaseResult purchaseResult = ((AdaptyResult.Success) result).getValue(); if (purchaseResult instanceof AdaptyPurchaseResult.Success) { AdaptyProfile profile = ((AdaptyPurchaseResult.Success) purchaseResult).getProfile(); // successful cross-grade } else if (purchaseResult instanceof AdaptyPurchaseResult.UserCanceled) { // user canceled the purchase flow } else if (purchaseResult instanceof AdaptyPurchaseResult.Pending) { // the purchase has not been finished yet, e.g. user will pay offline by cash } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle the error } }); ``` 追加リクエストパラメータ: | パラメータ | 必須 | 説明 | | :--------------------------- | :------- | :----------------------------------------------------------- | | **subscriptionUpdateParams** | 必須 | [`AdaptySubscriptionUpdateParameters`](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/) オブジェクト。 | サブスクリプションと置き換えモードの詳細については、Google Developer のドキュメントをご覧ください: - [置き換えモードについて](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())。注意:実際のサブスクリプション変更は、現在のサブスクリプションの請求期間が終了した時点でのみ発生します。 ### プリペイドプランを管理する \{#manage-prepaid-plans\} アプリユーザーが[プリペイドプラン](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans)(例:数ヶ月分の非自動更新サブスクリプションを購入)を利用できる場合、プリペイドプランの[保留中のトランザクション](https://developer.android.com/google/play/billing/subscriptions#pending)を有効にできます。 ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withEnablePendingPrepaidPlans(true) .build() ``` ```java showLineNumbers new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withEnablePendingPrepaidPlans(true) .build(); ``` --- # File: android-restore-purchase --- --- title: "Android SDKで購入を復元する" description: "Adaptyで購入を復元し、シームレスなユーザー体験を実現する方法を学びましょう。" --- 購入の復元は、サブスクリプションやアプリ内課金などの購入済みコンテンツに、再度課金されることなくアクセスを取り戻せる機能です。アプリをアンインストールして再インストールしたユーザーや、新しいデバイスに乗り換えたユーザーが、以前の購入コンテンツに再び支払いなしでアクセスしたい場合に特に役立ちます。 :::note [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールでは、追加のコードなしで購入が自動的に復元されます。その場合は、このステップをスキップできます。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使ってペイウォールをカスタマイズしていない場合に購入を復元するには、`.restorePurchases()` メソッドを呼び出してください。 ```kotlin showLineNumbers Adapty.restorePurchases { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // successful access restore } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); if (profile != null) { AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("YOUR_ACCESS_LEVEL"); if (premium != null && premium.isActive()) { // successful access restore } } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` レスポンスパラメータ: | パラメータ | 説明 | |---------|-----------| | **Profile** |

[`AdaptyProfile`](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/) オブジェクト。このモデルにはアクセスレベル、サブスクリプション、買い切り購入に関する情報が含まれています。

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

| :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: implement-observer-mode-android --- --- title: "Android SDKにオブザーバーモードを実装する" description: "Android SDKでAdaptyのオブザーバーモードを実装し、ユーザーのサブスクリプションイベントを追跡します。" --- すでに独自の購入インフラがあり、Adaptyへの完全な移行を検討していない場合は、[オブザーバーモード](observer-vs-full-mode)を検討してみてください。基本的な機能として、オブザーバーモードは高度なアナリティクスと、アトリビューションおよびアナリティクスシステムとのシームレスな連携を提供します。 これで十分な場合、必要な作業は以下の2つだけです: 1. `observerMode` パラメータを `true` に設定して、Adapty SDKの設定時にオブザーバーモードを有効化する。[Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk)のセットアップ手順を参照してください。 2. 既存の購入インフラから[トランザクションをAdaptyに報告する](report-transactions-observer-mode-android)。 ## オブザーバーモードのセットアップ \{#observer-mode-setup\} 購入とサブスクリプションのステータスを自分で管理し、サブスクリプションイベントとアナリティクスの送信にAdaptyを使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作している場合、Adapty SDKはトランザクションをクローズしません。そのため、ご自身でトランザクションを処理するようにしてください。 ::: ```kotlin showLineNumbers class MyApplication : Application() { override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObserverMode(true) //default false .build() ) } ``` ```java showLineNumbers public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); Adapty.activate( applicationContext, new AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withObserverMode(true) //default false .build() ); } ``` パラメータ: | パラメータ | 説明 | | --------------------------- | ------------------------------------------------------------ | | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御するboolean値。デフォルト値は `false` です。 | ## オブザーバーモードでAdaptyのペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adaptyのペイウォールとそれを利用したA/Bテスト機能も使用したい場合は可能ですが、オブザーバーモードでは追加の設定が必要です。上記の手順に加えて、以下の作業が必要です: 1. [リモートコンフィグペイウォール](present-remote-config-paywalls-android)の場合は通常通りペイウォールを表示する。ペイウォールビルダーのペイウォールについては、[Android](android-present-paywall-builder-paywalls-in-observer-mode)の専用セットアップガイドを参照してください。 3. 購入トランザクションに[ペイウォールを関連付ける](report-transactions-observer-mode-android)。 --- # File: report-transactions-observer-mode-android --- --- title: "Android SDKのオブザーバーモードでトランザクションを報告する" description: "Android SDKのAdaptyオブザーバーモードで購入トランザクションを報告し、ユーザーインサイトと収益トラッキングを行います。" --- オブザーバーモードでは、Adapty SDKは既存の購入システムを通じて行われた購入を自動的に追跡できません。アプリストアからのトランザクションを自分で報告する必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を完了しておくことが重要です。 各トランザクションをAdaptyに明示的に報告するには、`reportTransaction`を使用してください。 :::warning **トランザクションの報告をスキップしないでください!** `reportTransaction`を呼び出さない場合、Adaptyはそのトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に`variationId`を含めてください。これにより、購入がトリガーとなったペイウォールに紐付けられ、正確なペイウォールアナリティクスが確保されます。 ```kotlin showLineNumbers val transactionInfo = TransactionInfo.fromPurchase(purchase) Adapty.reportTransaction(transactionInfo, variationId) { result -> if (result is AdaptyResult.Success) { // success } } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- | ------------------------------------------------------------ | | transactionInfo | 必須 | 購入からのTransactionInfoです。purchaseはBillingライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。 | | variationId | 任意 | バリアントの文字列識別子です。[AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | ```java showLineNumbers TransactionInfo transactionInfo = TransactionInfo.fromPurchase(purchase); Adapty.reportTransaction(transactionInfo, variationId, result -> { if (result instanceof AdaptyResult.Success) { // success } }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- | ------------------------------------------------------------ | | transactionInfo | 必須 | 購入からのTransactionInfoです。purchaseはBillingライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。 | | variationId | 任意 | バリアントの文字列識別子です。[AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | オブザーバーモードでは、Adapty SDKは既存の購入システムを通じて行われた購入を自動的に追跡できません。アプリストアからのトランザクションを報告するか、復元する必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を完了しておくことが重要です。 トランザクションをAdaptyに報告するには、`restorePurchases`を使用してください。 :::warning **購入の復元をスキップしないでください!** `restorePurchases`を呼び出さない場合、Adaptyはそのトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、`setVariationId`メソッドを使用して、トランザクションを購入のきっかけとなったペイウォールに紐付けてください。これにより、正確なアナリティクスのために購入がトリガーとなったペイウォールに正しく関連付けられます。この手順は、Adaptyのペイウォールを使用している場合にのみ必要です。 ```kotlin showLineNumbers Adapty.restorePurchases { result -> if (result is AdaptyResult.Success) { // success } } Adapty.setVariationId(transactionId, variationId) { error -> if (error == null) { // success } } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | 購入の文字列識別子(`purchase.getOrderId`)です。purchaseはBillingライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。 | | variationId | 必須 | バリアントの文字列識別子です。[AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | ```java showLineNumbers Adapty.restorePurchases(result -> { if (result instanceof AdaptyResult.Success) { // success } }); Adapty.setVariationId(transactionId, variationId, error -> { if (error == null) { // success } }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | 購入の文字列識別子(`purchase.getOrderId`)です。purchaseはBillingライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。 | | variationId | 必須 | バリアントの文字列識別子です。[AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | **トランザクションの報告** オブザーバーモードでAdaptyにトランザクションを報告するには、[モバイルコードでの購入の復元](android-restore-purchase)ページで説明されているように`restorePurchases`を使用してください。 :::warning **トランザクションの報告をスキップしないでください!** `restorePurchases`を呼び出さない場合、Adaptyはそのトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: **ペイウォールとトランザクションの関連付け** Adapty SDKは購入の発生元を判断できません。購入の処理はあなた自身が行うためです。そのため、オブザーバーモードでペイウォールやA/B テストを使用する場合は、アプリストアからのトランザクションをモバイルアプリのコード内で対応するペイウォールに関連付ける必要があります。アプリのリリース前にこれを正しく設定しておくことが重要です。設定しないと、アナリティクスにエラーが発生します。 ```kotlin Adapty.setVariationId(transactionId, variationId) { error -> if (error == null) { // success } } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | 購入の文字列識別子(purchase.getOrderId)です。purchaseはBillingライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。 | | variationId | 必須 | バリアントの文字列識別子です。[AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | ```java Adapty.setVariationId(transactionId, variationId, error -> { if (error == null) { // success } }); ``` | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | 購入の文字列識別子(purchase.getOrderId)です。purchaseはBillingライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。 | | variationId | 必須 | バリアントの文字列識別子です。[AdaptyPaywall](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | --- # File: android-present-paywall-builder-paywalls-in-observer-mode --- --- title: "Android SDKのオブザーバーモードでPaywall Builderのペイウォールを表示する" description: "Adaptyのペイウォールビルダーを使用してオブザーバーモードでペイウォールを表示する方法について説明します。" --- フローまたはペイウォールをフローまたはペイウォールビルダーを使って作成した場合、モバイルアプリのコードでユーザーに表示するためのレンダリング処理を気にする必要はありません。そのようなフローやペイウォールには、表示する内容とその表示方法の両方が含まれています。 :::warning このセクションは[オブザーバーモード](observer-vs-full-mode)専用です。オブザーバーモードで作業していない場合は、[Android - フロー&ペイウォールの表示](android-present-paywalls)のトピックを参照してください。 :::
フローの表示を始める前に(クリックして展開) 1. Adapty と [Google Play の初期連携](initial-android)を設定する。 2. SDK をインストールして設定する。`observerMode` パラメータを `true` に設定してください。[Android 向けのフレームワーク別手順](sdk-installation-android)を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 4. [ビルダーでフローまたはペイウォールを設定](create-paywall)し、プロダクトを割り当てる。 5. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールを割り当てる](create-placement)。 6. モバイルアプリのコードで[フローとその設定を取得する](android-get-pb-paywalls)。

1. `AdaptyUiObserverModeHandler` を実装します。 `onPurchaseInitiated` イベントは、ユーザーが購入を開始したことを通知します。このコールバックに応じて、カスタム購入フローをトリガーできます。 ```kotlin showLineNumbers val observerModeHandler = AdaptyUiObserverModeHandler { product, flow, flowView, onStartPurchase, onFinishPurchase -> onStartPurchase() yourBillingClient.makePurchase( product, onSuccess = { purchase -> onFinishPurchase() //handle success }, onError = { onFinishPurchase() //handle error }, onCancel = { onFinishPurchase() //handle cancel } ) } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = (product, flow, flowView, onStartPurchase, onFinishPurchase) -> { onStartPurchase.invoke(); yourBillingClient.makePurchase( product, purchase -> { onFinishPurchase.invoke(); //handle success }, error -> { onFinishPurchase.invoke(); //handle error }, () -> { //cancellation onFinishPurchase.invoke(); //handle cancel } ); }; ``` Observerモードでの購入復元を処理するには、`getRestoreHandler()`をオーバーライドします。デフォルトでは`null`を返し、Adaptyの組み込み`Adapty.restorePurchases()`フローが使われます。独自の復元実装を提供するには: ```kotlin showLineNumbers val observerModeHandler = object : AdaptyUiObserverModeHandler { // onPurchaseInitiated implementation (see above) override fun getRestoreHandler() = AdaptyUiObserverModeHandler.RestoreHandler { onStartRestore, onFinishRestore -> onStartRestore() yourBillingClient.restorePurchases( onSuccess = { restoredPurchases -> onFinishRestore() //handle successful restore }, onError = { onFinishRestore() //handle error } ) } } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = new AdaptyUiObserverModeHandler() { // onPurchaseInitiated implementation (see above) @Override public RestoreHandler getRestoreHandler() { return (onStartRestore, onFinishRestore) -> { onStartRestore.invoke(); yourBillingClient.restorePurchases( restoredPurchases -> { onFinishRestore.invoke(); //handle successful restore }, error -> { onFinishRestore.invoke(); //handle error } ); }; } }; ``` AdaptyUIに購入またはリストア処理を通知するために、以下のコールバックを呼び出すことを忘れないでください。これは、ローダーの表示など、適切なフローの動作に必要です。 | コールバック | 説明 | | :----------------- |:---------------------------------------------------------------------------------------| | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | | onStartRestore() | 省略可。復元が開始されたことを AdaptyUI に通知するために呼び出せるコールバックです。 | | onFinishRestore() | 省略可。復元が完了したことを AdaptyUI に通知するために呼び出せるコールバックです。 | 2. デバイス画面にビジュアルフローを表示するには、まずそれを設定する必要があります。 そのためには、`AdaptyUI.getFlowView()` メソッドを呼び出すか、`AdaptyFlowView` を直接作成してください: ```kotlin showLineNumbers val flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler, ) ``` ```kotlin showLineNumbers val flowView = AdaptyFlowView(activity) // or retrieve it from xml ... with(flowView) { showFlow( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler, ) } ``` ```java showLineNumbers AdaptyFlowView flowView = AdaptyUI.getFlowView( activity, flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler ); ``` ```java showLineNumbers AdaptyFlowView flowView = new AdaptyFlowView(activity); //必要に応じてビュー階層に追加するか、XMLから受け取ります ... flowView.showFlow(flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler); ``` ```xml showLineNumbers ``` ビューが正常に作成されたら、それをビュー階層に追加して表示できます。 これを行うには、次のコンポーザブル関数を使用します: ```kotlin showLineNumbers AdaptyFlowScreen( flowConfiguration, products, eventListener, insets, customAssets, tagResolver, timerResolver, observerModeHandler, ) ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **flowConfiguration** | 必須 | フローの視覚的な詳細を含む `AdaptyUI.FlowConfiguration` オブジェクトを指定します。ロードには `AdaptyUI.getFlowConfiguration(flow)` メソッドを使用してください。詳細は [ビュー設定の取得](android-get-pb-paywalls#fetch-the-view-configuration) を参照してください。 | | **products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために、`AdaptyPaywallProduct` の配列を指定します。`null` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **eventListener** | 任意 | フローイベントを監視するために `AdaptyFlowEventListener` を指定します。使いやすさのため、`AdaptyFlowDefaultEventListener` を継承することをおすすめします。詳細は [フロー&ペイウォールイベントの処理](android-handling-events) を参照してください。 | | **insets** | 任意 | インセットは、タップ可能な要素がシステムバーの背後に隠れないようにするための、フロー周囲の余白です。デフォルト: `Unspecified`(Adapty がインセットを自動的に調整します)。[フローインセットの変更](android-present-paywalls#change-flow-insets) を参照してください。 | | **customAssets** | 任意 | フローまたはペイウォールの画像や動画を実行時に差し替えるために、`AdaptyCustomAssets` オブジェクトを渡します。詳細は [アセットのカスタマイズ](android-get-pb-paywalls#customize-assets) を参照してください。 | | **tagResolver** | 任意 | フローのテキスト内のカスタムタグを解決するために `AdaptyUiTagResolver` を使用します。このリゾルバはタグパラメータを受け取り、対応する文字列に変換します。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | | **observerModeHandler** | オブザーバーモードの場合は必須 | 前のステップで実装した `AdaptyUiObserverModeHandler`。 | :::warning [ペイウォールを購入トランザクションに紐づける](report-transactions-observer-mode-android)ことを忘れないようにしてください。これを行わないと、Adapty は購入のソースフローを特定できません。 :::
ペイウォールを表示する前に(クリックして展開) 1. Adaptyの初期インテグレーションを[Google Play](initial-android)および[App Store](initial_ios)と設定してください。 2. SDKをインストールして設定し、`observerMode`パラメータを`true`に設定してください。フレームワーク別の手順は[Android向け](sdk-installation-android)を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 4. Adapty ダッシュボードで[ペイウォールを設定してプロダクトを割り当て](create-paywall)、ペイウォールビルダーを使用してカスタマイズしてください。 5. Adapty ダッシュボードで[プレースメントを作成してペイウォールを割り当て](create-placement)てください。 6. モバイルアプリのコード内で[ペイウォールビルダーのペイウォールとその設定を取得](android-get-pb-paywalls)してください。

1. `AdaptyUiObserverModeHandler` を実装します。 `onPurchaseInitiated` イベントは、ユーザーが購入を開始したことを通知します。このコールバックに応答して、独自の購入フローをトリガーできます。 ```kotlin showLineNumbers val observerModeHandler = AdaptyUiObserverModeHandler { product, paywall, paywallView, onStartPurchase, onFinishPurchase -> onStartPurchase() yourBillingClient.makePurchase( product, onSuccess = { purchase -> onFinishPurchase() //handle success }, onError = { onFinishPurchase() //handle error }, onCancel = { onFinishPurchase() //handle cancel } ) } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = (product, paywall, paywallView, onStartPurchase, onFinishPurchase) -> { onStartPurchase.invoke(); yourBillingClient.makePurchase( product, purchase -> { onFinishPurchase.invoke(); //handle success }, error -> { onFinishPurchase.invoke(); //handle error }, () -> { //cancellation onFinishPurchase.invoke(); //handle cancel } ); }; ``` Observerモードでリストアを処理するには、`getRestoreHandler()`をオーバーライドしてください。デフォルトでは`null`が返され、Adaptyの組み込み`Adapty.restorePurchases()`フローが使われます。独自のリストア実装を提供するには: ```kotlin showLineNumbers val observerModeHandler = object : AdaptyUiObserverModeHandler { // onPurchaseInitiated implementation (see above) override fun getRestoreHandler() = AdaptyUiObserverModeHandler.RestoreHandler { onStartRestore, onFinishRestore -> onStartRestore() yourBillingClient.restorePurchases( onSuccess = { restoredPurchases -> onFinishRestore() //handle successful restore }, onError = { onFinishRestore() //handle error } ) } } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = new AdaptyUiObserverModeHandler() { // onPurchaseInitiated implementation (see above) @Override public RestoreHandler getRestoreHandler() { return (onStartRestore, onFinishRestore) -> { onStartRestore.invoke(); yourBillingClient.restorePurchases( restoredPurchases -> { onFinishRestore.invoke(); //handle successful restore }, error -> { onFinishRestore.invoke(); //handle error } ); }; } }; ``` AdaptyUIに購入または復元プロセスを通知するために、以下のコールバックを呼び出してください。これはローダーの表示など、ペイウォールの適切な動作に必要です: | コールバック | 説明 | | :----------------- |:---------------------------------------------------------------------------------------| | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | | onStartRestore() | 任意。復元が開始されたことを AdaptyUI に通知するために呼び出せるコールバックです。 | | onFinishRestore() | 任意。復元が完了したことを AdaptyUI に通知するために呼び出せるコールバックです。 | 2. デバイス画面にビジュアルペイウォールを表示するには、まず設定が必要です。 これを行うには、`AdaptyUI.getPaywallView()` メソッドを呼び出すか、`AdaptyPaywallView` を直接作成します。 ```kotlin showLineNumbers val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler, ) ``` ```kotlin showLineNumbers val paywallView = AdaptyPaywallView(activity) // or retrieve it from xml ... with(paywallView) { showPaywall( viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler, ) } ``` ```java showLineNumbers AdaptyPaywallView paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler ); ``` ```java showLineNumbers AdaptyPaywallView paywallView = new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml ... paywallView.showPaywall(viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, observerModeHandler); ``` ```xml showLineNumbers ``` ビューの作成に成功したら、それをビュー階層に追加して表示できます。 これを行うには、次のコンポーザブル関数を使用します: ```kotlin showLineNumbers AdaptyPaywallScreen( viewConfiguration, products, eventListener, personalizedOfferResolver, tagResolver, timerResolver, ) ``` リクエストパラメータ: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **Products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` の配列を渡します。`null` を渡した場合、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **ViewConfiguration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyViewConfiguration` オブジェクトを渡します。`Adapty.getViewConfiguration(paywall)` メソッドを使って読み込んでください。詳細は [ペイウォールのビジュアル設定を取得する](#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) をご参照ください。 | | **EventListener** | 任意 | ペイウォールのイベントを監視するために `AdaptyUiEventListener` を渡します。使いやすさのために `AdaptyUiDefaultEventListener` を継承することを推奨します。詳細は [ペイウォールイベントの処理](android-handling-events) をご参照ください。 | | **PersonalizedOfferResolver** | 任意 | パーソナライズされた価格([詳細はこちら](https://developer.android.com/google/play/billing/integrate#personalized-price))を示すには、`AdaptyUiPersonalizedOfferResolver` を実装し、`AdaptyPaywallProduct` の価格がパーソナライズされている場合に `true`、そうでない場合に `false` を返す独自のロジックを渡します。 | | **TagResolver** | 任意 | ペイウォールテキスト内のカスタムタグを解決するために `AdaptyUiTagResolver` を使います。このリゾルバーはタグパラメーターを受け取り、対応する文字列に変換します。詳細はペイウォールビルダーのカスタムタグのトピックをご参照ください。 | | **ObserverModeHandler** | オブザーバーモードでは必須 | 前のステップで実装した `AdaptyUiObserverModeHandler`。 | | **variationId** | 必須 | バリエーションの文字列識別子。[`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) オブジェクトの `variationId` プロパティから取得できます。 | | **transaction** | 必須 |

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

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

Android の場合: 購入の文字列識別子(`purchase.getOrderId()`)。ここで purchase は billing ライブラリの [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。

|
ペイウォールを表示する前に(クリックして展開) 1. Adapty の初期インテグレーションを [Google Play](initial-android) および [App Store](initial_ios) と設定します。 2. SDK をインストールして設定します。`observerMode` パラメーターを `true` に設定してください。フレームワーク別の手順は [Android](sdk-installation-android)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk)、[Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk) を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. Adapty ダッシュボードで[ペイウォールを設定してプロダクトを割り当て](create-paywall)、ペイウォールビルダーを使ってカスタマイズします。 5. Adapty ダッシュボードで[プレースメントを作成してペイウォールを割り当て](create-placement)ます。 6. モバイルアプリのコードで [Paywall Builder のペイウォールとその設定を取得](android-get-pb-paywalls)します。
1. `AdaptyUiObserverModeHandler` を実装します。`AdaptyUiObserverModeHandler` のコールバック(`onPurchaseInitiated`)は、ユーザーが購入を開始したときに通知します。このコールバックに応じてカスタム購入フローをトリガーするには、次のようにします。 ```kotlin showLineNumbers val observerModeHandler = AdaptyUiObserverModeHandler { product, paywall, paywallView, onStartPurchase, onFinishPurchase -> onStartPurchase() yourBillingClient.makePurchase( product, onSuccess = { purchase -> onFinishPurchase() //handle success }, onError = { onFinishPurchase() //handle error }, onCancel = { onFinishPurchase() //handle cancel } ) } ``` ```java showLineNumbers AdaptyUiObserverModeHandler observerModeHandler = (product, paywall, paywallView, onStartPurchase, onFinishPurchase) -> { onStartPurchase.invoke(); yourBillingClient.makePurchase( product, purchase -> { onFinishPurchase.invoke(); //handle success }, error -> { onFinishPurchase.invoke(); //handle error }, () -> { //cancellation onFinishPurchase.invoke(); //handle cancel } ); }; ``` また、これらのコールバックを AdaptyUI に呼び出すことを忘れないでください。これは、ローダーの表示など、ペイウォールが適切に動作するために必要です。 | Kotlinのコールバック | Javaのコールバック | 説明 | | :----------------- | :------------------------ | :-------------------------------------------------------------------------------------------------------------------------------- | | onStartPurchase() | onStartPurchase.invoke() | 購入が開始されたことをAdaptyUIに通知するために呼び出すコールバックです。 | | onFinishPurchase() | onFinishPurchase.invoke() | 購入が正常に完了したか失敗したか、またはキャンセルされたことをAdaptyUIに通知するために呼び出すコールバックです。 | 2. ビジュアルペイウォールを表示するには、まず初期化が必要です。これを行うには、`AdaptyUI.getPaywallView()` メソッドを呼び出すか、`AdaptyPaywallView` を直接作成します。 ```kotlin showLineNumbers val paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), eventListener, personalizedOfferResolver, tagResolver, observerModeHandler, ) //======= OR ======= val paywallView = AdaptyPaywallView(activity) // or retrieve it from xml ... with(paywallView) { setEventListener(eventListener) setObserverModeHandler(observerModeHandler) showPaywall( viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), personalizedOfferResolver, tagResolver, ) } ``` ```java showLineNumbers AdaptyPaywallView paywallView = AdaptyUI.getPaywallView( activity, viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), eventListener, personalizedOfferResolver, tagResolver, observerModeHandler ); //======= OR ======= AdaptyPaywallView paywallView = new AdaptyPaywallView(activity); //add to the view hierarchy if needed, or you receive it from xml ... paywallView.setEventListener(eventListener); paywallView.setObserverModeHandler(observerModeHandler); paywallView.showPaywall(viewConfiguration, products, AdaptyPaywallInsets.of(topInset, bottomInset), personalizedOfferResolver); ``` ```xml showLineNumbers ``` ビューが正常に作成されたら、ビュー階層に追加して表示できます。 リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` の配列を指定します。`null` を渡した場合、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **ViewConfiguration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyViewConfiguration` オブジェクトを指定します。`Adapty.getViewConfiguration(paywall)` メソッドを使って読み込んでください。詳細は [ペイウォールのビジュアル設定を取得する](android-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) を参照してください。 | | **Insets** | 必須 | システムバーが重なる領域の情報を含む `AdaptyPaywallInsets` オブジェクトを定義し、コンテンツの上下マージンを設定します。ステータスバーやナビゲーションバーが `AdaptyPaywallView` に重ならない場合は `AdaptyPaywallInsets.NONE` を渡してください。システムバーが UI の一部に重なるフルスクリーンモードの場合は、表の下に示す方法でインセットを取得してください。 | | **EventListener** | 任意 | ペイウォールのイベントを監視するために `AdaptyUiEventListener` を指定します。使いやすさのため、AdaptyUiDefaultEventListener を拡張することを推奨します。詳細は [ペイウォールイベントの処理](android-handling-events) を参照してください。 | | **PersonalizedOfferResolver** | 任意 | パーソナライズされた価格([詳細はこちら](https://developer.android.com/google/play/billing/integrate#personalized-price))を示すには、`AdaptyUiPersonalizedOfferResolver` を実装し、`AdaptyPaywallProduct` の価格がパーソナライズされている場合に true、そうでない場合に false を返す独自ロジックを渡してください。 | | **TagResolver** | 任意 | ペイウォールテキスト内のカスタムタグを解決するために `AdaptyUiTagResolver` を使用します。このリゾルバーはタグパラメーターを受け取り、対応する文字列に解決します。詳細はペイウォールビルダーのカスタムタグに関するトピックを参照してください。 | | **ObserverModeHandler** | Observer モードで必須 | 前のステップで実装した `AdaptyUiObserverModeHandler`。 | | **variationId** | 必須 | バリアントの文字列識別子。[`AdaptyPaywall`](https://android.adapty.io/adapty/com.adapty.models/-adapty-paywall/) オブジェクトの `variationId` プロパティで取得できます。 | | **transaction** | 必須 |

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

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

Android の場合: 購入の文字列識別子(`purchase.getOrderId()`)。ここで purchase は billing ライブラリの [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。

| システムバーがUIの一部に重なるフルスクリーンモードでは、以下の方法でインセットを取得します。 ```kotlin showLineNumbers import androidx.core.graphics.Insets import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat //create extension function fun View.onReceiveSystemBarsInsets(action: (insets: Insets) -> Unit) { ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets -> val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()) ViewCompat.setOnApplyWindowInsetsListener(this, null) action(systemBarInsets) insets } } //and then use it with the view paywallView.onReceiveSystemBarsInsets { insets -> val paywallInsets = AdaptyPaywallInsets.of(insets.top, insets.bottom) paywallView.setEventListener(eventListener) paywallView.setObserverModeHandler(observerModeHandler) paywallView.showPaywall(viewConfig, products, paywallInsets, personalizedOfferResolver, tagResolver) } ``` ```java showLineNumbers import androidx.core.graphics.Insets; import androidx.core.view.ViewCompat; import androidx.core.view.WindowInsetsCompat; ... ViewCompat.setOnApplyWindowInsetsListener(paywallView, (view, insets) -> { Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars()); ViewCompat.setOnApplyWindowInsetsListener(paywallView, null); AdaptyPaywallInsets paywallInsets = AdaptyPaywallInsets.of(systemBarInsets.top, systemBarInsets.bottom); paywallView.setEventListener(eventListener); paywallView.setObserverModeHandler(observerModeHandler); paywallView.showPaywall(viewConfiguration, products, paywallInsets, personalizedOfferResolver, tagResolver); return insets; }); ``` 戻り値: | オブジェクト | 説明 | | :------------------ | :------------------------------------------------- | | `AdaptyPaywallView` | リクエストされたペイウォール画面を表すオブジェクト。 | :::warning [購入トランザクションへのペイウォールの紐付け](report-transactions-observer-mode-android)をお忘れなく。これを行わないと、Adapty は購入元のペイウォールを特定できません。 :::
--- # File: android-troubleshoot-purchases --- --- title: "Android SDKでの購入に関するトラブルシューティング" description: "Android SDKでの購入に関するトラブルシューティング" --- このガイドでは、Android SDKで手動購入を実装する際によく発生する問題の解決方法を説明します。 ## makePurchaseが正常に完了してもプロファイルが更新されない \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **問題**: `makePurchase` メソッドが正常に完了するにもかかわらず、ユーザーのプロファイルとサブスクリプション状態がAdaptyで更新されない。 **原因**: 通常、Google Play Storeのセットアップが不完全であるか、設定に問題があることを示しています。 **解決策**: [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-android)を参照してください。 ## 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 Storeから課金不可エラーが返ってくる。 **原因**: このエラーはAdaptyとは無関係です。デバイスで課金が利用できないことを示すGoogle Play Billing Libraryのエラーです。 **解決策**: このエラーは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\} **問題**: 上記に該当しない購入関連の問題が発生している。 **解決策**: 必要に応じて[移行ガイド](android-sdk-migration-guides)を参照し、SDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: android-identifying-users --- --- title: "Android SDKでユーザーを識別する" description: "Adaptyでユーザーを識別して、パーソナライズされたサブスクリプション体験を向上させます(Android)。" --- 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`パラメータとして渡すだけです: ```kotlin showLineNumbers Adapty.activate(applicationContext, "PUBLIC_SDK_KEY", customerUserId = "YOUR_USER_ID") ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 設定後にCustomer User IDを設定する \{#setting-customer-user-id-after-configuration\} SDK設定時にユーザーIDがない場合は、`.identify()`メソッドを使っていつでも後から設定できます。このメソッドを使う最も一般的なケースは、ユーザーが匿名ユーザーから認証済みユーザーに切り替わる登録後や認証後です。 ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> if (error == null) { // successful identify } } ``` ```java showLineNumbers Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` リクエストパラメータ: - **Customer User ID**(必須):文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信 ユーザーが再度アカウントにログインする場合など、Adaptyのサーバーにそのユーザーの情報がすでに存在するケースがあります。このような場合、Adapty SDKは自動的に新しいユーザーとして切り替えて動作します。カスタム属性やサードパーティネットワークからのアトリビューションなど、匿名ユーザーに渡したデータがある場合は、識別済みユーザーに対してそのデータを再送信する必要があります。 また、新しいユーザーのデータが異なる場合があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得する必要がある点にも注意してください。 ::: ### ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()`メソッドを呼び出すことで、いつでもユーザーをログアウトできます: ```kotlin showLineNumbers Adapty.logout { error -> if (error == null) { // successful logout } } ``` ```java showLineNumbers Adapty.logout(error -> { if (error == null) { // successful logout } }); ``` その後、`.identify()`メソッドを使ってユーザーをログインできます。 ### デバイスをまたいでユーザーを検出する \{#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: android-setting-user-attributes --- --- title: "Android SDKでユーザー属性を設定する" description: "Adaptyでユーザー属性を設定してオーディエンスのセグメンテーションを改善する方法を学びます。" --- メールアドレスや電話番号などのオプション属性をアプリのユーザーに設定できます。設定した属性を使って、ユーザーの[セグメント](segments)を作成したり、CRMで確認したりすることができます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します。 ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.OTHER) .withBirthday(AdaptyProfile.Date(1970, 1, 3)) Adapty.updateProfile(builder.build()) { error -> if (error != null) { // handle the error } } ``` ```java showLineNumbers AdaptyProfileParameters.Builder builder = new AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.OTHER) .withBirthday(new AdaptyProfile.Date(1970, 1, 3)); Adapty.updateProfile(builder.build(), error -> { if (error != null) { // handle the error } }); ``` `updateProfile` メソッドで以前に設定した属性はリセットされませんのでご注意ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 使用可能なキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters.Builder` で使用できるキー `` と値 `` の一覧は以下のとおりです。 | キー | 値 | |---|-----| |

email

phoneNumber

firstName

lastName

| String | | gender | Enum。使用可能な値: `female`、`male`、`other` | | birthday | Date | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定することもできます。カスタム属性は通常、アプリの使用状況に関連するものです。たとえば、フィットネスアプリなら週あたりの運動回数、語学学習アプリならユーザーの習熟度レベルなどが挙げられます。セグメントで活用してターゲットを絞ったペイウォールやオファーを作成したり、アナリティクスでどのプロダクト指標が収益に最も影響するかを把握したりすることができます。 ```kotlin showLineNumbers builder.withCustomAttribute("key1", "value1") ``` ```java showLineNumbers builder.withCustomAttribute("key1", "value1"); ``` 既存のキーを削除するには、`.withRemoved(customAttributeForKey:)` メソッドを使用します。 ```kotlin showLineNumbers builder.withRemovedCustomAttribute("key2") ``` ```java showLineNumbers builder.withRemovedCustomAttribute("key2"); ``` これまでに設定されたカスタム属性を確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning ユーザー属性は異なるデバイスからいつでも送信される可能性があるため、`customAttributes` の値は最新の状態ではない場合があります。最後の同期後にサーバー上の属性が更新されている可能性があります。 ::: ### 制限事項 \{#limits\} - ユーザーごとに最大30件のカスタム属性を設定可能 - キー名は最大30文字。キー名には英数字と以下の記号が使用可能: `_` `-` `.` - 値は文字列またはfloatで、最大50文字まで。 --- # File: android-listen-subscription-changes --- --- title: "Android SDKでサブスクリプションステータスを確認する" description: "Adaptyを使用してAndroidアプリのユーザーサブスクリプションステータスを追跡・管理し、顧客維持率を向上させましょう。" --- Adaptyを使えば、サブスクリプションのステータス管理が簡単になります。プロダクトIDをコードに直接記述する必要はありません。アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプションステータスを手軽に把握できます。 サブスクリプションステータスの確認を始める前に、[リアルタイム デベロッパー通知(RTDN)](enable-real-time-developer-notifications-rtdn)を設定してください。 ## アクセスレベルとAdaptyProfileオブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは[AdaptyProfile](https://android.adapty.io/adapty/com.adapty.models/-adapty-profile/)オブジェクトのプロパティです。アプリ起動時(例:[ユーザーを識別する](android-identifying-users#setting-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更があるたびに更新することをおすすめします。こうすることで、毎回リクエストを送らずともプロファイルオブジェクトを活用できます。 プロファイルの更新通知を受け取るには、以下の[プロファイル更新(アクセスレベルを含む)をリッスンする](android-listen-subscription-changes)セクションで説明している方法でプロファイルの変更を監視してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()`メソッドを使用します: ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); // check the access } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` レスポンスパラメーター: | パラメーター | 説明 | | --------- | ------------------------------------------------------------ | | Profile |

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

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

| `.getProfile()`メソッドはユーザープロファイルを返し、そこからアクセスレベルのステータスを取得できます。アプリごとに複数のアクセスレベルを設定することが可能です。たとえばニュースアプリで異なるトピックへのサブスクリプションを個別に販売する場合、「sports」や「science」といったアクセスレベルを作成できます。ただし、ほとんどの場合は1つのアクセスレベルで十分であり、その場合はデフォルトの「premium」アクセスレベルを使用するだけで問題ありません。 デフォルトの「premium」アクセスレベルを確認する例: ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value if (profile.accessLevels["premium"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success) result).getValue(); AdaptyProfile.AccessLevel premium = profile.getAccessLevels().get("premium"); if (premium != null && premium.isActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` ### サブスクリプションステータスの更新をリッスンする \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adaptyはイベントを発火します。 Adaptyからメッセージを受け取るには、追加の設定が必要です: ```kotlin showLineNumbers Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state } ``` ```java showLineNumbers t Adapty.setOnProfileUpdatedListener(profile -> { // handle any changes to subscription state }); ``` Adaptyはアプリケーション起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDKに実装されているキャッシュは、プロファイルのサブスクリプションステータスを保存します。そのため、サーバーが利用できない状況でも、キャッシュされたデータからプロファイルのサブスクリプションステータスを取得できます。 ただし、キャッシュから直接データをリクエストすることはできません。SDKは1分ごとにサーバーへクエリを送り、プロファイルに関する更新や変更を確認します。新しいトランザクションやその他の更新があった場合、それらはサーバーとの同期を保つためにキャッシュデータへ反映されます。 --- # File: kids-mode-android --- --- title: "Android SDKのキッズモード" description: "キッズモードを簡単に有効化してGoogleのポリシーに準拠。Android SDKではGAIDや広告データは収集されません。" --- Androidアプリが子ども向けの場合、[Google](https://support.google.com/googleplay/android-developer/answer/9893335)のポリシーに従う必要があります。Adapty SDKを使用している場合、いくつかの簡単な手順でこれらのポリシーに準拠し、アプリストアの審査を通過できるよう設定できます。 ## 必要な対応 \{#whats-required\} Adapty SDKで以下の収集を無効化する必要があります: - [Android広告ID(AAID/GAID)](https://support.google.com/googleplay/android-developer/answer/6048248) - [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\} ポリシーに準拠するため、Adapty SDKの初期化時にAndroid広告ID(AAID/GAID)とIPアドレスの収集を無効化する必要があります: **Kotlin:** ```kotlin showLineNumbers override fun onCreate() { super.onCreate() Adapty.activate( applicationContext, AdaptyConfig.Builder("PUBLIC_SDK_KEY") // highlight-start .withAdIdCollectionDisabled(true) // set to `true` .withIpAddressCollectionDisabled(true) // set to `true` // highlight-end .build() ) } ``` **Java:** ```java showLineNumbers @Override public void onCreate() { super.onCreate(); Adapty.activate( applicationContext, new AdaptyConfig.Builder("PUBLIC_SDK_KEY") // highlight-start .withAdIdCollectionDisabled(true) // set to `true` .withIpAddressCollectionDisabled(true) // set to `true` // highlight-end .build() ); } ``` ### Androidマニフェストでの設定 \{#updates-in-your-android-manifest\} :::note アプリが子ども**専用**であり、Android 13(API 33)以上をターゲットとしてコンパイルしている場合、Google Playでは`AD_ID`パーミッションをリクエストしないことが求められます。分析、アトリビューション、または広告向けの別のSDKがマニフェストのマージを通じてこのパーミッションを追加している場合があります。`withAdIdCollectionDisabled(true)`を設定するとAdaptyによるIDの収集は停止しますが、他のSDKが宣言したパーミッションは削除されません。 ::: パーミッションを削除するには、`app/src/main/AndroidManifest.xml`の``要素内に以下を追加してください。``要素では`xmlns:tools="http://schemas.android.com/tools"`を宣言する必要があります。 ```xml showLineNumbers title="AndroidManifest.xml" ``` --- # File: android-get-onboardings --- --- title: "Android SDK でオンボーディングを取得する" description: "Adapty for Android でオンボーディングを取得する方法を説明します。" --- :::tip **SDK v4 以降**では、オンボーディングのより強力な代替手段として[フロー](android-get-pb-paywalls)を構築できます。オンボーディングが WebView 内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされます。これにより、よりスムーズなアニメーション、一貫した Android の外観、高速な読み込み、そして WebView ランタイムへの依存がなくなります。始めるには[フローとペイウォールの取得](android-get-pb-paywalls)および[フローとペイウォールの表示](android-present-paywalls)をご覧ください。 ::: Adapty ダッシュボードのビルダーで[オンボーディングのビジュアルデザインを作成](design-onboarding)したら、Android アプリに表示できます。このプロセスの最初のステップは、以下に説明するように、プレースメントに関連付けられたオンボーディングとそのビュー設定を取得することです。 始める前に、以下を確認してください: 1. [Adapty Android SDK](sdk-installation-android) バージョン 3.8.0 以上をインストールしていること。 2. [オンボーディングを作成](create-onboarding)していること。 3. オンボーディングを[プレースメント](placements)に追加していること。 ## オンボーディングを取得する \{#fetch-onboarding\} [オンボーディング](onboardings)をノーコードビルダーで作成すると、アプリが取得・表示するためのコンテナとして設定が保存されます。このコンテナは表示するコンテンツ、その見せ方、クイズの回答やフォームの入力といったユーザー操作の処理まで、体験全体を管理します。また、コンテナは自動的にアナリティクスイベントをトラッキングするため、ビューのトラッキングを別途実装する必要はありません。 パフォーマンスを最大限に引き出すために、ユーザーに表示する前に画像をダウンロードする時間を確保できるよう、オンボーディングの設定はなるべく早めに取得してください。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```kotlin showLineNumbers Adapty.getOnboarding("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val onboarding = result.value // the requested onboarding } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` パラメータ: | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

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

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

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

内部的に複数のリクエストで構成される場合があるため、まれに `loadTimeout` で指定した時間よりも若干遅れてタイムアウトすることがあります。

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

| レスポンスパラメータ: | パラメータ | 説明 | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | オンボーディングの識別子と設定、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyOnboarding`](https://android.adapty.io/adapty/com.adapty.models/-adapty-onboarding/) オブジェクト。 | ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングのフェッチはほぼ瞬時に完了するため、この処理の高速化を特別に意識する必要はありません。ただし、オーディエンスやオンボーディングの数が多く、ユーザーのインターネット接続が不安定な場合は、フェッチに予想以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないよりも、デフォルトのオンボーディングを表示してスムーズなユーザー体験を提供したほうがよいでしょう。 この問題に対処するには、`getOnboardingForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けオンボーディングを取得します。ただし、推奨されるアプローチは [オンボーディングの取得](#fetch-onboarding) セクションで詳しく説明されている `getOnboarding` メソッドでオンボーディングを取得することである点を理解しておくことが重要です。 :::warning `getOnboardingForDefaultAudience` の代わりに `getOnboarding` の使用を検討してください。前者には以下の重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のある設計が必要になるか、古いバージョンでは正しく表示されない可能性を受け入れる必要があります。 - **パーソナライズなし**: 「すべてのユーザー」オーディエンス向けのコンテンツのみ表示され、国、アトリビューション、カスタム属性に基づくターゲティングが利用できません。 取得速度の向上がこれらのデメリットを上回る場合は、以下に示すように `getOnboardingForDefaultAudience` を使用してください。それ以外の場合は、[上記](#fetch-onboarding)で説明した `getOnboarding` を使用してください。 ::: ```kotlin Adapty.getOnboardingForDefaultAudience("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val onboarding = result.value // Handle successful onboarding retrieval } is AdaptyResult.Error -> { val error = result.error // Handle error case } } } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** |

任意

デフォルト: `en`

|

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

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

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

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

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

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

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

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

| --- # File: android-present-onboardings --- --- title: "Android SDKでのオンボーディングの表示" description: "効果的なユーザーエンゲージメントのためにAndroidでオンボーディングを表示する方法を学びます。" --- :::tip **SDK v4以降**では、オンボーディングのより強力な代替手段として[フロー](android-get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされます。これにより、スムーズなアニメーション、一貫したAndroidのルック&フィール、高速な読み込み、WebViewランタイムへの依存なしで動作します。開始するには、[フロー&ペイウォールの取得](android-get-pb-paywalls)と[フロー&ペイウォールの表示](android-present-paywalls)をご覧ください。 ::: 始める前に、以下を確認してください: 1. [Adapty Android SDK](sdk-installation-android) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 オンボーディングビルダーを使ってオンボーディングをカスタマイズした場合、ユーザーに表示するためのレンダリングコードをアプリ側で実装する必要はありません。このようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 デバイス画面にビジュアルオンボーディングを表示するには、まず設定が必要です。`AdaptyUI.getOnboardingView()` メソッドを呼び出すか、`OnboardingView` を直接作成してください: ```kotlin val onboardingView = AdaptyUI.getOnboardingView( activity = this, viewConfig = onboardingConfig, eventListener = eventListener ) ``` ```kotlin val onboardingView = AdaptyOnboardingView(activity) onboardingView.show( viewConfig = onboardingConfig, delegate = eventListener ) ``` ```java AdaptyOnboardingView onboardingView = AdaptyUI.getOnboardingView( activity, onboardingConfig, eventListener ); ``` ```java AdaptyOnboardingView onboardingView = new AdaptyOnboardingView(activity); onboardingView.show(onboardingConfig, eventListener); ``` ```xml ``` ビューが正常に作成されたら、ビュー階層に追加してデバイス画面に表示できます。 リクエストパラメータ: | パラメーター | 必須/任意 | 説明 | | :-------- | :------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **viewConfig** | 必須 | `AdaptyUI.getOnboardingConfiguration()` から取得したオンボーディング設定 | | **eventListener** | 必須 | オンボーディングイベントを処理するための `AdaptyOnboardingEventListener` の実装。詳細は[オンボーディングイベントの処理](android-handle-onboarding-events)を参照してください。 | ## ローディングインジケーターの色を変更する \{#change-loading-indicator-color\} 以下の方法でローディングインジケーターのデフォルトカラーをオーバーライドできます: ```xml ``` ## スプラッシュ画面とオンボーディング間のスムーズなトランジションを追加する \{#add-smooth-transitions-between-the-splash-screen-and-onboarding\} デフォルトでは、スプラッシュ画面とオンボーディングの間に、オンボーディングが完全に読み込まれるまでローディング画面が表示されます。ただし、トランジションをよりスムーズにしたい場合は、スプラッシュ画面を延長するか、別のものを表示するかをカスタマイズできます。 これを行うには、`res/layout` に `adapty_onboarding_placeholder_view.xml` を作成し、そこにプレースホルダー(オンボーディングの読み込み中に表示する内容)を定義します。 プレースホルダーを定義すると、オンボーディングはバックグラウンドで読み込まれ、準備が整い次第自動的に表示されます。 ## セーフエリアのパディングを無効にする \{#disable-safe-area-paddings\} デフォルトでは、オンボーディングビューはステータスバーやナビゲーションバーなどのシステム UI 要素を避けるため、セーフエリアのパディングを自動的に適用します。ただし、この動作を無効にしてレイアウトを完全に制御したい場合は、`safeAreaPaddings` パラメータを `false` に設定することで対応できます。 ```kotlin val onboardingView = AdaptyUI.getOnboardingView( activity = this, viewConfig = onboardingConfig, eventListener = eventListener, safeAreaPaddings = false ) ``` ```kotlin val onboardingView = AdaptyOnboardingView(activity) onboardingView.show( viewConfig = onboardingConfig, delegate = eventListener, safeAreaPaddings = false ) ``` ```java AdaptyOnboardingView onboardingView = AdaptyUI.getOnboardingView( activity, onboardingConfig, eventListener, false ); ``` ```java AdaptyOnboardingView onboardingView = new AdaptyOnboardingView(activity); onboardingView.show(onboardingConfig, eventListener, false); ``` または、アプリにブールリソースを追加することで、この動作をグローバルに制御することもできます: ```xml false ``` `safeAreaPaddings` を `false` に設定すると、オンボーディングは自動的なパディング調整なしにフルスクリーンに広がります。これによりレイアウトを完全に制御でき、オンボーディングのコンテンツが画面全体を使用できるようになります。 ## オンボーディングでのリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディングでのリンクの開き方のカスタマイズは、Adapty SDK v3.15.1 以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、ユーザーがアプリを切り替えることなくウェブページを閲覧できる、シームレスなユーザー体験が提供されます。 外部ブラウザでリンクを開くように変更したい場合は、`externalUrlsPresentation` パラメータを `AdaptyWebPresentation.ExternalBrowser` に設定することで、この動作をカスタマイズできます。 ```kotlin val onboardingConfig = AdaptyUI.getOnboardingConfiguration( onboarding = onboarding, externalUrlsPresentation = AdaptyWebPresentation.ExternalBrowser // default – InAppBrowser ) ``` ```java AdaptyOnboardingConfiguration onboardingConfig = AdaptyUI.getOnboardingConfiguration( onboarding, AdaptyWebPresentation.ExternalBrowser // default – InAppBrowser ); ``` --- # File: android-handle-onboarding-events --- --- title: "Android SDKでオンボーディングイベントを処理する" description: "Adaptyを使用してAndroidでオンボーディング関連のイベントを処理します。" --- :::tip **SDK v4以降**、オンボーディングのより強力な代替手段として[フロー](android-get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したAndroidのルック&フィール、高速な読み込み、WebViewランタイムへの依存なしで利用できます。開始するには、[フロー&ペイウォールの取得](android-get-pb-paywalls)と[フロー&ペイウォールの表示](android-present-paywalls)を参照してください。 ::: 始める前に、以下を確認してください: 1. [Adapty Android SDK](sdk-installation-android) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ビルダーで設定したオンボーディングは、アプリが応答できるイベントを生成します。これらのイベントへの応答方法については、以下をご覧ください。 Android アプリのオンボーディング画面で発生するプロセスを制御・監視するには、`AdaptyOnboardingEventListener` インターフェースを実装してください。 ## カスタムアクション \{#custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。そのIDをコード内で使用し、カスタムアクションとして処理できます。 例えば、ユーザーが **Login** や **Allow notifications** などのカスタムボタンをタップすると、デリゲートメソッド `onCustomAction` がビルダーで設定したアクション ID とともに呼び出されます。"allowNotifications" のように、任意の ID を自由に作成できます。 ```kotlin showLineNumbers class YourActivity : AppCompatActivity() { private val eventListener = object : AdaptyOnboardingEventListener { override fun onCustomAction(action: AdaptyOnboardingCustomAction, context: Context) { when (action.actionId) { "allowNotifications" -> { // Request notification permissions } } } override fun onError(error: AdaptyOnboardingError, context: Context) { // Handle errors } // ... other required delegate methods } } ```
イベントの例(クリックして展開) ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ```
## オンボーディングを閉じる \{#closing-onboarding\} オンボーディングは、ユーザーが**Close**アクションが割り当てられたボタンをタップすると閉じられます。ユーザーがオンボーディングを閉じたときの処理を実装する必要があります。例えば: :::important ユーザーがオンボーディングを閉じたときの処理を実装する必要があります。たとえば、オンボーディング画面自体を非表示にする必要があります。 ::: 例: ```kotlin override fun onCloseAction(action: AdaptyOnboardingCloseAction, context: Context) { // Dismiss the onboarding screen (context as? Activity)?.onBackPressed() } ```
イベントの例(クリックして展開) ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
## ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。ペイウォールが閉じられた後に開きたい場合は、[`AdaptyOnboardingCloseAction`](#closing-onboarding) を処理してペイウォールをイベントデータに依存せずに開く、よりシンプルな方法があります。 ::: オンボーディングでペイウォールを扱う最もスムーズな方法は、アクション ID をペイウォールのプレースメント ID と同じにすることです。こうすることで、`AdaptyOnboardingOpenPaywallAction` の後、プレースメント ID を使ってすぐにペイウォールを取得して開くことができます。 ```kotlin override fun onOpenPaywallAction(action: AdaptyOnboardingOpenPaywallAction, context: Context) { // Get the paywall using the placement ID from the action Adapty.getPaywall(placementId = action.actionId) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // Get the paywall configuration AdaptyUI.getViewConfiguration(paywall) { result -> when(result) { is AdaptyResult.Success -> { val paywallConfig = result.value // Create and present the paywall val paywallView = AdaptyUI.getPaywallView( activity = this, viewConfig = paywallConfig, products, eventListener = paywallEventListener ) // Add the paywall view to your layout binding.container.addView(paywallView) } is AdaptyResult.Error -> { val error = result.error // handle the error } } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } } ```
イベント例(クリックして展開) ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ```
## オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、このメソッドが呼び出されます: ```kotlin override fun onFinishLoading(action: AdaptyOnboardingLoadedAction, context: Context) { // Handle loading completion } ```
イベント例(クリックして展開) ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ```
## ナビゲーションイベント \{#navigation-events\} `onAnalyticsEvent` メソッドは、オンボーディングフローの進行中にさまざまな分析イベントが発生したときに呼び出されます。 `event` オブジェクトには、以下のタイプがあります。 |タイプ | 説明 | |------------|-------------| | `OnboardingStarted` | オンボーディングが読み込まれたとき | | `ScreenPresented` | 任意の画面が表示されたとき | | `ScreenCompleted` | 画面が完了したとき。オプションの `elementId`(完了した要素の識別子)とオプションの `reply`(ユーザーからの応答)を含みます。ユーザーが画面を離れるアクションを実行したときにトリガーされます。 | | `SecondScreenPresented` | 2番目の画面が表示されたとき | | `UserEmailCollected` | 入力フィールドを通じてユーザーのメールアドレスが収集されたときにトリガーされます | | `OnboardingCompleted` | ユーザーが `final` IDを持つ画面に到達したときにトリガーされます。このイベントが必要な場合は、最後の画面に `final` IDを割り当ててください。 | | `Unknown` | 認識されないイベントタイプの場合。`name`(不明なイベントの名前)と `meta`(追加のメタデータ)を含みます | 各イベントには以下のフィールドを含む `meta` 情報が含まれています: | フィールド | 説明 | |------------|-------------| | `onboardingId` | オンボーディングフローの一意識別子 | | `screenClientId` | 現在の画面の識別子 | | `screenIndex` | フロー内での現在の画面の位置 | | `totalScreens` | フロー内の画面の総数 | 以下は、トラッキングのためにアナリティクスイベントを利用する方法の例です: ```kotlin override fun onAnalyticsEvent(event: AdaptyOnboardingAnalyticsEvent, context: Context) { when (event) { is AdaptyOnboardingAnalyticsEvent.OnboardingStarted -> { // Track onboarding start trackEvent("onboarding_started", event.meta) } is AdaptyOnboardingAnalyticsEvent.ScreenPresented -> { // Track screen presentation trackEvent("screen_presented", event.meta) } is AdaptyOnboardingAnalyticsEvent.ScreenCompleted -> { // Track screen completion with user response trackEvent("screen_completed", event.meta, event.elementId, event.reply) } is AdaptyOnboardingAnalyticsEvent.OnboardingCompleted -> { // Track successful onboarding completion trackEvent("onboarding_completed", event.meta) } is AdaptyOnboardingAnalyticsEvent.Unknown -> { // Handle unknown events trackEvent(event.name, event.meta) } // Handle other cases as needed } } ```
イベントの例(クリックして展開) ```javascript // OnboardingStarted { "name": "onboarding_started", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } // ScreenPresented { "name": "screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "interests_screen", "screen_index": 2, "total_screens": 4 } } // ScreenCompleted { "name": "screen_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 }, "params": { "element_id": "profile_form", "reply": "success" } } // SecondScreenPresented { "name": "second_screen_presented", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // UserEmailCollected { "name": "user_email_collected", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 1, "total_screens": 4 } } // OnboardingCompleted { "name": "onboarding_completed", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ```
--- # File: android-onboarding-input --- --- title: "Android SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用して、AndroidアプリのオンボーディングからデータをAndroid SDKで保存・活用する方法を解説します。" --- :::tip **SDK v4以降**では、オンボーディングのより強力な代替手段として[フロー](android-get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのとは異なり、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したAndroidのルック&フィール、高速な読み込み、WebViewランタイムへの依存なしで利用できます。始めるには、[フローとペイウォールの取得](android-get-pb-paywalls)および[フローとペイウォールの表示](android-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`onStateUpdatedAction` メソッドが呼び出されます。フィールドの種類をコード内で保存・処理することができます。 例: ```kotlin override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) { // Store user preferences or responses when (val params = action.params) { is AdaptyOnboardingStateUpdatedParams.Select -> { // Handle single selection } is AdaptyOnboardingStateUpdatedParams.MultiSelect -> { // Handle multiple selections } is AdaptyOnboardingStateUpdatedParams.Input -> { // Handle text input } is AdaptyOnboardingStateUpdatedParams.DatePicker -> { // Handle date selection } } } ``` アクション形式については[こちら](https://android.adapty.io/adapty-ui/com.adapty.ui.onboardings.actions/-adapty-onboarding-state-updated-action/)をご覧ください。
保存されたデータの例(フォーマットは実装によって異なる場合があります) ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ```
## ユースケース \{#use-cases\} ### ユーザープロファイルをデータで充実させる \{#enrich-user-profiles-with-data\} 入力データをユーザープロファイルと即座に紐づけ、同じ情報を二度尋ねないようにするには、アクションを処理する際に入力データで[ユーザープロファイルを更新](android-setting-user-attributes)する必要があります。 たとえば、`name` IDのテキストフィールドでユーザーに名前の入力を求め、その値をユーザーの名(ファーストネーム)として設定したい場合や、`email` フィールドでメールアドレスを入力してもらう場合、アプリのコードは次のようになります。 ```kotlin showLineNumbers override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) { // Store user preferences or responses when (val params = action.params) { is AdaptyOnboardingStateUpdatedParams.Input -> { // Handle text input val builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field when (action.elementId) { "name" -> { when (val inputParams = params.params) { is AdaptyOnboardingInputParams.Text -> { builder.withFirstName(inputParams.value) } } } "email" -> { when (val inputParams = params.params) { is AdaptyOnboardingInputParams.Email -> { builder.withEmail(inputParams.value) } } } } Adapty.updateProfile(builder.build()) { error -> if (error != null) { // handle the error } } } } } ``` ### 回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングでクイズを使うと、オンボーディング完了後にユーザーに表示するペイウォールもカスタマイズできます。 たとえば、スポーツの経験についてユーザーに質問し、ユーザーグループごとに異なるCTAやプロダクトを表示することができます。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、各選択肢に意味のあるIDを割り当てます。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](android-setting-user-attributes)します。 ```kotlin showLineNumbers override fun onStateUpdatedAction(action: AdaptyOnboardingStateUpdatedAction, context: Context) { // Handle quiz responses and set custom attributes when (val params = action.params) { is AdaptyOnboardingStateUpdatedParams.Select -> { // Handle quiz selection val builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes when (action.elementId) { "experience" -> { // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.withCustomAttribute("experience", params.params.value) } } Adapty.updateProfile(builder.build()) { error -> if (error != null) { // handle the error } } } } } ``` 3. カスタム属性の値ごとに[セグメントを作成](segments)します。 4. [プレースメント](placements)を作成し、作成した各セグメントの[オーディエンス](audience)を追加します。 5. アプリのコードでそのプレースメントの[ペイウォールを表示](android-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[そのボタンのアクションへのレスポンス](android-handle-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: android-sdk-call-order --- --- title: "Android SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的なADAPTY_NOT_INITIALIZEDエラーを回避できます。" --- `Adapty.activate()` が完了してから、他のAdapty SDKメソッドを呼び出す必要があります。完了するまでSDKは状態を持ちません。`activate()` の前または並行して発行された呼び出しはすべて [`ADAPTY_NOT_INITIALIZED`](android-sdk-error-handling) で失敗します。 アプリがユーザーを認証し、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `Adapty.identify()` を呼び出してください。`identify` の完了コールバックが発火するまで、ユーザー操作に関わるメソッドを呼び出さないようにしてください。`identify` と競合する呼び出しは、コールバックでエラーが返るか、アクティベーション時に作成された匿名プロファイルに対して処理されます。この状態になると、アトリビューション、`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)`AdaptyConfig.Builder` に渡してください。このパスでは匿名プロファイルが作成されないため、ステップ4は不要です。 | ステップ | 呼び出し | タイミング | 備考 | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | MMPまたはアナリティクスSDKの初期化(AppsFlyer、Adjust、PostHog、Branch) | アプリ起動時、最初に | MMPのUIDコールバック(例: `getAppsFlyerUID`)を待つこと。 | | 2a | `Adapty.activate(context, AdaptyConfig.Builder("KEY").withCustomerUserId(...).build())` | アプリ起動時、ステップ1の後、カスタマーユーザーIDが取得できる場合 | 推奨。匿名プロファイルは一切作成されない。 | | 2b | `Adapty.activate(context, AdaptyConfig.Builder("KEY").build())` — `customerUserId` なし | アプリ起動時、ステップ1の後、カスタマーユーザーIDが取得できない場合(または取得しない場合) | Adaptyが匿名プロファイルを作成する。 | | 3 | 各MMPに対して `Adapty.setIntegrationIdentifier("appsflyer_id", uid)` | ステップ2の後、ユーザー操作の呼び出しより前 | MMP IDを正しいプロファイルに紐付けるために必要。 | | 4 | `Adapty.identify("YOUR_USER_ID") { error -> ... }` | ステップ3の後(MMPがない場合はステップ2の後)、ステップ5より前 — 認証ありのパス2bのみ | 完了コールバックを使用すること。`identify` 中の並行呼び出しは匿名プロファイルに対して処理される場合がある。 | | 5 | `getPaywall`、`getPaywallProducts`、`restorePurchases`、`makePurchase`、`updateAttribution`、`updateProfile` | `identify` を呼び出す場合はステップ4の後、それ以外はステップ3の後(またはMMPがない場合はステップ2の後) | これらの呼び出しには安定したプロファイルが必要。 | :::important これらのステップをスキップすると、再インストールユーザーのプレミアムアクセスが失われたり、プロファイルに `appsflyer_id` が記録されなかったり、誤ったオーディエンスに対してペイウォールが返されたりする原因となります。 ::: ## Web2appおよびウェブファネル経由のインストール \{#web2app-and-web-funnel-installs\} ユーザーがウェブチェックアウト(Stripe、Paddle)で購入し、後からネイティブアプリをインストールした場合、デバイス初回の `activate()` により新しい匿名プロファイルが作成されます。このプロファイルはウェブプロファイルとは紐付けられません。認証フローやインストールリファラーなどからアプリ起動前にカスタマーユーザーIDを解決できる場合は、`AdaptyConfig.Builder` に直接渡してください。それ以外の場合、`identify("YOUR_USER_ID")` を呼び出して `restorePurchases` を実行するまで、ウェブでの購入はデバイス上に表示されません。 各ウェブチェックアウトで送信するメタデータについては、以下を参照してください。 - [Stripe](stripe) - [Paddle](paddle) --- # File: android-optimize-paywall-fetching --- --- title: "Android SDKでペイウォールの取得を最適化する" description: "Android向けにAdaptyペイウォールを確実に取得する:タイミング、キャッシュ、フォールバックのパターン。" --- Android上での信頼性の高いペイウォール取得は、3つのことを実現します:高速なレンダリング、オーディエンスターゲティングされたペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバック。以下のルールは、これを実現するためのタイミング、キャッシュ、フォールバックのパターンをカバーしています。 :::tip これらのルールは、`Adapty.activate()` と `Adapty.identify()` がすでに完了していることを前提としています。[Android SDKの呼び出し順序](android-sdk-call-order)を参照してください。 ::: ## ルールと注意点 \{#rules-and-pitfalls\} | こうする | こうしない | 理由 | |---|---|---| | これから表示するプレースメントを取得する。 | 起動時にすべてのプレースメントを並列でプリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、バースト中にブラックスクリーンが表示される。 | | アトリビューションが解決される機会を持った後に `getPaywall` を取得する — たとえば、`activate` の1〜2秒後、または `setOnProfileUpdatedListener` が発火した後。 | `Application.onCreate()` で `getPaywall` を呼び出す。 | アトリビューションがまだ反映されていない。ペイウォールはデフォルトのオーディエンスに対して解決され、セグメントやASAのパーソナライゼーションが暗黙的にスキップされる。 | | `loadTimeout` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無期限に待つ。 | タイムアウトがないと、接続が不安定なユーザーはネットワークが解決するまで、またはアプリを閉じるまで空白の画面を見続けることになる。 | `fetchPolicy` と `loadTimeout` パラメーターのリファレンスは[ペイウォールとプロダクトの取得](fetch-paywalls-and-products-android)を、適切なプレースメントの選び方は[プレースメント](placements)を参照してください。 ## 接続が不安定な環境向けのチューニング \{#tune-for-poor-connectivity\} 接続が常に不安定な市場(農村部、交通機関、ルーティングの問題が多い地域)向けには: - 最初の取得を除くすべての取得で、`fetchPolicy` を `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` に設定する。 - Adapty ダッシュボードのすべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeout` を3〜5秒に設定し、タイムアウト発生時はフォールバックを受け入れる。 - `getProfile` にペイウォールの表示を依存させない。`getPaywall` は独立して呼び出し、プロファイルの取得が遅くてもUIをブロックしないようにする。 --- # File: android-test --- --- title: "Android SDKのテストとリリース" description: "AdaptyでAndroidアプリのサブスクリプション状態を確認する方法を学びます。" --- AdaptyのSDKをAndroidアプリに実装済みの場合は、すべてが正しく設定されており、購入が期待通りに動作することをテストする必要があります。これには、SDK統合のテストと、Google Playのサンドボックス環境での実際の購入フローのテストが含まれます。 ## アプリをテストする \{#test-your-app\} サンドボックステストやクローズドトラックの検証を含む、アプリ内課金の包括的なテスト方法については、[テストガイド](testing-on-android)をご覧ください。 ## リリースの準備 \{#prepare-for-release\} アプリをストアに申請する前に、[リリースチェックリスト](release-checklist)に従って以下を確認してください: - ストア接続とサーバー通知が設定されている - 購入が完了し、Adaptyに報告されている - アクセスが正しくアンロックおよび復元される - プライバシーとレビューの要件が満たされている --- # File: android-sdk-error-handling --- --- title: "Android SDKのエラーを処理する" description: "AdaptyのトラブルシューティングガイドでAndroid SDKのエラーを効果的に処理しましょう。" --- SDKから返されるエラーはすべて `AdaptyError` です。 :::tip **デバッグ前に詳細ログを有効にしてください。** ほとんどの `AdaptyError` は、Play Billing、ネットワーク、またはバックエンドのエラーをラップしています。詳細ログを有効にすると(`Adapty.logLevel = AdaptyLogLevel.VERBOSE` — [ログ記録](sdk-installation-android#logging)を参照)、ラップされたエラーがコンソールに出力され、実際の原因がわかることがほとんどです。 ::: :::important これらの解決策で問題が解決しない場合は、サポートに問い合わせる前に[その他の問題](#other-issues)を参照して、より効率的にサポートできるよう手順をご確認ください。 ::: | エラー | 解決策 | |----------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | UNKNOWN | 不明または予期しないエラーが発生したことを示します。 | | [ITEM_UNAVAILABLE](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_UNAVAILABLE()) | このエラーは主にテスト段階で発生します。プロダクトが本番環境に存在しないか、ユーザーが Google Play のテスターグループに属していない可能性があります。 | | ADAPTY_NOT_INITIALIZED | Adapty SDK が有効化されていません。
スプラッシュスクリーンや初期の UI フックが `Adapty.activate` の完了前に Adapty のメソッドを呼び出している場合によく見られます。実機ではエミュレーターと実行タイミングが異なるため、再現しないこともあります。`Adapty.activate` が完了してから、他の SDK 呼び出しを行うようにしてください。完全な手順については [Android SDK の呼び出し順序](android-sdk-call-order) を参照してください。また、`Adapty.activate` メソッドを使用して [Adapty SDK を正しく設定](sdk-installation-android#activate-adapty-module-of-adapty-sdk) する必要があります。 | | PROFILE_WAS_CHANGED | 操作中にユーザープロファイルが変更されました。
`Adapty.identify` の実行中に別のメソッドを呼び出すと発生します。実行中の呼び出しが切り替え直前のプロファイルに対して行われ、SDK によって拒否されます。`Adapty.identify` の完了後に他の SDK 呼び出しを行うようにしてください。[Android SDK の呼び出し順序](android-sdk-call-order) を参照してください。 | | PRODUCT_NOT_FOUND | 購入しようとしたプロダクトがストアで利用できないことを示します。 | | INVALID_JSON |

ローカルのフォールバックペイウォール JSON が無効です。

デフォルトの英語のペイウォールを修正してから、無効なローカルペイウォールを置き換えてください。ペイウォールの修正方法については [リモートコンフィグでペイウォールをカスタマイズする](customize-paywall-with-remote-config) を、ローカルペイウォールの置き換え方法については [ローカルフォールバックペイウォールを定義する](fallback-paywalls) を参照してください。

| |

CURRENT_SUBSCRIPTION_TO_UPDATE

\_NOT_FOUND_IN_HISTORY

| 置き換え対象の元のサブスクリプションが有効なサブスクリプションの中に見つかりません。 | | [BILLING_SERVICE_TIMEOUT](https://developer.android.com/google/play/billing/errors#service_timeout_error_code_-3) | Google Play が応答する前にリクエストが最大タイムアウトに達したことを示します。Play Billing Library の呼び出しで要求されたアクションの実行が遅延した場合などに発生します。 | | [FEATURE_NOT_SUPPORTED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#FEATURE_NOT_SUPPORTED()) | 要求された機能が現在のデバイスの Play Store でサポートされていません。 | | [BILLING_SERVICE_DISCONNECTED](https://developer.android.com/google/play/billing/errors#service_disconnected_error_code_-1) | クライアントアプリと `BillingClient` 経由の Google Play Store サービスとの接続が切断されたことを示します。 | | [BILLING_SERVICE_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#service_unavailable_error_code_2) | Google Play Billing サービスが現在利用できないことを示します。ほとんどの場合、クライアントデバイスと Google Play Billing サービスの間のどこかでネットワーク接続の問題が発生しています。 | | [BILLING_UNAVAILABLE](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) |

購入プロセス中に請求に関する問題が発生したことを示します。考えられる原因は以下のとおりです:

1. ユーザーのデバイスに Play Store アプリがインストールされていないか、古いバージョンです。

2. ユーザーがサポートされていない国にいます。

3. ユーザーが、管理者によって購入が無効化されているエンタープライズアカウントに属しています。

4. Google Play がユーザーの支払い方法に請求できませんでした(例:クレジットカードの有効期限切れ)。

5. ユーザーが Play Store アプリにログインしていません。

| | [DEVELOPER_ERROR](https://developer.android.com/google/play/billing/errors#developer_error) | API の使い方が正しくないことを示します。 | | [BILLING_ERROR](https://developer.android.com/google/play/billing/errors#error_error_code_6) | Google Play 自体の内部的な問題を示します。 | | [ITEM_ALREADY_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_ALREADY_OWNED()) | そのプロダクトはすでに購入済みです。 | | [ITEM_NOT_OWNED](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.BillingResponseCode#ITEM_NOT_OWNED()) | ユーザーがそのアイテムを所有していないため、要求されたアクションが失敗したことを示します。 | | [BILLING_NETWORK_ERROR](https://developer.android.com/google/play/billing/errors#network_error_error_code_12) | デバイスと Play のシステム間のネットワーク接続に問題があったことを示します。 | | NO_PRODUCT_IDS_FOUND |

ペイウォール内のプロダクトがいずれもストアで利用できないことを示します。

このエラーが発生した場合は、以下の手順で解決してください:

  1. すべてのプロダクトが Adapty ダッシュボードに追加されているか確認してください。
  2. アプリの **Package name** が Google Play Console のものと一致していることを確認してください。
  3. アプリストアのプロダクト ID がダッシュボードに追加したものと一致していることを確認してください。ストアにすでに Bundle ID が含まれている場合を除き、ID に Bundle ID を含めないようにしてください。
  4. Google の税設定でアプリの有料ステータスが **Active** になっていることを確認してください。税情報が最新であり、証明書が有効であることも確認してください。
  5. 収益化の対象となるよう、アプリに銀行口座が紐付けられているか確認してください。
  6. プロダクトがお住まいの地域で利用可能か確認してください。
  7. アプリがいずれかのテストトラックに登録されていることを確認してください。**Internal testing** トラックはレビュー不要でアプリが顧客に公開されないため、最も手軽な選択肢です。
| | NO_PURCHASES_TO_RESTORE | Google Play が復元する購入を見つけられなかったことを示します。 | | AUTHENTICATION_ERROR | `Adapty.activate` メソッドを使用して [Adapty SDK を正しく設定](sdk-installation-android#activate-adapty-module-of-adapty-sdk) する必要があります。 | | BAD_REQUEST | リクエストが不正です。
[Google Play との連携](google-play-store-connection-configuration) に必要なすべての手順を完了していることを確認してください。 | | SERVER_ERROR | サーバーエラーです。 | | REQUEST_FAILED | 正確に特定できないネットワークの問題を示します。 | | DECODING_FAILED | レスポンスのデコードに失敗しました。
コードを確認し、送信しているパラメータが有効であることを確認してください。例えば、無効な API キーを使用している場合にもこのエラーが発生することがあります。 | | ANALYTICS_DISABLED | [無効化されている](analytics-integration#disabling-external-analytics-for-a-specific-customer) ため、アナリティクスイベントを処理できません。 | | WRONG_PARAMETER | パラメータの一部が正しくないことを示します。空白にできない箇所が空白になっている、型が間違っているなどが原因として考えられます。 | ## その他の問題 \{#other-issues\} まだ解決策が見つかっていない場合は、次のステップを試してみてください。 - **SDKを最新バージョンにアップグレードする**: 最新のSDKバージョンは安定性が高く、既知の問題の修正が含まれているため、常にアップグレードをおすすめします。 - **サポートチームへの問い合わせ、またはコミュニティでの質問**: [サポートフォーラム](https://adapty.featurebase.app/)で他の開発者に質問することもできます。 - **[support@adapty.io](mailto:support@adapty.io) またはチャットでサポートチームに連絡する**: SDKのアップグレードが難しい場合や、アップグレードしても解決しない場合は、サポートチームにお問い合わせください。[詳細ログを有効化](sdk-installation-android#logging)してログを共有いただくと、問題の解決が早くなります。関連するコードスニペットを添付することもできます。 --- # File: migration-to-android-sdk-v4 --- --- title: "Adapty Android SDK を v. 4.0 に移行する" description: "ペイウォール API をフロー API に置き換えることで、Adapty Android SDK v4.0 に移行できます。Flow Builder と Paywall Builder の両方に対応しています。" --- Adapty Android SDK 4.0 ではフローが導入され、ペイウォール API の名称が変更されました。新しい API は、新しい Flow Builder と既存の Paywall Builder の両方で動作します。Adapty ダッシュボード側での設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` | | `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` | | `AdaptyUI.getViewConfiguration(paywall)` | `AdaptyUI.getFlowConfiguration(flow, locale)` | | `AdaptyUI.LocalizedViewConfiguration` | `AdaptyUI.FlowConfiguration` | | `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` | | `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` | | `AdaptyPaywall` | `AdaptyFlow` | | `AdaptyUI.getPaywallView(...)` | `AdaptyUI.getFlowView(...)` | | `AdaptyPaywallView` | `AdaptyFlowView` | | `AdaptyPaywallScreen` (Compose) | `AdaptyFlowScreen` | | `showPaywall(...)` | `showFlow(...)` | | `AdaptyPaywallInsets` | `AdaptyFlowInsets` | | `AdaptyUiEventListener` | `AdaptyFlowEventListener` | | `AdaptyUiDefaultEventListener` | `AdaptyFlowDefaultEventListener` | | `onPaywallShown` / `onPaywallClosed` | `onFlowShown` / `onFlowClosed` | | `onRenderingError` | `onError` | | `Adapty.updateAttribution(attribution, source)` (`source: String`) | `Adapty.updateAttribution(attribution, source)` (`source: AdaptyAttributionSource`) | | `Adapty.setIntegrationIdentifier(key, value)` | `Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier)` | `AdaptyPaywallProduct` はその名前を保持します。プロダクトは引き続きフローに属しており、`getPaywallProducts` は `AdaptyFlow` を受け取るようになります。その他の `AdaptyFlowEventListener` メソッド(`onProductSelected`、`onPurchaseStarted`、`onPurchaseFinished`、`onPurchaseFailure`、`onRestoreSuccess`、`onRestoreFailure`、`onActionPerformed`、`onAwaitingPurchaseParams`、`onLoadingProductsFailure` など)は、名前とシグネチャを変更しません。 ## インストール \{#installation\} `adapty-bom` のバージョンを `4.0.0`(以降)に設定し、プロジェクトを同期してください。BOM が対応する `android-sdk` と `android-ui` のバージョンを自動で解決します。依存関係の宣言方法については、[Adapty SDK のインストール](sdk-installation-android)を参照してください。 ## 削除および非推奨のAPI \{#removed-and-deprecated-apis\} - **`Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized, callback)`** — 削除されました。このオーバーロードはv3で非推奨になりました。代わりに `AdaptyPurchaseParameters` を使って同じオプションを渡してください: ```diff showLineNumbers - Adapty.makePurchase(activity, product, subscriptionUpdateParams, isOfferPersonalized) { result -> /* ... */ } + val params = AdaptyPurchaseParameters.Builder() + .withSubscriptionUpdateParams(subscriptionUpdateParams) + .withOfferPersonalized(isOfferPersonalized) + .build() + Adapty.makePurchase(activity, product, params) { result -> /* ... */ } ``` - **オンボーディングは非推奨です。** `AdaptyUI.getOnboardingView` および `AdaptyUI.getOnboardingConfiguration` は 4.0 で `@Deprecated` としてマークされています — オンボーディングを [フロービルダー](adapty-flow-builder) で作成したフローに移行してください。 ## フローの取得 \{#fetching-flows\} ### getPaywall + getViewConfiguration → getFlow + getFlowConfiguration \{#getpaywall--getviewconfiguration--getflow--getflowconfiguration\} フェッチの戻り値の型が `AdaptyPaywall` から `AdaptyFlow` に変わり、設定ローダーの名前が `AdaptyUI.getViewConfiguration` から `AdaptyUI.getFlowConfiguration` に変更されます(戻り値も `AdaptyUI.LocalizedViewConfiguration` の代わりに `AdaptyUI.FlowConfiguration` を返します)。`locale` パラメータはフェッチ呼び出しから `getFlowConfiguration` に移動します: ```diff showLineNumbers - Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") { result -> + Adapty.getFlow("YOUR_PLACEMENT_ID") { result -> if (result is AdaptyResult.Success) { - val paywall = result.value - if (!paywall.hasViewConfiguration) return@getPaywall - AdaptyUI.getViewConfiguration(paywall) { configResult -> + val flow = result.value + if (!flow.hasViewConfiguration) return@getFlow + AdaptyUI.getFlowConfiguration(flow, locale = "en") { configResult -> if (configResult is AdaptyResult.Success) { val flowConfiguration = configResult.value } } } } ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` は、`Adapty.getFlow` が返す `AdaptyFlow` を受け取るようになりました: ```diff showLineNumbers - Adapty.getPaywallProducts(paywall) { result -> /* products */ } + Adapty.getPaywallProducts(flow) { result -> /* products */ } ``` ## フローのビュー数トラッキング \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` は `logShowFlow` に名前が変更され、`AdaptyPaywall` の代わりに `AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリアションに対して記録されるため、既存のファネルや A/B テストの指標はダッシュボードを変更せずにそのまま機能します。 ```diff showLineNumbers - Adapty.logShowPaywall(paywall) + Adapty.logShowFlow(flow) ``` v3 と同様に、[フロービルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示する際は、このメソッドを呼び出す必要はありません。Adapty がそれらのビューを自動的に追跡します。 ## フローの表示 \{#displaying-flows\} ### getPaywallView / AdaptyPaywallView → getFlowView / AdaptyFlowView ファクトリーメソッドとビュータイプをリネームし、`AdaptyUI.FlowConfiguration` を渡します: ```diff showLineNumbers - val paywallView = AdaptyUI.getPaywallView( - activity, - viewConfiguration, - products, - eventListener, - ) + val flowView = AdaptyUI.getFlowView( + activity, + flowConfiguration, + products, + eventListener, + ) ``` ビューを直接作成する場合は、showメソッドもリネームされます: ```diff showLineNumbers - val paywallView = AdaptyPaywallView(activity) - paywallView.showPaywall(viewConfiguration, products, eventListener) + val flowView = AdaptyFlowView(activity) + flowView.showFlow(flowConfiguration, products, eventListener) ``` XML レイアウトでは、ビュータグを次のように更新してください: ```diff showLineNumbers - + ``` オプションの `personalizedOfferResolver` パラメータが `getFlowView` / `showFlow` / `AdaptyFlowScreen` から削除されました。パーソナライズ価格を示すには、`onAwaitingPurchaseParams` を通じてプロダクトごとに設定してください(`AdaptyPurchaseParameters.Builder().withOfferPersonalized(true)`)。新しいオプションの `customAssets` パラメータを使用すると、実行時に画像や動画をオーバーライドできます — [アセットのカスタマイズ](android-get-pb-paywalls#customize-assets)を参照してください。 ### AdaptyPaywallScreen → AdaptyFlowScreen Jetpack Compose では、コンポーザブルの名前を変更し、設定パラメータを更新します: ```diff showLineNumbers - AdaptyPaywallScreen( - viewConfiguration, + AdaptyFlowScreen( + flowConfiguration, products, eventListener, ) ``` ## イベントの処理 \{#handling-events\} イベントリスナーの名前が `AdaptyUiEventListener` から `AdaptyFlowEventListener` に変更されました(また `AdaptyUiDefaultEventListener` は `AdaptyFlowDefaultEventListener` に変更)。ほとんどのメソッド名は変わりませんが、ライフサイクルおよびレンダリングに関するコールバックは名前が変更されています: ```diff showLineNumbers - class YourListener : AdaptyUiDefaultEventListener() { + class YourListener : AdaptyFlowDefaultEventListener() { - override fun onPaywallShown(context: Context) {} - override fun onPaywallClosed() {} + override fun onFlowShown(context: Context) {} + override fun onFlowClosed() {} - override fun onRenderingError(error: AdaptyError, context: Context) {} + override fun onError(error: AdaptyError, context: Context) {} } ``` 既存のハンドラー本体はコードを変更する必要はありません。型名とオーバーライドの名前を変更するだけです。`onError` は、`onRenderingError` が対象としていたのと同じレンダリングエラーに加えて、その他の購入以外のランタイムエラーも対象としています。コールバックの完全な一覧については、[フロー&ペイウォールイベントの処理](android-handling-events)を参照してください。 v4では`onBackPressed(context): Boolean`コールバックも追加され、そのデフォルト動作がシステムの戻るボタンの挙動を変更しています。以前は戻るボタン(または戻るジェスチャー)がアクティビティやフラグメントにフォールスルーし、通常はペイウォールを閉じていました。v4ではデフォルト実装がそのプレスを消費するため、**システムの戻るボタンだけではフローが閉じなくなりました**。これはiOSの挙動(フローはシステムジェスチャーで閉じられない)に合わせたものです。ユーザーに明示的な退出手段(**Close**ボタンまたは`on_device_back`アクション)を提供するか、`onBackPressed`をオーバーライドして`false`を返すことで以前の動作に戻すことができます。詳細は[システムの戻るボタン](android-handling-events#system-back-button)を参照してください。 デフォルトの購入ハンドラーは、画面を閉じる動作も行わなくなりました。v3 では、デフォルトの `onPurchaseFinished` がユーザーのキャンセル以外の購入完了時(成功または保留中の購入)にペイウォールを閉じていました。v4 では何もしない(no-op)ため、**購入が完了してもフローは閉じられず、明示的に閉じるまで表示されたままになります** — これも iOS の動作と一致しています。自動クローズの動作に依存していた場合は、購入完了後に自分で画面を閉じてください。例については[購入の成功・キャンセル・保留](android-handling-events#successful-canceled-or-pending-purchase)を参照してください。 ## アトリビューションと統合識別子 \{#attribution-and-integration-identifiers\} ### updateAttribution `source` パラメーターが `String` 型から新しい `AdaptyAttributionSource` 型に変更され、`attribution` は `Map` になりました(JSON `String` のオーバーロードも利用可能です)。事前定義されたソースのいずれかを使用してください: ```diff showLineNumbers - Adapty.updateAttribution(attribution, "appsflyer") { error -> /* handle the error */ } + Adapty.updateAttribution(attribution, AdaptyAttributionSource.APPSFLYER) { error -> /* handle the error */ } ``` 定義済みのソース: `AdaptyAttributionSource.APPLE_ADS`、`.ADJUST`、`.APPSFLYER`、`.BRANCH`、`.TENJIN`。その他のソースには、文字列からソースを作成してください: `AdaptyAttributionSource("your_source")`。 ### setIntegrationIdentifier `setIntegrationIdentifier(key, value)` は、1つ以上の `AdaptyIntegrationIdentifier` 値を受け取るメソッドに置き換えられました。生の文字列キーを渡す代わりに、コンビニエンスメソッドで各識別子を作成してください: ```diff showLineNumbers - Adapty.setIntegrationIdentifier("appsflyer_id", appsFlyerId) { error -> /* handle the error */ } + Adapty.setIntegrationIdentifier(AdaptyIntegrationIdentifier.appsflyerId(appsFlyerId)) { error -> /* handle the error */ } ``` 1回の呼び出しで複数の識別子を設定することもできます: ```kotlin showLineNumbers Adapty.setIntegrationIdentifier( listOf( AdaptyIntegrationIdentifier.appsflyerId(appsFlyerId), AdaptyIntegrationIdentifier.adjustDeviceId(adjustDeviceId), ) ) { error -> /* handle the error */ } ``` 古いキー文字列をそれぞれの便利メソッドに置き換えてください: | v3 キー | v4 `AdaptyIntegrationIdentifier` メソッド | |---|---| | `"adjust_device_id"` | `adjustDeviceId(value)` | | `"airbridge_device_id"` | `airbridgeDeviceId(value)` | | `"amplitude_user_id"` | `amplitudeUserId(value)` | | `"amplitude_device_id"` | `amplitudeDeviceId(value)` | | `"appmetrica_device_id"` | `appmetricaDeviceId(value)` | | `"appmetrica_profile_id"` | `appmetricaProfileId(value)` | | `"appsflyer_id"` | `appsflyerId(value)` | | `"branch_id"` | `branchId(value)` | | `"facebook_anonymous_id"` | `facebookAnonymousId(value)` | | `"firebase_app_instance_id"` | `firebaseAppInstanceId(value)` | | `"mixpanel_user_id"` | `mixpanelUserId(value)` | | `"one_signal_subscription_id"` | `oneSignalSubscriptionId(value)` | | `"one_signal_player_id"` | `oneSignalPlayerId(value)` | | `"posthog_distinct_user_id"` | `posthogDistinctUserId(value)` | | `"pushwoosh_hwid"` | `pushwooshHWID(value)` | | `"tenjin_analytics_installation_id"` | `tenjinAnalyticsInstallationId(value)` | キーがこのリストにない場合は、カスタム `Key` から識別子を直接作成します: `AdaptyIntegrationIdentifier(AdaptyIntegrationIdentifier.Key("custom"), customValue)`。 --- # File: migration-to-android-312 --- --- title: "Adapty Android SDK を v3.12 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty Android SDK v3.12 に移行する。" --- Adapty SDK 3.12.0 では、`logShowOnboarding` メソッドを SDK から削除しました。 このメソッドを使用していた場合、SDK をバージョン 3.12 以降にアップグレードすると利用できなくなります。 代わりに、[Adapty のノーコード オンボーディングビルダーでオンボーディングを作成](onboardings)できます。これらのオンボーディングの分析は自動的に追跡され、カスタマイズオプションも豊富に用意されています。 --- # File: migration-to-android-310 --- --- title: "Android Adapty SDK 3.10.0 移行ガイド" description: "" --- Adapty SDK 3.10.0 はメジャーリリースであり、いくつかの改善が含まれていますが、移行作業が必要な場合があります。 1. `AdaptyUiPersonalizedOfferResolver` が削除されました。使用している場合は、`onAwaitingPurchaseParams` コールバックで渡してください。 2. ペイウォールビルダーのペイウォールで使用している `onAwaitingSubscriptionUpdateParams` メソッドのシグネチャを更新してください。 ## 購入パラメータコールバックの更新 \{#update-purchase-parameters-callback\} `onAwaitingSubscriptionUpdateParams` メソッドは `onAwaitingPurchaseParams` に名称変更され、`AdaptySubscriptionUpdateParameters` の代わりに `AdaptyPurchaseParameters` を使用するようになりました。これにより、サブスクリプション切り替えパラメータ(クロスグレード)の指定、価格が個人向けかどうかの指定([詳細はこちら](https://developer.android.com/google/play/billing/integrate#personalized-price))、その他の購入パラメータを設定できます。 ```diff showLineNumbers - override fun onAwaitingSubscriptionUpdateParams( - product: AdaptyPaywallProduct, - context: Context, - onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback, - ) { - onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...)) - } + override fun onAwaitingPurchaseParams( + product: AdaptyPaywallProduct, + context: Context, + onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, + ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { + onPurchaseParamsReceived( + AdaptyPurchaseParameters.Builder() + .withSubscriptionUpdateParams(AdaptySubscriptionUpdateParameters(...)) + .withOfferPersonalized(true) + .build() + ) + return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked + } ``` 追加パラメータが不要な場合は、次のように記述できます。 ```kotlin showLineNumbers + override fun onAwaitingPurchaseParams( product: AdaptyPaywallProduct, context: Context, onPurchaseParamsReceived: AdaptyUiEventListener.PurchaseParamsCallback, ): AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked { onPurchaseParamsReceived(AdaptyPurchaseParameters.Empty) return AdaptyUiEventListener.PurchaseParamsCallback.IveBeenInvoked } ``` --- # File: migration-to-android-sdk-34 --- --- title: "Adapty Android SDK を v3.4 へ移行する" description: "Adapty Android SDK v3.4 への移行で、パフォーマンス向上と新しいマネタイズ機能を活用しましょう。" --- Adapty SDK 3.4.0 はメジャーリリースであり、お客様側での移行作業が必要な改善が含まれています。 ## フォールバックペイウォールファイルの更新 \{#update-fallback-paywall-files\} 新しい SDK バージョンとの互換性を確保するため、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新済みのフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の[既存のフォールバックペイウォールを新しいファイルに置き換え](android-use-fallback-paywalls)ます。 ## オブザーバーモードの実装を更新する \{#update-implementation-of-observer-mode\} オブザーバーモードを使用している場合は、その実装を更新してください。 以前のバージョンでは、オブザーバーモードで Adapty が独自インフラ経由のトランザクションに直接アクセスできないため、Adapty に認識させるには購入を復元する必要がありました。ペイウォールを使用していた場合は、各トランザクションをそれを起点としたペイウォールに手動で紐付ける必要もありました。 新しいバージョンでは、Adapty にトランザクションを認識させるために各トランザクションを明示的にレポートする必要があります。ペイウォールを使用している場合は、トランザクションを使用したペイウォールに紐付けるためにバリエーション ID も渡す必要があります。 :::warning **トランザクションのレポートを省略しないでください!** `reportTransaction` を呼び出さないと、Adapty はトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: ```diff showLineNumbers - Adapty.restorePurchases { result -> - if (result is AdaptyResult.Success) { - // success - } - } - - Adapty.setVariationId(transactionId, variationId) { error -> - if (error == null) { - // success - } - } + val transactionInfo = TransactionInfo.fromPurchase(purchase) + + Adapty.reportTransaction(transactionInfo, variationId) { result -> + if (result is AdaptyResult.Success) { + // success + } + } ``` ```diff showLineNumbers - Adapty.restorePurchases(result -> { - if (result instanceof AdaptyResult.Success) { - // success - } - }); - - Adapty.setVariationId(transactionId, variationId, error -> { - if (error == null) { - // success - } - }); + TransactionInfo transactionInfo = TransactionInfo.fromPurchase(purchase); + + Adapty.reportTransaction(transactionInfo, variationId, result -> { + if (result instanceof AdaptyResult.Success) { + // success + } + }); ``` --- # File: migration-to-android330 --- --- title: "Adapty Android SDK を v3.3 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty Android SDK v3.3 に移行します。" --- Adapty SDK 3.3.0 はメジャーリリースであり、いくつかの改善が含まれていますが、移行手順が必要になる場合があります。 1. ペイウォールビルダーで作成されていないペイウォールでの購入処理を更新してください。`USER_CANCELED` および `PENDING_PURCHASE` エラーコードの処理を停止してください。キャンセルされた購入はエラーとして扱われなくなり、エラーなしの購入結果として返されます。 2. ペイウォールビルダーで作成されたペイウォールの `onPurchaseCanceled` および `onPurchaseSuccess` イベントを、新しい `onPurchaseFinished` イベントに置き換えてください。この変更も同じ理由です:キャンセルされた購入はエラーとして扱われなくなり、エラーなしの購入結果に含まれます。 3. ペイウォールビルダーのペイウォールに対する `onAwaitingSubscriptionUpdateParams` のメソッドシグネチャを変更してください。 4. ファイル URI を直接渡してフォールバックペイウォールを提供している場合は、その方法を更新してください。 5. Adjust、AirBridge、Amplitude、AppMetrica、Appsflyer、Branch、Facebook Ads、Firebase and Google Analytics、Mixpanel、OneSignal、Pushwoosh のインテグレーション設定を更新してください。 ## 購入処理の更新 \{#update-making-purchase\} 以前は、キャンセルされた購入と保留中の購入はエラーとして扱われ、それぞれ `USER_CANCELED` および `PENDING_PURCHASE` コードが返されていました。 新しい `AdaptyPurchaseResult` クラスを使用して、キャンセル・成功・保留中の購入を示すようになりました。以下のように購入コードを更新してください: ~~~diff Adapty.makePurchase(activity, product) { result -> when (result) { is AdaptyResult.Success -> { - val info = result.value - val profile = info?.profile - - if (profile?.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true) { - // Grant access to the paid features - } + when (val purchaseResult = result.value) { + is AdaptyPurchaseResult.Success -> { + val profile = purchaseResult.profile + if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { + // Grant access to the paid features + } + } + + is AdaptyPurchaseResult.UserCanceled -> { + // Handle the case where the user canceled the purchase + } + + is AdaptyPurchaseResult.Pending -> { + // Handle deferred purchases (e.g., the user will pay offline with cash + } + } } is AdaptyResult.Error -> { val error = result.error // Handle the error } } } ~~~ 完全なコード例については、[モバイルアプリで購入する](android-making-purchases#make-purchase) ページをご覧ください。 ## ペイウォールビルダーの購入イベントを変更する \{#modify-paywall-builder-purchase-events\} 1. `onPurchaseFinished` イベントを追加します: ```diff showLineNumbers + public override fun onPurchaseFinished( + purchaseResult: AdaptyPurchaseResult, + product: AdaptyPaywallProduct, + context: Context, + ) { + when (purchaseResult) { + is AdaptyPurchaseResult.Success -> { + // Grant access to the paid features + } + is AdaptyPurchaseResult.UserCanceled -> { + // Handle the case where the user canceled the purchase + } + is AdaptyPurchaseResult.Pending -> { + // Handle deferred purchases (e.g., the user will pay offline with cash) + } + } + } ``` 完全なコード例については、[成功・キャンセル・保留中の購入](android-handling-events#successful-canceled-or-pending-purchase) とイベントの説明をご覧ください。 2. `onPurchaseCancelled` イベントの処理を削除します: ```diff showLineNumbers - public override fun onPurchaseCanceled( - product: AdaptyPaywallProduct, - context: Context, - ) {} ``` 3. `onPurchaseSuccess` を削除します: ```diff showLineNumbers - public override fun onPurchaseSuccess( - profile: AdaptyProfile?, - product: AdaptyPaywallProduct, - context: Context, - ) { - // Your logic on successful purchase - } ``` ## onAwaitingSubscriptionUpdateParams メソッドのシグネチャを変更する \{#change-the-signature-of--onawaitingsubscriptionupdateparams-method\} 別のサブスクリプションがアクティブな状態で新しいサブスクリプションが購入された場合、新しいサブスクリプションで既存のサブスクリプションを置き換えるには `onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters...))` を、既存のサブスクリプションをアクティブに維持しながら新しいサブスクリプションを別途追加するには `onSubscriptionUpdateParamsReceived(null)` を呼び出してください: ```diff showLineNumbers - public override fun onAwaitingSubscriptionUpdateParams( - product: AdaptyPaywallProduct, - context: Context, - ): AdaptySubscriptionUpdateParameters? { - return AdaptySubscriptionUpdateParameters(...) - } + public override fun onAwaitingSubscriptionUpdateParams( + product: AdaptyPaywallProduct, + context: Context, + onSubscriptionUpdateParamsReceived: SubscriptionUpdateParamsCallback, + ) { + onSubscriptionUpdateParamsReceived(AdaptySubscriptionUpdateParameters(...)) + } ``` 最終的なコード例については、[サブスクリプションのアップグレード](android-handling-events#upgrade-subscription) のドキュメントセクションをご覧ください。 ## フォールバックペイウォールの提供方法を更新する \{#update-providing-fallback-paywalls\} フォールバックペイウォールを提供するためにファイル URI を渡している場合は、以下のように更新してください: ```diff showLineNumbers val fileUri: Uri = // Get the URI for the file with fallback paywalls - Adapty.setFallbackPaywalls(fileUri, callback) + Adapty.setFallbackPaywalls(FileLocation.fromFileUri(fileUri), callback) ``` ```diff showLineNumbers Uri fileUri = // Get the URI for the file with fallback paywalls - Adapty.setFallbackPaywalls(fileUri, callback); + Adapty.setFallbackPaywalls(FileLocation.fromFileUri(fileUri), callback); ``` ## サードパーティインテグレーションの SDK 設定を更新する \{#update-third-party-integration-sdk-configuration\} Adapty Android SDK 3.3.0 以降でインテグレーションが正しく動作するように、以下のセクションに従って各インテグレーションの SDK 設定を更新してください。 ### Adjust 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Adjust インテグレーションの SDK 設定](adjust#connect-your-app-to-adjust) をご覧ください。 ```diff showLineNumbers - Adjust.getAttribution { attribution -> - if (attribution == null) return@getAttribution - - Adjust.getAdid { adid -> - if (adid == null) return@getAdid - - Adapty.updateAttribution(attribution, AdaptyAttributionSource.ADJUST, adid) { error -> - // Handle the error - } - } - } + Adjust.getAdid { adid -> + if (adid == null) return@getAdid + + Adapty.setIntegrationIdentifier("adjust_device_id", adid) { error -> + if (error != null) { + // Handle the error + } + } + } + + Adjust.getAttribution { attribution -> + if (attribution == null) return@getAttribution + + Adapty.updateAttribution(attribution, "adjust") { error -> + if (error != null) { + // Handle the error + } + } + } ``` ```diff showLineNumbers val config = AdjustConfig(context, adjustAppToken, environment) config.setOnAttributionChangedListener { attribution -> attribution?.let { attribution -> - Adapty.updateAttribution(attribution, AdaptyAttributionSource.ADJUST) { error -> + Adapty.updateAttribution(attribution, "adjust") { error -> if (error != null) { // Handle the error } } } } Adjust.onCreate(config) ``` ### AirBridge 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AirBridge インテグレーションの SDK 設定](airbridge#connect-your-app-to-airbridge) をご覧ください。 ```diff showLineNumbers Airbridge.getDeviceInfo().getUUID(object: AirbridgeCallback.SimpleCallback() { override fun onSuccess(result: String) { - val params = AdaptyProfileParameters.Builder() - .withAirbridgeDeviceId(result) - .build() - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("airbridge_device_id", result) { error -> + if (error != null) { + // Handle the error + } + } } override fun onFailure(throwable: Throwable) { } }) ``` ### Amplitude 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Amplitude インテグレーションの SDK 設定](amplitude#sdk-configuration) をご覧ください。 ```diff showLineNumbers // For Amplitude maintenance SDK (obsolete) val amplitude = Amplitude.getInstance() val amplitudeDeviceId = amplitude.getDeviceId() val amplitudeUserId = amplitude.getUserId() //for actual Amplitude Kotlin SDK val amplitude = Amplitude( Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext ) ) val amplitudeDeviceId = amplitude.store.deviceId val amplitudeUserId = amplitude.store.userId // - val params = AdaptyProfileParameters.Builder() - .withAmplitudeDeviceId(amplitudeDeviceId) - .withAmplitudeUserId(amplitudeUserId) - .build() - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("amplitude_user_id", amplitudeUserId) { error -> + if (error != null) { + // Handle the error + } + } + Adapty.setIntegrationIdentifier("amplitude_device_id", amplitudeDeviceId) { error -> + if (error != null) { + // Handle the error + } + } ``` ### AppMetrica 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppMetrica インテグレーションの SDK 設定](appmetrica#sdk-configuration) をご覧ください。 ```diff showLineNumbers val startupParamsCallback = object: StartupParamsCallback { override fun onReceive(result: StartupParamsCallback.Result?) { val deviceId = result?.deviceId ?: return - val params = AdaptyProfileParameters.Builder() - .withAppmetricaDeviceId(deviceId) - .withAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID") - .build() - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId) { error -> + if (error != null) { + // Handle the error + } + } + + Adapty.setIntegrationIdentifier("appmetrica_profile_id", "YOUR_ADAPTY_CUSTOMER_USER_ID") { error -> + if (error != null) { + // Handle the error + } + } } override fun onRequestError( reason: StartupParamsCallback.Reason, result: StartupParamsCallback.Result? ) { // Handle the error } } AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID)) ``` ### AppsFlyer 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppsFlyer インテグレーションの SDK 設定](appsflyer#connect-your-app-to-appsflyer) をご覧ください。 ```diff showLineNumbers val conversionListener: AppsFlyerConversionListener = object : AppsFlyerConversionListener { override fun onConversionDataSuccess(conversionData: Map) { - Adapty.updateAttribution( - conversionData, - AdaptyAttributionSource.APPSFLYER, - AppsFlyerLib.getInstance().getAppsFlyerUID(context) - ) { error -> - if (error != null) { - // Handle the error - } - } + val uid = AppsFlyerLib.getInstance().getAppsFlyerUID(context) + Adapty.setIntegrationIdentifier("appsflyer_id", uid) { error -> + if (error != null) { + // Handle the error + } + } + Adapty.updateAttribution(conversionData, "appsflyer") { error -> + if (error != null) { + // Handle the error + } + } } } ``` ### Branch 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Branch インテグレーションの SDK 設定](branch#connect-your-app-to-branch) をご覧ください。 ```diff showLineNumbers // Login and update attribution Branch.getAutoInstance(this) .setIdentity("YOUR_USER_ID") { referringParams, error -> referringParams?.let { data -> - Adapty.updateAttribution(data, AdaptyAttributionSource.BRANCH) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.updateAttribution(data, "branch") { error -> + if (error != null) { + // Handle the error + } + } } } // Logout Branch.getAutoInstance(context).logout() ``` ### Facebook Ads 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Facebook Ads インテグレーションの SDK 設定](facebook-ads#connect-your-app-to-facebook-ads) をご覧ください。 ```diff showLineNumbers - val builder = AdaptyProfileParameters.Builder() - .withFacebookAnonymousId(AppEventsLogger.getAnonymousAppDeviceGUID(context)) - - Adapty.updateProfile(builder.build()) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier( + "facebook_anonymous_id", + AppEventsLogger.getAnonymousAppDeviceGUID(context) + ) { error -> + if (error != null) { + // Handle the error + } + } ``` ### Firebase and Google Analytics 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Firebase and Google Analytics インテグレーションの SDK 設定](firebase-and-google-analytics) をご覧ください。 ```diff showLineNumbers // After Adapty.activate() FirebaseAnalytics.getInstance(context).appInstanceId.addOnSuccessListener { appInstanceId -> - Adapty.updateProfile( - AdaptyProfileParameters.Builder() - .withFirebaseAppInstanceId(appInstanceId) - .build() - ) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId) { error -> + if (error != null) { + // Handle the error + } + } } ``` ```diff showLineNumbers // After Adapty.activate() - FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> { - AdaptyProfileParameters params = new AdaptyProfileParameters.Builder() - .withFirebaseAppInstanceId(appInstanceId) - .build(); - - Adapty.updateProfile(params, error -> { - if (error != null) { - // Handle the error - } - }); - }); + FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> { + Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId, error -> { + if (error != null) { + // Handle the error + } + }); + }); ``` ### Mixpanel 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Mixpanel インテグレーションの SDK 設定](mixpanel#sdk-configuration) をご覧ください。 ```diff showLineNumbers - val params = AdaptyProfileParameters.Builder() - .withMixpanelUserId(mixpanelAPI.distinctId) - .build() - - Adapty.updateProfile(params) { error -> - if (error != null) { - // Handle the error - } - } + Adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelAPI.distinctId) { error -> + if (error != null) { + // Handle the error + } + } ``` ### OneSignal 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[OneSignal インテグレーションの SDK 設定](onesignal#sdk-configuration) をご覧ください。 ```diff showLineNumbers // SubscriptionID val oneSignalSubscriptionObserver = object: IPushSubscriptionObserver { override fun onPushSubscriptionChange(state: PushSubscriptionChangedState) { - val params = AdaptyProfileParameters.Builder() - .withOneSignalSubscriptionId(state.current.id) - .build() - - Adapty.updateProfile(params) { error -> + Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.current.id) { error -> if (error != null) { // Handle the error } } } } ``` ```diff showLineNumbers // SubscriptionID IPushSubscriptionObserver oneSignalSubscriptionObserver = state -> { - AdaptyProfileParameters params = new AdaptyProfileParameters.Builder() - .withOneSignalSubscriptionId(state.getCurrent().getId()) - .build(); - Adapty.updateProfile(params, error -> { + Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.getCurrent().getId(), error -> { if (error != null) { // Handle the error } }); }; ``` ```diff showLineNumbers // PlayerID val osSubscriptionObserver = OSSubscriptionObserver { stateChanges -> stateChanges?.to?.userId?.let { playerId -> - val params = AdaptyProfileParameters.Builder() - .withOneSignalPlayerId(playerId) - .build() - - Adapty.updateProfile(params) { error -> + Adapty.setIntegrationIdentifier("one_signal_player_id", playerId) { error -> if (error != null) { // Handle the error } - } } } ``` ```diff showLineNumbers // PlayerID OSSubscriptionObserver osSubscriptionObserver = stateChanges -> { OSSubscriptionState to = stateChanges != null ? stateChanges.getTo() : null; String playerId = to != null ? to.getUserId() : null; if (playerId != null) { - AdaptyProfileParameters params1 = new AdaptyProfileParameters.Builder() - .withOneSignalPlayerId(playerId) - .build(); - - Adapty.updateProfile(params1, error -> { + Adapty.setIntegrationIdentifier("one_signal_player_id", playerId, error -> { if (error != null) { // Handle the error } - }); } }; ``` ### Pushwoosh 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Pushwoosh インテグレーションの SDK 設定](pushwoosh#sdk-configuration) をご覧ください。 ```diff showLineNumbers - val params = AdaptyProfileParameters.Builder() - .withPushwooshHwid(Pushwoosh.getInstance().hwid) - .build() - Adapty.updateProfile(params) { error -> + Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().hwid) { error -> if (error != null) { // Handle the error } } ``` ```diff showLineNumbers - AdaptyProfileParameters params = new AdaptyProfileParameters.Builder() - .withPushwooshHwid(Pushwoosh.getInstance().getHwid()) - .build(); - - Adapty.updateProfile(params, error -> { + Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().getHwid(), error -> { if (error != null) { // Handle the error } }); ``` --- # File: migration-to-android-sdk-v3 --- --- title: "Adapty Android SDK を v3.0 に移行する" description: "Adapty Android SDK v3.0 に移行して、パフォーマンスの向上と新しいマネタイゼーション機能を活用しましょう。" --- Adapty SDK v3.0 では、新しい [Adapty ペイウォールビルダー](adapty-paywall-builder)をサポートしています。これはペイウォールをノーコードで作成できる使いやすいツールの新バージョンです。高い柔軟性と豊富なデザイン機能により、より効果的で収益性の高いペイウォールを作成できます。 Adapty SDK は BoM(Bill of Materials)として提供されており、アプリ内の Adapty SDK と AdaptyUI SDK のバージョンを常に一致させることができます。 v3.0 に移行するには、以下のようにコードを更新してください: ```diff showLineNumbers dependencies { ... - implementation 'io.adapty:android-sdk:2.11.5' - implementation 'io.adapty:android-ui:2.11.3' + implementation platform('io.adapty:adapty-bom:3.0.4') + implementation 'io.adapty:android-sdk' + implementation 'io.adapty:android-ui' } ``` ```diff showLineNumbers dependencies { ... - implementation("io.adapty:android-sdk:2.11.5") - implementation("io.adapty:android-ui:2.11.3") + implementation(platform("io.adapty:adapty-bom:3.0.4")) + implementation("io.adapty:android-sdk") + implementation("io.adapty:android-ui") } ``` ```diff showLineNumbers //libs.versions.toml [versions] .. - adapty = "2.11.5" - adaptyUi = "2.11.3" + adaptyBom = "3.0.4" [libraries] .. - adapty = { group = "io.adapty", name = "android-sdk", version.ref = "adapty" } - adapty-ui = { group = "io.adapty", name = "android-ui", version.ref = "adaptyUi" } + adapty-bom = { module = "io.adapty:adapty-bom", version.ref = "adaptyBom" } + adapty = { module = "io.adapty:android-sdk" } + adapty-ui = { module = "io.adapty:android-ui" } //module-level build.gradle.kts dependencies { ... + implementation(libs.adapty.bom) implementation(libs.adapty) implementation(libs.adapty.ui) } ``` --- # End of Documentation _Generated on: 2026-07-24T13:00:57.606Z_ _Successfully processed: 41/41 files_ # API - 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.608Z Total files: 18 --- # File: developer-cli --- --- title: "Developer CLI" description: "Adapty Developer CLI の概要。" --- **Adapty Developer CLI** は、ダッシュボードを開かずに Adapty アカウントを管理するためのコマンドラインツールです。ターミナルや自動化環境から、主要な設定操作を行うことができます。 **CLI でできること:** - Adapty アカウントへの iOS・Android アプリの作成と設定 - アクセスレベルの定義(アプリが実行時に確認するサブスクリプションのティア) - プロダクトの設定と App Store・Google Play のストア ID へのマッピング - ペイウォールの作成とプロダクトの割り当て - SDK 経由でペイウォールを取得するためのプレースメントの設定 :::link AI アシスタントや MCP クライアントを使用していますか?LLM が CLI を利用しやすくする [Adapty CLI スキル](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) が利用可能です。 ::: --- # File: developer-cli-quickstart --- --- title: "Adapty Developer CLI クイックスタートガイド" description: "Developer CLI を使って Adapty アカウントをエンドツーエンドでセットアップ — アプリ作成からプレースメント公開まで、数コマンドで完了。" --- :::link AI アシスタントを使っていますか?LLM が CLI を操作しやすくなる [Adapty CLI スキル](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli) が利用できます。 ::: Adapty CLI を使うと、アプリの設定をすべてコマンドラインから行えます。ターミナル作業を好む方や [MCP クライアント](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli)を使う方向けに、[ダッシュボードのクイックスタート](integrate-payments)の代替手段として活用できます。 :::note App Store Connect や Google Play への接続は、ダッシュボードでの一度きりのセットアップが必要です — 手順 3 で説明します。 ::: この手順を完了すると、アプリ・アクセスレベル・プロダクト・ペイウォール・プレースメントがすべて [Adapty ダッシュボード](https://app.adapty.io) に表示されます。 ## 1. CLI をインストールする \{#1-install-the-cli\} [Node.js](https://nodejs.org/en/download) 18 以降が必要です。 CLI をインストールするには、次のコマンドを実行します: ```bash npm install -g adapty ``` または、直接実行する場合: ```bash npx adapty auth login ``` ## 2. 認証する \{#2-authenticate\} ログインコマンドを実行して、CLI を Adapty アカウントに接続します。 ```bash adapty auth login ``` CLI がブラウザタブを開きます。ターミナルに表示されたコードとブラウザに表示されたコードが一致していることを確認し、**Authorize** をクリックします。認証が完了するとターミナルに確認メッセージが表示されます。 ## 3. アプリを作成する \{#3-create-your-app\} Adapty のアプリはモバイルアプリケーションを表します。1 つの Adapty アプリが App Store と Google Play の両方に接続されるため、公開するストアの数に関わらず、作成するのは 1 つで十分です。 ```bash adapty apps create --title "My App" --platform ios --platform android --apple-bundle-id com.example.app --google-bundle-id com.example.app ``` ```bash adapty apps create --title "My App" --platform ios --apple-bundle-id com.example.app ``` ```bash adapty apps create --title "My App" --platform android --google-bundle-id com.example.app ``` このコマンドは `` を返します。以降のコマンドではすべてこの ID を使用します。 :::important 次の手順に進む前に、Adapty ダッシュボードでアプリを App Store Connect および Google Play に接続してください。手順 5 では両ストアのプロダクト ID が必要です。 - [App Store Connect を接続する](app-store-connection-configuration) - [Google Play を接続する](google-play-store-connection-configuration) ::: ## 4. アクセスレベルを作成する(任意) \{#4-create-an-access-level-optional\} [アクセスレベル](access-level)は、購入後にユーザーがアクセスできる内容を管理します。特定のプロダクトを購入したかどうかを確認する代わりに、アプリはユーザーが特定のアクセスレベルを持っているかどうかを確認します。これにより、アプリのロジックを特定のプロダクト ID から切り離すことができます。 `premium` アクセスレベルは新しいアプリとともに自動的に作成されます。**ほとんどのアプリではこの手順はスキップできます。** 手順 5 ではアクセスレベル ID として `premium` を使用してください。 異なるプロダクトが異なるユーザーグループの異なる機能をアンロックする場合 — たとえば「Basic」サブスクライバーと「Pro」サブスクライバーがアプリの異なる部分にアクセスできる場合 — にのみ、このコマンドを実行してください。 ```bash adapty access-levels create --app --sdk-id "pro" --title "Pro" ``` - `--sdk-id` はアプリコード内でユーザーがその機能を利用できるかどうかを確認するために使う識別子です(例:`if user.hasAccessLevel("pro")`)。この手順をスキップしてデフォルトのアクセスレベルを使う場合、その `--sdk-id` は `premium` です。 - `--title` は Adapty ダッシュボードでの参照用に表示されるラベルです。 このコマンドは `` を返します。 ## 5. プロダクトを作成する \{#5-create-a-product\} Adapty における[プロダクト](product)は、アプリが販売するもの — サブスクリプションや買い切り購入 — を表します。App Store Connect と Google Play のアイテムを 1 つの Adapty プロダクトにまとめて、一元管理できます。 各ストアのプロダクト ID が必要です:App Store Connect の Apple プロダクト ID、および Google Play Console の Android プロダクト ID とベースプラン ID。確認方法の詳細は[プロダクト](quickstart-products)を参照してください。 手順 4 をスキップした場合は、手順 3 の `apps create` コマンドが返した `default_access_level.id` を `` として使用してください。 :::important ここでリンクするストアのプロダクト ID(`--ios-product-id`、`--android-product-id`)は作成後に変更できません。別のストアプロダクト ID を使用する場合は、新しいプロダクトを作成してください。 ::: ```bash adapty products create --app --title "My Product" --access-level-id --period monthly --ios-product-id --android-product-id --android-base-plan-id ``` ```bash adapty products create --app --title "My Product" --access-level-id --period monthly --ios-product-id ``` ```bash adapty products create --app --title "My Product" --access-level-id --period monthly --android-product-id --android-base-plan-id ``` このコマンドは `` を返します。 ## 6. ペイウォールを作成する \{#6-create-a-paywall\} [ペイウォール](paywalls)はプロダクトを格納するコンテナです。Adapty では、ペイウォールがユーザーにプロダクトを届ける唯一の方法です。すべてのプロダクトは、アプリに表示される前にペイウォールに含まれている必要があります。 :::important ペイウォールがプレースメントにリンクされると、そのプロダクトは変更できません。別のプロダクトを使用するには、新しいペイウォールを作成してプレースメントがそちらを参照するように更新してください。 ::: ```bash adapty paywalls create --app --title "My Paywall" --product-id ``` ```bash adapty paywalls create --app --title "My Paywall" --product-id --product-id ``` このコマンドは `` を返します。 ## 7. プレースメントを作成する \{#7-create-a-placement\} [プレースメント](placements)は、アプリ内でペイウォールを表示する場所を指します。アプリコードにハードコードするのはプレースメント ID だけです。どのペイウォールをどのユーザーに表示するかといった設定はすべて、新しいアプリバージョンをリリースすることなくダッシュボードから管理できます。 `--developer-id` は、後でアプリコードからこの場所に表示するペイウォールを Adapty に問い合わせる際に参照する文字列です。場所を表すわかりやすい名前(例:`"main"`、`"onboarding"`、`"settings"`)を指定してください。 ```bash adapty placements create --app --title "Main" --developer-id "main" --audiences '[{"segment_ids":[],"paywall_id":"","priority":0}]' ``` `--audiences` フラグは、どのユーザーにどのペイウォールを表示するかを制御します。上の例では単一のデフォルトオーディエンスを設定しており、このプレースメントのすべてのユーザーに同じペイウォールが表示されます。 ## 次のステップ \{#whats-next\} すべてのエンティティが [Adapty ダッシュボード](https://app.adapty.io) に表示されるようになりました。次は: - [ペイウォールをデザインする](adapty-paywall-builder) — ノーコードのペイウォールビルダーを使って、作成したペイウォールにビジュアル・レイアウト・コピーを追加します。 - [Adapty SDK を組み込む](quickstart-sdk) — アプリに SDK を追加して、プレースメントを取得・表示します。 - 異なるユーザー[セグメント](segments)を異なるペイウォールにルーティングする — 詳細は完全リファレンスの [`placements update`](developer-cli-reference#adapty-placements-update) と [`segments list`](developer-cli-reference#adapty-segments-list) を参照してください。 --- # File: developer-cli-authentication --- --- title: "Adapty Developer CLI での認証" description: "Adapty Developer CLI での認証方法について説明します。" --- :::link AIアシスタントを使用していますか?LLMがCLIを操作するための[Adapty CLIスキル](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli)が利用できます。 ::: CLIはAdapty APIを呼び出すために認証が必要です。 ## ログイン \{#log-in\} ログインするには: 1. ターミナルで次のコマンドを実行します: ```bash adapty auth login ``` 2. CLIが`XXXX-XXXX`形式の確認コードを表示し、Adapty ダッシュボードをブラウザで開きます。 3. 認証ページで、コードがターミナルの出力と一致していることを確認します。 4. **Authorize**をクリックします。ブラウザに「CLI authorized! You can close this tab.」と表示されます。 5. ターミナルに戻ると、CLIが認証済みであることを確認するメッセージが表示されます。 認証前にコードが期限切れになった場合、または**Deny**をクリックした場合は、次のコマンドを再度実行してフローを再開してください: ```bash adapty auth login ``` ## 認証の管理 \{#manage-authentication\} ### 認証状態の確認 \{#check-authentication-status\} 現在の認証状態を確認するには、次のコマンドを実行します: ```bash adapty auth status ``` 認証済みの場合、出力にはメールアドレス、マスクされたトークンのプレフィックス、およびローカル設定ファイルのパスが表示されます: ``` Email: you@example.com Token: abcd1234**** Config: ~/.config/adapty/config.json ``` 未認証の場合: ``` Not authenticated. Run `adapty auth login`. ``` ### トークンの検証 \{#verify-your-token\} トークンが有効であることを確認し、アカウントの詳細を表示するには、次のコマンドを実行します: ```bash adapty auth whoami ``` `adapty auth status`とは異なり、このコマンドはサーバーにリクエストを送信してトークンを検証します。 ### ログアウト \{#log-out\} 保存されている認証情報をローカルから削除するには、次のコマンドを実行します: ```bash adapty auth logout ``` これにより`~/.config/adapty/config.json`が削除されます。トークンは有効期限が切れるまでサーバー側では有効なままです。すぐに無効化する必要がある場合は、代わりに`adapty auth revoke`を使用してください。 ### トークンの失効 \{#revoke-your-token\} サーバー上のトークンを無効化し、ローカルからも削除するには、次のコマンドを実行します: ```bash adapty auth revoke ``` このコマンドは、たとえば認証情報が漏洩した可能性がある場合など、トークンを完全に無効化したいときに使用します。失効後、再認証するには`adapty auth login`を実行してください。 ## トークンエラー \{#token-errors\} トークンが失効または無効になった場合、CLIコマンドは401エラーを返します。再認証するには、次のコマンドを実行します: ```bash adapty auth login ``` --- # File: developer-cli-reference --- --- title: "Adapty Developer CLIの完全リファレンス" description: "すべてのAdapty Developer CLIコマンドの完全リファレンス。" --- :::link AIアシスタントを使っていますか?LLMがCLIを操作しやすいように[Adapty CLIスキル](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli)が用意されています。 ::: この記事では、Adapty CLIのすべてのコマンドと引数、フラグ、使用可能な値を一覧で紹介します。 :::link 認証の設定とトークン管理については、[認証](developer-cli-authentication)を参照してください。 ::: ## グローバルフラグ \{#global-flags\} これらのフラグはすべてのコマンドで使用できます。 | フラグ | 説明 | |---|---| | `--json` | フォーマットテキストの代わりにJSONで出力する | | `--help` | コマンドのヘルプを表示する | すべての `list` コマンドではページネーションフラグも使用できます: | フラグ | デフォルト | 説明 | |---|---|---| | `--page` | `1` | ページ番号 | | `--page-size` | `20` | 1ページあたりのアイテム数(最大:100) | ## アプリ \{#apps\} Adaptyアカウント内のアプリを管理します。ダッシュボードベースの設定については、[App settings](general)を参照してください。 ### adapty apps list \{#adapty-apps-list\} Adaptyアカウント内のすべてのアプリを一覧表示します。 ```bash adapty apps list ``` [ページネーションフラグ](#global-flags)を使用できます。 ### adapty apps get \{#adapty-apps-get\} 特定のアプリの詳細を取得します。 ```bash adapty apps get ``` | 引数 | 説明 | |---|---| | `app-id` | アプリID(UUID) | ### adapty apps create \{#adapty-apps-create\} 新しいアプリを作成します。 ```bash adapty apps create --title "My App" --platform ios --apple-bundle-id com.example.app ``` | フラグ | 必須 | 説明 | |---|---|---| | `--title` | はい | アプリのタイトル | | `--platform` | はい | プラットフォーム:`ios` または `android`。両方指定する場合は繰り返す:`--platform ios --platform android` | | `--apple-bundle-id` | `--platform ios` 指定時に必須 | AppleバンドルID | | `--google-bundle-id` | `--platform android` 指定時に必須 | GoogleバンドルID | ### adapty apps update \{#adapty-apps-update\} 既存のアプリを更新します。 ```bash adapty apps update --title "New Name" ``` | 引数 | 説明 | |---|---| | `app-id` | アプリID(UUID) | | フラグ | 説明 | |---|---| | `--title` | 新しいアプリタイトル | | `--apple-bundle-id` | 新しいAppleバンドルID | | `--google-bundle-id` | 新しいGoogleバンドルID | 少なくとも1つのフラグが必要です。`--platform` は作成後に変更できません。 ## アクセスレベル \{#access-levels\} ### adapty access-levels list \{#adapty-access-levels-list\} アプリのすべての[アクセスレベル](access-level)を一覧表示します。 ```bash adapty access-levels list --app ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | [ページネーションフラグ](#global-flags)を使用できます。 ### adapty access-levels get \{#adapty-access-levels-get\} 特定の[アクセスレベル](access-level)の詳細を取得します。 ```bash adapty access-levels get --app ``` | 引数 | 説明 | |---|---| | `access-level-id` | アクセスレベルID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | ### adapty access-levels create \{#adapty-access-levels-create\} 新しい[アクセスレベル](access-level)を作成します。 ```bash adapty access-levels create --app --sdk-id "pro" --title "Pro" ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--sdk-id` | はい | アプリコード内でアクセス確認に使用する識別子(例:`"pro"` や `"premium"`) | | `--title` | はい | Adaptyダッシュボードに表示されるラベル | ### adapty access-levels update \{#adapty-access-levels-update\} 既存の[アクセスレベル](access-level)を更新します。 ```bash adapty access-levels update --app --title "Pro Access" ``` | 引数 | 説明 | |---|---| | `access-level-id` | アクセスレベルID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | はい | 新しい表示ラベル | `--sdk-id` は作成後に変更できません。 ## プロダクト \{#products\} ### adapty products list \{#adapty-products-list\} アプリのすべての[プロダクト](product)を一覧表示します。 ```bash adapty products list --app ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | [ページネーションフラグ](#global-flags)を使用できます。 ### adapty products get \{#adapty-products-get\} 特定の[プロダクト](product)の詳細を取得します。 ```bash adapty products get --app ``` | 引数 | 説明 | |---|---| | `product-id` | プロダクトID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | ### adapty products create \{#adapty-products-create\} 新しい[プロダクト](product)を作成します。 :::important ストアのプロダクトID(`--ios-product-id`、`--android-product-id`、`--android-base-plan-id`)は作成後に変更できません。異なるストアプロダクトIDを使用したい場合は、新しいプロダクトを作成してください。 ::: ```bash adapty products create --app --title "Monthly" --access-level-id --period monthly --ios-product-id com.example.monthly ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | はい | プロダクトタイトル | | `--access-level-id` | はい | このプロダクトがアンロックする[アクセスレベル](access-level)ID(UUID) | | `--period` | はい | サブスクリプション期間:`weekly`、`monthly`、`2_months`、`3_months`、`6_months`、`yearly`、`lifetime` | | `--ios-product-id` | 少なくとも1つのプラットフォームが必須 | App Store ConnectのプロダクトID | | `--android-product-id` | 少なくとも1つのプラットフォームが必須 | Google Play ConsoleのプロダクトID | | `--android-base-plan-id` | `--android-product-id` 指定時に必須(`--period lifetime` の場合を除く) | Google Play ConsoleのベースプランID | ### adapty products update \{#adapty-products-update\} 既存の[プロダクト](product)を更新します。 ストアのプロダクトID(`--ios-product-id`、`--android-product-id`)は作成後に変更できないため、このコマンドでは使用できません。異なるストアプロダクトIDを使用したい場合は、新しいプロダクトを作成してください。 ```bash adapty products update --app --title "Monthly" --access-level-id ``` | 引数 | 説明 | |---|---| | `product-id` | プロダクトID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | いいえ | プロダクトタイトル | | `--access-level-id` | いいえ | このプロダクトがアンロックする[アクセスレベル](access-level)ID(UUID) | ## ペイウォール \{#paywalls\} ### adapty paywalls list \{#adapty-paywalls-list\} アプリのすべての[ペイウォール](paywalls)を一覧表示します。 ```bash adapty paywalls list --app ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | [ページネーションフラグ](#global-flags)を使用できます。 ### adapty paywalls get \{#adapty-paywalls-get\} 特定の[ペイウォール](paywalls)の詳細を取得します。 ```bash adapty paywalls get --app ``` | 引数 | 説明 | |---|---| | `paywall-id` | ペイウォールID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | ### adapty paywalls create \{#adapty-paywalls-create\} 新しい[ペイウォール](paywalls)を作成します。 ```bash adapty paywalls create --app --title "Default Paywall" --product-id ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | はい | ペイウォールタイトル | | `--product-id` | はい | [プロダクト](product)ID(UUID)。複数指定する場合は繰り返す:`--product-id --product-id ` | ### adapty paywalls update \{#adapty-paywalls-update\} 既存の[ペイウォール](paywalls)のすべてのフィールドを置き換えます。 :::important ペイウォールがプレースメントに紐付けられると、そのプロダクトは変更できません。本番稼働中のペイウォールで異なるプロダクトを使用したい場合は、新しいペイウォールを作成し、プレースメントがそちらを参照するよう更新してください。 ::: ```bash adapty paywalls update --app --title "Default Paywall" --product-id ``` このコマンドはプロダクトリスト全体を含む、ペイウォールのすべてのフィールドを置き換えます。 | 引数 | 説明 | |---|---| | `paywall-id` | ペイウォールID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | はい | ペイウォールタイトル | | `--product-id` | はい | [プロダクト](product)ID(UUID)。複数指定する場合は繰り返す:`--product-id --product-id ` | ### adapty paywalls placements \{#adapty-paywalls-placements\} 指定した[ペイウォール](paywalls)を現在使用しているすべての[プレースメント](placements)を一覧表示します。 ```bash adapty paywalls placements --app ``` | 引数 | 説明 | |---|---| | `paywall-id` | ペイウォールID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | ペイウォールを切り替える前に、このコマンドで影響を受けるプレースメントを確認してください。 ## プレースメント \{#placements\} ### adapty placements list \{#adapty-placements-list\} アプリのすべての[プレースメント](placements)を一覧表示します。 ```bash adapty placements list --app ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | [ページネーションフラグ](#global-flags)を使用できます。 ### adapty placements get \{#adapty-placements-get\} 特定の[プレースメント](placements)の詳細を取得します。 ```bash adapty placements get --app ``` | 引数 | 説明 | |---|---| | `placement-id` | プレースメントID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | レスポンスには `audiences` 配列が含まれます。各エントリは `{segment_ids, paywall_id, priority}` の形式です。デフォルトのオーディエンスは `segment_ids: []` を持ち、最も高いpriorityの値(最後に評価される)を持ちます。フォーマット済みの人間向け出力には、便宜上デフォルトオーディエンスから導出したトップレベルの `Paywall ID` も表示されます。`--json` を使用すると、加工されていないAPIレスポンスがそのまま返されます。 ### adapty placements create \{#adapty-placements-create\} 新しい[プレースメント](placements)を作成します。 ```bash adapty placements create --app --title "Main" --developer-id "main" --audiences '[{"segment_ids":[],"paywall_id":"","priority":0}]' ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | はい | プレースメントタイトル | | `--developer-id` | はい | アプリコード内でこの[プレースメント](placements)をリクエストする際に使用する文字列識別子 | | `--audiences` | どちらか一方 | `{segment_ids, paywall_id, priority}` エントリのJSON配列。[オーディエンスの形式](#audiences-shape)を参照 | | `--paywall-id` | どちらか一方 | **非推奨。** [ペイウォール](paywalls)ID(UUID)。クライアント側で単一のデフォルトオーディエンスにラップされます | `--audiences` または `--paywall-id` のいずれか一方のみを指定してください。両方指定または両方省略するとエラーになります。 :::warning `--paywall-id` は非推奨であり、今後削除される予定です。指定した場合、CLIはstderrに警告を出力し、値をデフォルトオーディエンスに変換します。新しい自動化処理では `--audiences` を使用してください。 ::: ### adapty placements update \{#adapty-placements-update\} 既存の[プレースメント](placements)のすべてのフィールドを置き換えます。 ```bash adapty placements update --app --title "Main" --developer-id "main" --audiences '[{"segment_ids":[],"paywall_id":"","priority":0}]' ``` このコマンドはオーディエンスリスト全体を含む、プレースメントのすべてのフィールドを置き換えます。 | 引数 | 説明 | |---|---| | `placement-id` | プレースメントID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | | `--title` | はい | プレースメントタイトル | | `--developer-id` | はい | アプリコード内でこの[プレースメント](placements)をリクエストする際に使用する文字列識別子 | | `--audiences` | どちらか一方 | `{segment_ids, paywall_id, priority}` エントリのJSON配列。[オーディエンスの形式](#audiences-shape)を参照 | | `--paywall-id` | どちらか一方 | **非推奨。** [ペイウォール](paywalls)ID(UUID)。すべてのオーディエンスを単一のデフォルトオーディエンスで置き換えます | :::warning `--paywall-id` を指定すると、プレースメントのすべてのオーディエンスが上書きされます。セグメント固有のオーディエンスは削除されます。それらを保持したい場合は `--audiences` を使用し、維持したいすべてのエントリを含めてください。 ::: #### オーディエンスの形式 \{#audiences-shape\} `--audiences` フラグはJSON配列を受け取ります。各エントリには以下のフィールドがあります: | フィールド | 型 | 説明 | |---|---|---| | `segment_ids` | `string[]` | このオーディエンスが対象とする[セグメント](segments)IDの配列。要素数は0または1。空配列は**デフォルトオーディエンス**(他のセグメントにマッチしないユーザーへのフォールバック)を表します | | `paywall_id` | `string` | このオーディエンスのユーザーに表示される[ペイウォール](paywalls)ID(UUID) | | `priority` | `number` | 0始まりで、プレースメント内で一意。オーディエンスは値の小さい順に評価され、デフォルトオーディエンスは最も高い値を持つ必要があります | プレースメントには必ずデフォルトオーディエンスが1つ必要です。 1つのターゲットオーディエンスと1つのデフォルトオーディエンスを持つ例: ```bash adapty placements update --app --title "Main" --developer-id "main" \ --audiences '[{"segment_ids":[""],"paywall_id":"","priority":0},{"segment_ids":[],"paywall_id":"","priority":1}]' ``` セグメント固有のルーティングを維持しながら複数のプレースメントでペイウォールを切り替えるには: 1. 影響を受けるプレースメントを確認する: ```bash adapty paywalls placements --app ``` 2. それぞれの `audiences` 配列全体を取得する: ```bash adapty placements get --app --json ``` 3. 対象の `paywall_id` の値をクライアント側で置き換える。 4. 変更したペイロードを書き戻す: ```bash adapty placements update --app --title "" --developer-id "<developer-id>" --audiences '<modified-payload>' ``` ## セグメント \{#segments\} [セグメント](segments)はCLI経由では読み取り専用です。作成・編集は[Adaptyダッシュボード](https://app.adapty.io)で行ってください。プレースメントのオーディエンスを構成する際にセグメントIDを調べるためにこれらのコマンドを使用します。 ### adapty segments list \{#adapty-segments-list\} アプリのすべての[セグメント](segments)を一覧表示します。 ```bash adapty segments list --app <app-id> ``` | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | [ページネーションフラグ](#global-flags)を使用できます。 ### adapty segments get \{#adapty-segments-get\} 特定の[セグメント](segments)の詳細を取得します。 ```bash adapty segments get --app <app-id> <segment-id> ``` | 引数 | 説明 | |---|---| | `segment-id` | セグメントID(UUID) | | フラグ | 必須 | 説明 | |---|---|---| | `--app` | はい | アプリID(UUID) | レスポンスには `id`、`title`、`description` が含まれます。フィルタールールはこのAPIでは公開されていません。 ## 認証 \{#auth\} | コマンド | 説明 | |---|---| | `adapty auth login` | デバイスフローを使用してブラウザ経由で認証する | | `adapty auth logout` | ローカルに保存された認証情報を削除する | | `adapty auth whoami` | サーバーでトークンを検証してユーザー情報を表示する | | `adapty auth status` | サーバーへの問い合わせなしにローカルの認証状態を表示する | | `adapty auth revoke` | サーバー側でトークンを失効させ、ローカルからも削除する | 各コマンドの詳細については[認証](developer-cli-authentication)を参照してください。 --- # File: getting-started-with-server-side-api --- --- title: "サーバーサイド API" description: "サブスクリプション管理のための Adapty サーバーサイド API を使ってみましょう。" --- :::tip AI コーディングエージェントを使っていますか?[バックエンドからサブスクリプションアクセスを確認・付与する](server-side-api-with-ai)に、一つのページにまとめたエンドツーエンドのレシピがあります。 ::: この API を使うと、以下のことができます: 1. ユーザーのサブスクリプション状態を確認する。 2. アクセスレベルでユーザーのサブスクリプションを有効化する。 3. ユーザー属性を取得する。 4. ユーザー属性を設定する。 5. ペイウォール設定を取得・更新する。 <img src="/assets/shared/img/server.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note サブスクリプションイベントを追跡するには、Adapty の [Webhook](webhook) 連携を利用するか、既存のサービスと直接連携してください。 ::: ## ウェブとモバイル間でサブスクライバーを同期する場合 \{#case-1-sync-subscribers-between-web-and-mobile\} StripeやChargeBeeなどのWeb決済プロバイダーを使用している場合、サブスクリプションユーザーを簡単に同期できます。手順は以下のとおりです: 1. <InlineTooltip tooltip="各ユーザーに一意のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip> 2. APIを使用して[サブスクリプションのステータスを確認する](api-adapty/operations/getProfile)。 3. ユーザーがフリーミアムプランの場合、Webサイトにペイウォールを表示する。 4. 決済が完了したら、APIを通じてAdaptyの[サブスクリプションステータスを更新する](api-adapty/operations/setTransaction)。 5. サブスクリプションユーザーはモバイルアプリと自動的に同期されます。 ## Case 2: サブスクリプションを付与する \{#case-2-grant-a-subscription\} :::note セキュリティ上の理由から、SDK を使ってサブスクリプションを付与することはできません。 ::: Google Play や App Store 以外のプラットフォーム(独自のオンラインストア、Amazon Appstore、Microsoft Store など)で販売している場合は、アクセス権の付与とアナリティクスでのトランザクション追跡を行うために、それらのトランザクションを Adapty と同期する必要があります。 1. <InlineTooltip tooltip="各ユーザーに固有のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip> 2. [Adapty ダッシュボードでプロダクトのカスタムストアを設定する](custom-store)。 3. [Set transaction](api-adapty/operations/setTransaction) API リクエストを使用して、トランザクションを Adapty に同期する。 ## ケース3: アクセスレベルを付与する \{#case-3-grant-an-access-level\} 7日間の無料トライアルプロモーションを実施していて、プラットフォーム間で一貫したエクスペリエンスを提供したいとします。モバイルアプリと同期するには: 1. <InlineTooltip tooltip="各ユーザーに一意のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip>。 2. APIを使用して、7日間の[プレミアムアクセスを付与](api-adapty/operations/grantAccessLevel)します。 7日間が経過しても購読しないユーザーは、無料プランにダウングレードされます。 ## ケース4: ユーザーのプロパティとカスタム属性を同期する \{#case-4-sync-users-properties-and-custom-attributes\} 言語学習アプリで学習した単語数など、ユーザー独自のカスタム属性がある場合も同期できます。 1. <InlineTooltip tooltip="各ユーザーに一意のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip>。 2. APIまたはSDKで[属性を更新](api-adapty/operations/updateProfile)する。 これらのカスタム属性を使用して、セグメントを作成したり A/B テストを実行したりできます。 ## ケース5: ペイウォール設定を管理する \{#case-5-manage-paywall-configurations\} アプリを再デプロイすることなく、ペイウォールの外観や動作を動的に変更するために、[ペイウォールのリモートコンフィグを更新](api-adapty/operations/updatePaywall)できます。 --- **次のステップ:** - [サーバーサイド API の認証](ss-authorization)に進む - リクエスト: - [プロファイルを取得する](api-adapty/operations/getProfile) - [プロファイルを作成する](api-adapty/operations/createProfile) - [プロファイルを更新する](api-adapty/operations/updateProfile) - [プロファイルを削除する](api-adapty/operations/deleteProfile) - [アクセスレベルを付与する](api-adapty/operations/grantAccessLevel) - [アクセスレベルを取り消す](api-adapty/operations/revokeAccessLevel) - [トランザクションを設定する](api-adapty/operations/setTransaction) - [購入を検証し、顧客にアクセスレベルを付与し、トランザクション履歴をインポートする](api-adapty/operations/validateStripePurchase) - [インテグレーション識別子を追加する](api-adapty/operations/setIntegrationIdentifiers) - [ペイウォールを取得する](api-adapty/operations/getPaywall) - [ペイウォール一覧を取得する](api-adapty/operations/listPaywalls) - [ペイウォールを更新する](api-adapty/operations/updatePaywall) --- # File: ss-authorization --- --- title: "サーバーサイド API の認証とリクエスト形式" description: "" --- ## 認証 \{#authorization\} API リクエストは、シークレットキーまたはパブリック API キーを Authorization ヘッダーとして使用して認証する必要があります。これらのキーは [**App Settings**](https://app.adapty.io/settings/general) で確認できます。値の形式は `Api-Key {your-secret-api-key}` で、例えば `Api-Key secret_live_...` のようになります。 :::important API キーはアプリごとに固有です。複数のアプリを持っている場合は、それぞれに異なるキーを使用してください。 ::: ## リクエスト形式 \{#request-format\} **ヘッダー** サーバーサイド API リクエストには特定のヘッダーと JSON ボディが必要です。以下の詳細を参考にリクエストを構成してください。 | **ヘッダー** | **説明** | | --------------------------- | ------------------------------------------------------------ | | **adapty-profile-id** | <p>ユーザーの Adapty プロファイル ID。[Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> 特定のプロファイルページの **Adapty ID** フィールドで確認できます。</p><p>**adapty-customer-user-id** と互換性があり、どちらでも使用できます。</p> | | **adapty-customer-user-id** | <p>あなたのシステムにおけるユーザー ID。[Adapty Dashboard -> **Profiles**](https://app.adapty.io/profiles/users) -> 特定のプロファイルページの **Customer user ID** フィールドで確認できます。</p><p>**adapty-profile-id** と互換性があり、どちらでも使用できます。</p><p>⚠️ Adapty SDK を使用してアプリコード内で<InlineTooltip tooltip="アプリ内でユーザーを識別する">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip>している場合にのみ機能します。</p> | | **adapty-platform** | (任意)アプリがインストールされているデバイスのプラットフォームを指定します。[Installation Meta](server-side-api-objects#installation-meta) オブジェクトを変更する [Create profile](api-adapty/operations/createProfile) および [Update profile](api-adapty/operations/updateProfile) リクエストでは、このパラメータを設定することを推奨します。これはユーザーが使用しているデバイスに依存し、1 人のユーザーが複数のデバイスを持つ場合があるためです。指定できる値: `iOS`、`macOS`、`iPadOS`、`visionOS`、`Android`、`web`。 | | **Content-Type** | API がリクエストを処理するために `application/json` に設定してください。 | **ボディ** API はリクエストに必要なデータを含む JSON 形式のボディを想定しています。 ## レート制限 \{#rate-limits\} スロットリングを避けるために、(アプリごとの)リクエスト数を 1 分あたり 40,000 件以下に抑えてください。 この制限を超えると、すべてのユーザーに最適なパフォーマンスを維持するために、システムが低速化したり、リクエストが一時的にブロックされる場合があります。 ## API キーのローテーション \{#rotate-api-keys\} シークレット API キーをローテーションする必要がある場合: 1. **Settings → General** で **Generate new key** をクリックし、古いキーの横にあるゴミ箱アイコンをクリックします。 2. アプリで使用しているキーを更新します。 --- **次のステップ: リクエスト:** - [プロファイルの取得](api-adapty/operations/getProfile) - [プロファイルの作成](api-adapty/operations/createProfile) - [プロファイルの更新](api-adapty/operations/updateProfile) - [プロファイルの削除](api-adapty/operations/deleteProfile) - [アクセスレベルの付与](api-adapty/operations/grantAccessLevel) - [アクセスレベルの取り消し](api-adapty/operations/revokeAccessLevel) - [トランザクションの設定](api-adapty/operations/setTransaction) - [購入の検証、顧客へのアクセスレベルの付与、およびトランザクション履歴のインポート](api-adapty/operations/validateStripePurchase) - [ペイウォールの取得](api-adapty/operations/getPaywall) - [ペイウォール一覧の取得](api-adapty/operations/listPaywalls) - [ペイウォールの更新](api-adapty/operations/updatePaywall) --- # File: server-side-api-specs --- --- title: "サーバーサイドAPIリクエスト" description: "高度な統合のためのAdaptyのサーバーサイドAPI仕様を探索してください。" --- AdaptyのサーバーサイドAPIを使用すると、サブスクリプションデータにプログラムでアクセスして管理でき、既存のサービスやインフラとのシームレスな統合が可能です。プラットフォーム間のデータ同期、アクセスレベルの付与、Stripeでの購入検証など、システムを同期させてユーザーエンゲージメントを維持するためのツールを提供します。 ## Postmanコレクションと環境 \{#postman-collection-and-environment\} サーバーサイドAPIの利用を簡単にするため、PostmanにダウンロードしてインポートできるPostmanコレクションと環境ファイルを用意しました。 - **リクエストコレクション**: AdaptyサーバーサイドAPIで利用可能なすべてのリクエストが含まれています。環境で定義できる変数を使用していることに注意してください。 - **環境**: 値を一度定義できる変数のリストが含まれています。サーバーサイドAPI、Web API、アナリティクスエクスポートAPIに対応した統合環境を用意しており、作業を簡単に進められます。この環境をアクティブにすると、Postmanがリクエスト内の定義済み変数値を自動的に置換します。 :::tip [コレクションと環境をダウンロード](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/Adapty_server_side_API_postman_collection.zip) ::: PostmanへのコレクションおよびEnvironmentのインポート方法については、[Postmanドキュメント](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-data/)を参照してください。 ### 使用される変数 \{#variables-used\} サーバーサイドAPI、Web API、アナリティクスエクスポートAPIのワークフローを簡略化するため、統合環境を作成しました。以下はサーバーサイドAPI固有の変数です: | 変数 | 説明 | 値の例 | | ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | | secret_api_key | [**App settings**](https://app.adapty.io/settings/general)の **Secret key** フィールドで確認できます。 | `secret_live_Pj1P1xzM.2CvSvE1IalQRFjsWy6csBVNpH33atnod` | | adapty-customer-user-id | あなたのシステムで使用しているユーザーID。Adapty ダッシュボードでは、プロファイルの **Customer user ID** フィールドで確認できます。 | `john.doe@example.com` | | adapty-profile-id | Adaptyが割り当てたユーザーID。Adapty ダッシュボードでは、プロファイルの **Adapty ID** フィールドで確認できます。 | `3286abd3-48b0-4e9c-a5f6-ac0a006333a6` | | Adapty-platform | ユーザーがアプリに使用するプラットフォーム。使用可能な値: `iOS`, `macOS`, `iPadOS`, `visionOS`, `Android`, `web`。 | `iOS` | | stripe_token | サブスクリプション(`sub_XXX`)やPayment Intent(`pi_XXX`)などの一意の購入を表すStripeオブジェクトのトークン。 | `sub_1JY8xLLy6P12345a` | **次のステップ:リクエスト:** - [プロファイルの取得](api-adapty/operations/getProfile) - [プロファイルの作成](api-adapty/operations/createProfile) - [プロファイルの更新](api-adapty/operations/updateProfile) - [プロファイルの削除](api-adapty/operations/deleteProfile) - [アクセスレベルの付与](api-adapty/operations/grantAccessLevel) - [アクセスレベルの取り消し](api-adapty/operations/revokeAccessLevel) - [トランザクションの設定](api-adapty/operations/setTransaction) - [購入の検証、アクセスレベルの付与、トランザクション履歴のインポート](api-adapty/operations/validateStripePurchase) - [インテグレーション識別子の追加](api-adapty/operations/setIntegrationIdentifiers) - [ペイウォールの取得](api-adapty/operations/getPaywall) - [ペイウォールの一覧表示](api-adapty/operations/listPaywalls) - [ペイウォールの更新](api-adapty/operations/updatePaywall) - [仮想通貨トランザクションの作成](api-adapty/operations/createVirtualCurrencyTransaction) - [仮想通貨トランザクションの一覧表示](api-adapty/operations/listVirtualCurrencyTransactions) - [仮想通貨残高の一覧表示](api-adapty/operations/listVirtualCurrencyBalances) --- # File: api-guides --- --- title: "APIガイド" description: "サーバーサイドAPIを使って特定のタスクを実行する方法を学びましょう。" --- このセクションでは、さまざまなユースケースを網羅したガイドを紹介しています。サーバーサイドAPIとAdapty SDKを使って特定のタスクを実行するのに役立ちます。 <CustomDocCardList /> --- # File: sync-subscribers-from-web --- --- title: "WebとモバイルのサブスクリプションをSync Purchasesで同期する" description: "WebとモバイルのサブスクライバーをSync Purchasesで同期します。" --- ユーザーが**ウェブサイト**でプロダクトを購入できる場合、**モバイルアプリ**とのアクセスレベルを自動的に同期できます。 このガイドでは、Adapty の API と SDK を使ってその方法を説明します。 #### ユースケースの例 例えば、アプリでユーザーがモバイルとウェブの両方でフリーミアムプランにサインアップできるとします。ウェブサイト上で Stripe や Chargebee を使って Premium プランへのアップグレードを許可している場合、ユーザーがウェブでサブスクリプションを購入したら、再ログインや待機なしにモバイルアプリでも即座に Premium アクセスを利用できるようにしたいはずです。 それを Adapty で自動化できます。 ## ステップ 1. ユーザーを識別する \{#step-1-identify-users\} Adapty はプラットフォーム間でユーザーを識別するために `customer_user_id` を使用します。 この ID は一度だけ作成し、モバイル SDK とウェブバックエンドの両方に渡してください。 ### ウェブからのサインアップ \{#sign-up-from-web\} ユーザーがウェブサイトでサインアップした際、サーバーサイド API を使って Adapty にプロファイルを作成する必要があります。 メソッドのリファレンスは[こちら](api-adapty/operations/createProfile)をご覧ください。 ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/profile/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: YOUR_CUSTOMER_USER_ID' ``` ### アプリからのサインアップ \{#sign-up-from-app\} ユーザーがアプリから初めてサインアップする場合、SDK のアクティベーション時に customer user ID を渡すか、サインアップ前に Adapty SDK をアクティベートしている場合は `identify` メソッドを使って新しいプロファイルを作成し、customer user ID を割り当てます。 :::important SDK のアクティベーション後にユーザーを識別する場合、SDK はプロファイルなしでは動作できないため、まず匿名プロファイルが作成されます。その後、ユーザーを識別して新しい customer user ID を割り当てると、新しいプロファイルが作成されます。 この動作は完全に正常であり、分析の精度には影響しません。詳しくは[こちら](ios-quickstart-identify)をご覧ください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## ステップ 2. API でサブスクリプションのステータスを確認する \{#step-2-check-subscription-status-via-api\} ユーザーがウェブサイトにログインしたら、API を使って Adapty プロファイルを取得します。 アクティブなサブスクリプションがない場合は、ペイウォールを表示できます。 メソッドのリファレンスは[こちら](api-adapty/operations/getProfile)をご覧ください。 ```bash curl --request GET \ --url https://api.adapty.io/api/v2/server-side-api/profile/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'adapty-customer-user-id: YOUR_USER_ID' \ ``` ## ステップ 3. ウェブサイトにペイウォールを表示する \{#step-3-display-a-paywall-on-your-website\} フリーミアムユーザー向けにウェブサイトでペイウォールを表示します。 決済プロバイダーは任意のものが使用できます(Stripe、Chargebee、LemonSqueezy など)。 ## ステップ 4. Adapty のサブスクリプションステータスを更新する \{#step-4-update-subscription-status-in-adapty\} ウェブサイトでの支払いが完了したら、Adapty API を呼び出して、ユーザーが購入したプロダクトに応じてアクセスレベルを更新します。 メソッドのリファレンスは[こちら](api-adapty/operations/grantAccessLevel)をご覧ください。 ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: YOUR_USER_ID' \ --data '{ "access_level_id": "YOUR_ACCESS_LEVEL" }' ``` ## ステップ 5. アプリでステータスを同期する \{#step-5-sync-status-in-the-app\} ユーザーがモバイルアプリを開いたら、更新されたプロファイルを取得して有料機能を解放します。 プロファイルを手動で取得するか、自動で同期する必要があります。その後、プロファイルからアクセスレベルを取得します。 以下では、プロファイルを取得してそのステータスを確認する方法を示します。詳細は[こちら](ios-check-subscription-status)をご覧ください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // check the access if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL").getIsActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access if (profile.AccessLevels["YOUR_ACCESS_LEVEL"]?.IsActive ?? false) { // grant access to premium features } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> </Tabs> --- # File: sync-purchases-from-custom-stores --- --- title: "カスタムストアのトランザクションを同期する" description: "カスタムストアのトランザクションを Adapty に同期して、アクセス管理と収益追跡を行います。" --- Amazon Appstore、Microsoft Store、または独自の決済プラットフォームなど、**カスタムストア**でサブスクリプションやアプリ内課金を販売している場合、それらのトランザクションを Adapty に同期することで、アクセスレベルの自動管理と収益のアナリティクス追跡が可能になります。 このガイドでは、SDK と API を使ってカスタムストアの購入を Adapty に連携する方法を説明します。 #### ユースケースの例 Amazon Appstore でアプリを配信している場合や、直接購入用の独自 Web ストアを構築している場合を考えてみましょう。ユーザーがこれらのプラットフォームで購入を完了したとき、次のことを実現したいはずです。 - モバイルアプリのプレミアム機能へのアクセスを自動的に付与する - App Store や Google Play の収益と並べて、Adapty アナリティクスでトランザクションを追跡する - 他のサブスクリプションと同様に、インテグレーションやウェブフックをトリガーする この連携によってそれらが実現できます。 ## ステップ 1. ユーザーを識別する \{#step-1-identify-users\} Adapty はプラットフォーム横断でユーザーを識別するために `customer_user_id` を使用します。 この ID はあらかじめ作成し、モバイル SDK とバックエンドの両方に渡す必要があります。ユーザーがアプリから初めてサインアップする際に SDK の起動時にカスタマーユーザー ID を渡すか、サインアップ前に Adapty SDK を起動済みの場合は `identify` メソッドを使って新しいプロファイルを作成し、カスタマーユーザー ID を割り当ててください。 :::important SDK 起動後に新しいユーザーを識別する場合、SDK はまず匿名プロファイルを作成します(SDK はプロファイルなしでは動作できません)。カスタマーユーザー ID を指定して `identify` を呼び出すと、新しいプロファイルが作成されます。 この動作は正常であり、アナリティクスの精度に影響しません。詳しくは[こちら](ios-quickstart-identify)をご覧ください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## ステップ 2. Adapty ダッシュボードでカスタムストアのプロダクトを作成する \{#step-2-create-products-in-a-custom-store-in-adapty-dashboard\} Adapty がカスタムストアのトランザクションをプロダクトと照合できるよう、プロダクトを追加してカスタムストアの詳細を設定する必要があります。 1. Adapty ダッシュボードの左メニューから [**Products**](https://app.adapty.io/settings/general) に移動し、**Create product** をクリックします。または、既存のプロダクトをクリックして編集します。 2. ユーザーがプロダクトを購入した際に付与する[アクセスレベル](access-level)が選択されていることを確認します。 3. **+** をクリックして **Add a custom store** を選択します。 4. **Create new custom store** をクリックします。 5. ストアの名前(例:「Amazon Appstore」「Microsoft Store」「Web Store」)と ID を入力し、**Create custom store** をクリックします。 6. **Save changes** をクリックして、プロダクトをカスタムストアに紐付けます。 7. そのストア内のプロダクトと対応付けるために **Store product ID** を入力し、**Save** をクリックします。 ## ステップ 3. API 経由でトランザクションを同期する \{#step-3-sync-transactions-via-api\} カスタムストアで購入が完了したら、サーバーサイド API を使って Adapty にその情報を同期する必要があります。 この API 呼び出しによって以下が実行されます。 - Adapty にトランザクションを記録する - 対応するアクセスレベルをユーザーに付与する - 設定済みのインテグレーションやウェブフックをトリガーする - アナリティクスにトランザクションを表示する メソッドの完全なリファレンスは[こちら](api-adapty/operations/setTransaction)をご覧ください。 ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/purchase/set/transaction/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: YOUR_CUSTOMER_USER_ID' \ --data '{ "purchase_type": "PRODUCT_PERIOD", "store": "YOUR_CUSTOM_STORE", "environment": "production", "store_product_id": "YOUR_STORE_PRODUCT_ID", "store_transaction_id": "STORE_TRANSACTION_ID", "store_original_transaction_id": "ORIGINAL_TRANSACTION_ID", "price": { "country": "COUNTRY_CODE", "currency": "CURRENCY_CODE", "value": "YOUR_PRICE" }, "purchased_at": "2024-01-15T10:30:00Z" }' ``` :::important 重要なパラメーター: - **store**: ステップ 2 で設定したカスタムストアの ID - **store_product_id**: ステップ 2 で設定したストアプロダクト ID - **store_transaction_id**: このトランザクションの一意の識別子 - **purchased_at**: 購入が発生した ISO 8601 形式のタイムスタンプ - **price**: ユーザーが支払った金額 ::: ## ステップ 4. アプリでアクセスを確認する \{#step-4-verify-access-in-the-app\} トランザクションが同期されると、ユーザーのプロファイルに新しいアクセスレベルが自動的に反映されます。 ユーザーがモバイルアプリを開いたら、プロファイルを取得してサブスクリプションの状態を確認し、プレミアム機能のロックを解除します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // check the access if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL").getIsActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access if (profile.AccessLevels["YOUR_ACCESS_LEVEL"]?.IsActive ?? false) { // grant access to premium features } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // grant access to premium features } } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> </Tabs> --- # File: grant-access-level --- --- title: "アクセスレベルを手動で付与する" description: "特定のユーザーまたはユーザーグループに対して、有料機能を手動でアンロックする" --- 特定のユーザーやユーザーグループに対して**プレミアム機能を手動でアンロック**したい場合、Adapty API を使って行うことができます。プロモーションキャンペーン、投資家へのアクセス付与、カスタマーサポートの特別対応などに役立ちます。 このガイドでは、ユーザーを識別してプログラムからアクセスレベルを付与する方法を説明します。 #### 利用シナリオの例 - **プロモコード**: ユーザーがアプリ内で有効なプロモコードを入力した際に、プレミアム機能へのアクセスを自動的に付与する。 - **投資家・ベータテスター向けアクセス**: カスタム属性を確認して、投資家やベータテスターにプレミアムアクセスを提供する。 :::note **Google Play プロモコード**: Google Play のプロモコードを使用した購入は、`orderId` なしで届く場合があります。Adapty の買い切り購入(サブスクリプション以外)のバリデーションには `orderId` が必要なため、こうしたコード引き換えは自動的にバリデーション・付与されません。以下の手順で手動でアクセスを付与してください。Server-Side API は `orderId` に依存しません。 ::: ## ステップ 1. ユーザーを識別する \{#step-1-identify-users\} Adapty はプラットフォームやデバイスをまたいでユーザーを識別するために `customer_user_id` を使用します。これにより、アプリの再インストールやデバイス切り替え後もユーザーのアクセスを継続させることができます。 この ID は一度だけ作成します。ユーザーがアプリから初めてサインアップする際に、SDK アクティベーション時に customer user ID を渡すか、サインアップ前に SDK をアクティベートした場合は `identify` メソッドを使用します。 :::important SDK アクティベーション後に新規ユーザーを識別する場合、SDK はまず匿名プロファイルを作成します(SDK は必ずプロファイルが必要です)。その後 `identify` を customer user ID で呼び出すと、新しいプロファイルが作成されます。 この動作は正常であり、アナリティクスの精度には影響しません。詳細は[こちら](ios-quickstart-identify)をご覧ください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") { error -> // Unique for each user if (error == null) { // successful identify } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID", error -> { if (error == null) { // successful identify } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { await Adapty().identify(customerUserId); // Unique for each user } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## ステップ 2. API でアクセスレベルを付与する \{#step-2-grant-access-level-via-api\} ユーザーが `customer_user_id` で識別されたら、サーバーサイド API を使ってアクセスレベルを付与できます。この API 呼び出しにより、ユーザーは実際に購入することなく有料機能にアクセスできるようになります。 メソッドの完全なリファレンスは[こちら](api-adapty/operations/grantAccessLevel)をご覧ください。 :::tip Adapty ダッシュボードでカスタム属性(例:Beta tester や Investor)を追加することで、ユーザーアクセスを管理できます。 アプリ起動時に[ユーザープロファイルのこの属性を確認](subscription-status)してアクセスを自動的に付与します。 アクセスを更新するには、ダッシュボードで属性を変更するだけです。 ::: ```bash curl --request POST \ --url https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/ \ --header 'Accept: application/json' \ --header 'Authorization: Api-Key YOUR_SECRET_API_KEY' \ --header 'Content-Type: application/json' \ --header 'adapty-customer-user-id: CUSTOMER_USER_ID' \ --data '{ "access_level_id": "YOUR_ACCESS_LEVEL" }' ``` ## ステップ 3. アプリ内でアクセスを確認する \{#step-3-verify-access-in-the-app\} API でアクセスを付与すると、ユーザーのプロファイルは自動的に更新されます。プロファイルを取得してサブスクリプションの状態を確認し、プレミアム機能をアンロックしてください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access if profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> <TabItem value="android" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive == true) { // grant access to premium features } } is AdaptyResult.Error -> { val error = result.error // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // check the access if (profile.getAccessLevels().get("YOUR_ACCESS_LEVEL_ID") != null && profile.getAccessLevels().get("YOUR_ACCESS_LEVEL_ID").getIsActive()) { // grant access to premium features } } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // handle the error } }); ``` </TabItem> <TabItem value="react-native" label="React Native" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```dart showLineNumbers try { final profile = await Adapty().getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive ?? false) { // grant access to premium features } } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access if (profile.AccessLevels["YOUR_ACCESS_LEVEL_ID"]?.IsActive ?? false) { // grant access to premium features } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform" default> ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive == true) { // grant access to premium features } } .onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor" default> ```typescript showLineNumbers try { const profile = await adapty.getProfile(); // check the access if (profile.accessLevels["YOUR_ACCESS_LEVEL_ID"]?.isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` </TabItem> </Tabs> --- # File: web-api --- --- title: Adapty Web API description: "" --- Web APIは、Webアプリで使用するためのサーバーサイドAPIの拡張機能です。関連するプレースメントIDを使用して正しいペイウォールを取得し、正確なコンバージョン追跡のためのペイウォール表示を記録できます。これにより、Adaptyで利用可能なA/Bテストとペイウォールのパーソナライゼーションを活用し、どのペイウォールが最も効果的かを追跡できます。 ## ユースケース:Webアプリからトランザクションを記録し、使用したペイウォールに紐付ける \{#use-case-record-a-transaction-from-your-web-app-and-link-it-to-the-used-paywall\} Webアプリでプロダクトを販売しているとしましょう。ユーザーにペイウォールを表示し、プロダクトを購入してもらい、その後トランザクションの詳細をAdaptyに追加する必要があります。アナリティクスが正確なデータを反映できるよう、これらのトランザクションをユーザーが購入した特定のペイウォールに紐付けることが重要です。これはAdapty APIを使って簡単に実現できます。 ### 前提条件 \{#prerequisites\} 1. Adapty ダッシュボードで、ペイウォールで使用する[プロダクトを作成](create-product)します。 2. Adapty ダッシュボードで[ペイウォールを作成](create-paywall)します。[リモートコンフィグを使用](customize-paywall-with-remote-config)して、WebペイウォールのデザインをカスタマイズしてURL。 3. Adapty ダッシュボードで[プレースメントを設定](create-placement)し、ペイウォールを紐付けます。 ### Adapty APIを使った手順 \{#steps-with-adapty-api\} 1. **ユーザープロファイルの作成:** Adaptyはペイウォールをリクエストする前にプロファイルを必要とし、リクエストしたユーザーに合わせて結果をパーソナライズします。[プロファイルの作成](api-adapty/operations/createProfile)リクエストを使用してユーザープロファイルを作成してください。 2. **ペイウォールの取得と表示:** ユーザーがWebアプリ内のペイウォールを表示すべきプレースメントに到達したら、[ペイウォールを取得](api-web/operations/getPaywall)リクエストを使用して[プレースメントID](placements)経由でペイウォールを取得します。結果として、ユーザーに対応する[オーディエンス](audience)のペイウォールが返されます。返されたプロダクトと(任意で)このペイウォールの[リモートコンフィグ](customize-paywall-with-remote-config)を使って、自分のコードでペイウォールを表示します。 3. **ペイウォール表示の記録:** [ペイウォール表示の記録](api-web/operations/recordPaywallView)を使用して、アナリティクスがイベントを正確に反映できるよう、ペイウォールの表示をAdaptyに記録します。これはコンバージョンを正しく追跡するために不可欠です。 4. **購入の記録:** ユーザーが購入を完了した場合、Adapty APIを使用してトランザクションの詳細をAdaptyに送信します。表示された特定のペイウォールにトランザクションを紐付けるために、このリクエストに**バリエーションID**を含めてください。詳細については、[モバイルアプリでのペイウォールとトランザクションの関連付け](report-transactions-observer-mode)のページを参照してください—同じアプローチがWebアプリにも適用されます。 5. **マーケティングアトリビューションデータの追加(該当する場合):** マーケティングアトリビューションデータ(キャンペーンや広告の詳細など)がある場合は、[アトリビューションの追加](api-web/operations/addAttribution)を使用してユーザープロファイルにマージし、アナリティクスを充実させ、Adaptyでの広告効果をより深く把握できます。 --- **次のステップ:** - [Web API認証](web-api-authorization)に進む - リクエスト: - [アトリビューションの追加](api-web/operations/addAttribution) - [ペイウォールの取得](api-web/operations/getPaywall) - [ペイウォール表示の記録](api-web/operations/recordPaywallView) --- # File: web-api-authorization --- --- title: Authorization and Request format for Web API description: "" --- ## 認証 \{#authorization\} APIリクエストは、公開APIキーを使って認証する必要があります。**Authorization** ヘッダーに `Api-Key {your_public_api_key}` という形式で値を設定してください(例: `Api-Key public_live_...`)。このキーは [Adapty Dashboard -> **App Settings** -> **General** タブ -> **API keys** セクション](https://app.adapty.io/settings/general) で確認できます。 :::important APIキーはアプリごとに固有です。複数のアプリを運用している場合は、それぞれ異なるキーを使用してください。 ::: ## リクエスト形式 \{#request-format\} - **Content-Type ヘッダー**: APIがリクエストを正しく処理できるよう、**Content-Type** ヘッダーを `application/json` に設定してください。 - **ボディ**: APIはリクエストボディをJSON形式で受け付けます。 --- # File: web-api-requests --- --- title: " Web API リクエスト" description: "" --- Adapty のサーバーサイド API を使うと、サブスクリプションデータにプログラムからアクセスして管理できます。既存のサービスやインフラとシームレスに統合し、プラットフォーム間のデータ同期、アクセスレベルの付与、Stripe での購入検証などをまとめて行えます。 ## Postman コレクションと環境 \{#postman-collection-and-environment\} Web API を手軽に使えるよう、Postman にインポートして使える Postman コレクションと環境ファイルを用意しました。 - **リクエストコレクション**: Adapty Web API で使用できるすべてのリクエストが含まれています。環境で定義できる変数を使用しています。 - **環境**: 変数の一覧が含まれており、値を一度設定するだけで使いまわせます。サーバーサイド API・Web API・アナリティクスエクスポート API を統合した環境を用意しているので、設定の手間を省けます。この環境をアクティブにすると、Postman がリクエスト内の変数値を自動的に置き換えます。 :::tip [コレクションと環境をダウンロード](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/Adapty_Web_API_postman_collection.zip) ::: Postman へのコレクションと環境のインポート方法については、[Postman ドキュメント](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-data/)を参照してください。 ## 使用する変数 \{#variables-used\} サーバーサイド API・Web API・アナリティクスエクスポート API を統合した環境を用意し、ワークフローを簡略化しています。Web API に固有の変数は以下のとおりです。 | 変数 | 説明 | 値の例 | | ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | | public_api_key | [**App settings**](https://app.adapty.io/settings/general) の **Public SDK key** フィールドで確認できます。 | `public_live_Pj1P1xzM.2CvSvE1IalQRFjsWy6csBVNpH33atnod` | | adapty-customer-user-id | お使いのシステムで使用するユーザー ID です。Adapty ダッシュボードでは、プロファイルの **Customer user ID** フィールドで確認できます。 | `john.doe@example.com` | | adapty-profile-id | Adapty が割り当てるユーザー ID です。Adapty ダッシュボードでは、プロファイルの **Adapty ID** フィールドで確認できます。 | `3286abd3-48b0-4e9c-a5f6-ac0a006333a6` | **次のステップ: リクエスト:** - [ペイウォールを取得する](api-web/operations/getPaywall) - [ペイウォール表示を記録する](api-web/operations/recordPaywallView) - [アトリビューションを追加する](api-web/operations/addAttribution) --- # File: export-analytics-api --- --- title: APIによるアナリティクスのエクスポート --- アナリティクスデータをCSVにエクスポートすることで、アプリのパフォーマンス指標をより深く分析し、レポートをカスタマイズして、時系列でのトレンドを把握できます。Adapty APIを使えば、詳細なアナリティクスデータを簡単にCSV形式で取得でき、データインサイトの追跡・共有・改善がスムーズに行えます。 :::tip AIエージェントやLLMでアナリティクスを取得したい場合は、[AIエージェントでアナリティクスをエクスポートする](export-analytics-with-ai)をご覧ください。 ::: ## アナリティクスエクスポート用APIをはじめる \{#getting-started-with-the-api-for-analytics-export\} アナリティクスエクスポートAPIでできることの例を紹介します。 1. **マーケティングキャンペーンのMRR分析**: 昨年のマーケティングキャンペーンが特定の国にどのような影響を与えたかを週次で測定し、最も高い収益をもたらしたキャンペーンを特定します。[アナリティクスデータの取得](api-export-analytics/operations/retrieveAnalyticsData)メソッドを使用してください。 2. **コホート別のリテンション追跡**: コホートごとにリテンションを追跡してドロップオフポイントを把握し、コホート間の比較を通じてトレンドやエンゲージメント施策が効果を発揮しやすいタイミングを明らかにします。特定のアプリストア・国・プロダクトに絞った分析が可能です。[コホートデータの取得](api-export-analytics/operations/retrieveCohortData)メソッドを使用してください。 3. **チャネル別のコンバージョン率評価**: 主要な獲得チャネルのコンバージョン率を分析し、初回購入を最も効果的に促進しているチャネルを特定します。これにより、パフォーマンスの高いチャネルへのマーケティング投資を優先できます。[コンバージョンデータの取得](api-export-analytics/operations/retrieveConversionData)メソッドを使用してください。 4. **チャーン率の確認**: ユーザーの解約ペースを監視してチャーンのパターンを把握したり、リテンション施策の効果を測定したりします。特定の国・プロダクトに絞った分析が可能です。[ファネルデータの取得](api-export-analytics/operations/retrieveFunnelData)メソッドを使用してください。 5. **ユーザーセグメント別のLTV評価**: 異なるユーザーセグメントのライフタイムバリューを特定し、どのグループが長期的に最も高い収益をもたらすかを把握します。長期サブスクライバーなど価値の高いセグメントに焦点を当て、その結果を獲得戦略の改善に活用してください。[LTVデータの取得](api-export-analytics/operations/retrieveLTVData)メソッドを使用してください。 6. **国別のリテンション確認**: 地域別のリテンション率を分析してエンゲージメントの高い市場を見つけ、ローカライズや地域戦略の指針にします。[リテンションデータの取得](api-export-analytics/operations/retrieveRetentionData)メソッドを使用してください。 --- **次のステップ**: - [認証とリクエスト形式](export-analytics-api-authorization) - [アナリティクスエクスポートのAPIリクエスト](export-analytics-api-requests) --- # File: export-analytics-api-authorization --- --- title: エクスポートアナリティクス API の認証とリクエスト形式 --- ## 認証 \{#authorization\} API リクエストの認証には、シークレット API キーを Authorization ヘッダーとして使用します。キーは [App Settings](https://app.adapty.io/settings/general) で確認できます。形式は `Api-Key {YOUR_SECRET_API_KEY}` で、例として `Api-Key secret_live_...` のように指定します。 :::important API キーはアプリごとに固有です。複数のアプリをお持ちの場合は、それぞれ異なるキーを使用してください。 ::: ## リクエスト形式 \{#request-format\} **ヘッダー** サーバーサイド API リクエストには、特定のヘッダーと JSON ボディが必要です。以下の内容を参考にリクエストを構成してください。 | ヘッダー | 説明 | | ------------ | ------------------------------------------------------------ | | Content-Type | (必須)API がリクエストを処理するために `application/json` を指定します。 | | Adapty-Tz | (任意)データのグループ化と表示に使用するタイムゾーンを設定します。[IANA タイムゾーンデータベース形式](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)(例: `Europe/Berlin`)を使用してください。 | ## ボディ \{#body\} API はリクエストに必要なデータを含む JSON 形式のボディを受け取ります。 ## レート制限 \{#rate-limits\} API キーごとに 1 秒あたり最大 2 リクエストまで送信できます。この制限を超えると `429 Too Many Requests` エラーが返されます。 ## API キーのローテーション \{#rotate-api-keys\} シークレット API キーをローテーションする必要がある場合は、以下の手順に従ってください。 1. **Settings → General** で **Generate new key** をクリックし、古いキーの横にあるゴミ箱アイコンをクリックします。 2. アプリで使用しているキーを更新します。 --- **次のステップ:リクエスト:** - [アナリティクスデータの取得](api-export-analytics/operations/retrieveAnalyticsData) - [コホートデータの取得](api-export-analytics/operations/retrieveCohortData) - [コンバージョンデータの取得](api-export-analytics/operations/retrieveConversionData) - [ファネルデータの取得](api-export-analytics/operations/retrieveFunnelData) - [LTV(ライフタイムバリュー)データの取得](api-export-analytics/operations/retrieveLTVData) - [リテンションデータの取得](api-export-analytics/operations/retrieveRetentionData) --- # File: export-analytics-api-requests --- --- title: アナリティクスAPIリクエストのエクスポート --- アナリティクスデータをCSV形式でエクスポートすると、アプリのパフォーマンス指標をより深く分析したり、レポートをカスタマイズしたり、時系列のトレンドを把握したりできます。Adapty APIを使えば、詳細なアナリティクスデータを簡単にCSV形式で取得でき、データインサイトの追跡・共有・改善が手軽に行えます。 ## Postmanコレクションと環境 \{#postman-collection-and-environment\} アナリティクスデータのエクスポートAPIを使いやすくするため、PostmanにインポートできるPostmanコレクションと環境ファイルを用意しました。 - **リクエストコレクション**: AdaptyアナリティクスエクスポートAPIで利用可能なすべてのリクエストを含みます。環境で定義できる変数を使用しています。 - **環境**: 変数の一覧を含んでおり、値を一度定義するだけで使い回せます。サーバーサイドAPI、Web API、アナリティクスエクスポートAPIを統合した環境を用意しており、この環境をアクティブにするとPostmanがリクエスト内の変数値を自動的に置換します。 :::tip [コレクションと環境をダウンロード](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/Adapty_export_analytics_API_postman_collection.zip) ::: PostmanへのコレクションおよびEnvironmentのインポート方法については、[Postmanドキュメント](https://learning.postman.com/docs/getting-started/importing-and-exporting/importing-data/)を参照してください。 ### 使用する変数 \{#variables-used\} サーバーサイドAPI、Web API、アナリティクスエクスポートAPIのワークフローを簡略化するため、統合環境を作成しました。以下はアナリティクスエクスポートAPIに固有の変数です: | 変数 | 説明 | 値の例 | | ----------------------- | ------------------------------------------------------------ | --------------------------------------------------------- | | secret_api_key | [**App settings**](https://app.adapty.io/settings/general) の **Secret key** フィールドで確認できます。 | `secret_live_Pj1P1xzM.2CvSvE1IalQRFjsWy6csBVNpH33atnod` | **リクエスト:** - [アナリティクスデータの取得](api-export-analytics/operations/retrieveAnalyticsData) - [コホートデータの取得](api-export-analytics/operations/retrieveCohortData) - [コンバージョンデータの取得](api-export-analytics/operations/retrieveConversionData) - [ファネルデータの取得](api-export-analytics/operations/retrieveFunnelData) - [LTV(ライフタイムバリュー)データの取得](api-export-analytics/operations/retrieveLTVData) - [リテンションデータの取得](api-export-analytics/operations/retrieveRetentionData) --- # End of Documentation _Generated on: 2026-07-24T13:00:57.616Z_ _Successfully processed: 17/18 files_ # CAPACITOR - 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.617Z Total files: 45 --- # File: capacitor-sdk-overview --- --- title: "Capacitor SDK overview" description: "Adapty Capacitor SDK とその主要機能についてご紹介します。" --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Capacitor.svg?style=flat&logo=capacitor)](https://github.com/adaptyteam/AdaptySDK-Capacitor/releases) ようこそ!アプリ内課金をもっと簡単にするお手伝いをします 🚀 [Adapty Capacitor SDK](https://github.com/adaptyteam/AdaptySDK-Capacitor/) は、アプリ内課金の手間を省き、あなたが本当にやりたいこと——素晴らしいアプリを作ること——に集中できるように設計しました。以下の処理をすべて代わりに行います: - 購入処理、レシート検証、サブスクリプション管理をすぐに使える状態で提供 - アップデートなしでペイウォールの作成・テストが可能 - ゼロセットアップで詳細な購入分析——コホート、LTV、チャーン、ファネル分析を含む - アプリセッションやデバイスをまたいでユーザーのサブスクリプション状態を常に最新に保つ - たった1行のコードでマーケティングのアトリビューションや分析サービスと連携 :::note コードに入る前に、App Store Connect および Google Play Console と Adapty を連携し、ダッシュボードでプロダクトを設定する必要があります。まず[クイックスタートガイド](quickstart)ですべての設定を完了させてください。 ::: ## はじめに \{#get-started\} 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. インテグレーションガイドでカバーする内容は次のとおりです: 1. [SDK のインストールと設定](sdk-installation-capacitor):SDKを[依存関係](https://www.npmjs.com/package/@adapty/capacitor)としてプロジェクトに追加し、コードで有効化します。 2. [ペイウォールを通じた購入の有効化](capacitor-quickstart-paywalls):ユーザーがプロダクトを購入できるよう購入フローを設定します。 3. [サブスクリプション状態の確認](capacitor-check-subscription-status):ユーザーのサブスクリプション状態を自動的にチェックし、有料コンテンツへのアクセスを制御します。 4. [ユーザーの識別(オプション)](capacitor-quickstart-identify):ユーザーを Adapty プロファイルに紐づけ、デバイスをまたいでデータを一貫して管理します。 ### 実際の動作を確認する \{#see-it-in-action\} 全体の仕組みを確認したいですか?サンプルをご用意しています: **サンプルアプリ**:完全なセットアップを示すサンプルをご覧ください: - [React](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-react-example) - [Vue.js](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-vue-example) - [Angular](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-angular-example) - [高度な開発ツール](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/adapty-devtools) ## 主要コンセプト \{#main-concepts\} コードに入る前に、Adapty の仕組みを支える主要なコンセプトを把握しておきましょう。 Adapty のアプローチの優れた点は、プレースメントだけがアプリにハードコードされるという点です。それ以外のすべて——プロダクト、ペイウォールのデザイン、価格、オファー——は、アプリをアップデートせずに Adapty ダッシュボードから柔軟に管理できます: 1. **プロダクト** - アプリ内で購入可能なもの全て——サブスクリプション、消耗型アイテム、永続アクセスなど。 2. **フローまたはペイウォール** - プレースメントに紐づけられた設定付きのプロダクトの束。2種類あります: - **[フロー](adapty-flow-builder)** - フロービルダーで構築されたビジュアルなノーコードインターフェース。Adapty が UI をレンダリングし、購入処理を行います。 - **[ペイウォール](paywalls)** - ビジュアル設定なし。独自コードで UI を構築し、自分で `makePurchase` を呼び出します。[ペイウォールを手動で実装する](capacitor-quickstart-manual)を参照してください。 SDK コードでは、どちらも同じ `getFlow` メソッドで取得します。 3. **プレースメント** - ペイウォールを表示したいユーザージャーニー上の戦略的なポイント。プレースメントはマネタイズ戦略の「どこで」「いつ」を定義します。主なプレースメントの例: - `main` - メインのペイウォール表示場所 - `onboarding` - ユーザーのオンボーディングフロー中に表示 - `settings` - アプリの設定画面からアクセス可能 最初のインテグレーションでは `main` や `onboarding` のような基本的なものから始め、その後アプリ内で購入意欲が高まりそな他の場所を検討しましょう。 4. **プロファイル** - ユーザーがプロダクトを購入すると、そのプロファイルに**アクセスレベル**が付与され、有料機能へのアクセス制御に使用します。 --- # File: sdk-installation-capacitor --- --- title: "Capacitor - Adapty SDK のインストールと設定" description: "サブスクリプション型アプリ向けに Capacitor へ Adapty SDK をインストールするためのステップバイステップガイド。" --- Adapty SDK には、Capacitor アプリへのシームレスな統合のために 2 つの主要モジュールが含まれています: - **Core Adapty**: アプリで Adapty を正しく動作させるために必要なモジュールです。 - **AdaptyUI**: [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合に必要なモジュールです。ペイウォールビルダーは、クロスプラットフォームのペイウォールを簡単に作成できるノーコードツールです。AdaptyUI はコアモジュールと同時に自動的に有効化されます。 :::tip Adapty SDKがモバイルアプリにどのように統合されるか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示す[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples)をご覧ください。 ::: ## 要件 \{#requirements\} [Adapty Capacitor SDK](https://github.com/adaptyteam/AdaptySDK-Capacitor/) には以下のバージョン要件があります: | Adapty SDK バージョン | Capacitor バージョン | iOS バージョン | |--------------------|-------------------|-------------| | 3.16.0+ | 8 | 15.0+ | | 3.15 | 7 | 14.0+ | Capacitor バージョン 6 以下はサポートされていません。 Adapty SDK v4(ベータ版)を iOS 向けにビルドするには、**Xcode 26** 以降が必要です。使用しているネイティブ iOS SDK は Swift tools 6.2 でビルドされています。iOS 15.0+、Capacitor 8、Android の minSdk 24 の要件は SDK 3.16+ と同じです。 :::info SDK v3.17 以降、Adapty SDK はデフォルトで Google Play Billing Library v8.0.0 を使用します。 ::: :::info SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ::: ## Adapty SDK のインストール \{#install-adapty-sdk\} :::important 以下の手順では Adapty SDK 3.x をインストールします。SDK v4(ベータ版)— [フローBuilder](adapty-flow-builder) に必要で、[クイックスタート](capacitor-quickstart-paywalls) でも使用されます — はインストール方法が異なります。下記の [Adapty SDK 4.0 (beta)](#adapty-sdk-40-beta) を参照するか、[移行ガイド](migration-to-capacitor-sdk-v4) をご確認ください。 ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-Capacitor.svg?style=flat&logo=capacitor)](https://github.com/adaptyteam/AdaptySDK-Capacitor/releases) Adapty SDK をインストールします: ```sh npm install @adapty/capacitor npx cap sync ``` ### Adapty SDK 4.0 (ベータ版) \{#adapty-sdk-40-beta\} Capacitor SDK 4.0 — [フロービルダー](adapty-flow-builder)のサポートを追加 — はプレリリース版です。正確なバージョンを指定してインストールしてください(npm はキャレット/チルダの範囲指定ではプレリリース版を解決しません)。その後、sync を実行します: ```sh npm install @adapty/capacitor@4.0.0-beta.2 ``` ```sh npx cap sync ``` iOS では、v4 はネイティブの Adapty SDK を **Swift Package Manager のみ**経由で取得します — CocoaPods の podspec は削除されました([CocoaPods のスペックリポジトリは2026年12月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/))。アプリの iOS プロジェクトでは、Capacitor の SPM インテグレーションを使用する必要があります: - 新しいアプリの場合、SPM パッケージマネージャーで iOS プラットフォームを追加します: ```sh npx cap add ios --packagemanager SPM ``` - 既存のアプリの場合、[Capacitor の既存プロジェクトへの SPM 導入ガイド](https://capacitorjs.com/docs/ios/spm#using-spm-in-an-existing-capacitor-project)に従って、iOS プロジェクトを CocoaPods から SPM に移行してください。 v4 での API 変更の全一覧については、[Adapty Capacitor SDK の v4 への移行](migration-to-capacitor-sdk-v4)を参照してください。 ## Adapty SDK の Adapty モジュールを有効化する \{#activate-adapty-module-of-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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 以下のコードをアプリの任意のファイルにコピーして、Adapty を有効化してください: ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { // verbose logging is recommended for the development purposes and for the first production release logLevel: 'verbose', // in the development environment, use this variable to avoid multiple activation errors. Set it to your development environment variable __ignoreActivationOnFastRefresh: true, } }); console.log('Adapty activated successfully!'); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` :::important `activate` の完了を待ってから、他の Adapty SDK メソッドを呼び出してください。完全な順序については、[Capacitor SDK の呼び出し順序](capacitor-sdk-call-order)を参照してください。 ::: :::tip 開発環境でのアクティベーションエラーを避けるには、[ヒント](#development-environment-tips)を参照してください。 ::: 次に、アプリにペイウォールを設定します: - [ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、[ペイウォールビルダークイックスタート](capacitor-quickstart-paywalls)に従ってください。 - 独自のペイウォール UI を構築する場合は、[カスタムペイウォールのクイックスタート](capacitor-quickstart-manual)を参照してください。 ## AdaptyUI モジュールを有効化する \{#activate-adaptui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する予定がある場合は、AdaptyUI モジュールが必要です。コアモジュールを有効化すると自動的に設定されるため、追加の作業は不要です。 ## オプション設定 \{#optional-setup\} ### ログ \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty はエラーやその他の重要な情報をログに記録し、何が起きているかを把握できるようにします。以下のログレベルが利用可能です。 | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | エラーのみがログに記録されます | | `warn` | エラーと、致命的なエラーにはならないが注意が必要なSDKからのメッセージがログに記録されます | | `info` | エラー、警告、および各種情報メッセージがログに記録されます | | `verbose` | 関数呼び出し、APIクエリなど、デバッグ時に役立つ追加情報がログに記録されます | Adapty の設定前または設定中にアプリのログレベルを設定できます。 ```typescript showLineNumbers // Set log level before activation adapty.setLogLevel({ logLevel: 'verbose' }); // Or set it during configuration await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { logLevel: 'verbose', } }); ``` ### データポリシー \{#data-policies\} Adaptyはユーザーの個人データを明示的に送信しない限り保存しませんが、ストアや国のガイドラインに準拠するために追加のデータセキュリティポリシーを設定することもできます。 #### IPアドレスの収集と共有を無効にする \{#disable-ip-address-collection-and-sharing\} Adaptyモジュールを有効化する際、`ipAddressCollectionDisabled` を `true` に設定すると、ユーザーのIPアドレスの収集と共有を無効にできます。デフォルト値は `false` です。 このパラメーターを使用すると、ユーザーのプライバシーを強化したり、地域のデータ保護規制(GDPRやCCPAなど)に準拠したり、アプリでIPベースの機能が不要な場合に不必要なデータ収集を減らしたりできます。 ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { ipAddressCollectionDisabled: true, } }); ``` #### 広告IDの収集と共有を無効にする \{#disable-advertising-id-collection-and-sharing\} Adaptyモジュールを有効化する際に、広告識別子の収集を無効にするには、`ios.idfaCollectionDisabled`(iOS)または`android.adIdCollectionDisabled`(Android)を`true`に設定してください。デフォルト値は`false`です。 このパラメータは、App Store / Play Storeのポリシーに準拠する場合、App Tracking Transparencyのプロンプトを表示したくない場合、または広告IDを使用したアトリビューションやアナリティクスが不要な場合にご利用ください。 ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, } }); ``` #### AdaptyUI のメディアキャッシュを設定する \{#set-up-media-cache-configuration-for-adaptyui\} デフォルトでは、AdaptyUI はパフォーマンスの向上とネットワーク使用量の削減のために、画像や動画などのメディアをキャッシュします。カスタム設定を指定することで、キャッシュの設定をカスタマイズできます。 デフォルトのキャッシュ設定を上書きするには、`mediaCache` を使用してください: ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, } }); ``` | パラメーター | 必須 | 説明 | |-----------|----------|-------------| | memoryStorageTotalCostLimit | 任意 | メモリ上のキャッシュサイズ(バイト単位)。デフォルト値はプラットフォームによって異なります。 | | memoryStorageCountLimit | 任意 | メモリストレージのアイテム数の上限。デフォルト値はプラットフォームによって異なります。 | | diskStorageSizeLimit | 任意 | ディスク上のファイルサイズの上限(バイト単位)。デフォルト値はプラットフォームによって異なります。 | ### ローカルアクセスレベルを有効にする(Android) \{#enable-local-access-levels-android\} デフォルトでは、[ローカルアクセスレベル](local-access-levels)は iOS では有効、Android では無効になっています。Android でも有効にするには、`localAccessLevelAllowed` を `true` に設定してください。 ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { android: { localAccessLevelAllowed: true, }, } }); ``` ### バックアップ復元時にデータを削除する \{#clear-data-on-backup-restore\} `clearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検知し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールなど、ローカルに保存されているすべてのSDKデータを削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { ios: { clearDataOnBackup: true, }, } }); ``` ## 開発環境のヒント \{#development-environment-tips\} #### Capacitorのライブリロードでのアクティベーションエラーのトラブルシューティング \{#troubleshoot-sdk-activation-errors-on-capacitors-live-reload\} CapacitorでAdapty SDKを開発中に、`Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` というエラーが発生することがあります。 これはCapacitorのライブリロード機能が開発中に複数回アクティベーションを呼び出すことが原因です。これを防ぐには、`__ignoreActivationOnFastRefresh` オプションにCapacitorの開発モードフラグを設定してください。使用しているバンドルによって異なります。 ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { // Set your development environment variable __ignoreActivationOnFastRefresh: true, } }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` ## トラブルシューティング \{#troubleshooting\} #### iOSの最低バージョンエラー \{#minimum-ios-version-error\} :::note これはCocoaPodsベースのプロジェクトで**SDK 3.x**を使用している場合に適用されます。SDK 4.0はSwift Package Manager経由でのみインストールされ(`Podfile`は不要)、iOS 15.0が必要です。Xcodeのデプロイメントターゲットを15.0に設定してください。 ::: SDK 3.xで最低iOSバージョンエラーが発生した場合は、Podfileを更新してください: ```diff -platform :ios, min_ios_version_supported +platform :ios, '15.0' ``` #### 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` ファイルのルートの `<manifest>` タグに tools が含まれていることを確認してください: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. `<application>` でバックアップ属性を上書きする \{#2-override-backup-attributes-in-application\} 同じ `AndroidManifest.xml` ファイルで、`<application>` タグを更新して、アプリが最終的な値を提供し、マニフェストマージャーにライブラリの値を置き換えるよう指示します: ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` いずれかの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" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Android 11以前**(従来のフルバックアップコンテンツ形式を使用): ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> :::tip ネイティブの Android ファイルを変更した後、プラットフォームを再生成する場合は `npx cap sync android` を実行して、Capacitor が更新されたリソースを取り込むようにしてください。 ::: #### 別のアプリから戻った後に Android で購入が失敗する \{#purchases-fail-after-returning-from-another-app-in-android\} 購入フローを開始する Activity が非デフォルトの `launchMode` を使用している場合、ユーザーが Google Play、銀行アプリ、またはブラウザから戻ったときに Android がその Activity を誤って再作成または再利用することがあります。これにより、購入結果が失われたり、キャンセルとして扱われたりする可能性があります。 購入フローを正しく動作させるには、購入フローを開始する Activity に `standard` または `singleTop` のみのランチモードを使用し、それ以外のモードは避けてください。 `AndroidManifest.xml` で、購入フローを開始する Activity が `standard` または `singleTop` に設定されていることを確認してください。 ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### Podfile の SWIFT_VERSION オーバーライドによる Swift 6 ビルドエラー \{#swift-6-build-errors-caused-by-podfile-swift_version-override\} :::note これは **SDK 3.x** の CocoaPods ベースのプロジェクトに適用されます。SDK 4.0 はネイティブ SDK を Swift Package Manager 経由でインストールするため、調整が必要な `Podfile` は存在しません。 ::: Capacitor アプリを iOS 向けにビルドする際、Adapty の pod ターゲットで Swift 6 のコンパイルエラーが発生することがあります。よくある症状としては、`AdaptyUIBuilderLogic` での `@Sendable` の不一致、Adapty 型への `Sendable` 準拠の欠如、またはアクター分離エラーなどが挙げられます。 Adapty の Pod は `s.swift_version = '6.0'` を宣言しており、ビルドに Swift 6 が必要です。アプリ本体のコードは Swift 5 のままで構いません。Swift 6 でビルドが必要なのは、Adapty の Pod ターゲット(`Adapty`、`AdaptyUI`、`AdaptyUIBuilder`、`AdaptyLogger`、`AdaptyPlugin`)のみです。 最もよくある原因は、`ios/App/Podfile` 内の `post_install` フックがすべての Pod ターゲットの `SWIFT_VERSION` を書き換えてしまっていることです。 ```ruby showLineNumbers title="ios/App/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/App/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 ``` 次に `npx cap sync ios` を実行してリビルドしてください。 確認するには、`ios/App/Pods/Pods.xcodeproj` を開き、`Adapty` pod ターゲットを選択して **Build Settings** → **Swift Language Version** を確認します。**Swift 6** になっているはずです。 --- # File: capacitor-quickstart-paywalls --- --- title: "Capacitor SDKでフローを使ってアプリ内課金を有効にする" description: "Adapty フローを使ってアプリ内課金を有効にするためのクイックスタートガイド。" --- アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**フロー**](adapty-flow-builder) – ノーコードのフロービルダーで作成した、ユーザーにプロダクトを提示する画面シーケンス。SDKは`getFlow`を通じてフローを取得します。独自のコードでUIを構築したい場合は、ペイウォールを使用してください — [ペイウォールを手動で実装する](capacitor-quickstart-manual)を参照してください。 - [**プレースメント**](placements) – アプリ内でフローを表示する場所とタイミング(`main`、`onboarding`、`settings`など)。ダッシュボードでフローをプレースメントに紐付け、コード内でプレースメントIDを指定してリクエストします。これにより、A/B テストの実施や、ユーザーごとに異なるフローを表示することが簡単になります。 Adapty では、アプリに課金機能を実装する方法を3つ提供しています。アプリの要件に合わせて選択してください。 | 実装方法 | 複雑さ | 使用するタイミング | |---|---|---| | Adapty フロービルダー | ✅ 簡単 | [ノーコードビルダーで購入可能な完全なフローを作成します](quickstart-paywalls)。Adapty が自動でレンダリングし、複雑な購入フロー、レシート検証、サブスクリプション管理をすべて裏側で処理します。 | | 手動作成のペイウォール | 🟡 普通 | アプリのコードでペイウォール UI を実装しますが、プロダクト提供の柔軟性を保つために Adapty からフローオブジェクトを取得します。[ガイド](capacitor-quickstart-manual)を参照してください。 | | オブザーバーモード | 🔴 難しい | 独自の購入処理インフラがすでにあり、それを引き続き使用したい場合に選択します。オブザーバーモードには Adapty での制限があることに注意してください。[記事](observer-vs-full-mode)を参照してください。 | :::important **以下の手順は、Adapty フロービルダーで作成したフローの実装方法を説明しています。** ペイウォールの UI を自分でビルドしたい場合は、[ペイウォールを手動で実装する](capacitor-quickstart-manual)を参照してください。 ::: Adapty フロービルダーで作成したフローを表示するには、アプリのコードで以下の操作を行うだけです。 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-capacitor)。 :::tip これらの手順を最速で完了するには、[クイックスタートガイド](quickstart)に従うか、[Developer CLI](developer-cli-quickstart)を使ってペイウォールとプレースメントを作成してください。 ::: ## 1. フローを取得する \{#1-get-the-flow\} フローはダッシュボードで設定したプレースメントに紐づいています。プレースメントを使うと、異なるオーディエンスに対して異なるフローを表示したり、[A/B テスト](ab-tests)を実施したりできます。 Adapty フロービルダーで作成したフローを取得するには、`getFlow` メソッドを使って[プレースメント](placements) ID から `flow` オブジェクトを取得します。フローには表示に必要な UI 要素とスタイルが含まれています。 ```typescript showLineNumbers title="Capacitor" try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow } catch (error) { // handle the error } ``` ## 2. フローを表示する \{#display-the-flow\} フローを取得したら、あとは数行追加するだけで表示できます。 `createFlowView` メソッドで `view` を作成し、イベントハンドラーを設定して、`view.present()` を呼び出します。各 `view` は一度しか使用できません。フローを再度表示する場合は、`createFlowView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 ```typescript showLineNumbers title="Capacitor" try { const view = await createFlowView(flow); await view.setEventHandlers({ onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases }, }); await view.present(); } catch (error) { // handle the error } ``` :::tip フローの表示方法の詳細については、[ガイド](capacitor-present-paywalls)をご覧ください。 ::: ## 3. ボタンアクションの処理 \{#handle-button-actions\} ユーザーがフロー内のボタンをクリックすると、Capacitor SDK は購入、復元、フローのクローズ、URLのオープンを自動的に処理します。 ただし、カスタムまたは事前定義済みの ID を持つボタンについては、コード内でアクションを処理する必要があります。また、デフォルトの動作をオーバーライドしたい場合もあります。 たとえば、以下は閉じるボタンのデフォルトの動作です。コードに追加する必要はありませんが、必要な場合にどのように実装するかを確認できます。 ```typescript showLineNumbers title="Capacitor" const unsubscribe = await view.setEventHandlers({ onCloseButtonPress() { return true; // allow the flow to close }, }); ``` :::tip ボタンの[アクション](capacitor-handle-paywall-actions)と[イベント](capacitor-handling-events)の処理方法については、ガイドをご覧ください。 ::: ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備ができました。[App Storeのサンドボックス](test-purchases-in-sandbox)または[Google Play Store](testing-on-android)でテスト購入を行い、ペイウォールからのテスト購入が正常に完了することを確認してください。 次に、適切なユーザーにペイウォールを表示したり有料機能へのアクセスを付与したりするため、[ユーザーのアクセスレベルを確認する](capacitor-check-subscription-status)必要があります。 ## 完全な使用例 \{#full-example\} このガイドの全手順をアプリに統合する方法を以下に示します。 ```typescript showLineNumbers title="Capacitor" export async function showFlow() { try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', }); const view = await createFlowView(flow); await view.setEventHandlers({ onCloseButtonPress() { return true; }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases }, }); await view.present(); } catch (error) { // handle any error that may occur during the process console.warn('Error showing flow:', error); } } ``` --- # File: capacitor-check-subscription-status --- --- title: "Capacitor SDKでサブスクリプションステータスを確認する" description: "AdaptyでCapacitorアプリのサブスクリプションステータスを確認する方法を学びましょう。" --- ユーザーが有料コンテンツにアクセスできるか、またはペイウォールを表示するかを決めるには、プロファイルの[アクセスレベル](access-level)を確認する必要があります。 この記事では、ユーザーにペイウォールを表示するか、有料機能へのアクセスを許可するかを判断するために、プロファイルの状態を取得する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ペイウォールまたは有料コンテンツを表示するかどうかを判断する際、ユーザーのプロファイルにある[アクセスレベル](access-level)を確認します。方法は2つあります: - アプリ起動時など、すぐに最新のプロファイルデータが必要な場合や強制的に更新したい場合は`getProfile`を呼び出します。 - サブスクリプションのステータスが変わるたびに自動的に更新されるローカルコピーを保持するには、**自動プロファイル更新**を設定します。 ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得する最も簡単な方法は、`getProfile`メソッドを使ってプロファイルにアクセスすることです: ```typescript showLineNumbers try { const profile = await adapty.getProfile(); } catch (error) { // handle the error } ``` ### サブスクリプションの更新を受け取る \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取るには: 1. `adapty.addListener('onLatestProfileLoad')` を使用してプロファイルの変更を監視します。ユーザーのサブスクリプションステータスが変わると、Adapty が自動的にこのメソッドを呼び出します。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存しておくことで、追加のネットワークリクエストなしにアプリ全体で利用できます。 ```typescript showLineNumbers class SubscriptionManager { private currentProfile: any = null; constructor() { // Listen for profile updates adapty.addListener('onLatestProfileLoad', (data) => { this.currentProfile = data.profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() hasAccess(): boolean { return this.currentProfile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive ?? false; } } ``` :::note Adapty は、アプリの起動時に自動的に `onLatestProfileLoad` イベントリスナーを呼び出し、デバイスがオフラインの場合でもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールロジックの連携 \{#connect-profile-with-paywall-logic\} ペイウォールの表示や有料機能へのアクセス付与をすぐに判断する必要がある場合、ユーザーのプロファイルを直接確認できます。このアプローチは、アプリの起動時、プレミアムセクションへの入場時、または特定のコンテンツを表示する前など、さまざまなシーンで役立ちます。 ```typescript showLineNumbers const checkAccessLevel = async () => { try { const profile = await adapty.getProfile(); return profile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive === true; } catch (error) { console.warn('Error checking access level:', error); return false; // Show paywall if access check fails } }; const getAccessLevel = (profile: AdaptyProfile) => { return profile.accessLevels?.['YOUR_ACCESS_LEVEL']; }; const initializePaywall = async () => { try { await loadPaywall(); const hasAccess = await checkAccessLevel(); if (!hasAccess) { // Show paywall if no access } } catch (error) { console.warn('Error initializing paywall:', error); } }; ``` ## 次のステップ \{#next-steps\} サブスクリプションステータスの確認方法がわかったら、次は[ユーザープロファイルの操作](capacitor-quickstart-identify)について学び、ユーザーが購入したコンテンツに確実にアクセスできるようにしましょう。 --- # File: capacitor-quickstart-identify --- --- title: "Capacitor SDKでユーザーを識別する" description: "Capacitorでのアプリ内サブスクリプション管理のためのAdaptyセットアップ クイックスタートガイド。" --- ユーザーの購入管理方法は、アプリの認証モデルによって異なります: - アプリでバックエンド認証を使用せず、ユーザーデータを保存しない場合は、[匿名ユーザーに関するセクション](#anonymous-users)をご覧ください。 - アプリにバックエンド認証がある(または予定している)場合は、[識別済みユーザーに関するセクション](#identified-users)をご覧ください。 :::tip **主な概念**: - **プロファイル**は、SDKが機能するために必要なエンティティです。Adaptyが自動的に作成します。匿名(カスタマーユーザーIDなし)または識別済み(カスタマーユーザーIDあり)のいずれかになります。 - **カスタマーユーザーID**は、**あなたが作成する**オプションの識別子で、ユーザーをAdaptyプロファイルに紐付けるために使用します。 ::: 匿名ユーザーと識別済みユーザーの違いは次のとおりです: | | 匿名ユーザー | 識別済みユーザー | |-------------------------|------------------------------------------------------|-------------------------------------------------------------------------| | **購入管理** | ストアレベルの購入復元 | カスタマーユーザーIDを通じてデバイスをまたいで購入履歴を維持 | | **プロファイル管理** | 再インストールごとに新しいプロファイルが作成される | セッションやデバイスをまたいで同じプロファイルを使用 | | **データの永続性** | 匿名ユーザーのデータはデバイス/インストールに紐付けられる | 識別済みユーザーのデータはデバイスやセッションをまたいで保持される | ## 匿名ユーザー \{#anonymous-users\} バックエンド認証がない場合、**アプリのコードで認証を処理する必要はありません**: 1. アプリの初回起動時にSDKが有効化されると、Adaptyが**ユーザーの新しいプロファイルを作成**します。 2. ユーザーがアプリ内で何かを購入すると、その購入は**そのユーザーのAdaptyプロファイルとストアアカウントに関連付け**られます。 3. ユーザーがアプリを**再インストール**したり、**新しいデバイス**にインストールしたりすると、Adaptyは有効化時に**新しい空のプロファイルを作成**します。 4. ユーザーがアプリで以前に購入をしていた場合、デフォルトでは、SDKの有効化時にApp Storeから購入が自動的に同期されます。 :::note バックアップからの復元は、再インストールとは動作が異なります。デフォルトでは、ユーザーがバックアップから復元した場合、SDKはキャッシュされたデータを保持し、新しいプロファイルを作成しません。この動作は`clearDataOnBackup`設定で変更できます。[詳細はこちら](sdk-installation-capacitor#clear-data-on-backup-restore)。 ::: ## 識別済みユーザー \{#identified-users\} - プロファイルにまだカスタマーユーザーIDがない場合(つまり、**ユーザーがサインインしていない**場合)、カスタマーユーザーIDを送信すると、そのプロファイルに関連付けられます。 - **再インストール、サインイン、または新しいデバイスからのインストール**で、以前にそのカスタマーユーザーIDを送信したことがある場合、新しいプロファイルは作成されません。代わりに、そのカスタマーユーザーIDに関連付けられた既存のプロファイルに切り替わります。 アプリでユーザーを識別する方法は2つあります: - [**ログイン/サインアップ時:**](#during-loginsignup) アプリ起動後にユーザーがサインインする場合、認証時に`identify()`をカスタマーユーザーIDとともに呼び出します。 - [**SDK有効化時:**](#during-the-sdk-activation) アプリ起動時にすでにカスタマーユーザーIDが保存されている場合、`activate()`を呼び出す際に送信します。 :::important デフォルトでは、Adaptyが現在別のカスタマーユーザーIDに関連付けられているカスタマーユーザーIDからの購入を受け取った場合、アクセスレベルは共有され、両方のプロファイルが有料アクセスを持ちます。この設定を変更して、有料アクセスを1つのプロファイルから別のプロファイルに移動したり、共有を完全に無効にしたりすることができます。詳細は[こちらの記事](general#6-sharing-paid-access-between-user-accounts)をご覧ください。 ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(例:アプリへのログインやサインアップ後)は、`identify`メソッドを使用してカスタマーユーザーIDを設定します。 - **このカスタマーユーザーIDを以前に使用したことがない**場合、Adaptyは自動的にそれを現在のプロファイルに紐付けます。 - **このカスタマーユーザーIDを以前にユーザーの識別に使用したことがある**場合、AdaptyはそのカスタマーユーザーIDに関連付けられたプロファイルに切り替えます。 :::tip カスタマーユーザーIDを作成する際は、ユーザーデータと一緒に保存しておくと、新しいデバイスからログインした場合やアプリを再インストールした際に同じIDを送信できます。 ::: 他のSDKメソッドを呼び出す前に、必ず`identify`を`await`してください。並行して呼び出すと`#3006 profileWasChanged`が発生するか、匿名プロファイルに対して操作が行われます。[Capacitor SDKの呼び出し順序](capacitor-sdk-call-order)を参照してください。 ```typescript showLineNumbers try { await adapty.identify({ customerUserId: "YOUR_USER_ID" }); // successfully identified } catch (error) { // handle the error } ``` ### SDK有効化時 \{#during-the-sdk-activation\} SDKを有効化するときにすでにカスタマーユーザーIDがわかっている場合は、`identify`を別途呼び出す代わりに、`activate`メソッドで送信できます。 カスタマーユーザーIDがわかっていても、有効化後にのみ設定する場合、有効化時にAdaptyは新しい空のプロファイルを作成し、`identify`を呼び出した後にのみ既存のプロファイルに切り替わります。 既存のカスタマーユーザーID(以前に使用したもの)と新しいもののどちらでも渡すことができます。新しいものを渡した場合、有効化時に作成された新しいプロファイルが自動的にそのカスタマーユーザーIDに紐付けられます。 :::tip 作成された空のプロファイルをダッシュボードのアナリティクスから除外するには、**App settings**に移動して[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```typescript showLineNumbers await adapty.activate({ apiKey: "YOUR_PUBLIC_SDK_KEY", params: { customerUserId: "YOUR_USER_ID" } }); ``` ### ユーザーをログアウトする \{#log-users-out\} ユーザーをログアウトするボタンがある場合は、`logout`メソッドを使用します。これにより、ユーザーに新しい匿名プロファイルIDが作成されます。 ```typescript showLineNumbers try { await adapty.logout(); // successful logout } catch (error) { // handle the error } ``` :::info ユーザーをアプリに再度ログインさせるには、`identify`メソッドを使用してください。 ::: ### ログインせずに購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリにログインする前後の両方で購入できる場合、追加の設定は不要です: 仕組みは次のとおりです: 1. ログアウト状態のユーザーが購入を行うと、Adaptyはその購入を匿名プロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルに切り替えます。 - 既存のカスタマーユーザーID(すでにプロファイルに紐付けられているカスタマーユーザーID)の場合、Adaptyはトランザクションを自動的に同期します。 - 新しいカスタマーユーザーID(例:登録前に購入が行われた場合)の場合、Adaptyは現在のプロファイルにカスタマーユーザーIDを割り当て、すべての購入履歴が維持されます。 --- # File: adapty-sdk-integration-skill-capacitor --- --- title: "SDKインテグレーションスキルを使ってAdaptyをCapacitorアプリに導入する" description: "adapty-sdk-integrationスキルを使って、AIコーディングツールでCapacitorアプリにAdapty SDKをエンドツーエンドで統合する方法を説明します。" --- :::important このスキルはベータ版です。処理が止まったり予期しない動作が発生した場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor-capacitor)を参照してください。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-capacitor --- --- title: "AIアシスタンスを使用してCapacitorアプリにAdaptyを統合する" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使用してCapacitorアプリにAdaptyを統合するステップバイステップガイド。" --- このガイドでは、AIコーディングツールを使ってCapacitorアプリにAdaptyを段階的に統合する方法を説明します。適切な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** に移動します。Capacitor アプリが両方のプラットフォームを対象とする場合は、App Store と Google Play の両方を連携してください。これは購入機能を動作させるために必要です。 [アプリストアを連携する](integrate-payments) 2. **公開 SDK キーをコピーする**: Adapty ダッシュボードで **App settings → General** に移動し、**API keys** セクションを確認します。コード内では、この文字列を `adapty.activate()` に渡します。 3. **プロダクトを少なくとも 1 つ作成する**: Adapty ダッシュボードで **Products** ページに移動します。コード内でプロダクトを直接参照する必要はありません — Adapty はペイウォールを通じてプロダクトを提供します。 [プロダクトを追加する](quickstart-products) 4. **ペイウォールとプレースメントを作成する**: Adapty ダッシュボードの **Paywalls** ページでペイウォールを作成し、**Placements** ページでプレースメントに割り当てます。コード内では、プレースメント ID が `adapty.getFlow()` に渡す文字列です。 [ペイウォールを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**: Adapty ダッシュボードの **Products** ページで、プロダクトごとに設定します。コード内では `profile.accessLevels['premium']?.isActive` で確認します。デフォルトの `premium` アクセスレベルは、ほとんどのアプリで利用できます。購入ユーザーがプロダクトによって異なる機能にアクセスできる場合(たとえば `basic` プランと `pro` プランなど)、コーディングを始める前に[追加のアクセスレベルを作成](assigning-access-level-to-a-product)してください。 :::tip 5つすべてが揃ったら、コードを書く準備完了です。LLMに「パブリックSDKキーはX、プレースメントIDはY」と伝えることで、正しい初期化とフロー取得コードを生成できます。 ::: ### 準備ができたら設定すること \{#set-up-when-ready\} コーディングを始める前に必須ではありませんが、統合が成熟するにつれて必要になります: - **A/B テスト**: **Placements** ページで設定します。コードの変更は不要です。 [A/B テスト](ab-tests) - **追加のペイウォールとプレースメント**: 異なるプレースメントIDで `getPaywall` の呼び出しを追加します。 - **アナリティクス連携**: **Integrations** ページで設定します。セットアップは連携先によって異なります。[アナリティクス連携](analytics-integration)と[アトリビューション連携](attribution-integration)を参照してください。 ## AdaptyドキュメントをLLMに提供する \{#feed-adapty-docs-to-your-llm\} ### Context7を使う(推奨) [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 Capacitor SDK ``` :::warning Context7によってドキュメントのリンクを手動で貼り付ける手間は省けますが、実装の順序は重要です。すべてが正しく動作するよう、以下の[実装手順](#implementation-walkthrough)にしたがって順番に進めてください。 ::: ### プレーンテキストのドキュメントを使う \{#use-plain-text-docs\} Adaptyのドキュメントはプレーンテキストのマークダウンとして取得できます。URLの末尾に `.md` を追加するか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例:[adapty-cursor-capacitor.md](https://adapty.io/docs/ja/adapty-cursor-capacitor.md) 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステージには、貼り付け用の `.md` リンクが含まれた「LLMに送るもの」ブロックがあります。 一度に複数のドキュメントが必要な場合は、以下の[インデックスファイルとプラットフォーム別サブセット](#plain-text-doc-index-files)を参照してください。 ## 実装ウォークスルー \{#implementation-walkthrough\} このガイドの残りでは、実装順序に沿ってAdapty統合を進めていきます。各ステージには、LLMに送るドキュメント、完了時に確認できること、よくある問題が含まれています。 ### インテグレーションを計画する \{#plan-your-integration\} コーディングを始める前に、LLM にプロジェクトを分析させて実装計画を立ててもらいましょう。AI ツールにプランニングモードがある場合(Cursor や Claude Code のプランモードなど)、コードを書く前に LLM がプロジェクト構造と Adapty のドキュメントを両方確認できるよう、そのモードを活用してください。 購入に使っているアプローチを LLM に伝えましょう。これによって参照すべきガイドが変わります: - [**Adapty フロービルダー**](adapty-flow-builder): Adapty のノーコードビルダーでフローを作成し、SDK が自動的にレンダリングします。 - [**手動で作成したペイウォール**](capacitor-making-purchases): 独自のペイウォール UI をコードで構築しながら、プロダクトの取得と購入処理には Adapty を使用します。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラをそのまま使用し、Adapty はアナリティクスとインテグレーションにのみ利用します。 どれを選べばよいかわからない場合は、[クイックスタートの比較表](capacitor-quickstart-paywalls)をご覧ください。 ### SDKのインストールと設定 \{#install-and-configure-the-sdk\} npm を使って Adapty SDK の依存関係を追加し、公開 SDK キーで有効化します。これがすべての基盤となります。これなしには何も動作しません。 **ガイド:** [Adapty SDK のインストールと設定](sdk-installation-capacitor) :::info このウォークスルーは Adapty Capacitor SDK v4(ベータ版)を対象としています — [クイックスタート](capacitor-quickstart-paywalls)で紹介している API です。v4 はプレリリース版のため、最新の安定版 3.x をインストールするのではなく、LLM が正確なバージョン(`npm install @adapty/capacitor@4.0.0-beta.2`)を固定するように注意してください。[SDK 4.0 インストールセクション](sdk-installation-capacitor#adapty-sdk-40-beta)と[移行ガイド](migration-to-capacitor-sdk-v4)をご参照ください。 ::: これを LLM に送信してください: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-capacitor.md ``` :::tip[チェックポイント] - **確認事項:** iOS・Android 両方でアプリがビルド・起動できること。コンソールに Adapty のアクティベーションログが表示されること。 - **よくある問題:** "Public API key is missing" → **App settings** のキーをプレースホルダーから実際のキーに置き換えたか確認してください。 ::: ### ペイウォールの表示と購入処理 \{#show-paywalls-and-handle-purchases\} プレースメント ID でペイウォールを取得し、表示して、購入イベントを処理します。必要なガイドは購入処理の方法によって異なります。 進めながら各購入をサンドボックスでテストしてください — 最後まで待たないようにしましょう。セットアップ手順は[サンドボックスでの購入テスト](test-purchases-in-sandbox)を参照してください。 <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Flow Builder" default> **ガイド:** - [フローを使って購入を有効にする(クイックスタート)](capacitor-quickstart-paywalls) - [フロー & ペイウォールを取得する](capacitor-get-pb-paywalls) - [フロー & ペイウォールを表示する](capacitor-present-paywalls) - [イベントを処理する](capacitor-handling-events) - [アクションに応答する](capacitor-handle-paywall-actions) ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/capacitor-quickstart-paywalls.md - https://adapty.io/docs/ja/capacitor-get-pb-paywalls.md - https://adapty.io/docs/ja/capacitor-present-paywalls.md - https://adapty.io/docs/ja/capacitor-handling-events.md - https://adapty.io/docs/ja/capacitor-handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される動作:** 設定したプロダクトがフローに表示される。プロダクトをタップするとサンドボックス購入ダイアログが起動する。 - **注意点:** フローが空または `getFlow` エラー → プレースメント ID がダッシュボードと完全に一致しているか、またプレースメントにオーディエンスが割り当てられているかを確認してください。 ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](capacitor-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products-capacitor) - [リモートコンフィグで設計したペイウォールを表示する](present-remote-config-paywalls-capacitor) - [購入する](capacitor-making-purchases) - [購入を復元する](capacitor-restore-purchase) ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/capacitor-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products-capacitor.md - https://adapty.io/docs/ja/present-remote-config-paywalls-capacitor.md - https://adapty.io/docs/ja/capacitor-making-purchases.md - https://adapty.io/docs/ja/capacitor-restore-purchase.md ``` :::tip[チェックポイント] - **期待される動作:** カスタムペイウォールに Adapty から取得したプロダクトが表示される。プロダクトをタップするとサンドボックスの購入ダイアログが起動する。 - **注意点:** プロダクト配列が空の場合 → ダッシュボードでペイウォールにプロダクトが割り当てられており、プレースメントにオーディエンスが設定されているか確認してください。 ::: </TabItem> <TabItem value="observer" label="Observer mode"> **ガイド:** - [Observer モードの概要](observer-vs-full-mode) - [Observer モードの実装](implement-observer-mode-capacitor) - [Observer モードでのトランザクションの報告](report-transactions-observer-mode-capacitor) ``` 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-capacitor.md - https://adapty.io/docs/ja/report-transactions-observer-mode-capacitor.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローを使ってサンドボックス購入を行った後、トランザクションが Adapty ダッシュボードの **Event Feed** に表示される。 - **注意点:** イベントが表示されない場合 → Adapty へのトランザクション報告が正しく行われているか、および両ストアのサーバー通知が設定されているかを確認してください。 ::: </TabItem> </Tabs> ### サブスクリプションステータスを確認する \{#check-subscription-status\} 購入後、ユーザープロファイルのアクティブなアクセスレベルを確認して、プレミアムコンテンツへのアクセスを制御します。 **ガイド:** [サブスクリプションステータスを確認する](capacitor-check-subscription-status) LLMに送るもの: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/capacitor-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックス購入後、`profile.accessLevels['premium']?.isActive` が `true` を返す。 - **注意点:** 購入後に `accessLevels` が空 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているか確認してください。 ::: ### ユーザーを識別する \{#identify-users\} 購入が複数のデバイスをまたいで維持されるよう、アプリのユーザーアカウントを Adapty プロファイルに紐付けます。 :::important アプリに認証機能がない場合は、このステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](capacitor-quickstart-identify) 以下を LLM に送信してください: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/capacitor-quickstart-identify.md ``` :::tip[Checkpoint] - **期待される動作:** `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 つのファイルにまとめたものです。非常に大きいため、全体像が必要な場合にのみ使用してください。 - Capacitor 専用の [`capacitor-llms.txt`](https://adapty.io/docs/ja/capacitor-llms.txt) と [`capacitor-llms-full.txt`](https://adapty.io/docs/ja/capacitor-llms-full.txt): サイト全体と比べてトークンを節約できるプラットフォーム固有のサブセットです。 --- # File: capacitor-paywalls --- --- title: "フローとペイウォール - Capacitor" description: "Adapty フロービルダーまたはペイウォールビルダーで作成したフローとペイウォールを Capacitor アプリで表示・管理します。" --- ## ペイウォールを表示する \{#display-paywalls\} ### Adapty フロービルダー & ペイウォールビルダー \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['capacitor-get-pb-paywalls', 'capacitor-present-paywalls', 'capacitor-handling-events', 'capacitor-handle-paywall-actions']} /> :::tip Adapty のフローとペイウォールをすばやく始めるには、[クイックスタートガイド](capacitor-quickstart-paywalls)をご覧ください。 ::: ### ペイウォールを手動で実装する \{#implement-paywalls-manually\} <CustomDocCardList ids={['capacitor-quickstart-manual', 'fetch-paywalls-and-products-capacitor', 'present-remote-config-paywalls-capacitor', 'capacitor-making-purchases']} /> ペイウォールの実装と購入の手動処理に関するその他のガイドは、[カテゴリ](capacitor-implement-paywalls-manually)をご覧ください。 ## 便利な機能 \{#useful-features\} <CustomDocCardList ids={['capacitor-use-fallback-paywalls', 'capacitor-web-paywall']} /> --- # File: capacitor-get-pb-paywalls --- --- title: "フローとペイウォールの取得 - Capacitor" description: "CapacitorアプリでAdaptyからフローとペイウォールを取得する方法。" --- <SDKv4> <MethodPromo method="getFlow" /> [フローまたはペイウォールビルダーのペイウォールをデザイン](adapty-paywall-builder)したら、モバイルアプリで表示できます。最初のステップは、プレースメントに紐づいたフローまたはペイウォールと、以下で説明するビュー設定を取得することです。 このトピックはフローおよびペイウォールビルダーでカスタマイズされたペイウォールに関するものです。ペイウォールを手動で実装している場合は、[リモートコンフィグペイウォールのペイウォールとプロダクトをモバイルアプリで取得する](fetch-paywalls-and-products-capacitor)トピックを参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリにフローとペイウォールを表示する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成し、プロダクトを追加](create-paywall)してください。 3. Adapty ダッシュボードで[プレースメントを作成し、フロー/ペイウォールを追加](create-placement)してください。 4. モバイルアプリに [Adapty SDK](sdk-installation-capacitor) をインストールしてください。 </details> ## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} Flow Builder または Paywall Builder でフローやペイウォールを設計した場合、それをユーザーに表示するためにモバイルアプリのコードでレンダリングについて心配する必要はありません。このようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてそのIDを取得し、ビュー設定を取得してから、モバイルアプリで表示する必要があります。 フローまたはペイウォールを取得し、その[ビューを作成](capacitor-get-pb-paywalls#fetch-the-view-configuration)するのは、表示するよりもできるだけ前に行うことをおすすめします。`createFlowView` メソッドはビューの設定を読み込み、画像のダウンロードとキャッシュをバックグラウンドで開始します。早く呼び出すほど、ダウンロードが完了するまでの時間を確保できます。フローまたはペイウォールを表示するタイミングには、設定と画像がすでにキャッシュされて表示準備が整っている状態にできます。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します。 ```typescript showLineNumbers try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow/paywall } catch (error) { // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |-------------------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `'reload_revalidating_cache_data'` | <p>オプションの `params` オブジェクト内で渡します。デフォルトでは、SDK はサーバーからデータを取得しようとし、失敗した場合はキャッシュされたデータを返します。この方式はユーザーが常に最新のデータを受け取れるため、推奨しています。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`'return_cache_data_else_load'` を使用してキャッシュが存在すればそれを返すことを検討してください。この場合、絶対的に最新のデータが届かないことがありますが、回線状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、ネットワークリクエストを減らす目的でセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存しています。上記の定期更新されるキャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより速く取得するために CDN を使用し、CDN に到達できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeoutMs** | デフォルト: 5秒 | <p>オプションの `params` オブジェクト内で渡します。このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。</p><p>まれに、内部で複数のリクエストが実行されるため、このメソッドが `loadTimeoutMs` に指定した時間よりわずかに遅れてタイムアウトする場合があります。</p> | **プロダクトIDをハードコードしないでください。** ハードコードすべきIDはプレースメントIDのみです。フローとペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変更される可能性があります。アプリはこれらの変更を動的に処理する必要があります。今日ペイウォールが2つのプロダクトを返し、明日3つを返しても、コードを変更せずにすべて表示できるようにしてください。 レスポンスパラメーター: | パラメータ | 説明 | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | フローの識別子(`id`、`variationId`)、名前、プレースメント、ペイウォールのバリアント(`paywalls`)、リモートコンフィグ(`remoteConfigs`)を持つ `AdaptyFlow` オブジェクト。 | ## ビュー設定を取得する \{#fetch-the-view-configuration\} :::important ビルダーで **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: プレースメントが **Flow Builder** または **Paywall Builder** でデザインされている場合、Adapty が UI をレンダリングします。`createFlowView` でビューを作成し、[フローまたはペイウォールを表示](capacitor-present-paywalls)してください。プレースメントがビルダー UI のないカスタムペイウォールの場合は、代わりに[リモートコンフィグペイウォールとして処理](present-remote-config-paywalls-capacitor)してください。 Capacitor SDK では、`createFlowView` を直接呼び出すことができます。事前にビューの設定を取得する必要はありません。 :::warning `createFlowView` メソッドの戻り値は一度しか使用できません。再度使用する必要がある場合は、`createFlowView` メソッドを再度呼び出してください。再生成せずに2回呼び出すとエラーが発生する場合があります。 ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | 必須 | 目的のフロー/ペイウォールのコントローラーを取得するための `AdaptyFlow` オブジェクト。 | | **customTags** | 任意 | カスタムタグとその解決済みの値の辞書を定義します。カスタムタグはコンテンツ内のプレースホルダーとして機能し、フロー/ペイウォール内のパーソナライズされたコンテンツに対して特定の文字列に動的に置き換えられます。詳細については、ペイウォールビルダーのカスタムタグに関するトピックを参照してください。 | | **prefetchProducts** | 任意 | 画面上のプロダクト表示タイミングを最適化するために有効にします。`true` の場合、AdaptyUI は必要なプロダクトを自動的に取得します。デフォルト: `true`。 | | **android.enableSafeArea** | 任意 | Android のみ(iOS では無視されます)。`android` キーの下にネストされます。`true` の場合、フロービューにセーフエリアのパディングが適用されます。デフォルト: `true`。デフォルト設定はほとんどのケースに適しています。 | :::note 複数の言語を使用している場合は、[フローのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の追加方法と、ロケールコードの正しい使い方について[こちら](capacitor-localizations-and-locale-codes)をご覧ください。 ::: ビューを取得したら、[フロー/ペイウォールを表示](capacitor-present-paywalls)してください。 ## デフォルトオーディエンスのフローまたはペイウォールをより速く取得する \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、フローやペイウォールはほぼ瞬時に取得されるため、この処理を高速化することを気にする必要はありません。ただし、オーディエンスやプレースメントの数が多く、ユーザーのインターネット接続が不安定な場合は、フローやペイウォールの取得に予想以上の時間がかかることがあります。そのような場合、何も表示しないよりもスムーズなユーザー体験を確保するために、デフォルトのフローまたはペイウォールを表示したいことがあるでしょう。 これに対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンスに対応するフローまたはペイウォールを取得します。ただし、推奨されるアプローチは `getFlow` メソッドでフローまたはペイウォールを取得することであり、詳細は上記の [フロー/ペイウォールの取得](#fetch-flowpaywall) セクションを参照してください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないペイウォールで問題が発生することを受け入れるかのいずれかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを許容してでもフローやペイウォールの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-flowpaywall)で説明した `getFlow` を使用してください。 ::: ```typescript showLineNumbers try { const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', }); // the requested flow/paywall } catch (error) { // handle the error } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `'reload_revalidating_cache_data'` | <p>省略可能な `params` オブジェクト内に渡します。デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるよう、この設定を推奨します。</p><p></p><p>ただし、ユーザーがネットワーク環境の不安定な状況を頻繁に経験する場合は、`'return_cache_data_else_load'` を使用してキャッシュが存在するときはキャッシュデータを返すことを検討してください。この場合、ユーザーが最新データを取得できないことがありますが、ネットワーク状況に関わらず読み込み時間が短縮されます。キャッシュはセッション中に定期的に更新されるため、ネットワークリクエストを避ける目的でキャッシュを使用しても安全です。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p> | ## アセットのカスタマイズ \{#customize-assets\} フロー/ペイウォールの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像とヒーロー動画には事前定義されたID(`hero_image` と `hero_video`)があります。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のようなことができます: - 一部のユーザーに異なる画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画の再生前にプレビュー画像を表示する。 カスタムアセットをシンプルなディクショナリで指定する例を以下に示します。 ```typescript showLineNumbers const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; const view = await createFlowView(flow, { customAssets }); ``` :::note アセットが見つからない場合、フロー/ペイウォールはデフォルトの外観にフォールバックします。 ::: </SDKv4> <SDKv3> [Adapty ダッシュボードの新しいペイウォールビルダーでペイウォールのビジュアル部分をデザイン](adapty-paywall-builder)したら、モバイルアプリでそれを表示できます。このプロセスの最初のステップは、以下で説明するように、プレースメントに関連付けられたペイウォールとそのビュー設定を取得することです。 このトピックは、ペイウォールビルダーでカスタマイズされたペイウォールに関するものです。リモートコンフィグのペイウォールを取得する方法については、[モバイルアプリでリモートコンフィグのペイウォールとプロダクトを取得する](fetch-paywalls-and-products-capacitor)を参照してください。 <details> <summary>モバイルアプリでペイウォールを表示する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加する](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加する](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-capacitor) をインストールする。 </details> ## ペイウォールビルダーで作成したペイウォールの取得 \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーを使ってペイウォールをデザインした場合](adapty-paywall-builder)、モバイルアプリのコードでレンダリングしてユーザーに表示する必要はありません。このようなペイウォールには、表示内容と表示方法の両方が含まれています。ただし、プレースメントを通じてペイウォールのIDを取得し、ビュー設定を行ったうえで、モバイルアプリ内に表示する必要があります。 最適なパフォーマンスを確保するために、ペイウォールとその[ビュー設定](capacitor-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードが完了するための十分な時間を確保することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します。 ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', }); // the requested paywall } catch (error) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 目的の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードである必要があります。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードとその推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **params** | 任意 | ペイウォールを取得するための追加パラメーター。 | **プロダクトIDをハードコードしないでください。** ハードコードしてよいのはプレースメントIDだけです。ペイウォールはリモートで設定されるため、プロダクト数や利用可能なオファーはいつでも変更される可能性があります。アプリはこれらの変更を動的に処理する必要があります。今日は2つのプロダクトが返ってきて、明日は3つになったとしても、コードを変更せずにすべてを表示できるようにしてください。 レスポンスパラメーター: | パラメーター | 説明 | | :-------- |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | プロダクトIDのリスト、ペイウォール識別子、リモートコンフィグ、その他のプロパティを含む [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーの **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、`ViewConfiguration` が含まれているかどうかを確認してください。これが存在する場合、ペイウォールビルダーで作成されたペイウォールであることを示します。この情報をもとに、ペイウォールの表示方法を決定します。`ViewConfiguration` が存在する場合はペイウォールビルダーのペイウォールとして扱い、存在しない場合は[リモートコンフィグのペイウォールとして処理してください](present-remote-config-paywalls-capacitor)。 Capacitor SDK では、ビュー設定を手動で取得することなく、直接 `createPaywallView` メソッドを呼び出してください。 :::warning `createPaywallView` メソッドの結果は一度しか使用できません。再度使用する必要がある場合は、`createPaywallView` メソッドを新たに呼び出してください。 ::: ```typescript showLineNumbers if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { // use your custom logic } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | | :------------------- | :------- | :----------------------------------------------------------- | | **paywall** | 必須 | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **customTags** | 任意 | カスタムタグとその解決済みの値の辞書を定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツ向けに特定の文字列へ動的に置換されます。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | | **prefetchProducts** | 任意 | 画面上のプロダクト表示タイミングを最適化するために有効にします。`true` の場合、AdaptyUI は必要なプロダクトを自動的に取得します。デフォルト: `false`。 | :::note 複数の言語を使用している場合は、[ペイウォールビルダーのローカライゼーションの追加方法](add-paywall-locale-in-adapty-paywall-builder)と、ロケールコードの正しい使い方[こちら](capacitor-localizations-and-locale-codes)をご確認ください。 ::: ビューを取得したら、[ペイウォールを表示](capacitor-present-paywalls)します。 ## デフォルトオーディエンス向けペイウォールを取得してより速く表示する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ瞬時に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、かつユーザーのインターネット接続が不安定な場合は、取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したい場合があります。 これに対処するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、**All Users** オーディエンス向けに指定されたプレースメントのペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の[ペイウォール情報を取得する](#fetch-paywall-designed-with-paywall-builder)セクションを参照してください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行版と将来版)に対して異なるペイウォールを表示する必要がある場合、現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがペイウォールを正しくレンダリングできない問題を受け入れるかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーに **All Users** オーディエンス向けに設計された同じペイウォールが表示されます。これにより、国、マーケティングのアトリビューション、独自のカスタム属性に基づくターゲティングなど、パーソナライズされたターゲティングが失われます。 これらのデメリットを許容してでもペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` をご利用ください。 ::: ```typescript showLineNumbers try { const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', }); // the requested paywall } catch (error) { // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-remote-config-locale)の識別子です。このパラメータは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語を、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよび推奨される使用方法については、[ローカライゼーションとロケールコード](capacitor-localizations-and-locale-codes)を参照してください。</p> | | **params** | 任意 | ペイウォールを取得するための追加パラメータです。 | ## アセットのカスタマイズ \{#customize-assets\} ペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には事前定義されたIDがあります:`hero_image` と `hero_video` です。カスタムアセットバンドルでは、これらのIDを使って対象の要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のようなことができます: - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中にローカルのプレビュー画像を表示する。 - 動画再生前にプレビュー画像を表示する。 以下は、シンプルなディクショナリーを使ってカスタムアセットを提供する例です: ```typescript showLineNumbers const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; view = await createPaywallView(paywall, { customAssets }); ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの外観にフォールバックします。 ::: </SDKv3> --- # File: capacitor-present-paywalls --- --- title: "フローとペイウォールの表示 - Capacitor" description: "Capacitor アプリで Adapty を使用してフローとペイウォールをユーザーに表示します。" --- <SDKv4> フローまたはペイウォールをフローエビルダーで作成した場合、それをモバイルアプリのコードでレンダリングしてユーザーに表示する方法を気にする必要はありません。フローには、表示する内容とその表示方法の両方が含まれています。 始める前に、以下を確認してください。 1. [フローまたはペイウォールを作成](create-paywall)している。 2. [プレースメント](placements)に追加している。 3. [フローをフェッチしてビューを準備](capacitor-get-pb-paywalls)している。 :::warning このガイドは**フローおよびペイウォールビルダーのペイウォール**専用です。SDK v4.0以降が必要です。リモートコンフィグペイウォールの表示方法は異なります。 - **リモートコンフィグペイウォール**の表示については、[リモートコンフィグで設計したペイウォールを表示する](present-remote-config-paywalls-capacitor)を参照してください。 ::: フローまたはペイウォールをスタンドアロン画面として表示するには、[`createFlowView`](capacitor-get-pb-paywalls#fetch-the-view-configuration) メソッドで作成した `view` に対して `view.present()` メソッドを使用します。各 `view` は一度しか使用できません。フローを再度表示する必要がある場合は、`createFlowView` を再度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用することは禁止されています。エラーが発生します。 ::: ```typescript showLineNumbers const view = await createFlowView(flow); // Optional: handle flow events (close, purchase, restore, etc) // await view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` :::important `setEventHandlers` を複数回呼び出すと、指定したハンドラーが上書きされ、そのイベントに対するデフォルトおよび以前に設定したハンドラーが置き換えられます。 ::: ## iOSのプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのフローの表示スタイルを設定できます。このパラメータは `'full_screen'`(デフォルト)または `'page_sheet'` を受け付けます。Android では、フローは常にフルスクリーンのアクティビティとして表示されます。 ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## 開発者定義タイマーを使用する \{#use-developer-defined-timer\} モバイルアプリで開発者定義タイマーを使用するには、`timerId`(この例では `CUSTOM_TIMER_NY`)を使用します。これは Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。これにより、アプリはタイマーを正しい値(例:タイマーの終了時刻(元日など)から現在時刻を引いた `13d 09h 03m 34s`)で動的に更新できます。 ```typescript showLineNumbers const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createFlowView(flow, { customTimers }); ``` この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。タイマーを使うことで、アプリが正しい値(例: `13d 09h 03m 34s`、元日などのタイマー終了時刻から現在時刻を引いた値)を動的に表示できます。 ## ダイアログを表示する \{#show-dialog\} Android でフロービューが表示されている場合、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートがフロービューの後ろに表示されるため、ユーザーには見えません。このメソッドを使用することで、すべてのプラットフォームでフローの上に正しくダイアログが表示されます。 ```typescript showLineNumbers try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the flow await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## 別のサブスクリプションへの切り替え \{#replace-one-subscription-with-another\} Android でユーザーが別のサブスクリプションを有効にした状態で新しいサブスクリプションを購入しようとする場合、フロービューを作成する際にサブスクリプション更新パラメータを渡すことで、新しい購入の処理方法を制御できます。現在のサブスクリプションを新しいものに切り替えるには、`createFlowView` の `productPurchaseParams` に `oldSubVendorProductId` と `prorationMode` パラメータを指定してください。 ```typescript showLineNumbers const productPurchaseParams = flow.paywalls .flatMap((paywall) => paywall.productIdentifiers) .map((productId) => { const params: MakePurchaseParamsInput = {}; if (Capacitor.getPlatform() === 'android') { params.android = { subscriptionUpdateParams: { oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION', prorationMode: 'with_time_proration', }, }; } return { productId, params }; }); const view = await createFlowView(flow, { productPurchaseParams }); ``` </SDKv4> <SDKv3> ペイウォールビルダーを使ってペイウォールをカスタマイズした場合、モバイルアプリのコードでそれをレンダリングしてユーザーに表示する手間はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このガイドは**ペイウォールビルダーのペイウォール**専用です。リモートコンフィグのペイウォールを表示するプロセスは異なります。**リモートコンフィグのペイウォール**の表示については、[リモートコンフィグで設計したペイウォールのレンダリング](present-remote-config-paywalls)をご覧ください。 ::: ペイウォールを表示するには、[`createPaywallView`](capacitor-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。ペイウォールを再度表示する必要がある場合は、`createPaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用すると、エラーが発生する場合があります。 ::: ```typescript showLineNumbers const view = await createPaywallView(paywall); view.setEventHandlers({ onUrlPress(url) { window.open(url, '_blank'); return false; }, }); try { await view.present(); } catch (error) { // handle the error } ``` ## 開発者定義タイマーを使用する \{#use-developer-defined-timer\} モバイルアプリで開発者定義タイマーを使用するには、`timerId`(この例では `CUSTOM_TIMER_NY`)を使用します。これは、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。これにより、アプリはタイマーを正しい値(例:元旦までの残り時間を現在時刻から引いた `13d 09h 03m 34s` など)で動的に更新できます。 ```typescript showLineNumbers const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createPaywallView(paywall, { customTimers }); ``` この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。タイマーを使用することで、アプリは正しい値(例: `13d 09h 03m 34s`、タイマーの終了時刻(元日など)から現在時刻を引いて算出)でタイマーを動的に更新できます。 ## ダイアログの表示 \{#show-dialog\} Android でペイウォールビューが表示されている場合は、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートがペイウォールビューの背後に表示されてしまい、ユーザーには見えなくなります。このメソッドを使用することで、すべてのプラットフォームでペイウォールの上に正しくダイアログを表示できます。 ```typescript showLineNumbers title="Capacitor" try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## iOSの表示スタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOSでのペイウォールの表示スタイルを設定できます。このパラメーターには `'full_screen'`(デフォルト)または `'page_sheet'` を指定できます。 ```typescript showLineNumbers await view.present({ iosPresentationStyle: 'page_sheet' }); ``` </SDKv3> --- # File: capacitor-handle-paywall-actions --- --- title: "フローのアクションに応答する - Capacitor" description: "AdaptyのCapacitorを使用して、フローやペイウォールのボタンアクションを処理し、アプリの収益化を向上させましょう。" --- <SDKv4> Adaptyの[フロービルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)を使ってフローやペイウォールを構築している場合、ボタンを適切に設定することが重要です。 1. [ビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよび既存アクションをコードで処理する方法を説明します。 :::warning **購入、復元、フローとペイウォールのクローズ、URL のオープンは自動的に処理されます。** デフォルトの動作をカスタマイズしたり、カスタムアクションに対するレスポンスを実装したりできます。 ::: :::note イベントのハンドラーを設定すると、そのデフォルトの動作が完全に置き換えられます。設定しないハンドラーはデフォルトの動作を維持します。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローやペイウォールを閉じるボタンを追加するには: 1. ビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、フローやペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info Capacitor SDK では、`close` アクションはデフォルトでフローまたはペイウォールを閉じます。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるフローを閉じると同時に別のフローを開くといった実装が可能です。 ::: ```typescript showLineNumbers const view = await createFlowView(flow); const unsubscribe = await view.setEventHandlers({ onCloseButtonPress() { return true; // allow the flow to close }, }); ``` Androidでは、システムの **Back** ボタンとバックジェスチャーが別の `onAndroidSystemBack` イベントをトリガーします。SDK v4では、デフォルトでフローを閉じなくなりました。**Back** ボタンでフローを閉じたい場合は、ハンドラーから `true` を返してください: ```typescript showLineNumbers const unsubscribe = await view.setEventHandlers({ onAndroidSystemBack() { return true; // close the flow when the Back button is pressed }, }); ``` ## フローおよびペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクをまとめて追加したい場合(利用規約や購入の復元など)は、ビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: フローやペイウォールにリンクを開くボタンを追加するには(**Terms of use** や **Privacy policy** など): 1. ビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. 必要に応じて、アプリのコードに `openUrl` アクションのハンドラーを実装し、受け取ったURLを独自の方法で開きます。 :::info Capacitor SDKでは、URLをタップするとデフォルトでネイティブブラウザで開きます。SDKは`adapty.openWebUrl({ url, openIn })`を呼び出し、ビルダーで設定した**Open in**オプションに従いつつ、フローを開いたままにします。ただし、必要に応じてコードでこの動作を上書きすることも可能です。 ::: ```typescript showLineNumbers const unsubscribe = await view.setEventHandlers({ onUrlPress(url) { // Open the URL your own way, e.g. with the Capacitor Browser plugin Browser.open({ url }); return false; // keep the flow open }, }); ``` ## カスタムアクションを処理する \{#handle-custom-actions\} 他のアクションを処理するボタンを追加するには: 1. ビルダーでボタンを追加し、**Custom** アクションを割り当てて、IDを設定します。 2. アプリのコードで、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます: ```typescript showLineNumbers const unsubscribe = await view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another flow or paywall } }, }); ``` </SDKv4> <SDKv3> Adapty ペイウォールビルダーを使ってペイウォールを作成する場合、ボタンを適切に設定することが重要です。 1. [ペイウォールビルダーにボタンを追加し](paywall-buttons)、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、コード内でカスタムアクションおよび既存アクションを処理する方法を説明します。 ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info Capacitor SDK では、`close` アクションはデフォルトでペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコードでこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じたときに別のペイウォールを開くようにすることも可能です。 ::: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { console.log('User closed paywall'); return true; // Allow the paywall to close } }); ``` ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションが設定されたボタンと同じ方法で処理してください。 ::: ペイウォールにリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info Capacitor SDK では、`window.open` アクションはデフォルトで URL を開く動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。 ::: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onUrlPress(url) { window.open(url, '_blank'); return false; // Don't close the paywall }, }); ``` ## アプリにログインする \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコードで、ユーザーを識別する `login` アクションのハンドラーを実装します。 ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'login') { // Navigate to login screen console.log('User requested login'); } } }); ``` ## カスタムアクションを処理する \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当て、IDを設定します。 2. アプリのコードに、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のペイウォールを表示するボタンを追加できます: ```typescript showLineNumbers const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another paywall } }, }); ``` </SDKv3> --- # File: capacitor-handling-events --- --- title: "フロー・ペイウォールイベントの処理 - Capacitor" description: "Adapty の SDK を使用して Capacitor アプリでフローおよびペイウォールイベントを処理します。" --- <SDKv4> :::important このガイドでは、購入・復元・プロダクト選択・フローのレンダリングに関するイベント処理について説明します。ボタン操作(フローを閉じる、リンクを開く、カスタムアクションなど)のハンドリング設定については、[ボタンアクションの処理に関するガイド](capacitor-handle-paywall-actions)をご覧ください。 ::: [Flow Builder](adapty-flow-builder) で作成したフローとペイウォールは、購入や復元のために追加コードは不要です。ただし、アプリが対応できるイベントがいくつか生成されます。それらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や、フロー上で行われた購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。 アプリ内のフロー画面で発生するプロセスを制御・監視するには、`view.setEventHandlers` メソッドを実装してください。 :::important イベントごとに設定できるハンドラーは1つだけです。`setEventHandlers` を複数回呼び出すと、指定したハンドラーが上書きされ、対象イベントのデフォルトおよび以前に設定したハンドラーがいずれも置き換えられます。設定しなかったハンドラーはデフォルトの動作を維持します。`setEventHandlers` はアンサブスクライブ関数を返し、`view.dismiss()` はすべてのハンドラーをクリアします。 ::: ```typescript showLineNumbers const view = await createFlowView(flow); const unsubscribe = await view.setEventHandlers({ onCloseButtonPress() { return true; // close the flow (default behavior) }, onAndroidSystemBack() { return true; // close the flow; by default, it stays open }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type === 'success'; // close the flow on a successful purchase, keep it open for cancelled or pending purchases }, onPurchaseStarted(product) { /***/ }, onPurchaseFailed(error, product) { /***/ }, onRestoreCompleted(profile) { /***/ }, onRestoreFailed(error) { /***/ }, onProductSelected(productId) { /***/ }, onError(error) { /***/ }, onLoadingProductsFailed(error) { /***/ }, onUrlPress(url, openIn) { adapty.openWebUrl({ url, openIn }).catch(console.warn); // same as the SDK default return false; // keep the flow open }, onAppeared() { /***/ }, onDisappeared() { /***/ }, onWebPaymentNavigationFinished() { /***/ }, }); ``` <Details> <summary>イベントの例(クリックして展開)</summary> 以下の例は、各ハンドラーで利用可能なプロパティを、コメント内にサンプル値とともに示しています。 ```typescript // onUrlPress url; // 'https://example.com/terms' openIn; // 'browser_in_app' or 'browser_out_app' // onCustomAction actionId; // 'login' // onProductSelected productId; // 'premium_monthly' // onPurchaseStarted, onPurchaseCompleted, onPurchaseFailed product.vendorProductId; // 'premium_monthly' product.localizedTitle; // 'Premium Monthly' product.localizedDescription; // 'Premium subscription for 1 month' product.price?.amount; // 9.99 product.price?.currencyCode; // 'USD' product.price?.localizedString; // '$9.99' // onPurchaseCompleted purchaseResult.type; // 'success', 'pending', or 'user_cancelled' if (purchaseResult.type === 'success') { purchaseResult.profile.accessLevels['premium']?.isActive; // true } // onRestoreCompleted profile.accessLevels['premium']?.isActive; // true // onPurchaseFailed, onRestoreFailed, onError, onLoadingProductsFailed error.message; // 'Purchase failed due to insufficient funds' ``` </Details> 必要なイベントハンドラーだけを登録し、不要なものは省略できます。この場合、未使用のイベントリスナーは作成されません。必須のイベントハンドラーはありません。 イベントハンドラーはboolean値を返します。`true`が返された場合、表示プロセスが完了したとみなされ、フロー画面が閉じられ、そのビューのイベントリスナーが削除されます。 一部のイベントハンドラーにはデフォルトの動作があり、必要に応じてオーバーライドできます: - `onCloseButtonPress`: 閉じるボタンが押されたときにフローを閉じます。 - `onUrlPress`: タップされた URL を `adapty.openWebUrl` 経由でネイティブブラウザで開き、ビルダーで設定された **Open in** オプションを適用してフローを開いたままにします。 - `onAndroidSystemBack`: **Back** ボタンが押されたときにフローを開いたままにします。閉じるには `true` を返してください。 - `onPurchaseCompleted`: 購入完了後もフローを開いたままにします。閉じるには `true` を返してください。 - `onRestoreCompleted`: 復元が成功した後もフローを開いたままにします。閉じるには `true` を返してください。 - `onError`: レンダリングに失敗した場合にフローを閉じます。 ### イベントハンドラー \{#event-handlers\} | イベントハンドラー | 説明 | |:-----------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | ユーザーがカスタムアクションを実行したとき(例:[カスタムボタン](paywall-buttons)のクリック)に呼び出されます。 | | **onUrlPress** | ユーザーがフロー内のURLをクリックしたときに呼び出されます。 | | **onAndroidSystemBack** | ユーザーがAndroidのシステムの**Back**ボタンをタップしたときに呼び出されます。デフォルトではフローは開いたままです。`true`を返すと閉じます。 | | **onCloseButtonPress** | 閉じるボタンが表示されており、ユーザーがそれをタップしたときに呼び出されます。このハンドラー内でフロー画面を閉じることを推奨します。 | | **onPurchaseCompleted** | 購入が完了したとき(成功・ユーザーによるキャンセル・承認待ちのいずれの場合も)に呼び出されます。購入が成功した場合は、更新済みの`AdaptyProfile`が提供されます。ユーザーによるキャンセルや保留中の支払い(例:ペアレンタルアプルーバルが必要な場合)は`onPurchaseFailed`ではなく、このイベントをトリガーします。 | | **onPurchaseStarted** | ユーザーが「購入」アクションボタンをタップして購入プロセスを開始したときに呼び出されます。 | | **onPurchaseFailed** | エラー(例:支払い制限、無効なプロダクト、ネットワーク障害、トランザクション検証の失敗)によって購入が失敗したときに呼び出されます。ユーザーによるキャンセルや保留中の支払いではなく、それらは代わりに`onPurchaseCompleted`をトリガーします。 | | **onRestoreStarted** | ユーザーが購入の復元プロセスを開始したときに呼び出されます。 | | **onRestoreCompleted** | 購入の復元が成功し、更新済みの`AdaptyProfile`が提供されたときに呼び出されます。ユーザーが必要な`accessLevel`を持っている場合は画面を閉じることを推奨します。確認方法については[サブスクリプションのステータス](capacitor-listen-subscription-changes)を参照してください。 | | **onRestoreFailed** | 復元プロセスが失敗し、`AdaptyError`が提供されたときに呼び出されます。 | | **onProductSelected** | フロービュー内でいずれかのプロダクトが選択されたときに呼び出されます。購入前にユーザーが選択した内容を確認できます。 | | **onError** | ビューのレンダリング中にエラーが発生し、`AdaptyError`が提供されたときに呼び出されます。このようなエラーは本来発生しないものです。発生した場合はご報告ください。 | | **onLoadingProductsFailed** | プロダクトの読み込みが失敗し、`AdaptyError`が提供されたときに呼び出されます。ビュー作成時に`prefetchProducts: true`を設定していない場合、AdaptyUIがサーバーから必要なオブジェクトを自動取得します。 | | **onAppeared** | フローがユーザーに表示されたときに呼び出されます。iOSでは、ユーザーがフロー内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップし、アプリ内ブラウザでウェブペイウォールが開いたときにも呼び出されます。 | | **onDisappeared** | フローがユーザーによって閉じられたときに呼び出されます。iOSでは、フローからアプリ内ブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えたときにも呼び出されます。 | | **onWebPaymentNavigationFinished** | [ウェブペイウォール](web-paywall)を購入のために開こうとした後(成功・失敗を問わず)に呼び出されます。 | | **onRequestAppReview** | フローからのアプリレビューリクエスト用に予約されています。フローはまだアプリレビューリクエストをトリガーしないため、実装は不要です。 | | **onAnalytics** | フローからのカスタム分析イベント用に予約されています。フローはまだこれらをコードに送出しないため、実装は不要です。 | | **onRequestPermission** | フローからのシステム権限リクエスト(プッシュ通知やカメラアクセスなど)用に予約されています。フローはまだ権限リクエストをトリガーしないため、実装は不要です。 | | **onObserverPurchaseInitiated** | オブザーバーモード専用:ユーザーがフロー内の購入ボタンをタップしたときに呼び出されます。Adaptyは購入を実行しません。独自の購入コードで購入を行い、その後トランザクションをAdaptyに報告してください。下記の[オブザーバーモードでの購入処理](#handle-purchases-in-observer-mode)を参照してください。 | | **onObserverRestoreInitiated** | オブザーバーモード専用:ユーザーがフロー内の復元ボタンをタップしたときに呼び出されます。Adaptyは復元を実行しません。自分で復元を行い、復元されたトランザクションを報告してください。下記の[オブザーバーモードでの購入処理](#handle-purchases-in-observer-mode)を参照してください。 | ### オブザーバーモードでの購入処理 \{#handle-purchases-in-observer-mode\} [オブザーバーモード](implement-observer-mode-capacitor)(`observerMode: true`)でSDKを有効化し、Adaptyがレンダリングするフローを表示している場合、SDKは購入処理を自動で行いません。ユーザーが購入ボタンまたは復元ボタンをタップすると、SDKは`onObserverPurchaseInitiated`または`onObserverRestoreInitiated`を呼び出すので、独自のコードで購入や復元を実行できます。詳細なセットアップ手順は[オブザーバーモードでのフローの表示](capacitor-present-flows-in-observer-mode)を参照してください。 </SDKv4> <SDKv3> :::important このガイドでは、購入、復元、プロダクト選択、ペイウォールのレンダリングに関するイベント処理を説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の処理も実装する必要があります。詳しくは[ボタンアクションの処理に関するガイド](capacitor-handle-paywall-actions)をご覧ください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定したペイウォールは、購入や復元のために追加コードは不要です。ただし、アプリが応答できるイベントが発生します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連アクションの通知が含まれます。これらのイベントへの対応方法については以下をご覧ください。 モバイルアプリ内でペイウォール画面上の処理を制御・監視するには、`view.setEventHandlers` メソッドを実装してください: ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { console.log('User closed paywall'); return true; // Allow the paywall to close }, onAndroidSystemBack() { console.log('User pressed back button'); return true; // Allow the paywall to close }, onAppeared() { console.log('Paywall appeared'); return false; // Don't close the paywall }, onDisappeared() { console.log('Paywall disappeared'); }, onPurchaseCompleted(purchaseResult, product) { console.log('Purchase completed:', purchaseResult); return purchaseResult.type !== 'user_cancelled'; // Close if not cancelled }, onPurchaseStarted(product) { console.log('Purchase started:', product); return false; // Don't close the paywall }, onPurchaseFailed(error, product) { console.error('Purchase failed:', error); return false; // Don't close the paywall }, onRestoreCompleted(profile) { console.log('Restore completed:', profile); return true; // Close the paywall after successful restore }, onRestoreFailed(error) { console.error('Restore failed:', error); return false; // Don't close the paywall }, onProductSelected(productId) { console.log('Product selected:', productId); return false; // Don't close the paywall }, onRenderingFailed(error) { console.error('Rendering failed:', error); return false; // Don't close the paywall }, onLoadingProductsFailed(error) { console.error('Loading products failed:', error); return false; // Don't close the paywall }, onUrlPress(url) { window.open(url, '_blank'); return false; // Don't close the paywall }, }); ``` <Details> <summary>イベント例(クリックして展開)</summary> ```typescript // onCloseButtonPress { "event": "close_button_press" } // onAndroidSystemBack { "event": "android_system_back" } // onAppeared { "event": "paywall_shown" } // onDisappeared { "event": "paywall_closed" } // onUrlPress { "event": "url_press", "url": "https://example.com/terms" } // onCustomAction { "event": "custom_action", "actionId": "login" } // onProductSelected { "event": "product_selected", "productId": "premium_monthly" } // onPurchaseStarted { "event": "purchase_started", "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // onPurchaseCompleted - Success { "event": "purchase_completed", "purchaseResult": { "type": "success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // onPurchaseCompleted - Cancelled { "event": "purchase_completed", "purchaseResult": { "type": "user_cancelled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } // onPurchaseFailed { "event": "purchase_failed", "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } // onRestoreCompleted { "event": "restore_completed", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } // onRestoreFailed { "event": "restore_failed", "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } // onRenderingFailed { "event": "rendering_failed", "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } // onLoadingProductsFailed { "event": "loading_products_failed", "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> 必要なイベントハンドラーだけ登録し、不要なものは省略できます。この場合、未使用のイベントリスナーは作成されません。必須のイベントハンドラーはありません。 イベントハンドラーはブール値を返します。`true` を返すと、表示プロセスが完了したとみなされ、ペイウォール画面が閉じられ、このビューのイベントリスナーが削除されます。 一部のイベントハンドラーにはデフォルトの動作があり、必要に応じてオーバーライドできます: - `onCloseButtonPress`: 閉じるボタンが押されたときにペイウォールを閉じます。 - `onAndroidSystemBack`: **Back** ボタンが押されたときにペイウォールを閉じます。 - `onRestoreCompleted`: 復元が成功した後にペイウォールを閉じます。 - `onPurchaseCompleted`: ユーザーがキャンセルしない限りペイウォールを閉じます。 - `onRenderingFailed`: レンダリングに失敗した場合にペイウォールを閉じます。 - `onUrlPress`: システムブラウザでURLを開き、ペイウォールは閉じません。 ### イベントハンドラー \{#event-handlers\} | イベントハンドラー | 説明 | |:----------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | ユーザーがカスタムアクション(例:[カスタムボタン](paywall-buttons)のクリック)を実行したときに呼び出されます。 | | **onUrlPress** | ユーザーがペイウォール内のURLをクリックしたときに呼び出されます。 | | **onAndroidSystemBack** | ユーザーがAndroidのシステム **Back** ボタンをタップしたときに呼び出されます。 | | **onCloseButtonPress** | 閉じるボタンが表示されていてユーザーがそれをタップしたときに呼び出されます。このハンドラー内でペイウォール画面を閉じることを推奨します。 | | **onPurchaseCompleted** | 購入が完了したときに呼び出されます(成功・ユーザーによるキャンセル・承認待ちのいずれの場合も)。購入が成功した場合は、更新された `AdaptyProfile` が提供されます。ユーザーによるキャンセルや支払い保留(保護者の承認が必要な場合など)は、`onPurchaseFailed` ではなくこのイベントをトリガーします。 | | **onPurchaseStarted** | ユーザーが「購入」アクションボタンをタップして購入プロセスを開始したときに呼び出されます。 | | **onPurchaseCancelled** | ユーザーが購入プロセスを開始した後、手動で中断(支払いダイアログをキャンセル)したときに呼び出されます。 | | **onPurchaseFailed** | エラー(支払い制限、無効なプロダクト、ネットワーク障害、取引検証の失敗など)によって購入が失敗したときに呼び出されます。ユーザーによるキャンセルや支払い保留の場合は呼び出されず、代わりに `onPurchaseCompleted` がトリガーされます。 | | **onRestoreStarted** | ユーザーが購入の復元プロセスを開始したときに呼び出されます。 | | **onRestoreCompleted** | 購入の復元が成功したときに呼び出され、更新された `AdaptyProfile` が提供されます。ユーザーが必要な `accessLevel` を持っている場合は画面を閉じることを推奨します。確認方法については[サブスクリプションのステータス](capacitor-listen-subscription-changes)を参照してください。 | | **onRestoreFailed** | 復元プロセスが失敗したときに呼び出され、`AdaptyError` が提供されます。 | | **onProductSelected** | ペイウォールビュー内のいずれかのプロダクトが選択されたときに呼び出されます。購入前にユーザーが何を選択しているかを把握できます。 | | **onAppeared** | ペイウォールビューが画面に表示されたときに呼び出されます。iOS では、ユーザーがペイウォール内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップしてインアプリブラウザでウェブペイウォールが開いた場合にも呼び出されます。 | | **onDisappeared** | ペイウォールビューが画面から消えたときに呼び出されます。iOS では、ペイウォールからインアプリブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えた場合にも呼び出されます。 | | **onRenderingFailed** | ビューのレンダリング中にエラーが発生したときに呼び出され、`AdaptyError` が提供されます。このようなエラーは通常発生しないため、もし遭遇した場合はお知らせください。 | | **onLoadingProductsFailed** | プロダクトの読み込みが失敗したときに呼び出され、`AdaptyError` が提供されます。ビュー作成時に `prefetchProducts: true` を設定していない場合、AdaptyUI が自動的にサーバーから必要なオブジェクトを取得します。 | </SDKv3> --- # File: capacitor-use-fallback-paywalls --- --- title: "Capacitor - フォールバックペイウォールを使用する" description: "ユーザーがオフラインの場合やAdaptyサーバーが利用できない場合の対応方法" --- スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} ### Android 1. フォールバック設定ファイルをアプリケーションに追加します。以下のいずれかのディレクトリを選択してください: * **android/app/src/main/assets/** * **android/app/src/main/res/raw/** :::note `res/raw` フォルダには特別なファイル命名規則があります(先頭は英字、大文字不可、アンダースコア以外の特殊文字不可、スペース不可)。 ::: 2. `FileLocation` 定数の `android` プロパティを更新してください: * ファイルが `assets` ディレクトリにある場合は、そのディレクトリからの相対パスを渡してください。 * ファイルが `res/raw` ディレクトリにある場合は、拡張子なしのファイル名を渡してください。 ### iOS 1. フォールバックJSONファイルをプロジェクトバンドルに追加します:XCodeの **File** メニューを開き、**Add Files to "YourProjectName"** を選択します。 2. 設定ファイルの名前を `FileLocation` 定数の `ios` プロパティに指定します。 ## 例 \{#example\} ```typescript showLineNumbers const fileLocation = { ios: { fileName: 'ios_fallback.json' }, android: { //if the file is located in 'android/app/src/main/assets/' relativeAssetPath: 'android_fallback.json' } }; await adapty.setFallback({ fileLocation }); ``` :::important `setFallback` は、SDK がターゲットのフロー、ペイウォール、またはオンボーディングを取得する前に実行する必要があります。 ::: パラメーター: | パラメーター | 説明 | | :------------------- | :------------------------------------------------------- | | **fileLocation** | フォールバック設定ファイルの場所を表すオブジェクト。 | --- # File: capacitor-localizations-and-locale-codes --- --- title: "Capacitor SDKでローカライゼーションとロケールコードを使用する" description: "Adapty SDKを使用してCapacitorアプリのペイウォールをローカライズする方法を学びましょう。" --- <SDKv4> ## これが重要な理由 \{#why-this-is-important\} ロケールコードは、Adaptyがフローのローカライズを選択するときや、カスタムペイウォール向けのリモートコンフィグを読み込むときに使われます。 ロケールコードはプラットフォームによって異なる場合があり複雑なため、Adaptは対応するすべてのプラットフォームで1つの内部標準に統一しています。この標準を理解することで、ユーザーがどのローカライズを受け取るかを予測できます。 ## 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. Adapty はロケールコードが完全に一致するローカライズを検索します 3. 一致するものが見つからない場合、最初のハイフンより前の部分文字列(`pt-br` に対しては `pt`)を使って一致するローカライズを検索します 4. それでも一致するものが見つからない場合、Adapty はデフォルトの `en` ローカライズを返します このため、`'pt_BR'`、`pt-BR`、`pt-br` はすべて同じローカライズに解決されます。 ## ローカライズの実装 \{#implementing-localizations\} SDK v4では、フローを取得する際にロケールコードを渡す必要はありません。 - **フロービルダーおよびペイウォールビルダーのペイウォール**: Adapty は、デバイスの設定とビルダーで設定したローカライズをもとに、自動でローカライズを解決します。`createFlowView` でフローをレンダリングするだけで、ロケールコードは不要です。 - **カスタム(リモートコンフィグ)ペイウォール**: `getFlow` は設定されたすべてのローカライズを `flow.remoteConfigs` に返します。各エントリには `lang` コードと `data` オブジェクトが含まれます。ユーザーに合ったエントリを独自のフォールバックロジックで選択してください。 ```typescript showLineNumbers const flow = await adapty.getFlow({ placementId: 'placement_id' }); const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0]; // read your values from config?.data ``` 上記のロケールコードのマッチングルールは、Adapty が各リモートコンフィグに保存されている `lang` コードを正規化する方法を説明しています。 </SDKv4> <SDKv3> ## これが重要な理由 \{#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 を呼び出す際にそのキーの値を取り出して使用します。例を示します: ```javascript showLineNumbers // 1. Modify your localization files (e.g., using react-i18next) /* en.json */ { "adapty_paywalls_locale": "en" } /* es.json */ { "adapty_paywalls_locale": "es" } /* pt-BR.json */ { "adapty_paywalls_locale": "pt-br" } // 2. Extract and use the locale code const MyComponent = () => { const { t } = useTranslation(); const fetchPaywall = async () => { const locale = t('adapty_paywalls_locale'); // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; }; ``` That way you can ensure you're in full control of what localization will be retrieved for every user of your app. ## ローカライゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} すべてのローカライゼーションにロケールコードを明示的に定義しなくても、同様の(ただし完全に同一ではない)結果を得ることができます。これは、プラットフォームが提供する他のオブジェクトからロケールコードを取得する方法です。例えば次のようにします: ```javascript showLineNumbers const getLocaleCode = () => { if (Capacitor.getPlatform() === 'ios') { return navigator.language || 'en'; } else { return navigator.language || 'en'; } }; const fetchPaywall = async () => { const locale = getLocaleCode(); // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; ``` この方法はいくつかの理由からお勧めしません: 1. iOSでは、優先言語と現在のロケールは必ずしも同一ではありません。ローカライゼーションが正しく選択されるようにするには、ローカライズされた文字列ファイルを使用する推奨アプローチを採用してAppleのロジックに任せるか、自分でそれを再現する必要があります。 2. Adaptyのサーバーが実際に何を受け取るかを予測するのは難しい場合があります。たとえばiOSでは、デバイスから `ar_OM@numbers='latn'` のようなロケールを取得してサーバーに送信することがあります。この場合、期待していた `ar-om` ローカライゼーションではなく、`ar` が返されることになり、意図しない結果になる可能性があります。 そのアプローチを使用する場合は、関連するすべてのユースケースを確実にカバーしてください。 </SDKv3> --- # File: capacitor-web-paywall --- --- title: "Webペイウォールの実装" description: "Adapty SDKを使ってCapacitorアプリにWebペイウォールを実装する方法を学びましょう。" --- :::important 始める前に、[ダッシュボードでWebペイウォールを設定](web-paywall)し、Adapty SDKバージョン3.6.1以降をインストールしていることを確認してください。 ::: ## Webペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールでWebペイウォールを扱う場合は、SDKのメソッドを使用する必要があります。`.openWebPaywall` メソッドは以下を行います: 1. Adaptyが特定のユーザーに表示されたペイウォールとリダイレクト先のWebページを紐付けるための一意のURLを生成します。 2. ユーザーがアプリに戻ったタイミングを追跡し、プロファイルのアクセス権が更新されたかどうかを確認するために短い間隔で `.getProfile` を呼び出します。 支払いが成功してアクセス権が更新されると、サブスクリプションはほぼ即座にアプリ内で有効になります。 ```typescript showLineNumbers try { await adapty.openWebPaywall({ paywallOrProduct: product }); } catch (error) { console.error('Failed to open web paywall:', error); } ``` :::note `openWebPaywall` メソッドには2つのバージョンがあります: 1. `openWebPaywall({ paywallOrProduct: product })` — ペイウォールを基にURLを生成し、プロダクトデータもURLに追加します。 2. `openWebPaywall({ paywallOrProduct: paywall })` — ペイウォールを基にURLを生成しますが、プロダクトデータはURLに追加しません。AdaptyのペイウォールのプロダクトがWebペイウォールのプロダクトと異なる場合に使用してください。 SDK v4では、`paywallOrProduct`のペイウォール側は`AdaptyFlowPaywall`(取得したフローのペイウォールバリアント)を受け取ります。インデックスアクセスする前に`flow.paywalls`が空でないことを確認してください(例:`flow.paywalls[0]`)。 ::: #### エラーの処理 \{#handle-errors\} | エラー | 説明 | 推奨される対処法 | |-----------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | ペイウォールにウェブ購入 URL が設定されていません | Adapty ダッシュボードでペイウォールが正しく設定されているか確認してください | | AdaptyError.productWithoutPurchaseUrl | プロダクトにウェブ購入 URL がありません | Adapty ダッシュボードでプロダクトの設定を確認してください | | AdaptyError.failedOpeningWebPaywallUrl | ブラウザで URL を開くことができませんでした | デバイスの設定を確認するか、別の購入方法を提供してください | | AdaptyError.failedDecodingWebPaywallUrl | URL 内のパラメーターを正しくエンコードできませんでした | URL パラメーターが有効かつ正しい形式であるか確認してください | ## ウェブペイウォールのURLを自分で取得する \{#get-the-web-paywall-url-without-opening-it\} SDKにページを開かせるのではなく、ウェブ購入ページを自分で表示したい場合は、`createWebPaywallUrl` を使用してください。これは `openWebPaywall` が開くのと同じ固有のURLを返すので、独自のウェブビューでレンダリングしたり、リダイレクトを自分でハンドリングしたりできます。引数には `openWebPaywall` と同じ `paywallOrProduct` を渡します。フェッチしたフローのペイウォールバリアント(`AdaptyFlowPaywall`)または `AdaptyPaywallProduct` を指定できます。 ```typescript showLineNumbers try { const url = await adapty.createWebPaywallUrl({ paywallOrProduct: product }); // open `url` in your own web view, or handle the redirect yourself } catch (error) { console.error('Failed to create web paywall URL:', error); } ``` :::note 任意のURL(ウェブペイウォール以外)をネイティブブラウザで開く場合——たとえばフローのボタンから——は、代わりに [`adapty.openWebUrl`](capacitor-handle-paywall-actions#open-urls-from-flows-and-paywalls) を使用してください。 ::: ## ウェブペイウォールをアプリ内ブラウザで開く \{#open-web-paywalls-in-an-in-app-browser\} :::important アプリ内ブラウザでウェブペイウォールを開く機能は、Adapty SDK v3.15 以降でサポートされています。 ::: デフォルトでは、ウェブペイウォールは外部ブラウザで開きます。 シームレスなユーザー体験を提供するために、ウェブペイウォールをアプリ内ブラウザで開くことができます。これにより、アプリを切り替えることなく、アプリ内でウェブ購入ページを表示してトランザクションを完了できます。 これを有効にするには、`openWebPaywall` の `openIn` に `WebPresentation.BrowserInApp` を設定します。 ```typescript showLineNumbers try { await adapty.openWebPaywall({ paywallOrProduct: product, openIn: WebPresentation.BrowserInApp, // default – WebPresentation.BrowserOutApp }); } catch (error) { console.error('Failed to open web paywall:', error); } ``` --- # File: capacitor-present-flows-in-observer-mode --- --- title: "Capacitor SDKのObserverモードでフローを表示する" description: "Capacitor アプリの Observer モードでフローとペイウォールビルダーのペイウォールを表示し、独自のコードで購入を処理します。" --- ビルダーを使用してフローやペイウォールをカスタマイズした場合、それをモバイルアプリのコードでレンダリングしてユーザーに表示する方法を気にする必要はありません。このようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このセクションは[オブザーバーモード](observer-vs-full-mode)専用です。オブザーバーモードで作業していない場合は、[フローとペイウォールの表示](capacitor-present-paywalls)のトピックを参照してください。 ::: :::info この機能を使用するには Adapty Capacitor SDK 4.0 以降が必要です。以前はネイティブの iOS および Android SDK でのみ利用可能でした。アップグレードするには[移行ガイド](migration-to-capacitor-sdk-v4)を参照してください。 ::: <details> <summary>フローの表示を始める前に(クリックして展開)</summary> 1. Adaptyを[App Storeと連携](initial_ios)、および[Google Playと連携](initial-android)するための初期設定を行います。 2. Adapty SDKをインストールして設定します。`observerMode`パラメータを`true`に設定してください。[Capacitor SDKインストールガイド](sdk-installation-capacitor#activate-adapty-module-of-adapty-sdk)を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. [ビルダーでフローまたはペイウォールを設定](create-paywall)し、プロダクトを割り当てます。 5. [プレースメントを作成し、フローまたはペイウォールを割り当てます](create-placement)。 6. モバイルアプリのコード内で[フローとその設定を取得](capacitor-get-pb-paywalls)します。 </details> オブザーバーモードでは、SDKが代わりに購入処理を行うことはありません。ユーザーがAdaptyでレンダリングされたフローまたはペイウォールの購入ボタンや復元ボタンをタップすると、SDKは購入や復元を実行する代わりに `onObserverPurchaseInitiated` または `onObserverRestoreInitiated` イベントハンドラーを呼び出します。そこで独自のコードを使って購入・復元処理を行ってください。 1. ビューにオブザーバーモードのイベントハンドラーを設定します。他のプラットフォームとは異なり、リゾルバーオブジェクトは別途存在せず、ハンドラーは通常の[イベントハンドラー](capacitor-handling-events)の一部です。そのため、作成するすべてのビューに設定してください。 ```typescript showLineNumbers title="Capacitor" import { adapty, createFlowView } from '@adapty/capacitor'; const view = await createFlowView(flow); const unsubscribe = await view.setEventHandlers({ onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) { onStartPurchase(); // the view shows its loading indicator myPurchaseApi(product.vendorProductId) .then((transactionId) => adapty.reportTransaction({ transactionId, variationId: flow.variationId }), ) .finally(() => onFinishPurchase()); // the view hides the loading indicator return false; // keep the flow open; dismiss it yourself after success }, onObserverRestoreInitiated(onStartRestore, onFinishRestore) { onStartRestore(); myRestoreApi().finally(() => onFinishRestore()); return false; }, }); ``` `onObserverPurchaseInitiated` ハンドラーはユーザーが購入を開始したことを、`onObserverRestoreInitiated` はユーザーがリストアを開始したことをそれぞれ通知します。これらを受け取ったら、カスタムの購入またはリストアフローを実行してください。 また、購入やリストアの処理状況を AdaptyUI に通知するために、以下のコールバックも必ず呼び出してください。ローダーの表示など、フローが正しく動作するために必要です。 | コールバック | 説明 | | :----------------- | :------------------------------------------------------------------------------- | | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | | onStartRestore() | 復元が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishRestore() | 復元が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | 2. 通常通りフロービューを表示します:[フローを取得してビューを作成し](capacitor-get-pb-paywalls)、[表示します](capacitor-present-paywalls)。追加のパラメータは不要です — ハンドラーは SDK が `observerMode: true` で起動された場合にのみ実行されます。 :::warning [トランザクションを報告してペイウォールと関連付ける](report-transactions-observer-mode-capacitor)ことを忘れないでください。これを行わないと、Adapty はトランザクションを認識できず、購入元のペイウォールを特定できません。 ::: --- # File: capacitor-implement-paywalls-manually --- --- title: "ペイウォールを手動で実装する" description: "Adapty SDK を使って Capacitor アプリでペイウォールを手動で実装する方法を学びましょう。" --- ## 購入を受け付ける \{#accept-purchases\} 自分で実装したペイウォールを使用している場合、`makePurchase` メソッドを使って購入処理を Adapty に委任できます。これにより、すべてのユーザーシナリオは Adapty が処理し、開発者は購入結果の処理だけに集中できます。 :::important `makePurchase` は Adapty ダッシュボードで作成したプロダクトと連携します。[クイックスタートガイド](quickstart)に従って、ダッシュボードでプロダクトの設定と取得方法を必ず構成してください。 ::: <CustomDocCardList ids={['capacitor-quickstart-manual', 'fetch-paywalls-and-products-capacitor', 'present-remote-config-paywalls-capacitor', 'capacitor-making-purchases', 'capacitor-restore-purchase']} /> ## オブザーバーモード \{#observer-mode\} 購入処理ロジックをゼロから独自に実装したい場合でも、Adapty の高度な分析機能を活用したいなら、オブザーバーモードを使用できます。 :::important オブザーバーモードの制限事項については[こちら](observer-vs-full-mode)をご確認ください。 ::: <CustomDocCardList ids={['implement-observer-mode-capacitor', 'report-transactions-observer-mode-capacitor']} /> --- # File: capacitor-quickstart-manual --- --- title: "Capacitor SDKのカスタムペイウォールで購入を有効化する" description: "Adapty SDKをカスタムのCapacitorペイウォールに統合して、アプリ内課金を有効化します。" --- このガイドでは、カスタムペイウォールへのAdaptyの統合方法を説明します。Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を担当しながら、ペイウォールの実装を完全にコントロールできます。このガイドはAdapty Capacitor SDK v4のAPIを使用しています。v3をお使いの場合は、対応するメソッド名について[移行ガイド](migration-to-capacitor-sdk-v4)をご覧ください。 :::important **このガイドは、カスタムペイウォールを実装する開発者向けです。** 課金を最も簡単に導入したい場合は、[Adapty ペイウォールビルダー](capacitor-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 は匿名ユーザーと識別済みユーザーを異なる方法で扱います。詳細と正しいユーザー管理の方法については、[識別クイックスタートガイド](capacitor-quickstart-identify)をご覧ください。 ## ステップ 1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、以下の手順を実行します: 1. [プレースメント](placements) ID を `getFlow` メソッドに渡して `flow` オブジェクトを取得します。 2. `getPaywallProducts` メソッドを使って、このフローのプロダクト配列を取得します。 ```typescript showLineNumbers async function loadPaywall() { try { const flow: AdaptyFlow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); const products: AdaptyPaywallProduct[] = await adapty.getPaywallProducts({ flow }); // Use products to build your custom paywall UI } catch (error) { // Handle the error } } ``` ## ステップ2:購入を受け付ける \{#step-2-accept-purchases\} ユーザーがカスタムペイウォール上のプロダクトをタップしたら、選択されたプロダクトで `makePurchase` メソッドを呼び出します。これにより購入フローが処理され、更新されたプロファイルが返されます。 ```typescript showLineNumbers async function purchaseProduct(product: AdaptyPaywallProduct) { try { const result: AdaptyPurchaseResult = await adapty.makePurchase({ product }); if (result.type === 'success') { // Purchase successful, profile updated } else if (result.type === 'user_cancelled') { // User canceled the purchase } else if (result.type === 'pending') { // Purchase is pending (e.g., user will pay offline with cash) } } catch (error) { // Handle the error } } ``` ## ステップ3. 購入を復元する \{#step-3-restore-purchases\} アプリストアは、サブスクリプションを提供するすべてのアプリに対して、ユーザーが購入を復元できる手段を設けることを義務付けています。 ユーザーが復元ボタンをタップしたときに `restorePurchases` メソッドを呼び出してください。これにより、購入履歴がAdaptyと同期され、更新されたプロファイルが返されます。 ```typescript showLineNumbers async function restorePurchases() { try { const profile: AdaptyProfile = await adapty.restorePurchases(); // Restore successful, profile updated } catch (error) { // Handle the error } } ``` ## ステップ 4. サブスクリプションのステータスを確認する \{#step-4-check-the-subscription-status\} 購入またはリストア後、ペイウォールを表示するか有料機能をアンロックするかを判断するために、ユーザーの[アクセスレベル](access-level)を確認してください。`makePurchase` および `restorePurchases` メソッドはすでに更新済みのプロファイルを返しますが、アプリ内の他の場所で現在のステータスが必要な場合は `getProfile` メソッドを使用してください。 ```typescript showLineNumbers async function hasPremiumAccess(): Promise<boolean> { try { const profile = await adapty.getProfile(); return profile.accessLevels?.['premium']?.isActive ?? false; } catch (error) { // Handle the error } return false; } ``` サブスクリプションのステータスを確認・監視する方法(リアルタイムの更新を受け取る方法を含む)については、[サブスクリプションのステータスを確認する](capacitor-check-subscription-status)を参照してください。 ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備が整いました。[App Store サンドボックス](test-purchases-in-sandbox)または[Google Play ストア](testing-on-android)でテスト購入を行い、ペイウォールからテスト購入を完了できることを確認してください。本番環境に対応した実装例については、サンプルアプリの [App.tsx](https://github.com/adaptyteam/AdaptySDK-Capacitor/blob/master/examples/adapty-devtools/src/screens/app/App.tsx) を参照してください。適切なエラーハンドリング、ローディング状態、および包括的な SDK インテグレーションを含む購入処理の実装例を確認できます。 --- # File: fetch-paywalls-and-products-capacitor --- --- title: "Capacitor SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "Adapty Capacitor SDKでペイウォールとプロダクトを取得し、ユーザーの収益化を強化します。" --- <SDKv4> リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。**Flow Builder** や **Paywall Builder** でカスタマイズされたフローやペイウォールの取得方法については、[Flow Builder のフローと Paywall Builder のペイウォールおよびその設定を取得する](capacitor-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでフローとプロダクトの取得を開始する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[フローまたはペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに[Adapty SDK をインストール](sdk-installation-capacitor)する。 </details> ## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)はApp StoreとGoogle Play両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームのプロダクトはフローやペイウォールに統合されており、モバイルアプリ内の特定のプレースメントで表示できます。 プロダクトを表示するには、`getFlow` メソッドを使って、いずれかの[プレースメント](placements)から `AdaptyFlow` を取得する必要があります。 :::important **プロダクト ID をハードコードしないでください。** ハードコードすべき ID はプレースメント ID のみです。フローはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変更される可能性があります。アプリはこれらの変更を動的に処理する必要があります。フローが今日は 2 つのプロダクトを返し、明日は 3 つを返す場合でも、コードを変更せずにすべてを表示できるようにしてください。 ::: ```typescript showLineNumbers try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); // the requested flow } catch (error) { console.error('Failed to fetch flow:', error); } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **params.fetchPolicy** | <p>任意</p><p>デフォルト: `'reload_revalidating_cache_data'`</p> | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット環境が不安定な場合は、`'return_cache_data_else_load'` を使用してキャッシュが存在する場合はそれを返すことを検討してください。この場合、最新データが取得できないこともありますが、接続状況に関わらずより速い読み込みが期待できます。キャッシュは定期的に更新されるため、ネットワークリクエストを減らすためにセッション中に使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はフローとペイウォールを2つの層で保存しています。1つは上述の定期更新されるキャッシュ、もう1つは[フォールバックペイウォール](capacitor-use-fallback-paywalls)です。また、フローとペイウォールをより速く取得するために CDN を使用し、CDN に到達できない場合に備えてスタンドアローンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも信頼性を確保しながら、常に最新のフローを取得できるよう設計されています。</p> | | **params.loadTimeoutMs** | <p>任意</p><p>デフォルト: 5000 ms</p> | <p>このメソッドのタイムアウト(ミリ秒)を制限する値です。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p></p><p>このメソッドは内部で複数のリクエストを行う場合があるため、まれに `loadTimeoutMs` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p> | :::note v4 では、`getFlow` は `locale` パラメータを受け取らなくなりました。カスタムペイウォールの場合、利用可能なすべてのロケールはフローのリモートコンフィグ(`flow.remoteConfigs`)で返されます。ユーザーのデバイスまたはアプリの設定に合うものを選択してください。 ::: プロダクト ID をハードコードしないでください!フローはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特別オファー(無料トライアルなど)は随時変更される可能性があります。コードがこれらのシナリオに対応できるようにしてください。 たとえば、最初に 2 つのプロダクトを取得した場合、アプリはその 2 つを表示する必要があります。その後 3 つのプロダクトを取得した場合は、コードを変更することなく 3 つすべてを表示できるようにしてください。ハードコードする必要があるのはプレースメント ID だけです。 レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | プレースメント、識別子(`id`、`variationId`)、名前、ペイウォールのバリアント(`paywalls`)、および設定済みロケールごとに1エントリの `remoteConfigs` 配列を含む `AdaptyFlow` オブジェクト。フローのプロダクトを取得するには、`getPaywallProducts({ flow })` を呼び出してください。 | ## プロダクトの取得 \{#fetch-products\} フローを取得したら、それに対応するプロダクトの配列を取得できます。 ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ flow }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) オブジェクトのリストで、プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティが含まれます。 | 独自のペイウォールデザインを実装する際には、[`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。よく使用されるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づきます。 | | **Price** | ローカライズされた価格を表示するには、`product.price?.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づきます。`product.price?.amount` を使うと、数値として価格を取得することもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには、`product.price?.currencySymbol` を使用します。 | | **Subscription Period** | サブスクリプション期間(週・月・年など)を表示するには、`product.subscription?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づきます。サブスクリプション期間をプログラムで取得するには、`product.subscription?.subscriptionPeriod` を使用します。ここから `unit` プロパティにアクセスすると、期間の単位(`'day'`・`'week'`・`'month'`・`'year'`・`'unknown'`)を取得できます。`numberOfUnits` の値で期間の単位数を取得できます。たとえば四半期ごとのサブスクリプションの場合、`unit` プロパティは `'month'`、`numberOfUnits` は `3` となります。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかどうかをバッジなどで示すには、`product.subscription?.offer?.phases` プロパティを確認してください。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下の便利なプロパティがあります:<br/>• `paymentMode`:`'free_trial'`・`'pay_as_you_go'`・`'pay_up_front'`・`'unknown'` のいずれかの値を持つ文字列です。無料トライアルは `'free_trial'` タイプになります。<br/>• `price`:数値としての割引価格です。無料トライアルの場合は `0` になります。<br/>• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列です。たとえば3日間のトライアルオファーの場合、このフィールドには `'3 days'` と表示されます。<br/>• `subscriptionPeriod`:オファー期間の個別の詳細を取得するには、このプロパティを使用します。オファーに対しても、前のセクションで説明したのと同じように機能します。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間です。 | ## デフォルトオーディエンスのフローでフロー取得を高速化する \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ瞬時に取得されるため、この処理を高速化することを心配する必要はありません。ただし、オーディエンスやプレースメントの数が多く、ユーザーの通信環境が悪い場合は、フローの取得に想定以上の時間がかかることがあります。そのような状況では、何も表示しないよりも、デフォルトのフローを表示してスムーズなユーザー体験を提供したい場合があるでしょう。 この問題に対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンスのフローを取得します。ただし、推奨されるアプローチは `getFlow` メソッドでフローを取得することである点を十分に理解してください。詳細は上記の[フロー情報の取得](fetch-paywalls-and-products-capacitor#fetch-flow-information)セクションを参照してください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります。 - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるフローを表示する必要がある場合、課題が生じる可能性があります。現在(レガシー)バージョンに対応したフローを設計するか、現在(レガシー)バージョンのユーザーがフローを正しく表示できないリスクを受け入れるかのいずれかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じフローを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを受け入れてでも高速なフロー取得のメリットを活用したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-capacitor#fetch-flow-information)で説明した `getFlow` を使用してください。 ::: ```typescript showLineNumbers try { const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); // the requested flow } catch (error) { console.error('Failed to fetch default audience flow:', error); } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **params.fetchPolicy** | <p>任意</p><p>デフォルト: `'reload_revalidating_cache_data'`</p> | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。この方式を推奨するのは、ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定だと想定される場合は、`'return_cache_data_else_load'` を使用してキャッシュが存在する場合にキャッシュデータを返すことを検討してください。この場合、ユーザーは必ずしも最新データを取得できるわけではありませんが、接続状況に左右されずに高速な読み込みを体験できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても安全です。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でクリアした場合にのみ消去されます。</p> | </SDKv4> <SDKv3> リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズされたペイウォールの取得方法については、[ペイウォールビルダーのペイウォールとその設定を取得する](capacitor-get-pb-paywalls)をご参照ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. [ペイウォールを作成し、プロダクトをペイウォールに組み込む](create-paywall)(Adapty ダッシュボード内)。 3. [プレースメントを作成し、ペイウォールをプレースメントに組み込む](create-placement)(Adapty ダッシュボード内)。 4. [Adapty SDK をインストールする](sdk-installation-capacitor)(モバイルアプリ内)。 </details> ## ペイウォール情報の取得 \{#fetch-paywall-information\} Adapty では、[プロダクト](product)はApp StoreとGoogle Playの両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームのプロダクトはペイウォールに統合されており、モバイルアプリの特定のプレースメント内で表示できます。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)のいずれかから[ペイウォール](paywalls)を取得する必要があります。 ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); // the requested paywall } catch (error) { console.error('Failed to fetch paywall:', error); } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-remote-config-locale)の識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよび推奨される使用方法については、[ローカライゼーションとロケールコード](capacitor-localizations-and-locale-codes)を参照してください。</p> | | **params.fetchPolicy** | <p>任意</p><p>デフォルト: `'reload_revalidating_cache_data'`</p> | <p>デフォルトでは、SDKはサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法はユーザーが常に最新のデータを取得できるため、推奨しています。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を使用していると考えられる場合は、`'return_cache_data_else_load'` を使用してキャッシュデータが存在する場合にそれを返すことを検討してください。この場合、ユーザーが最新のデータを取得できないこともありますが、インターネット接続が不安定であっても、より速い読み込み速度を体験できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるためにキャッシュを使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリのアンインストールまたは手動でのクリーンアップ時にのみクリアされます。</p> | | **params.loadTimeoutMs** | <p>任意</p><p>デフォルト: 5000 ms</p> | <p>このメソッドのタイムアウト(ミリ秒)を制限する値です。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。</p><p></p><p>このメソッドは内部で複数のリクエストを行う場合があるため、`loadTimeoutMs` で指定した時間よりもわずかに遅くタイムアウトすることがまれにあります。</p> | **プロダクトIDをハードコードしないでください。** ハードコードすべきIDはプレースメントIDのみです。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。たとえば、今日のペイウォールが2つのプロダクトを返し、明日3つを返す場合でも、コードを変更せずにすべて表示できるようにしてください。 レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォールの識別子、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) オブジェクト。 | ## プロダクトを取得する \{#fetch-products\} ペイウォールを取得したら、それに対応するプロダクトの配列を取得できます: ```typescript showLineNumbers try { const products = await adapty.getPaywallProducts({ paywall }); // the requested products list } catch (error) { console.error('Failed to fetch products:', error); } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他いくつかのプロパティを含みます。 | 独自のペイウォールデザインを実装する場合、[`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) オブジェクトの以下のプロパティが必要になります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **タイトル** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **価格** | ローカライズされた価格を表示するには、`product.price?.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づいています。`product.price?.amount` を使って数値としての価格にアクセスすることもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには、`product.price?.currencySymbol` を使用します。 | | **サブスクリプション期間** | 期間(週、月、年など)を表示するには、`product.subscription?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づいています。プログラムでサブスクリプション期間を取得するには、`product.subscription?.subscriptionPeriod` を使用します。ここから `unit` プロパティにアクセスして長さ(`'day'`、`'week'`、`'month'`、`'year'`、`'unknown'` のいずれか)を取得できます。`numberOfUnits` の値で期間の単位数を取得できます。たとえば、四半期ごとのサブスクリプションの場合、unit プロパティには `'month'`、numberOfUnits プロパティには `3` が表示されます。 | | **初回オファー** | サブスクリプションに初回オファーが含まれていることを示すバッジやインジケーターを表示するには、`product.subscription?.offer?.phases` プロパティを確認してください。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下の便利なプロパティがあります:<br/>• `paymentMode`:`'free_trial'`、`'pay_as_you_go'`、`'pay_up_front'`、`'unknown'` のいずれかの値を持つ文字列。無料トライアルは `'free_trial'` タイプになります。<br/>• `price`:数値としての割引価格。無料トライアルの場合は `0` になります。<br/>• `localizedNumberOfPeriods`:デバイスのロケールを使用してローカライズされた文字列で、オファーの期間を表します。たとえば、3日間のトライアルオファーの場合、このフィールドには `'3 days'` と表示されます。<br/>• `subscriptionPeriod`:このプロパティを使ってオファー期間の個別の詳細を取得することもできます。オファーに対しても前のセクションで説明したのと同様の方法で機能します。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## デフォルトオーディエンスのペイウォールでフェッチを高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ瞬時にフェッチされるため、この処理を高速化することを意識する必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーの通信環境が不安定な場合は、フェッチに想定より時間がかかることがあります。そのような状況では、ペイウォールがまったく表示されないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したいと思うでしょう。 これに対処するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、**All Users** オーディエンスに対して指定されたプレースメントのペイウォールを取得します。ただし、推奨されるアプローチは、上記の [ペイウォール情報の取得](fetch-paywalls-and-products-capacitor#fetch-paywall-information) セクションで詳しく説明されているように、`getPaywall` メソッドでペイウォールを取得することである点を理解することが重要です。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現在と将来)に対して異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンをサポートするペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないペイウォールの問題に遭遇することを許容するかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 デフォルトオーディエンス向けの高速なペイウォール取得というメリットを受け入れられる場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-capacitor#fetch-paywall-information)で説明した `getPaywall` を使用してください。 ::: ```typescript showLineNumbers try { const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); // the requested paywall } catch (error) { console.error('Failed to fetch default audience paywall:', error); } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメータは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよび推奨される使用方法については、[ローカライズとロケールコード](capacitor-localizations-and-locale-codes)を参照してください。</p> | | **params.fetchPolicy** | <p>任意</p><p>デフォルト: `'reload_revalidating_cache_data'`</p> | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるようになるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を利用していると想定される場合は、`'return_cache_data_else_load'` を使用してキャッシュが存在すればそれを返すことを検討してください。この場合、ユーザーが受け取るデータが最新でない可能性がありますが、インターネット接続が不安定な状況でも読み込み速度が向上します。キャッシュは定期的に更新されるため、ネットワークリクエストを減らす目的でセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p> | </SDKv3> --- # File: present-remote-config-paywalls-capacitor --- --- title: "Capacitor SDKでリモートコンフィグで設計されたペイウォールをレンダリングする" description: "Adapty Capacitor SDKでリモートコンフィグペイウォールを表示し、ユーザー体験をパーソナライズする方法をご紹介します。" --- <SDKv4> リモートコンフィグを使用してフローをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングを実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、フロービューをどのように表示するかはあなた次第です。リモートコンフィグの設定を取得するメソッドを提供しているので、リモートコンフィグで設定したカスタムフローを自由に表示できます。 ## フローのリモートコンフィグを取得して表示する \{#get-flow-remote-config-and-present-it\} v4 では、フローは設定された言語ごとに1つの `AdaptyRemoteConfig` エントリを `remoteConfigs` 配列に持ちます。ユーザーの言語設定に合った言語を選択し、その `data` から必要な値を読み取ってください。 ```typescript showLineNumbers try { const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0]; const headerText = config?.data?.['header_text']; } catch (error) { console.error('Failed to fetch flow:', error); } ``` この段階で、必要な値をすべて取得したら、それらをレンダリングして視覚的に魅力的なページに組み立てましょう。さまざまなモバイル端末の画面サイズや向きに対応したデザインにして、異なるデバイスでもシームレスで使いやすい体験を提供することが重要です。 :::warning 以下で説明するように、必ず[ペイウォール表示イベントを記録](present-remote-config-paywalls-capacitor#track-paywall-view-events)してください。これにより、Adapty アナリティクスがファネルや A/B テスト用の情報を収集できるようになります。 ::: フローの表示が完了したら、購入フローの設定に進みます。ユーザーが購入を行う際は、フローから取得したプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実行](capacitor-making-purchases)をご覧ください。 インターネット接続がない場合やキャッシュが利用できない場合にも円滑なエクスペリエンスを提供するため、[フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](capacitor-use-fallback-paywalls)をおすすめします。 ## フローの表示イベントを記録する \{#track-paywall-view-events\} Adapty はフローのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、フローの表示ログはお客様自身が記録する必要があります。フローがいつユーザーに表示されるかを把握できるのはお客様だけだからです。 フローの表示イベントを記録するには、`.logShowFlow({ flow })` を呼び出すだけです。この情報はファネルや A/B テストのペイウォール指標に反映されます。 :::important [フローBuilder](adapty-flow-builder) や [ペイウォールビルダー](adapty-paywall-builder) でレンダリングされたフローやペイウォールを表示する場合、`.logShowFlow({ flow })` の呼び出しは不要です。Adapty はそれらのケースでビューを自動的に追跡します。 ::: ```typescript showLineNumbers await adapty.logShowFlow({ flow }); ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | | :-------- | :------- |:-------------------------------------------------------------------------------------| | **flow** | 必須 | `adapty.getFlow({ placementId })` で取得した `AdaptyFlow` オブジェクト。 | </SDKv4> <SDKv3> リモートコンフィグを使ってペイウォールをカスタマイズした場合は、ユーザーに表示するためのレンダリングをアプリのコードで実装する必要があります。リモートコンフィグはニーズに合わせた柔軟な設計が可能なため、何を含めるか、ペイウォールをどのように表示するかはすべて開発者が自由に決めることができます。リモートコンフィグの取得メソッドを提供しているので、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); const headerText = paywall.remoteConfig?.data?.['header_text']; } catch (error) { console.error('Failed to fetch paywall:', error); } ``` ここまでで必要な値をすべて取得できたら、次はそれらをレンダリングして視覚的に魅力的なページに組み立てます。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、デバイスを問わずシームレスで使いやすい体験を提供しましょう。 :::warning 後述の手順に従って[ペイウォール表示イベントを記録](present-remote-config-paywalls-capacitor#track-paywall-view-events-1)してください。これにより、Adapty アナリティクスがファネルや A/B テスト用の情報を収集できるようになります。 ::: ペイウォールの表示が完了したら、購入フローの設定に進みます。ユーザーが購入を行う際は、ペイウォールのプロダクトを使って`.makePurchase()`を呼び出すだけです。`.makePurchase()`メソッドの詳細については、[購入の実装](capacitor-making-purchases)をご覧ください。 [フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](capacitor-use-fallback-paywalls)をおすすめします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーへ表示され、そのような状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス計測をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはお客様自身が記録する必要があります。ペイウォールがいつ表示されるかを把握できるのは開発者のみであるためです。 ペイウォールの表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。この呼び出しにより、ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールを表示する場合は、`.logShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```typescript showLineNumbers try { await adapty.logShowPaywall({ paywall }); } catch (error) { console.error('Failed to log paywall view:', error); } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :---------- | :------- | :--------------------------------------------------------- | | **paywall** | 必須 | [`AdaptyPaywall`](https://capacitor.adapty.io/interfaces/adaptypaywall) オブジェクト。 | </SDKv3> --- # File: capacitor-making-purchases --- --- title: "Capacitor SDK でアプリ内課金を行う" description: "Adapty を使ってアプリ内課金とサブスクリプションを処理するガイド。" --- モバイルアプリ内でペイウォールを表示することは、ユーザーにプレミアムコンテンツやサービスへのアクセスを提供するうえで欠かせないステップです。ただし、購入をサポートするためにペイウォールを表示するだけで十分なのは、[ペイウォールビルダー](adapty-paywall-builder)を使ってペイウォールをカスタマイズしている場合に限られます。 ペイウォールビルダーを使用しない場合は、`.makePurchase()` という専用のメソッドを使って購入を完了し、目的のコンテンツをアンロックする必要があります。このメソッドは、ユーザーがペイウォールを通じて購入手続きを進めるための入口となります。 購入しようとしているプロダクトに有効なプロモーションオファーがある場合、Adapty は購入時に自動的にそれを適用します。 [初期設定](quickstart)をすべてのステップを飛ばさずに完了しておいてください。設定が完了していないと、購入を検証できません。 ## 購入処理 \{#make-purchase\} :::note **[ペイウォールビルダー](adapty-paywall-builder)を使用していますか?** 購入は自動的に処理されるため、このステップはスキップできます。 **ステップバイステップのガイドをお探しですか?** 詳細なコンテキストを含むエンドツーエンドの実装手順については、[クイックスタートガイド](capacitor-implement-paywalls-manually)をご確認ください。 ::: ```typescript showLineNumbers try { const result = await adapty.makePurchase({ product }); if (result.type === 'success') { const isSubscribed = result.profile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features console.log('User is now subscribed!'); } } else if (result.type === 'user_cancelled') { console.log('Purchase cancelled by user'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { console.error('Purchase failed:', error); } ``` リクエストパラメータ: | パラメータ | 必須 | 説明 | | :---------- | :------- |:----------------------------------------------------------------------------------------------------------------------------| | **product** | 必須 | `getPaywallProducts` を通じてフローから取得した [`AdaptyPaywallProduct`](https://capacitor.adapty.io/interfaces/adaptypaywallproduct) オブジェクト。 | レスポンスパラメータ: | パラメータ | 説明 | |---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **result** | 購入結果を示す `type` フィールド(`'success'`、`'user_cancelled'`、または `'pending'`)と、購入成功時に更新された [`AdaptyProfile`](https://capacitor.adapty.io/interfaces/adaptyprofile) を含む `profile` フィールドを持つ [`AdaptyPurchaseResult`](https://capacitor.adapty.io/types/adaptypurchaseresult) オブジェクト。 | ## 購入時にサブスクリプションを変更する \{#change-subscription-when-making-a-purchase\} ユーザーが現在のサブスクリプションを更新するのではなく、新しいサブスクリプションを選択した場合、動作はアプリストアによって異なります。 - App Store の場合、サブスクリプショングループ内でサブスクリプションは自動的に更新されます。ユーザーがあるグループのサブスクリプションを購入済みの状態で別のグループのサブスクリプションを購入した場合、両方のサブスクリプションが同時にアクティブになります。 - Google Play の場合、サブスクリプションは自動的に更新されません。以下で説明するように、アプリのコード内で切り替えを管理する必要があります。 Androidでサブスクリプションを別のものに切り替えるには、追加パラメーターを指定して `.makePurchase()` メソッドを呼び出します。 ```typescript showLineNumbers try { const result = await adapty.makePurchase({ product, params: { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } } }); if (result.type === 'success') { const isSubscribed = result.profile?.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features console.log('Subscription updated successfully!'); } } else if (result.type === 'user_cancelled') { console.log('Purchase cancelled by user'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { console.error('Purchase failed:', error); } ``` 追加リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :----------- | :-------- | :----------------------------------------------------------- | | **params** | 任意 | プラットフォーム固有の購入パラメーターを含む [`MakePurchaseParamsInput`](https://capacitor.adapty.io/types/makepurchaseparamsinput) 型のオブジェクト。 | `MakePurchaseParamsInput` 構造体には以下が含まれます: ```typescript { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } } ``` サブスクリプションと置き換えモードの詳細については、Google Developer ドキュメントをご参照ください: - [交換モードについて](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())。注意: 実際のサブスクリプション変更は、現在のサブスクリプションの請求期間が終了した時点でのみ行われます。 ### プリペイドプランの管理(Android) \{#manage-prepaid-plans-android\} アプリユーザーが[プリペイドプラン](https://developer.android.com/google/play/billing/subscriptions#prepaid-plans)(例: 数ヶ月分の非更新型サブスクリプションを購入)を利用できる場合、プリペイドプランに対して[保留中のトランザクション](https://developer.android.com/google/play/billing/subscriptions#pending)を有効にできます。 ```typescript showLineNumbers await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { android: { pendingPrepaidPlansEnabled: true, }, } }); ``` ## iOSでオファーコードを利用する \{#redeem-offer-codes-in-ios\} <Details> <summary>オファーコードについて</summary> オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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アナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。 </Details> アプリでコード引き換えシートを表示するには: ```typescript showLineNumbers try { await adapty.presentCodeRedemptionSheet(); } catch (error) { console.error('Failed to present code redemption sheet:', error); } ``` :::danger 私たちの観察によると、一部のアプリではオファーコード引き換えシートが正常に動作しないことがあります。ユーザーをApp Storeに直接リダイレクトすることをお勧めします。 これを行うには、次の形式のURLを開く必要があります: `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: --- # File: capacitor-restore-purchase --- --- title: "Capacitor SDKでモバイルアプリの購入を復元する" description: "Adaptyでアプリのシームレスなユーザーエクスペリエンスのためにアプリ内課金の復元方法を学びましょう。" --- 購入の復元は、iOSとAndroidの両方で利用できる機能で、ユーザーが以前購入したサブスクリプションやアプリ内課金などのコンテンツに、再度課金されることなくアクセスできるようにするものです。アプリをアンインストールして再インストールした場合や、新しいデバイスに移行した場合に、過去の購入を再度支払わずに利用できるため、特に便利な機能です。 :::note [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールでは、追加のコードなしに購入が自動的に復元されます。その場合は、このステップをスキップできます。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしていない場合、購入を復元するには `.restorePurchases()` メソッドを呼び出します。 ```typescript showLineNumbers try { const profile = await adapty.restorePurchases(); const isSubscribed = profile.accessLevels?.['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Restore access to paid features console.log('Access restored successfully!'); } else { console.log('No active subscriptions found'); } } catch (error) { console.error('Failed to restore purchases:', error); } ``` レスポンスパラメーター: | パラメーター | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **profile** | [`AdaptyProfile`](https://capacitor.adapty.io/interfaces/adaptyprofile) オブジェクトです。このモデルにはアクセスレベル、サブスクリプション、買い切り購入に関する情報が含まれています。ユーザーがアプリにアクセスできるかどうかを判断するには、**アクセスレベルのステータス**を確認してください。 | --- # File: implement-observer-mode-capacitor --- --- title: "Capacitor SDKでオブザーバーモードを実装する" description: "Adapty でオブザーバーモードを実装して、Capacitor SDK でユーザーのサブスクリプションイベントを追跡します。" --- すでに独自の購入インフラを持っており、Adapty への完全な移行を検討していない場合は、[オブザーバーモード](observer-vs-full-mode)をご利用いただけます。基本的な形では、オブザーバーモードは高度なアナリティクスと、アトリビューション・アナリティクスシステムとのシームレスな連携を提供します。 このニーズに合う場合は、以下の手順だけで設定できます: 1. Adapty SDK の設定時に `observerMode` パラメータを `true` に設定してオンにする。[Capacitor](sdk-installation-capacitor#activate-adapty-module-of-adapty-sdk) のセットアップ手順に従ってください。 2. 既存の購入インフラから Adapty に[トランザクションを報告する](report-transactions-observer-mode-capacitor)。 :::tip SDK v4では、ObserverモードでAdaptyがレンダリングするフローやペイウォールを表示することもできます。ユーザーが購入または復元ボタンをタップすると、SDKがそのアクションをあなたのコードに渡し、購入や復元を自分で実行できます。詳しくは[Observerモードでのフローの表示](capacitor-present-flows-in-observer-mode)を参照してください。 ::: ### オブザーバーモードの設定 \{#observer-mode-setup\} 購入やサブスクリプションのステータス管理を自前で行い、Adapty をサブスクリプションイベントの送信と分析にのみ使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作中、Adapty SDK はトランザクションをクローズしません。そのため、トランザクションの処理は必ずご自身で行ってください。 ::: ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { observerMode: true // Enable observer mode } }); } catch (error) { console.error('Failed to activate Adapty:', error); } ``` | パラメーター | 説明 | | ----------- | ---- | | **observerMode** | [オブザーバーモード](observer-vs-full-mode)を制御するブール値。デフォルト値は `false` です。 | ## ObserverモードでAdaptyのペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adaptyのペイウォールやオーディエンスベースのターゲティング機能もあわせて利用したい場合は可能ですが、Observerモードでは追加のセットアップが必要です。上記の手順に加えて、以下を行ってください: 1. [リモートコンフィグペイウォール](present-remote-config-paywalls-capacitor)の通常の方法でペイウォールを表示します。 2. 購入トランザクションに[ペイウォールを関連付け](report-transactions-observer-mode-capacitor)ます。 --- # File: report-transactions-observer-mode-capacitor --- --- title: "Capacitor SDKのオブザーバーモードでトランザクションを報告する" description: "Capacitor SDKのAdaptyオブザーバーモードで購入トランザクションを報告し、ユーザーインサイトと収益トラッキングを実現します。" --- オブザーバーモードでは、Adapty SDKは既存の購入システムを通じて行われた購入を自動で追跡できません。アプリストアからのトランザクションを手動で報告する必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を行うことが重要です。 `reportTransaction` を使用して、各トランザクションをAdaptyに明示的に報告してください。 :::warning **トランザクションの報告を省略しないでください!** `reportTransaction` を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に `variationId` を含めてください。これにより、購入がそれを起動したペイウォールに紐付けられ、正確なペイウォールアナリティクスが確保されます。 ```typescript showLineNumbers const variationId = paywall.variationId; try { await adapty.reportTransaction({ transactionId: 'your_transaction_id', variationId: variationId }); } catch (error) { console.error('Failed to report transaction:', error); } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | -------- | ------------------------------------------------------------ | | **transactionId** | 必須 | <ul><li>iOS の場合: トランザクションの識別子。</li><li>Android の場合: 購入の文字列識別子(`purchase.getOrderId`)。ここで purchase は、ビリングライブラリの [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。</li></ul> | | **variationId** | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://capacitor.adapty.io/interfaces/adaptypaywall) オブジェクトの `variationId` プロパティから取得できます。 | --- # File: capacitor-user --- --- title: "ユーザーとアクセス" description: "Adapty SDK を使用して Capacitor アプリでユーザーとアクセスレベルを操作する方法について説明します。" --- <CustomDocCardList /> --- # File: capacitor-identifying-users --- --- title: "Capacitor SDKでユーザーを識別する" description: "Adapty SDKを使用してCapacitorアプリでユーザーを識別する方法を学びます。" --- 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`パラメーターとして渡すだけです: ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { customerUserId: 'YOUR_USER_ID' } }); } catch (error) { console.error('Failed to activate Adapty:', error); } ``` ### 設定後にCustomer User IDを設定する \{#setting-customer-user-id-after-configuration\} SDKの設定時にユーザーIDがない場合は、`.identify()`メソッドを使っていつでも後から設定できます。このメソッドの最も一般的なユースケースは、ユーザーが匿名ユーザーから認証済みユーザーに切り替わる際の登録後または認証後です。 ```typescript showLineNumbers try { await adapty.identify({ customerUserId: 'YOUR_USER_ID' }); console.log('User identified successfully'); } catch (error) { console.error('Failed to identify user:', error); } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **customerUserId** | 必須 | 文字列のユーザー識別子。 | :::warning 重要なユーザーデータの再送信 ユーザーが再度アカウントにログインする場合など、Adaptyのサーバーにすでにそのユーザーの情報が存在していることがあります。このような場合、Adapty SDKは自動的に新しいユーザーに切り替えて動作します。カスタム属性やサードパーティネットワークからのアトリビューションなど、匿名ユーザーに渡したデータがある場合は、識別されたユーザーに対してそのデータを再送信する必要があります。 また、新しいユーザーのデータが異なる可能性があるため、ユーザーを識別した後にすべてのペイウォールとプロダクトを再取得する必要があることも重要です。 ::: ### ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()`メソッドを呼び出すことで、いつでもユーザーをログアウトできます: ```typescript showLineNumbers try { await adapty.logout(); console.log('User logged out successfully'); } catch (error) { console.error('Failed to logout user:', error); } ``` その後、`.identify()`メソッドを使ってユーザーをログインできます。 ## `appAccountToken`を設定する(iOS) \{#assign-appaccounttoken-ios\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:))は、App Storeのトランザクションを内部ユーザーIDにリンクするための**UUID**です。 StoreKitはこのトークンをすべてのトランザクションに関連付けるため、バックエンドがApp StoreのデータをユーザーIDと照合できます。 ユーザーごとに生成した安定したUUIDを使用し、同じアカウントに対してデバイスをまたいで再利用してください。 これにより、購入とApp Storeの通知が正しく紐付けられます。 トークンは2つの方法で設定できます。SDKのアクティベーション時、またはユーザーを識別する際です。 :::important `appAccountToken`は必ず`customerUserId`と一緒に渡す必要があります。 トークンのみを渡した場合、トランザクションに含まれません。 ::: ```typescript showLineNumbers // During configuration: await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { customerUserId: 'YOUR_USER_ID', ios: { appAccountToken: "YOUR_APP_ACCOUNT_TOKEN" }, } }); // Or when identifying users await adapty.identify({ customerUserId: 'YOUR_USER_ID', params: { ios: { appAccountToken: 'YOUR_APP_ACCOUNT_TOKEN' }, } }); ``` ### 難読化されたアカウントIDを設定する(Android) \{#set-obfuscated-account-ids-android\} Google Playでは、ユーザーのプライバシーとセキュリティを強化するために、特定のユースケースで難読化されたアカウントIDが必要です。これらのIDにより、Google Playはユーザー情報を匿名のまま購入を識別できます。これは不正防止や分析において特に重要です。 アプリが機密性の高いユーザーデータを扱う場合や、特定のプライバシー規制に準拠する必要がある場合は、これらのIDを設定する必要があります。難読化されたIDにより、Google Playは実際のユーザー識別子を公開せずに購入を追跡できます。 ```typescript showLineNumbers // During configuration: await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' }, } }); // Or when identifying users await adapty.identify({ customerUserId: 'YOUR_USER_ID', params: { android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' }, } }); ``` ## デバイスをまたいだユーザー検出 \{#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: capacitor-setting-user-attributes --- --- title: "Capacitor SDKでユーザー属性を設定する" description: "Adapty SDKを使ってCapacitorアプリでユーザー属性とプロファイルデータを更新する方法を解説します。" --- メールアドレスや電話番号など、アプリのユーザーにオプションの属性を設定できます。設定した属性は、ユーザーの[セグメント](segments)作成やCRMでの閲覧に活用できます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します: ```typescript showLineNumbers const params = { email: 'email@email.com', phoneNumber: '+18888888888', firstName: 'John', lastName: 'Appleseed', gender: 'other', birthday: new Date().toISOString(), }; try { await adapty.updateProfile(params); console.log('Profile updated successfully'); } catch (error) { console.error('Failed to update profile:', error); } ``` `updateProfile` メソッドで以前に設定した属性はリセットされないのでご注意ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 使用可能なキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters` で使用可能なキーとその値は以下の通りです: | キー | 値 | |---|-----| | **email** | 文字列 | | **phoneNumber** | 文字列 | | **firstName** | 文字列 | | **lastName** | 文字列 | | **gender** | 列挙型。使用可能な値: `'female'`、`'male'`、`'other'` | | **birthday** | ISO形式の日付文字列 | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定することもできます。通常、アプリの利用状況に関連するものです。たとえば、フィットネスアプリなら週あたりの運動回数、語学学習アプリならユーザーの習熟度レベルなどが該当します。セグメントに活用してターゲットを絞ったペイウォールやオファーを作成したり、収益に最も影響を与えるプロダクト指標を分析することもできます。 ```typescript showLineNumbers try { await adapty.updateProfile({ codableCustomAttributes: { key_1: 'value_1', key_2: 2, }, }); console.log('Custom attributes updated successfully'); } catch (error) { console.error('Failed to update custom attributes:', error); } ``` 既存のキーを削除するには、値として `null` を渡します: ```typescript showLineNumbers try { // to remove keys, pass null as their values await adapty.updateProfile({ codableCustomAttributes: { key_1: null, key_2: null, }, }); console.log('Custom attributes removed successfully'); } catch (error) { console.error('Failed to remove custom attributes:', error); } ``` 事前に設定されているカスタム属性を確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning `customAttributes` の値は最新でない可能性があります。ユーザー属性は異なるデバイスからいつでも送信される可能性があるため、最後の同期以降にサーバー上の属性が変更されている場合があります。 ::: ### 制限事項 \{#limits\} - ユーザーあたり最大30個のカスタム属性 - キー名は最大30文字。使用できる文字は英数字と `_`、`-`、`.` のいずれか - 値は文字列または浮動小数点数で、50文字以内 --- # File: capacitor-listen-subscription-changes --- --- title: "Capacitor SDKでのサブスクリプション状態の確認" description: "Adaptyでユーザーのサブスクリプション状態を追跡・管理し、Capacitorアプリの顧客維持率を向上させましょう。" --- Adaptyを使えば、サブスクリプションのステータス管理が簡単になります。プロダクトIDをコードに手動で埋め込む必要はありません。アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプション状態をすぐに把握できます。 <details> <summary>サブスクリプションステータスの確認を始める前に(クリックして展開)</summary> - iOSの場合は、[App Store サーバー通知](enable-app-store-server-notifications)を設定してください - Androidの場合は、[リアルタイム デベロッパー通知(RTDN)](enable-real-time-developer-notifications-rtdn)を設定してください </details> ## アクセスレベルとAdaptyProfileオブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは[AdaptyProfile](https://capacitor.adapty.io/interfaces/adaptyprofile)オブジェクトのプロパティです。アプリの起動時(たとえば[ユーザーを識別する](capacitor-identifying-users#setting-customer-user-id-on-configuration)タイミング)にプロファイルを取得し、変更があるたびに更新することをおすすめします。こうすることで、都度リクエストすることなくプロファイルオブジェクトを活用できます。 プロファイルの更新通知を受け取るには、以下の[プロファイルの更新(アクセスレベルを含む)のリッスン](capacitor-listen-subscription-changes)セクションで説明されているように、プロファイルの変更をリッスンしてください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()` メソッドを使用します。 ```typescript showLineNumbers try { const profile = await adapty.getProfile(); console.log('Profile retrieved successfully'); } catch (error) { console.error('Failed to get profile:', error); } ``` レスポンスパラメーター: | パラメータ | 説明 | | --------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **profile** | [AdaptyProfile](https://capacitor.adapty.io/interfaces/adaptyprofile) オブジェクト。通常は、ユーザーがアプリのプレミアムアクセスを持っているかどうかを判断するために、プロファイルのアクセスレベルのステータスのみを確認します。`.getProfile` メソッドは常に API へのクエリを試みるため、最新の結果を提供します。何らかの理由(例:インターネット接続なし)で Adapty SDK がサーバーから情報を取得できない場合は、キャッシュのデータが返されます。また、Adapty SDK は `AdaptyProfile` のキャッシュを定期的に更新し、情報を可能な限り最新の状態に保つことにも注意してください。 | `.getProfile()` メソッドを使うと、ユーザーのプロファイルを取得でき、そこからアクセスレベルの状態を確認できます。アプリには複数のアクセスレベルを設定することも可能です。たとえば、ニュースアプリでトピックごとに独立したサブスクリプションを販売する場合、「sports」と「science」というアクセスレベルを作成できます。ただし、ほとんどの場合はアクセスレベルが1つあれば十分なので、デフォルトの「premium」アクセスレベルをそのまま使えば大丈夫です。 デフォルトの「premium」アクセスレベルを確認する例を以下に示します。 ```typescript showLineNumbers try { const profile = await adapty.getProfile(); const isActive = profile.accessLevels?.['premium']?.isActive; if (isActive) { // Grant access to premium features console.log('User has premium access'); } else { console.log('User does not have premium access'); } } catch (error) { console.error('Failed to check subscription status:', error); } ``` ### サブスクリプション状態の更新をリッスンする \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adapty はイベントを発行します。 Adapty からメッセージを受信するには、追加の設定が必要です: ```typescript showLineNumbers // Create an "onLatestProfileLoad" event listener adapty.addListener('onLatestProfileLoad', (data) => { const profile = data.profile; const isActive = profile.accessLevels?.['premium']?.isActive; if (isActive) { console.log('Subscription status updated: User has premium access'); } else { console.log('Subscription status updated: User does not have premium access'); } }); ``` Adapty はアプリ起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションのステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDK に実装されたキャッシュは、プロファイルのサブスクリプションステータスを保存します。これにより、サーバーが利用できない場合でも、キャッシュされたデータを参照してプロファイルのサブスクリプションステータスに関する情報を取得できます。 ただし、キャッシュから直接データをリクエストすることはできません。SDKは1分ごとにサーバーへ定期的に問い合わせを行い、プロファイルに関する更新や変更がないかを確認します。新しいトランザクションやその他の更新など、何らかの変更があった場合は、サーバーとの同期を保つためにキャッシュされたデータへ反映されます。 --- # File: capacitor-deal-with-att --- --- title: "Capacitor SDK で ATT を処理する" description: "Capacitor で Adapty を使い始めて、サブスクリプションの設定と管理を効率化しましょう。" --- アプリが AppTrackingTransparency フレームワークを使用してアプリトラッキングの認証リクエストをユーザーに表示している場合は、[認証ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/)を Adapty に送信する必要があります。 ```typescript showLineNumbers try { await adapty.updateProfile({ appTrackingTransparencyStatus: AppTrackingTransparencyStatus.Authorized, }); console.log('ATT status updated successfully'); } catch (error) { console.error('Failed to update ATT status:', error); } ``` :::warning この値は変更があった際にできるだけ早く送信することを強くお勧めします。そうすることで、設定済みのインテグレーションにタイムリーにデータが送信されます。 ::: --- # File: capacitor-onboardings --- --- title: "オンボーディング" description: "Adapty SDK を使って Capacitor アプリでオンボーディングを操作する方法を説明します。" --- :::warning **オンボーディングは SDK v4 で非推奨となり、将来のリリースで削除される予定です。** 修正や改善は行われません。代わりに[フロー](capacitor-get-pb-paywalls)を使用してください。オンボーディングが WebView 内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、アニメーションがスムーズで、一貫したネイティブな外観と操作感、高速な読み込み時間、WebView ランタイムへの依存がありません。開始するには[フローとペイウォールの取得](capacitor-get-pb-paywalls)および[フローとペイウォールの表示](capacitor-present-paywalls)を参照してください。 ::: <CustomDocCardList /> --- # File: capacitor-get-onboardings --- --- title: "Capacitor SDKでオンボーディングを取得する" description: "Capacitor向けAdaptyでオンボーディングを取得する方法を学びましょう。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](capacitor-get-pb-paywalls)をご利用ください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存がなくなります。まずは[フローとペイウォールの取得](capacitor-get-pb-paywalls)および[フローとペイウォールの表示](capacitor-present-paywalls)をご覧ください。 ::: Adapty ダッシュボードのビルダーで[オンボーディングのビジュアル部分をデザインした](design-onboarding)後、Capacitor アプリに表示できます。このプロセスの最初のステップは、以下に説明するように、プレースメントに関連付けられたオンボーディングとそのビュー設定を取得することです。 始める前に、以下を確認してください: 1. [オンボーディングを作成](create-onboarding)していること。 2. オンボーディングを[プレースメント](placements)に追加していること。 ## オンボーディングの取得 \{#fetch-onboarding\} [オンボーディング](onboardings)をノーコードビルダーで作成すると、アプリが取得・表示する必要のある設定コンテナとして保存されます。このコンテナは、表示するコンテンツ、その見せ方、ユーザーのインタラクション(クイズの回答やフォームへの入力など)の処理方法といった、体験全体を管理します。また、コンテナはアナリティクスイベントを自動的に記録するため、ビュートラッキングを別途実装する必要はありません。 パフォーマンスを最大化するために、ユーザーに表示する前に画像をダウンロードする時間を確保できるよう、早い段階でオンボーディングの設定を取得してください。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```typescript showLineNumbers try { const onboarding = await adapty.getOnboarding({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data', // Load from server, fallback to cache loadTimeoutMs: 5000 // 5 second timeout } }); console.log('Onboarding fetched successfully'); } catch (error) { console.error('Failed to fetch onboarding:', error); } ``` 次に、`createOnboardingView` メソッドを呼び出してビューインスタンスを作成します。 :::warning `createOnboardingView` メソッドの戻り値は一度しか使用できません。再度使用する必要がある場合は、`createOnboardingView` メソッドを改めて呼び出してください。 ::: ```typescript showLineNumbers if (onboarding.hasViewConfiguration) { try { const view = await createOnboardingView(onboarding); console.log('Onboarding view created successfully'); } catch (error) { console.error('Failed to create onboarding view:', error); } } else { // Use your custom logic console.log('Onboarding does not have view configuration'); } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライズ識別子。マイナス(**-**)で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードと推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)をご覧ください。</p> | | **params.fetchPolicy** | <p>任意</p><p>デフォルト: `'reload_revalidating_cache_data'`</p> | <p>デフォルトでは、SDK はサーバーからデータを取得しようとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるよう、このオプションを推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を使用している場合は、`'return_cache_data_else_load'` を使用してキャッシュが存在する場合にキャッシュデータを返すことを検討してください。この場合、ユーザーが受け取るデータが最新でないことがありますが、インターネット接続が不安定でも読み込みが速くなります。キャッシュはこまめに更新されるため、セッション中のネットワークリクエスト削減を目的として安心して利用できます。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリアを行った場合にのみ削除されます。</p> | | **params.loadTimeoutMs** | <p>任意</p><p>デフォルト: 5000 ms</p> | <p>このメソッドのタイムアウト(ミリ秒単位)を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>内部的に複数のリクエストで構成されている場合があるため、まれに `loadTimeoutMs` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | |:----------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding** | オンボーディングの識別子と設定、リモートコンフィグ、およびその他のプロパティを含む [`AdaptyOnboarding`](https://capacitor.adapty.io/interfaces/adaptyonboarding) オブジェクト。 | ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ瞬時にフェッチされるため、このプロセスの高速化を気にする必要はありません。ただし、オーディエンスやオンボーディングが多数あり、ユーザーのインターネット接続が不安定な場合、オンボーディングのフェッチに想定以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないよりも、デフォルトのオンボーディングを表示してスムーズなユーザー体験を提供した方がよいでしょう。 この問題を解決するには、`getOnboardingForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンス向けのオンボーディングを取得します。ただし、推奨されるアプローチは `getOnboarding` メソッドでオンボーディングを取得することであり、詳細は上記の[オンボーディングの取得](#fetch-onboarding)セクションをご覧ください。 :::warning `getOnboardingForDefaultAudience` ではなく `getOnboarding` の使用をご検討ください。前者には重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のある設計が必要になるか、古いバージョンでは正しく表示されない場合があります。 - **パーソナライズなし**: 「すべてのユーザー」オーディエンス向けのコンテンツのみが表示され、国・アトリビューション・カスタム属性によるターゲティングができなくなります。 取得速度の向上がこれらのデメリットを上回る場合は、以下に示す `getOnboardingForDefaultAudience` を使用してください。そうでない場合は、[上記](#fetch-onboarding)で説明した `getOnboarding` を使用してください。 ::: ```typescript showLineNumbers try { const onboarding = await adapty.getOnboardingForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en', params: { fetchPolicy: 'reload_revalidating_cache_data' // Load from server, fallback to cache } }); console.log('Default audience onboarding fetched successfully'); } catch (error) { console.error('Failed to fetch default audience onboarding:', error); } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライズ識別子。このパラメータは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードおよびその推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **params.fetchPolicy** | <p>任意</p><p>デフォルト: `'reload_revalidating_cache_data'`</p> | <p>デフォルトでは、SDKはサーバーからデータの読み込みを試み、失敗した場合はキャッシュデータを返します。このオプションを推奨するのは、常に最新のデータをユーザーに提供できるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`'return_cache_data_else_load'` を使用してキャッシュデータが存在すればそれを返すことを検討してください。この場合、最新のデータが提供されないことがありますが、接続状況に関わらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中のネットワークリクエストを避けるために安全に使用できます。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリア時にのみ削除されます。</p> | --- # File: capacitor-present-onboardings --- --- title: "Capacitor SDKでオンボーディングを表示する" description: "Capacitor でオンボーディングを表示してコンバージョンと収益を向上させる方法を解説します。" --- :::warning **オンボーディングは SDK v4 で非推奨となり、今後のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](capacitor-get-pb-paywalls)を使用してください。オンボーディングは WebView 内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブな外観、高速な読み込み、WebView ランタイムへの依存がなくなります。始めるには、[フローとペイウォールの取得](capacitor-get-pb-paywalls)および[フローとペイウォールの表示](capacitor-present-paywalls)を参照してください。 ::: ビルダーを使ってオンボーディングをカスタマイズした場合、それをモバイルアプリのコードでレンダリングしてユーザーに表示する必要はありません。このようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [オンボーディングを作成](create-onboarding)していること。 2. オンボーディングを[プレースメント](placements)に追加していること。 ## オンボーディングを表示する \{#present-onboarding\} オンボーディングを表示するには、`createOnboardingView` メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。オンボーディングを再度表示する必要がある場合は、`createOnboardingView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning `view` を再作成せずに再利用すると、エラーが発生する場合があります。 ::: ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onClose: (actionId, meta) => { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom: (actionId, meta) => { console.log('Custom action:', actionId); return false; // Don't close the onboarding } }); await view.present(); console.log('Onboarding presented successfully'); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## iOSの表示スタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOSでのオンボーディングの表示方法を設定できます。このパラメーターには `'full_screen'`(デフォルト)または `'page_sheet'` を指定できます。 ```typescript showLineNumbers await view.present({ iosPresentationStyle: 'page_sheet' }); ``` ## オンボーディングでのリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディングでのリンクの開き方のカスタマイズは、Adapty SDK v3.15 以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、アプリを切り替えることなくウェブページを表示できるため、シームレスなユーザー体験を提供できます。 外部ブラウザでリンクを開きたい場合は、`openIn` パラメーターを `browser_out_app` に設定することでこの動作をカスタマイズできます。 ```typescript showLineNumbers await view.present({ openIn: 'browser_out_app' }); // default — browser_in_app ``` ## 次のステップ \{#next-steps\} オンボーディングを表示したら、[ユーザーのインタラクションとイベントを処理](capacitor-handling-onboarding-events)しましょう。オンボーディングイベントの処理方法を学んで、ユーザーのアクションに応答し、アナリティクスを追跡してください。 --- # File: capacitor-handling-onboarding-events --- --- title: "Capacitor SDKでオンボーディングイベントを処理する" description: "Adaptyを使用してCapacitorでオンボーディング関連のイベントを処理します。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](capacitor-get-pb-paywalls)をご利用ください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブな外観、高速な読み込み、WebViewランタイムへの依存がなくなります。まずは[フローとペイウォールの取得](capacitor-get-pb-paywalls)と[フローとペイウォールの表示](capacitor-present-paywalls)をご覧ください。 ::: ビルダーで設定されたオンボーディングは、アプリが応答できるイベントを生成します。スタンドアロンの画面表示でこれらのイベントを処理するには、`setEventHandlers` メソッドを使用してください。 始める前に、以下を確認してください: 1. [オンボーディングを作成](create-onboarding)済みであること。 2. オンボーディングを[プレースメント](placements)に追加済みであること。 ## イベントハンドラーの設定 \{#set-up-event-handlers\} オンボーディングのイベントを処理するには、`view.setEventHandlers` メソッドを使用します。 ```typescript showLineNumbers try { const view = await createOnboardingView(onboarding); view.setEventHandlers({ onAnalytics(event, meta) { console.log('Analytics event:', event); }, onClose(actionId, meta) { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, onCustom(actionId, meta) { console.log('Custom action:', actionId); return false; // Don't close the onboarding }, onPaywall(actionId, meta) { console.log('Paywall action:', actionId); view.dismiss().then(() => { openPaywall(actionId); }); }, onStateUpdated(action, meta) { console.log('State updated:', action); }, onFinishedLoading(meta) { console.log('Onboarding finished loading'); }, onError(error) { console.error('Onboarding error:', error); }, }); await view.present(); } catch (error) { console.error('Failed to present onboarding:', error); } ``` ## イベントの種類 \{#event-types\} 以下のセクションでは、処理できるさまざまなイベントの種類を説明します。 ### カスタムアクションの処理 \{#handle-custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。 <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> その後、このIDをコードで使用し、カスタムアクションとして処理できます。たとえば、ユーザーが **Login** や **Allow notifications** などのカスタムボタンをタップすると、ビルダーの **Action ID** と一致する `actionId` パラメータを持つイベントハンドラが呼び出されます。"allowNotifications" のような独自のIDを作成できます。 ```typescript showLineNumbers view.setEventHandlers({ onCustom(actionId, meta) { switch (actionId) { case 'login': console.log('Login action triggered'); break; case 'allow_notifications': console.log('Allow notifications action triggered'); break; } return false; // Don't close the onboarding }, }); ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "actionId": "allow_notifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ### オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、このイベントがトリガーされます: ```typescript showLineNumbers view.setEventHandlers({ onFinishedLoading(meta) { console.log('Onboarding loaded:', meta.onboardingId); }, }); ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ### オンボーディングを閉じる \{#closing-onboarding\} ユーザーが**Close**アクションが割り当てられたボタンをタップすると、オンボーディングは閉じられたとみなされます。 <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important ユーザーがオンボーディングを閉じたときの処理は、ご自身で実装する必要があります。たとえば、オンボーディング自体の表示を停止する処理などが必要です。 ::: ```typescript showLineNumbers view.setEventHandlers({ onClose(actionId, meta) { console.log('Onboarding closed:', actionId); return true; // Allow the onboarding to close }, }); ``` <Details> <summary>イベントの例(クリックで展開)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ### ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。ペイウォールを閉じた後に別のペイウォールを開きたい場合は、もっとシンプルな方法があります。クローズアクションを処理して、イベントデータに依存せずにペイウォールを開いてください。 ::: オンボーディングでペイウォールをシームレスに扱う方法は、アクション ID をペイウォールのプレースメント ID と同じにすることです。 :::note iOSでは、一度に画面に表示できるビュー(ペイウォールまたはオンボーディング)は1つだけです。オンボーディングの上にペイウォールを表示した場合、バックグラウンドのオンボーディングをプログラムで操作することはできません。オンボーディングを閉じようとすると、代わりにペイウォールが閉じられ、オンボーディングが残ったままになります。これを防ぐため、ペイウォールを表示する前に必ずオンボーディングビューを閉じてください。 ::: ```typescript showLineNumbers view.setEventHandlers({ onPaywall(actionId, meta) { // ペイウォールを表示する前にオンボーディングを閉じる view.dismiss().then(() => { openPaywall(actionId); }); }, }); async function openPaywall(placementId: string) { // ここにペイウォールを開くロジックを実装する } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ### ナビゲーションのトラッキング \{#tracking-navigation\} オンボーディングフローの実行中にさまざまなナビゲーション関連イベントが発生すると、アナリティクスイベントを受け取ります。 ```typescript showLineNumbers view.setEventHandlers({ onAnalytics(event, meta) { console.log('Analytics event:', 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` | フロー内のスクリーンの総数 | <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } } ``` </Details> --- # File: capacitor-onboarding-input --- --- title: "Capacitor SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用して、Capacitorアプリでオンボーディングのデータを保存・活用する方法を説明します。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](capacitor-get-pb-paywalls)をご利用ください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブな外観、高速な読み込み、WebViewランタイムへの依存がなくなります。まずは[フローとペイウォールの取得](capacitor-get-pb-paywalls)と[フローとペイウォールの表示](capacitor-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`onStateUpdated` メソッドが呼び出されます。このフィールドタイプをコード内で保存または処理できます。 例: ```typescript view.setEventHandlers({ onStateUpdated(action, meta) { // Process data }, }); ``` アクションのフォーマットは[こちら](https://capacitor.adapty.io/types/onboardingstateupdatedaction)を参照してください。 <Details> <summary>保存されたデータの例(実装によってフォーマットが異なる場合があります)</summary> ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ``` </Details> ## ユースケース \{#use-cases\} ### ユーザープロファイルにデータを紐付ける \{#enrich-user-profiles-with-data\} 入力データをユーザープロファイルにすぐに紐付け、同じ情報を二度尋ねないようにするには、アクションの処理時に入力データで[ユーザープロファイルを更新](capacitor-setting-user-attributes)する必要があります。 たとえば、`name` という ID のテキストフィールドでユーザーに名前を入力してもらい、その値をユーザーの名(ファーストネーム)として設定したい場合や、`email` フィールドでメールアドレスを入力してもらいたい場合、アプリのコードは次のようになります。 ```typescript showLineNumbers view.setEventHandlers({ onStateUpdated(action, meta) { // Store user preferences or responses if (action.elementType === 'input') { const profileParams: any = {}; // Map elementId to appropriate profile field switch (action.elementId) { case 'name': if (action.value.type === 'text') { profileParams.firstName = action.value.value; } break; case 'email': if (action.value.type === 'email') { profileParams.email = action.value.value; } break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile({ params: profileParams }).catch((error) => { // handle the error }); } } }, }); ``` ### オンボーディングの回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングにクイズを使うことで、オンボーディング完了後にユーザーへ表示するペイウォールもカスタマイズできます。 例えば、スポーツの経験について質問し、ユーザーグループごとに異なる CTA やプロダクトを表示することが可能です。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、各選択肢に意味のある ID を割り当てます。 2. ID をもとにクイズの回答を処理し、ユーザーに[カスタム属性を設定](capacitor-setting-user-attributes)します。 ```typescript showLineNumbers view.setEventHandlers({ onStateUpdated(action, meta) { // Handle quiz responses and set custom attributes if (action.elementType === 'select') { const profileParams: any = {}; // Map quiz responses to custom attributes switch (action.elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) profileParams.codableCustomAttributes = { experience: action.value.value }; break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile({ params: profileParams }).catch((error) => { // handle the error }); } } }, }); ``` 3. カスタム属性の各値に対して[セグメントを作成](segments)します。 4. [プレースメント](placements)を作成し、作成した各セグメントに対して[オーディエンス](audience)を追加します。 5. アプリのコードでプレースメントの[ペイウォールを表示](capacitor-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[このボタンのアクションへの応答](capacitor-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: capacitor-best-practices --- --- title: "Capacitor SDKのベストプラクティス" description: "Adapty SDKをCapacitorに統合する際のリファレンスパターン — 呼び出し順序、エラーハンドリング、その他の本番環境対応ルール。" --- <CustomDocCardList /> --- # File: capacitor-sdk-call-order --- --- title: "Capacitor SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的な#2002エラーを回避できます。" --- `adapty.activate()` が完了してから、他のAdapty SDKメソッドを呼び出す必要があります。解決するまで、SDKには状態がありません。`activate()` より前、または並行して発行された呼び出しは、[`#2002 notActivated`](capacitor-handle-errors#custom-network-codes) で失敗します。 アプリがユーザーを認証し、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `adapty.identify()` を呼び出してください。`identify` が完了するまで、ユーザー操作に関するメソッドを呼び出さないでください。`identify` と競合する呼び出しは、[`#3006 profileWasChanged`](capacitor-handle-errors#custom-network-codes) エラーで失敗するか、アクティベーション時に作成された匿名プロファイルに対して実行されてしまいます。この場合、アトリビューション・`appsflyer_id` などのMMP ID・インストールの帰属情報が、識別済みプロファイルに正しく引き継がれないことがあります。アプリがユーザーを認証しない場合は、`identify` をスキップして匿名プロファイルのまま使用し続けてください。 MMP やアナリティクス SDK(AppsFlyer、Adjust、Branch、PostHog)も同じルールに従います。`adapty.activate` を呼び出す前に、これらを先に初期化して UID コールバックを待ってください。そうしないと、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({ apiKey: '...', params: { customerUserId: '...' } })` | アプリ起動時、ステップ 1 の後、customer user ID がある場合 | 推奨。匿名プロファイルは作成されません。 | | 2b | `adapty.activate({ apiKey: '...' })` (`customerUserId` なし) | アプリ起動時、ステップ 1 の後、customer user ID がない場合(または収集しない場合) | Adapty が匿名プロファイルを作成します。 | | 3 | 各 MMP に対して `adapty.setIntegrationIdentifier({ key: '...', value: '...' })` | ステップ 2 の後、ユーザーアクションの呼び出し前 | MMP の ID を正しいプロファイルに紐付けるために必要です。 | | 4 | `await adapty.identify({ customerUserId: 'YOUR_USER_ID' })` | ステップ 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()` は新しい匿名プロファイルを作成します。このプロファイルはウェブのプロファイルとは紐付けられません。アプリ起動前に(認証フローやインストールリファラーなどから)カスタマーユーザーIDを取得できる場合は、そのIDを直接 `activate()` に渡してください。そうでない場合、`identify({ customerUserId: 'YOUR_USER_ID' })` を呼び出してから `restorePurchases` を実行するまで、ウェブでの購入はデバイス上では確認できません。 各ウェブチェックアウトで送信するメタデータについては、以下を参照してください: - [Stripe](stripe) - [Paddle](paddle) --- # File: capacitor-optimize-paywall-fetching --- --- title: "Capacitor SDK でのペイウォールフェッチを最適化する" description: "Adapty のペイウォールを確実にフェッチする:Capacitor 向けのタイミング、キャッシュ、フォールバックのパターン。" --- Capacitor で確実なペイウォールフェッチを実現するには、高速なレンダリング、オーディエンスターゲティングに対応したペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバックという3つの要件を満たす必要があります。以下のルールでは、それを達成するためのタイミング、キャッシュ、フォールバックのパターンについて説明します。 :::tip 以下のルールは、`adapty.activate()` と `adapty.identify()` がすでに完了していることを前提としています。詳しくは [Capacitor SDK の呼び出し順序](capacitor-sdk-call-order) を参照してください。 ::: 以下のアドバイスでは v3 のメソッド名を使用しています。SDK v4 では `getPaywall` が `getFlow` に改名されています([移行ガイド](migration-to-capacitor-sdk-v4) 参照)が、すべてのルールはそのまま適用されます。 ## ルールと注意事項 \{#rules-and-pitfalls\} | すること | しないこと | 理由 | |---|---|---| | 表示しようとしているプレースメントを取得する。 | 起動時にすべてのプレースメントを並行してプリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、バースト中に黒画面を引き起こす。 | | アトリビューションが解決される機会を得た後に `getPaywall` を取得する — たとえば、`activate` の 1〜2 秒後、または `onLatestProfileLoad` リスナーが発火した後。 | `App.tsx` のアプリ起動時に `getPaywall` を呼び出す。 | アトリビューションがまだ反映されていないため、ペイウォールはデフォルトのオーディエンスに対して解決され、セグメントや ASA パーソナライズが暗黙的にスキップされる。 | | `loadTimeoutMs` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無制限に待機する。 | タイムアウトを設定しないと、接続が不安定なユーザーはネットワークが解決するまで空白画面を見続けるか、アプリを閉じてしまう。 | 詳細については、[ペイウォールとプロダクトの取得](fetch-paywalls-and-products-capacitor)(`fetchPolicy` および `loadTimeoutMs` パラメータのリファレンス)と[プレースメント](placements)(適切なプレースメントの選択方法)を参照してください。 ## 通信状態が悪い場合のチューニング \{#tune-for-poor-connectivity\} 通信状態が常に悪い市場(地方エリア、移動中、ルーティングの問題がある地域)向けには: - 初回以外のすべての取得で `fetchPolicy: 'return_cache_data_else_load'` を設定する。 - Adapty ダッシュボードですべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeoutMs` を3000〜5000ミリ秒に設定し、タイムアウト時はフォールバックを受け入れる。 - `adapty.getProfile()` の完了をペイウォール表示の条件にしない。プロファイルの遅延でUIがブロックされないよう、`getPaywall` は独立して呼び出す。 --- # File: capacitor-show-aa-targeted-paywall --- --- title: "Capacitor SDKでの初回起動時にApple Ads対象ペイウォールを表示する" description: "Capacitorで初回起動時すぐにペイウォールを表示し、AdaptyProfile.appliedAttributionSourcesを使用してApple Adsユーザーにアトリビューションが適用された後にペイウォールをアップグレードする方法を説明します。" --- Apple Ads(AA)のアトリビューションは `adapty.activate()` の後に非同期で届きます。初回起動時はまだ届いていないことが多いため、`getFlow` はデフォルトのオーディエンスで解決され、Apple Ads ユーザーは AA セグメント向けのペイウォールを見逃してしまいます。アトリビューションが届くまでペイウォールの表示を遅らせるのではなく、まず即座に表示し、AA アトリビューションが適用されたタイミングでリフレッシュしましょう。こうすることで、Apple Ads ユーザーにはターゲット設定済みのバリアントが表示され、それ以外のユーザーは待ち時間なしでペイウォールを見ることができます。`AdaptyProfile.appliedAttributionSources` を使うと、AA アトリビューションが適用されたタイミングを確認できます。 ## 始める前に \{#before-you-start\} 必要なもの: - Adapty Capacitor SDK **3.17.1** 以降。 - AdaptyでApple Adsがアプリに設定済みであること。[Apple Ads](apple-search-ads) を参照してください。 ## 仕組み \{#how-it-works\} `adapty.activate()` を呼び出すと、SDKはバックグラウンドでApple Ads アトリビューションをAppleにリクエストし、その結果をAdaptyのバックエンドに転送します。AA がプロファイルのアクティブなアトリビューションソースになると、SDKは `onLatestProfileLoad` リスナーに更新された `AdaptyProfile` を届けます。このとき、`appliedAttributionSources` 配列には `'apple_search_ads'` が含まれています。 これにより、ペイウォールを2つのステップで読み込むことができます。 1. すぐに `getFlow` を呼び出します。アトリビューションがまだ適用されていない状態では、Adapty はデフォルトのオーディエンスに対してリクエストを解決するため、ユーザーにはすぐにペイウォールが表示されます。 2. `'apple_search_ads'` が現れたら、再度 `getFlow` を呼び出します。Adapty は Apple Ads オーディエンスに対してリクエストを解決し、ターゲットに合わせたペイウォールを返します。これにより、最初のペイウォールが置き換えられます。 `appliedAttributionSources` は空または存在しない場合があります。これは次のいずれかを意味します: - このプロファイルに対して Apple Ads アトリビューションがまだ処理されていない、または - アトリビューションがまったく届いていない。 どちらの場合でも、ステップ1は安全です — Adaptyは現在のプロファイル状態に一致するオーディエンス(通常はデフォルトオーディエンス)に対してリクエストを解決します。ステップ2は`'apple_search_ads'`が現れたときにのみ実行されます。 :::important その後のすべての起動では、キャッシュされたプロファイルの`appliedAttributionSources`にすでに`'apple_search_ads'`が含まれているため、最初の`getFlow`の時点でApple広告でセグメントされたペイウォールが返されます — 2回目のフェッチや表示上の変化は発生しません。この2ステップのフローが重要なのは、アトリビューションがまだ取得中の初回起動時のみです。 ::: ## 実装 \{#implementation\} ペイウォールをすぐに表示し、`'apple_search_ads'` を受信したらペイウォールを更新します。 1. **SDKを有効化します。** [Capacitor SDKのインストールと設定](sdk-installation-capacitor)をご覧ください。 2. **`getFlow`を使ってペイウォールを読み込み、表示します** — アトリビューションを待たずに進めてください。 3. **`adapty.addListener('onLatestProfileLoad', …)`でプロファイルの更新を購読し**、`'apple_search_ads'`が現れるのを監視します。これが表示されたら、ペイウォールを再取得して更新済みのものを表示してください。まだリスナーを設定していない場合は、[サブスクリプション更新のリッスン](capacitor-check-subscription-status#listen-to-subscription-updates)をご覧ください。 ```typescript const listener = await adapty.addListener('onLatestProfileLoad', async ({ profile }) => { if (!profile.appliedAttributionSources?.includes('apple_search_ads')) return; const targeted = await adapty.getFlow({ placementId }); // present the targeted flow in place of the first one }); // Call listener.remove() after the upgrade, or after a timeout (see below). ``` 4. **タイムアウト後にリスナーを停止する。** Apple Ads のアトリビューションを受け取るユーザーは多くないため、セッション全体で待ち続けるのではなく、一定時間後にリスナーを削除してください。リクエストが失敗した場合でもユーザーに必ず何かが表示されるよう、プレースメントに[フォールバックペイウォール](capacitor-use-fallback-paywalls)を設定しておきましょう。 ## 完全な例 \{#complete-example\} `onAppleAdsAttribution` は、Apple Ads のアトリビューションが適用されると解決し、`timeoutMs` 経過後に拒否されます。以下の使用例では、まずペイウォールをすぐに読み込んでおき、アトリビューションが届いた時点で再取得します。Apple Ads のユーザーにはターゲットペイウォールが表示され、アトリビューションが届かない場合は最初のペイウォールがそのまま表示されます。 ```typescript const APPLE_ADS_SOURCE = 'apple_search_ads'; const placementId = 'YOUR_PLACEMENT_ID'; function hasAppleAdsAttribution(profile: AdaptyProfile): boolean { return profile.appliedAttributionSources?.includes(APPLE_ADS_SOURCE) ?? false; } /** * Resolves once Apple Ads attribution is applied to the profile. * Rejects with a timeout error if attribution never arrives within `timeoutMs`. * Call after `adapty.activate()`. */ export function onAppleAdsAttribution(timeoutMs: number): Promise<void> { return new Promise((resolve, reject) => { let timer: ReturnType<typeof setTimeout> | undefined; let handle: { remove: () => void } | undefined; const stop = () => { clearTimeout(timer); handle?.remove(); }; adapty .addListener('onLatestProfileLoad', ({ profile }) => { if (!hasAppleAdsAttribution(profile)) return; stop(); resolve(); }) .then(listener => { handle = listener; }); timer = setTimeout(() => { stop(); reject(new Error(`Apple Ads attribution timed out after ${timeoutMs}ms`)); }, timeoutMs); }); } let flow = await adapty.getFlow({ placementId }); onAppleAdsAttribution(30_000) .then(() => adapty.getFlow({ placementId })) .then(updated => { flow = updated; }) .catch(() => { console.log('Apple Ads attribution or loading failed'); }); ``` 初回起動時、Apple Ads ユーザーにはデフォルトのペイウォールが一瞬表示された後、差し替えられます。ペイウォールビルダーでペイウォールを表示している場合は、再表示が許容できるかどうかを判断するか、ペイウォールを表示する前にアップグレードを適用してください。`timeoutMs` は、どのくらいの時間待ち受けるかに合わせて調整してください。アトリビューションが届く場合、通常は起動から数秒以内に到着します。 アプリがすでに別の目的(例:[サブスクリプション状態の確認](capacitor-check-subscription-status#listen-to-subscription-updates))のために `onLatestProfileLoad` をリッスンしている場合、変更の必要はありません。`adapty.addListener` は複数の独立したリスナーをサポートしているため、既存のリスナーに影響を与えることなく、新しいリスナーを追加できます。 --- # File: capacitor-test --- --- title: "Capacitor SDKでのテストとリリース" description: "Adapty SDKを使用してCapacitorアプリをテストおよびリリースする方法をご覧ください。" --- すでにCapacitorアプリにAdapty SDKを実装している場合は、すべてが正しく設定されており、iOSとAndroidの両プラットフォームで購入が期待通りに機能することをテストする必要があります。これには、SDKの統合テストと、AppleのサンドボックスEnvironmentおよびGoogle Playのテスト環境を使用した実際の購入フローのテストが含まれます。 ## アプリのテスト \{#test-your-app\} アプリ内課金の包括的なテストについては、プラットフォームごとのテストガイドをご参照ください:[iOSテストガイド](test-purchases-in-sandbox)および[Androidテストガイド](testing-on-android)。 ## リリースの準備 \{#prepare-for-release\} アプリをストアに申請する前に、[リリースチェックリスト](release-checklist)に従って以下を確認してください: - ストア接続とサーバー通知が設定されている - 購入が完了し、Adaptyに報告されている - アクセスレベルが正しくアンロックおよびリストアされる - プライバシーおよびレビューの要件を満たしている --- # File: kids-mode-capacitor --- --- title: "Capacitor SDKのキッズモード" description: "AppleとGoogleのポリシーに準拠するためのキッズモードを簡単に有効化。Capacitor SDKではIDFA、GAID、広告データは収集されません。" --- Capacitorアプリが子ども向けの場合、[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の使用には注意が必要です。`<FirstName.LastName>` 形式のユーザー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、GAID、およびIPアドレスの収集を無効にしてください。 ```typescript showLineNumbers try { await adapty.activate({ apiKey: 'YOUR_PUBLIC_SDK_KEY', params: { // Disable IP address collection ipAddressCollectionDisabled: true, // Disable IDFA collection on iOS ios: { idfaCollectionDisabled: true }, // Disable Google Advertising ID collection on Android android: { adIdCollectionDisabled: true } } }); console.log('Adapty activated with Kids Mode enabled'); } catch (error) { console.error('Failed to activate Adapty with Kids Mode:', error); } ``` ### プラットフォーム固有の設定 \{#platform-specific-configurations\} #### iOS \{#ios\} <SDKv4> IDFAの収集をコード上で無効にしていても(上記参照)、ビルドには`AdSupport`および`AppTrackingTransparency`フレームワークが含まれたままになります。App StoreのKidsカテゴリではこれらのフレームワークは許可されていません。また、v4 SDKはネイティブのiOS SDKをSwift Package Manager経由でインストールするため、Podfileでこれらを除外するステップが存在しません。 Appleの要件に準拠するには、SDKに同梱されている`adapty-kids-mode`コマンドをアプリの`postinstall`に追加してください。これにより、SDKの`KidsMode`トレイトが有効になり、該当コードがコンパイル時に除外されます。このコマンドはインストールのたびに再適用されます。 ```json showLineNumbers title="package.json" { "scripts": { "postinstall": "adapty-kids-mode" } } ``` その後、iOS パッケージを再インストール・再解決し、**Xcode 26** 以降でビルドします: ```sh showLineNumbers title="Shell" npm install npx cap sync ios ``` Kids Mode を無効にするには、`adapty-kids-mode disable` を実行して再度同期してください。 </SDKv4> <SDKv3> iOS に CocoaPods を使用している場合は、ネイティブレベルで Kids Mode を有効にすることもできます: 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 ``` </SDKv3> #### Android: 広告IDパーミッションの削除 \{#android-remove-the-advertising-id-permission\} `adIdCollectionDisabled: true`(上記)を設定すると、AdaptyによるAdvertising IDの収集は停止されますが、SDKは引き続き`AD_ID`パーミッションを宣言します。アプリが**子供専用**を対象とし、Android 13(API 33)以上でコンパイルされている場合、Google Playはそのリクエスト自体を禁止しています。 `<manifest>`要素に次の2つを追加してください: 1. `tools` 名前空間を宣言します(Capacitor のデフォルトマニフェストにはこれが含まれていません)。 2. `AD_ID` の `<uses-permission>` エントリを `tools:node="remove"` 付きで追加して、削除します。 ```xml showLineNumbers title="android/app/src/main/AndroidManifest.xml" <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" /> </manifest> ``` ## 次のステップ \{#next-steps\} キッズモードを有効にしたら、以下を確認してください: 1. アプリを十分にテストし、すべての機能が正常に動作することを確認する 2. 無効にしたデータ収集を反映するよう、アプリのプライバシーポリシーを見直す 3. キッズモードのコンプライアンスに関する明確なドキュメントを添えてアプリを審査に提出する プラットフォーム固有の要件の詳細については: - [iOS SDKのキッズモード](kids-mode)(追加のiOS設定の詳細) - [Android SDKのキッズモード](kids-mode-android)(追加のAndroid設定の詳細) --- # File: capacitor-reference --- --- title: "リファレンス" description: "Adapty Capacitor SDK のリファレンスドキュメント。" --- このページには、Adapty Capacitor SDK のリファレンスドキュメントが含まれています。必要なトピックを選択してください: - **[SDK モデル](https://capacitor.adapty.io/)** - SDK が使用するデータモデルと構造 - **[エラーの処理](capacitor-handle-errors)** - エラーハンドリングとトラブルシューティング --- # File: capacitor-handle-errors --- --- title: "Capacitor SDKでエラーを処理する" description: "Capacitor SDKでエラーを処理します。" --- SDKが返すエラーはすべて `AdaptyError` インスタンスです。以下はその例です。 :::tip **デバッグ前に詳細ログを有効にしてください。** ほとんどの `AdaptyError` は、StoreKit、Play Billing、ネットワーク、またはバックエンドのエラーをラップしています。詳細ログを有効にすると(`adapty.setLogLevel({ logLevel: 'verbose' })` — [ログ設定](sdk-installation-capacitor#logging)を参照)、ラップされたエラーがコンソールに出力され、実際の原因がわかります。`AdaptyError` の `detail` プロパティはログレベルに関係なく値が入っていますが、詳細ログを使うとコンソールにも表示されます。 ::: ```typescript showLineNumbers try { const result = await adapty.makePurchase({ product }); // Handle purchase result if (result.type === 'success') { console.log('Purchase successful:', result.profile); } else if (result.type === 'user_cancelled') { console.log('User cancelled the purchase'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { if (error instanceof AdaptyError) { console.error('Adapty error:', error.adaptyCode, error.localizedDescription); // Handle specific error codes switch (error.adaptyCode) { case ErrorCodeName.cantMakePayments: console.log('In-app purchases are not allowed on this device'); break; case ErrorCodeName.notActivated: console.log('Adapty SDK is not activated'); break; case ErrorCodeName.productPurchaseFailed: console.log('Purchase failed:', error.detail); break; default: console.log('Other error occurred:', error.detail); } } else { console.error('Non-Adapty error:', error); } } ``` ## エラープロパティ \{#error-properties\} `AdaptyError`クラスは以下のプロパティを提供します: | プロパティ | 型 | 説明 | |----------|------|-------------| | `adaptyCode` | `number` | 数値エラーコード(例:`cantMakePayments`の場合は`1003`) | | `localizedDescription` | `string` | ユーザー向けのエラーメッセージ | | `detail` | `string \| undefined` | 追加のエラー詳細(任意) | | `message` | `string` | コードと説明を含む完全なエラーメッセージ | ## エラーコード \{#error-codes\} SDKはエラーコードを扱うための定数とユーティリティをエクスポートしています: ### ErrorCodeName定数 \{#errorcodename-constant\} 文字列識別子を数値コードにマッピングします: ```typescript ErrorCodeName.cantMakePayments // 1003 ErrorCodeName.notActivated // 2002 ErrorCodeName.networkFailed // 2005 ``` ### ErrorCode定数 \{#errorcode-constant\} 数値コードを文字列識別子にマッピングします: ```typescript ErrorCode[1003] // 'cantMakePayments' ErrorCode[2002] // 'notActivated' ErrorCode[2005] // 'networkFailed' ``` ### ヘルパー関数 \{#helper-functions\} ```typescript // Get numeric code from string name: getErrorCode('cantMakePayments') // 1003 // Get string name from numeric code: getErrorPrompt(1003) // 'cantMakePayments' ``` ### エラーコードの比較 \{#comparing-error-codes\} **重要:** `error.adaptyCode`は**数値**なので、数値コードと直接比較してください: ```typescript // Option 1: Use ErrorCodeName constant (recommended) ✅ if (error.adaptyCode === ErrorCodeName.cantMakePayments) { console.log('Cannot make payments'); } // Option 2: Compare with numeric literal ✅ if (error.adaptyCode === 1003) { console.log('Cannot make payments'); } // NOT like this ❌ - compares number to string and will never match if (error.adaptyCode === ErrorCode[1003]) { } ``` ## グローバルエラーハンドラー \{#global-error-handler\} すべての Adapty エラーをキャッチするグローバルエラーハンドラーを設定できます。 ```typescript showLineNumbers // Set up global error handler AdaptyError.onError = (error: AdaptyError) => { console.error('Global Adapty error:', { code: error.adaptyCode, message: error.localizedDescription, detail: error.detail }); // Handle specific error types globally if (error.adaptyCode === ErrorCodeName.notActivated) { // SDK not activated - maybe retry activation console.log('SDK not activated, attempting to reactivate...'); } }; ``` ## よくあるエラー処理パターン \{#common-error-handling-patterns\} ### 購入エラーの処理 \{#handle-purchase-errors\} ```typescript showLineNumbers async function handlePurchase(product: AdaptyPaywallProduct) { try { const result = await adapty.makePurchase({ product }); if (result.type === 'success') { console.log('Purchase successful:', result.profile); } else if (result.type === 'user_cancelled') { console.log('User cancelled the purchase'); } else if (result.type === 'pending') { console.log('Purchase is pending'); } } catch (error) { if (error instanceof AdaptyError) { switch (error.adaptyCode) { case ErrorCodeName.cantMakePayments: console.log('In-app purchases not allowed'); break; case ErrorCodeName.productPurchaseFailed: console.log('Purchase failed:', error.detail); break; default: console.error('Purchase error:', error.localizedDescription); } } } } ``` ### ネットワークエラーへの対処 \{#handle-network-errors\} ```typescript showLineNumbers async function fetchFlow(placementId: string) { try { const flow = await adapty.getFlow({ placementId }); return flow; } catch (error) { if (error instanceof AdaptyError) { switch (error.adaptyCode) { case ErrorCodeName.networkFailed: console.log('Network error, retrying...'); // Implement retry logic break; case ErrorCodeName.serverError: console.log('Server error:', error.detail); break; case ErrorCodeName.notActivated: console.log('SDK not activated'); break; default: console.error('Paywall fetch error:', error.localizedDescription); } } throw error; } } ``` ## システム StoreKit コード \{#system-storekit-codes\} | エラー | コード | 説明 | |-----|----|-----------| | unknown | 0 | 不明または予期しないエラーが発生したことを示します。 | | clientInvalid | 1 | クライアントが実行しようとした操作を許可されていないことを示します。 | | paymentCancelled | 2 | <p>ユーザーが支払いリクエストをキャンセルしたことを示します。</p><p>特に対応は不要ですが、ビジネスロジックの観点から、ユーザーに割引を提示したり、後でリマインドしたりすることができます。</p> | | paymentInvalid | 3 | 支払いパラメーターのいずれかがストアに認識されなかったことを示します。 | | paymentNotAllowed | 4 | <p>ユーザーが支払いを承認する権限を持っていないことを示します。考えられる原因:</p><p></p><p>- ユーザーの国では支払いがサポートされていない。</p><p>- ユーザーが未成年である。</p> | | storeProductNotAvailable | 5 | リクエストされたプロダクトが App Store に存在しないことを示します。対象国でプロダクトが利用可能になっているか確認してください。 | | cloudServicePermissionDenied | 6 | ユーザーがクラウドサービス情報へのアクセスを許可していないことを示します。 | | cloudServiceNetworkConnectionFailed | 7 | デバイスがネットワークに接続できなかったことを示します。 | | cloudServiceRevoked | 8 | ユーザーがクラウドサービスの使用許可を取り消したことを示します。 | | privacyAcknowledgementRequired | 9 | ユーザーがストアのプライバシーポリシーにまだ同意していないことを示します。 | | unauthorizedRequestData | 10 | リクエストが正しく構築されていないことを示します。 | | invalidOfferIdentifier | 11 | <p>オファー識別子が無効です。考えられる原因:</p><p></p><p>- App Store でその識別子のオファーをまだ設定していない。</p><p>- オファーを取り消している。</p><p>- オファー ID を誤って入力している。</p> | | invalidSignature | 12 | 支払いディスカウントの署名が無効であることを示します。**In-app purchase Key ID** フィールドに入力し、**In-App Purchase Private Key** ファイルをアップロードしているか確認してください。詳細は [App Store インテグレーションの設定](app-store-connection-configuration) を参照してください。 | | missingOfferParams | 13 | <p>Adapty インテグレーションまたはオファーに問題があることを示します。</p><p>設定方法の詳細は [App Store インテグレーションの設定](app-store-connection-configuration) および [オファー](offers) を参照してください。</p> | | invalidOfferPrice | 14 | ストアで指定した価格が無効になったことを示します。オファーは常に割引価格である必要があります。 | ## カスタム Android コード \{#custom-android-codes\} | エラー | コード | 説明 | |-----|----|-----------| | adaptyNotInitialized | 20 | `Adapty.activate` メソッドで Adapty SDK を正しく設定する必要があります。設定方法は [React Native 向けのガイド](sdk-installation-reactnative) を参照してください。 | | productNotFound | 22 | 購入リクエストされたプロダクトがストアで利用できないことを示します。 | | invalidJson | 23 | ペイウォールの JSON が無効です。Adapty ダッシュボードで修正してください。修正方法の詳細は [リモートコンフィグでペイウォールをカスタマイズする](customize-paywall-with-remote-config) を参照してください。 | | currentSubscriptionToUpdateNotFoundInHistory | 24 | 更新が必要な元のサブスクリプションが見つかりません。 | | pendingPurchase | 25 | 購入状態が「購入済み」ではなく「保留中」であることを示します。詳細は Android デベロッパー ドキュメントの [保留中のトランザクションの処理](https://developer.android.com/google/play/billing/integrate#pending) を参照してください。 | | billingServiceTimeout | 97 | Google Play が応答する前にリクエストが最大タイムアウトに達したことを示します。Play Billing Library の呼び出しで要求されたアクションの実行が遅延した場合などに発生します。 | | featureNotSupported | 98 | リクエストされた機能が現在のデバイスの Play Store でサポートされていません。 | | billingServiceDisconnected | 99 | `BillingClient` 経由でのクライアントアプリと Google Play Store サービスの接続が切断されたことを示す致命的なエラーです。 | | billingServiceUnavailable | 102 | Google Play Billing サービスが現在利用できないことを示す一時的なエラーです。ほとんどの場合、クライアントデバイスと Google Play Billing サービス間のどこかでネットワーク接続に問題があることを意味します。 | | billingUnavailable | 103 | <p>購入プロセス中にユーザーの課金エラーが発生したことを示します。発生する状況の例:</p><p></p><p>1. ユーザーのデバイスの Play Store アプリが古い。</p><p>2. ユーザーがサポート対象外の国にいる。</p><p>3. ユーザーがエンタープライズユーザーであり、エンタープライズ管理者が購入を無効にしている。</p><p>4. Google Play がユーザーの支払い方法に課金できない(クレジットカードの有効期限切れなど)。</p><p>5. ユーザーが Play Store アプリにログインしていない。</p> | | developerError | 105 | API の使い方が正しくないことを示す致命的なエラーです。 | | billingError | 106 | Google Play 内部の問題を示す致命的なエラーです。 | | itemAlreadyOwned | 107 | 消耗型アイテムがすでに購入済みです。 | | itemNotOwned | 108 | アイテムに対してリクエストされたアクションが失敗したことを示します。 | ## カスタム StoreKit コード \{#custom-storekit-codes\} | エラー | コード | 説明 | |-----|----|-----------| | noProductIDsFound | 1000 | <p>ペイウォール内のプロダクトがいずれもストアで利用できないことを示します。</p><p>このエラーが発生した場合は、以下の手順で解決してください:</p><p></p><p>1. すべてのプロダクトが Adapty ダッシュボードに追加されているか確認する。</p><p>2. アプリの Bundle ID が Apple Connect のものと一致しているか確認する。</p><p>3. アプリストアのプロダクト識別子がダッシュボードに追加したものと一致しているか確認する。識別子にはストアにすでに含まれている場合を除き、Bundle ID を含めないこと。</p><p>4. Apple の税務設定でアプリの有料ステータスがアクティブになっているか確認する。税務情報が最新であり、証明書が有効であることを確認する。</p><p>5. アプリに銀行口座が紐付けられており、収益化の対象になっているか確認する。</p><p>6. プロダクトがすべての地域で利用可能になっているか確認する。また、プロダクトのステータスが **"Ready to Submit"** になっていることを確認する。</p> | | productRequestFailed | 1002 | <p>現時点で利用可能なプロダクトを取得できません。考えられる原因:</p><p></p><p>- キャッシュがまだ作成されておらず、同時にインターネット接続もない。</p> | | cantMakePayments | 1003 | このデバイスではアプリ内課金が許可されていません。 | | noPurchasesToRestore | 1004 | Google Play が復元対象の購入を見つけられなかったことを示します。 | | cantReadReceipt | 1005 | <p>デバイス上に有効なレシートがありません。サンドボックステスト中に発生することがあります。</p><p>特に対応は不要ですが、ビジネスロジックの観点から、ユーザーに割引を提示したり、後でリマインドしたりすることができます。</p> | | productPurchaseFailed | 1006 | プロダクトの購入に失敗しました。このエラーは内部の StoreKit エラーをラップしています。実際の原因を確認するには、ラップされたエラーを読み取るか(または詳細ログを有効にしてコンソールで確認)してください。ラップされたエラーは通常、上記の StoreKit コード 0〜14 のいずれかで、最も多いのは `paymentCancelled`、`paymentInvalid`、`paymentNotAllowed`、`invalidOfferPrice` です。原因が特定できない場合は、新しい[サンドボックスプロファイル](test-purchases-in-sandbox)でお試しください。それでも解決しない場合は Apple サポートにお問い合わせください。 | | refreshReceiptFailed | 1010 | レシートが受信されなかったことを示します。StoreKit 1 のみ対象です。 | | receiveRestoredTransactionsFailed | 1011 | 購入の復元に失敗しました。 | ## カスタムネットワークコード \{#custom-network-codes\} | エラー | コード | 説明 | | :------------------- | :--- | :----------------------------------------------------------- | | notActivated | 2002 | `Adapty.activate` メソッドで Adapty SDK を正しく設定する必要があります。設定方法は [React Native 向けのガイド](sdk-installation-reactnative) を参照してください。 | | badRequest | 2003 | リクエストが不正です。 | | serverError | 2004 | サーバーエラーです。 | | networkFailed | 2005 | ネットワークリクエストに失敗しました。 | | decodingFailed | 2006 | レスポンスのデコードに失敗したことを示します。 | | encodingFailed | 2009 | リクエストのエンコードに失敗したことを示します。 | | analyticsDisabled | 3000 | アナリティクスをオプトアウトしているため、アナリティクスイベントを処理できません。詳細は [アナリティクスインテグレーション](analytics-integration) を参照してください。 | | wrongParam | 3001 | パラメーターの一部が正しくないことを示します(空白にできない箇所が空白になっている、型が違うなど)。 | | activateOnceError | 3005 | `.activate` メソッドを複数回呼び出すことはできません。 | | profileWasChanged | 3006 | 操作中にユーザープロファイルが変更されました。 | | fetchTimeoutError | 3101 | 設定された制限時間内にペイウォールを取得できなかったことを示します。この状況を回避するには、[ローカルフォールバックを設定](fetch-paywalls-and-products)してください。 | | operationInterrupted | 9000 | この操作はシステムによって中断されました。 | --- # File: capacitor-sdk-migration-guides --- --- title: "Capacitor SDK マイグレーションガイド" description: "Adapty Capacitor SDK バージョンのマイグレーションガイド。" --- このページには、Adapty Capacitor SDK のすべてのマイグレーションガイドが含まれています。詳細な手順については、移行先のバージョンを選択してください: - **[v4.0(ベータ版)へ移行](migration-to-capacitor-sdk-v4)** - [**v3.16 へ移行**](migration-to-capacitor-316) --- # File: migration-to-capacitor-sdk-v4 --- --- title: "Adapty Capacitor SDK を v. 4.0 へ移行する" description: "ペイウォール API をフロー API に置き換えて Adapty Capacitor SDK v4.0 (beta) へ移行します。Flow Builder と Paywall Builder の両方に対応しています。" --- Adapty Capacitor SDK 4.0 (beta) ではフローが導入され、それに伴いペイウォール API の名称が変更されました。新しい API は新しい Flow Builder と既存の Paywall Builder の両方で動作します。Adapty ダッシュボード側の設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `adapty.getPaywall({ placementId, locale?, params? })` | `adapty.getFlow({ placementId, params? })` | | `adapty.getPaywallForDefaultAudience({ placementId, locale?, params? })` | `adapty.getFlowForDefaultAudience({ placementId, params? })` | | `adapty.getPaywallProducts({ paywall })` | `adapty.getPaywallProducts({ flow })` | | `adapty.logShowPaywall({ paywall })` | `adapty.logShowFlow({ flow })` | | `AdaptyPaywall`(型) | `AdaptyFlow` + `AdaptyFlowPaywall` | | `createPaywallView(paywall, params?)` | `createFlowView(flow, params?)` | | `PaywallViewController` | `FlowViewController` | | `EventHandlers`(型) | `FlowEventHandlers` | | `CreatePaywallViewParamsInput` | `CreateFlowViewParamsInput` | | `onRenderingFailed` | `onError` | `AdaptyPaywallProduct` はその名前を維持します — プロダクトは引き続きフローに属し、`getPaywallProducts` も名前を維持したまま、`AdaptyFlow` を受け取るようになります。`getFlow` および `getFlowForDefaultAudience` メソッドは `locale` パラメータを受け取らなくなりました。購入とプロファイルに関するAPI(`makePurchase`、`restorePurchases`、`getProfile`、`identify`、`updateProfile`)、および `setFallback` によるフォールバックは変更ありません。ビューメソッド `present`、`dismiss`、`setEventHandlers`、`showDialog`、およびイベントハンドラ `onCloseButtonPress`、`onUrlPress`、`onCustomAction`、`onProductSelected`、`onPurchaseStarted`、`onPurchaseCompleted`、`onPurchaseFailed`、`onRestoreStarted`、`onRestoreCompleted`、`onRestoreFailed`、`onLoadingProductsFailed`、`onWebPaymentNavigationFinished`、`onAndroidSystemBack` は v3 と同じ名前を維持します。オンボーディングメソッドは引き続き動作しますが、非推奨となっています — 詳しくは[オンボーディング API の非推奨化](#onboarding-api-deprecation)を参照してください。一部のデフォルト動作が変更されています — 詳しくは[デフォルト動作の変更点](#default-behavior-changes)を参照してください。 ## 最小バージョン \{#minimum-versions\} ランタイムの要件はv3.16+から変わらず、**iOS 15.0**、**Android minSdk 24**、**Capacitor 8**です。デプロイターゲットの変更は不要です。 新たなビルド要件が1つあります:**Xcode 26以降** — このリリースに同梱されているネイティブAdapty iOS SDK 4.0.0-beta.2はSwift tools 6.2を使用しています。 v4にはネイティブAdapty SDK iOS 4.0.0-beta.2およびAndroid BOM 4.0.0-beta.1が含まれています。 ## インストール \{#installation\} ### パッケージを更新する \{#update-the-package\} v4.0 はプレリリースのため、npm がキャレット/チルダ範囲でプレリリースバージョンを選択しないよう、正確なバージョンを指定してください: ```bash showLineNumbers npm install @adapty/capacitor@4.0.0-beta.2 ``` 次に、ネイティブプロジェクトを同期します: ```bash showLineNumbers npx cap sync ``` ### iOS: Swift Package Manager のみ \{#ios-swift-package-manager-only\} [CocoaPods の spec リポジトリは 2026 年 12 月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)。そのため、v4 以降は `AdaptyCapacitor.podspec` が削除され、iOS への SDK インストールは **Swift Package Manager (SPM) のみ**対応となります。アプリの iOS プロジェクトで Capacitor の SPM 連携を使用する必要があります。 - 新規アプリの場合: SPM パッケージマネージャーを指定して iOS プラットフォームを追加します。 ```bash showLineNumbers npx cap add ios --packagemanager SPM ``` - CocoaPods を使用している既存アプリの場合: [既存プロジェクトで SPM を使用するための Capacitor ガイド](https://capacitorjs.com/docs/ios/spm#using-spm-in-an-existing-capacitor-project)に従って iOS プロジェクトを移行してください。 完全なセットアップ手順については、[SDK のインストール](sdk-installation-capacitor)をご覧ください。 ## フローの取得 \{#fetching-flows\} ### getPaywall → getFlow 返り値の型が `AdaptyPaywall` から `AdaptyFlow` に変わり、`locale` オプションが削除されました。フローをレンダリングする際、ロケールは自動的に解決されます。カスタムペイウォールの場合、すべてのロケールは `flow.remoteConfigs` に含まれます: ```diff showLineNumbers - const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); ``` `getPaywallForDefaultAudience` も同様にリネームされています: ```diff showLineNumbers - const paywall = await adapty.getPaywallForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID', locale: 'en' }); + const flow = await adapty.getFlowForDefaultAudience({ placementId: 'YOUR_PLACEMENT_ID' }); ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` は名前を維持しますが、`AdaptyFlow` を受け取るようになります: ```diff showLineNumbers - const products = await adapty.getPaywallProducts({ paywall }); + const products = await adapty.getPaywallProducts({ flow }); ``` ## データモデル \{#data-model\} `getFlow` は `AdaptyPaywall` の代わりに `AdaptyFlow` を返し、オブジェクトの形状が変更されました。 | v3 `AdaptyPaywall` フィールド | v4 `AdaptyFlow` フィールド | 操作 | |---|---|---| | `remoteConfig?`(単一) | `remoteConfigs?: AdaptyRemoteConfig[]`(配列) | フローは設定された言語ごとにリモートコンフィグを1つ持ちます。ユーザーに合致するものを取得してください:`flow.remoteConfigs?.find((c) => c.lang === 'en')`。 | | `products` | `flow.paywalls[i].productIdentifiers` | プロダクト識別子は、フロー自体ではなく各フローバリアントに移動しました。 | | `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | フローから各ペイウォールバリアントに移動しました。 | | `version?: number` | `flowVersionId?: string` | リネームされ、型が `number` から `string` に変更されました。 | | `hasViewConfiguration` | 削除 | コードから `hasViewConfiguration` のチェックをすべて削除してください — `createFlowView` が代わりにスローするようになりました([フローの表示](#displaying-flows)を参照)。 | | `requestLocale` | 削除 | ロケールはモデルの一部ではなくなりました。 | | _(新規)_ | `paywalls: AdaptyFlowPaywall[]` | 各エントリはフロー内のペイウォールバリアント1つを表します。 | | _(新規)_ | `responseCreatedAt: number` | サーバーレスポンスのタイムスタンプ(ミリ秒単位)。 | `hasViewConfiguration` と `requestLocale` は `AdaptyOnboarding` に残ります — フローモデルからのみ削除されます。 プロダクト識別子はフローから各バリアントに移動しました: ```diff showLineNumbers - const ids = paywall.products; + const ids = flow.paywalls[0].productIdentifiers; ``` ## Web ペイウォールのメソッド \{#web-paywall-methods\} `openWebPaywall` と `createWebPaywallUrl` は名前が変わらず、`paywallOrProduct` オプションに渡す型が `AdaptyPaywall` から `AdaptyFlowPaywall`(フローのバリアント)になります。`AdaptyPaywallProduct` は引き続き渡せます。最初のエントリを読み取る前に `flow.paywalls` が空でないことを確認してください。 ```diff showLineNumbers const flow = await adapty.getFlow({ placementId: 'YOUR_PLACEMENT_ID' }); - await adapty.openWebPaywall({ paywallOrProduct: paywall }); + await adapty.openWebPaywall({ paywallOrProduct: flow.paywalls[0] }); ``` ## フローのビュー数を追跡する \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` は `logShowFlow` に名称変更され、`AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリエーションに対して記録されるため、既存のファネルや A/B テストの指標はダッシュボードを変更することなく機能し続けます。 ```diff showLineNumbers - await adapty.logShowPaywall({ paywall }); + await adapty.logShowFlow({ flow }); ``` v3 と同様に、[フロービルダー](adapty-flow-builder) または [ペイウォールビルダー](adapty-paywall-builder) でレンダリングされたフローやペイウォールを表示する際には、このメソッドを呼び出す必要はありません — Adapty がそれらのビューを自動的に追跡します。 ## フローの表示 \{#displaying-flows\} ### createPaywallView → createFlowView ファクトリー関数名を変更し、`AdaptyFlow` を渡します。返されるコントローラーは `PaywallViewController` から `FlowViewController` に改名されましたが、そのメソッド(`present`、`dismiss`、`setEventHandlers`、`showDialog`)は変わりません。パラメーターの型は `CreatePaywallViewParamsInput` から `CreateFlowViewParamsInput` に改名されました: ```diff showLineNumbers - import { createPaywallView } from '@adapty/capacitor'; + import { createFlowView } from '@adapty/capacitor'; - const view = await createPaywallView(paywall); + const view = await createFlowView(flow); await view.present(); ``` `createFlowView` はビューが設定されていないフローの場合に `AdaptyError` をスローします — これは v3 の `hasViewConfiguration` チェックを置き換えるものです: ```diff showLineNumbers - if (paywall.hasViewConfiguration) { - const view = await createPaywallView(paywall); - await view.present(); - } + try { + const view = await createFlowView(flow); + await view.present(); + } catch (error) { + // the flow has no view configured, or view creation failed + } ``` :::note フロービューは使い捨てです。`dismiss()` を呼び出すとビューは破棄されてイベントハンドラーもクリアされるため、フローを再度表示するには `createFlowView` を呼び出し直してください。 ::: ### Android のセーフエリアパディング \{#android-safe-area-paddings\} `CreateFlowViewParamsInput` に新しいパラメーター `enableSafeArea` が追加されました。このパラメーターは Android のセーフエリアパディングを実行時に制御します。`android` キーの下にネストされており、デフォルト値は `true` です。 ```typescript showLineNumbers const view = await createFlowView(flow, { android: { enableSafeArea: true }, }); ``` ## イベントの処理 \{#handling-events\} イベントハンドラーのインターフェース名が `EventHandlers` から `FlowEventHandlers` に変更され、コールバックが1つ改名されました。既存のハンドラー本体はコードの変更不要です。名前だけ変えてください: ```diff showLineNumbers - onRenderingFailed: (error) => { /* … */ }, + onError: (error) => { /* … */ }, ``` 他のすべてのイベントハンドラーはそのまま名前が変わりません。ただし、2つのハンドラーには第2引数が追加されています。`onPurchaseCompleted` は `(purchaseResult, product)`、`onPurchaseFailed` は `(error, product)` となり、`product` は関連する `AdaptyPaywallProduct` です。詳細は[フロー&ペイウォールイベントの処理](capacitor-handling-events)を参照してください。 v4 では、オプトインで使用できる機能もいくつか追加されています。 - `adapty.openWebUrl({ url, openIn })` と `adapty.requestAppReview()` メソッド — これらはデフォルトの `onUrlPress` および `onRequestAppReview` ハンドラーをバックアップするもので、URLやアプリレビューのプロンプトはそのままネイティブで処理されます。これらのハンドラーをオーバーライドする場合にのみ、直接呼び出してください。 - オブザーバーモードでのフロー内購入処理は、新しい `onObserverPurchaseInitiated` / `onObserverRestoreInitiated` ハンドラーを使用します。詳しくは[オブザーバーモードでフローを表示する](capacitor-present-flows-in-observer-mode)を参照してください。 ## デフォルト動作の変更 \{#default-behavior-changes\} これらの変更はコンパイルエラーを引き起こさないため、実行時にテストしてください: - **`onAndroidSystemBack`**: デフォルトの動作が、ビューを閉じる動作から開いたままにする動作に変更されました。以前の動作に戻すには、ハンドラーから `true` を返してください。 - **`onPurchaseCompleted`**: デフォルトの動作が、ビューを閉じる動作(ユーザーが購入をキャンセルした場合を除く)から、常に開いたままにする動作に変更されました。以前の動作に戻すには、ハンドラーから `purchaseResult.type !== 'user_cancelled'` を返してください。 - **`onRestoreCompleted`**: デフォルトの動作が、復元成功後にビューを閉じる動作から開いたままにする動作に変更されました。以前の動作に戻すには、ハンドラーから `true` を返してください。 - **`onUrlPress`**: デフォルトでネイティブレイヤーを通じてURLを開くようになり、ダッシュボードのアプリ内ブラウザまたは外部ブラウザの設定が反映されます。URLを独自に開く場合は、ハンドラーをオーバーライドしてください。 - **ビューは使い捨て**: `dismiss()` を呼び出すと、ビューは破棄されます。フローを再度表示するには、`createFlowView` を再度呼び出してください。 ## 削除された API \{#removed-apis\} ### 削除されたエクスポート \{#removed-exports\} 以下のシンボルは `@adapty/capacitor` からエクスポートされなくなりました。これらのインポートを削除してください: - **`AdaptyPaywall`**: 代わりに `AdaptyFlow` および `AdaptyFlowPaywall` を使用してください。 - **`ProductReference`**: 代わりに `AdaptyProductIdentifier` を使用してください。`flow.paywalls[i].productIdentifiers` から読み取ります。 - **`AdaptyPaywallBuilder`**: 削除されました。フローとペイウォールはネイティブでレンダリングされます。 - **`AdaptyAndroidSubscriptionUpdateParameters`**: ネストされた `android` 購入パラメータの形式を使用してください(下記参照)。 ### activate: lockMethodsUntilReady `lockMethodsUntilReady`(v3 ではすでに非推奨の no-op でした)は削除されました。`activate` の呼び出しから削除してください — そのままではコンパイルが通りません: ```diff showLineNumbers - await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY', params: { lockMethodsUntilReady: true } }); + await adapty.activate({ apiKey: 'PUBLIC_SDK_KEY' }); ``` ### makePurchase: Android パラメーター \{#makepurchase-android-parameters\} 非推奨となっていた `MakePurchaseParamsInput` のフラットな Android 形式は削除されました。ネストされた形式のみが使用可能です。Android の購入パラメーターは `params: { android: { ... } }` に移動してください。完全な例については[購入の実装](capacitor-making-purchases)を参照してください。 ## オンボーディング API の非推奨化 \{#onboarding-api-deprecation\} 従来のオンボーディング API は v4.0 で非推奨となり、[Flow Builder](adapty-flow-builder) に置き換えられました。現在も動作しますが、将来のリリースで削除される予定です。オンボーディングを Flow Builder へ移行する計画を立ててください。 非推奨のシンボル: `getOnboarding`、`getOnboardingForDefaultAudience`、`createOnboardingView`、および `OnboardingViewController`。 --- # File: migration-to-capacitor-316 --- --- title: "Adapty Capacitor SDK を v3.16 に移行する" description: "より良いパフォーマンスと新しいマネタイズ機能のために Adapty Capacitor SDK v3.16 に移行します。" --- Adapty SDK v3.16.0 以降、Capacitor 8 が必要です。Capacitor 7 を使用する場合は、Adapty SDK v3.15 をご利用ください。 Capacitor SDK v3.16 にアップグレードするには、プロジェクトが Capacitor 8 を使用していることを確認してください。まだ Capacitor 7 を使用している場合は、次の 2 つの選択肢があります。 1. **Capacitor 8 にアップグレードする**: [公式 Capacitor 移行ガイド](https://capacitorjs.com/docs/updating/8-0)に従ってプロジェクトを更新し、Adapty SDK v3.16 をインストールします。 2. **Adapty SDK v3.15 を使い続ける**: Capacitor 8 へのアップグレードが難しい場合は、Capacitor 7 をサポートする Adapty SDK v3.15 を引き続き使用してください。 --- # End of Documentation _Generated on: 2026-07-24T13:00:57.636Z_ _Successfully processed: 45/45 files_ # 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: ^<the latest SDK version> ``` 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<MyApp> { @override void initState() { _initializeAdapty(); super.initState(); } Future<void> _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` ファイルのルートの `<manifest>` タグに tools が含まれていることを確認してください: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. `<application>` でバックアップ属性を上書きする \{#2-override-backup-attributes-in-application\} 同じ `AndroidManifest.xml` ファイルで、`<application>` タグを更新して、アプリが最終的な値を提供し、マニフェストマージャーにライブラリの値を置き換えるよう指示します: ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` いずれかの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" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Android 11以前**(従来のフルバックアップコンテンツ形式を使用): ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.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 <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### 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<FlowScreen> createState() => _FlowScreenState(); } class _FlowScreenState extends State<FlowScreen> { @override void initState() { super.initState(); _showFlowIfNeeded(); } Future<void> _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<bool> _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<void> _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)を参照してください。 ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ログイン・サインアップ時 \{#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)を参照してください。 <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **ガイド:** - [ペイウォールを使って購入を有効にする(クイックスタート)](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がダッシュボードと完全に一致しているか、プレースメントにオーディエンスが割り当てられているか確認する。 ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](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から取得したプロダクトが表示される。プロダクトをタップするとサンドボックス購入ダイアログが表示される。 - **注意点:** プロダクト配列が空 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、プレースメントにオーディエンスがあるか確認する。 ::: </TabItem> <TabItem value="observer" label="Observer mode"> **ガイド:** - [オブザーバーモードの概要](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へのトランザクション報告が行われているか、両ストアでサーバー通知が設定されているか確認する。 ::: </TabItem> </Tabs> ### サブスクリプションステータスを確認する \{#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 からフローとペイウォールを取得する方法。" --- <SDKv4> <MethodPromo method="getFlow" /> [フローまたはペイウォールビルダーのペイウォールを設計](adapty-paywall-builder)したら、モバイルアプリに表示できます。最初のステップは、以下に説明するように、プレースメントに関連付けられたフローまたはペイウォールとそのビュー設定を取得することです。 このトピックはフローおよびペイウォールビルダーでカスタマイズされたペイウォールに関するものです。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォール用のペイウォールとプロダクトの取得](fetch-paywalls-and-products-flutter)トピックを参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリにフローとペイウォールを表示する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フロー/ペイウォールを組み込む](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-flutter) をインストールする。 </details> ## フローまたはペイウォールの取得 \{#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` | <p>デフォルトでは、SDK はサーバーからデータの取得を試み、失敗した場合はキャッシュされたデータを返します。この方式を推奨しているのは、常に最新のデータをユーザーに届けられるためです。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を利用していると考えられる場合は、`.returnCacheDataElseLoad` を使用することを検討してください。キャッシュが存在する場合はそちらを返す方式です。この場合、ユーザーが最新データを受け取れないことがありますが、通信状況が不安定でも高速に読み込めます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても安全です。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールを2つの層でローカルに保存しています。上述の定期更新されるキャッシュと、[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより高速に取得するために CDN を使用し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのペイウォールを提供できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウトを制限する `Duration`。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p>なお、内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。</p> | レスポンスパラメータ: | パラメーター | 説明 | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 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` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーのインターネット環境が不安定だと考えられる場合は、`.returnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュデータを返します。この場合、最新のデータが届かない可能性はありますが、接続状況に関わらず読み込みが速くなります。キャッシュはセッション中に定期的に更新されるため、ネットワークリクエストを減らす目的でキャッシュを利用しても問題ありません。</p><p></p><p>なお、キャッシュはアプリの再起動後も保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p> | ## アセットのカスタマイズ \{#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 時間の残り時間。 </SDKv4> <SDKv3> [Adapty ダッシュボードのペイウォールビルダー](adapty-paywall-builder)でペイウォールのビジュアル部分をデザインしたら、モバイルアプリに表示できます。まず、プレースメントに関連付けられたペイウォールとそのビュー設定を取得する必要があります。詳細は以下をご覧ください。 :::warning 新しいペイウォールビルダーは Flutter SDK バージョン 3.3.0 以上が必要です。 ::: ペイウォールビルダーでカスタマイズしたペイウォールについての説明です。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォールのペイウォールとプロダクトを取得する](fetch-paywalls-and-products-flutter)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールの表示を開始する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[ペイウォールを作成してプロダクトを追加](create-paywall)する。 3. Adapty ダッシュボードで[プレースメントを作成してペイウォールを追加](create-placement)する。 4. モバイルアプリに [Adapty SDK](sdk-installation-flutter) をインストールする。 </details> ## ペイウォールビルダーで作成したペイウォールを取得する \{#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** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子です。このパラメータは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードや推奨される使用方法については、[ローカライズとロケールコード](flutter-localizations-and-locale-codes)をご覧ください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この方法を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合はキャッシュデータを返すことも検討してください。この場合、ユーザーが最新のデータを受け取れないことがありますが、通信状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても問題ありません。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストール時または手動でのクリーンアップ時にのみクリアされます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2つの層で保存します。1つは上記の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。またCDNを使用してペイウォールの取得を高速化し、CDNが利用できない場合に備えたスタンドアロンのフォールバックサーバーも用意しています。このシステムにより、インターネット接続が不安定な状況でも確実に最新のペイウォールを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。</p><p>内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p><p>Android の場合: 拡張関数(例: `5.seconds`、`.seconds` は `import com.adapty.utils.seconds` から)を使用して `TimeInterval` を作成するか、`TimeInterval.seconds(5)` を使用できます。制限を設けない場合は `TimeInterval.INFINITE` を使用してください。</p> | レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | 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** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメータは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードの詳細と推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用して、キャッシュが存在する場合はキャッシュされたデータを返すことを検討してください。この場合、最新データが取得できないことがありますが、接続状況に関わらず高速な読み込みが可能になります。キャッシュはセッション中も定期的に更新されるため、ネットワークリクエストを減らす目的で安全に使用できます。</p><p></p><p>なお、キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ削除されます。</p> | ## アセットのカスタマイズ \{#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時間のうち、残りの時間。 </SDKv3> --- # File: flutter-present-paywalls --- --- title: "フローとペイウォールの表示 - Flutter" description: "Adapty のマネタイズ機能を使って Flutter アプリでフローとペイウォールを表示する方法を説明します。" --- <SDKv4> 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) } } ``` ::: </SDKv4> <SDKv3> ペイウォールビルダーでペイウォールをカスタマイズした場合、モバイルアプリのコード側でレンダリングの処理を実装しなくても、ユーザーに表示できます。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。 :::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) } } ``` ::: </SDKv3> --- # File: flutter-handle-paywall-actions --- --- title: "Flutter SDKでボタンアクションに応答する" description: "AdaptyのFlutterでペイウォールのボタンアクションを処理し、アプリの収益化を改善します。" --- <SDKv4> 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; } } ``` </SDKv4> <SDKv3> ペイウォールビルダーを使ってペイウォールを構築する場合、ボタンを適切に設定することが重要です: 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; } } ``` </SDKv3> --- # File: flutter-handling-events --- --- title: "Flutter - フロー & ペイウォールイベントの処理" description: "Adapty を使って Flutter でサブスクリプション関連のイベントを処理し、ユーザーの操作を効果的に追跡する方法を解説します。" --- <SDKv4> :::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) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```dart void flowViewDidSelectProduct(AdaptyUIFlowView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ``` </Details> #### 購入の開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void flowViewDidStartPurchase(AdaptyUIFlowView view, AdaptyPaywallProduct product) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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' } ``` </Details> #### 購入完了 \{#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; } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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; } } ``` </Details> :::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) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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) } ``` </Details> ユーザーが必要な `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` は任意です。 </SDKv4> <SDKv3> :::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) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```dart void paywallViewDidSelectProduct(AdaptyUIPaywallView view, String productId) { // productId is a String: productId; // 'premium_monthly' } ``` </Details> #### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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' } ``` </Details> #### 購入完了 \{#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; } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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; } } ``` </Details> このような場合はスクリーンを閉じることをおすすめします。ペイウォール画面を閉じる方法については、[ボタンアクションへの対応](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`。 | <Details> <summary>イベント例(クリックして展開)</summary> ```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 } } ``` </Details> #### 購入失敗 \{#failed-purchase\} このメソッドは、支払いの問題やネットワークエラーなどにより購入が失敗した場合に呼び出されます。ユーザーが自発的にキャンセルした場合やペンディング中のトランザクションには**呼び出されません**。それらは `paywallViewDidFinishPurchase` で処理されます: ```dart showLineNumbers title="Flutter" void paywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } ``` </Details> #### 復元の開始 \{#started-restore\} ユーザーが復元プロセスを開始すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### 復元成功 \{#successful-restore\} 購入の復元が成功すると、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```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) } ``` </Details> ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることを推奨します。確認方法については [サブスクリプションのステータス](flutter-listen-subscription-changes) を、ペイウォール画面を閉じる方法については [ボタン操作への対応](flutter-handle-paywall-actions) を参照してください。 #### 復元の失敗 \{#failed-restore\} 購入の復元に失敗した場合、このメソッドが呼び出されます: ```dart showLineNumbers title="Flutter" void paywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } ``` </Details> ### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクト配列を渡さなかった場合、AdaptyUIはサーバーから必要なオブジェクトを自動的に取得します。この処理が失敗した場合、AdaptyUIは以下のメソッドを呼び出してエラーを通知します: ```dart showLineNumbers title="Flutter" void paywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```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 } ``` </Details> #### レンダリングエラー \{#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 } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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() } ``` </Details> 通常の状況では、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひご連絡ください。 </SDKv3> --- # 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: "アプリのローカリゼーションとロケールコードを管理して、グローバルなユーザーにリーチしましょう。" --- <SDKv4> ## これが重要な理由 \{#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 がどのように正規化するかを説明しています。 </SDKv4> <SDKv3> ## これが重要な理由 \{#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` が返されることになり、予期しない動作となる可能性があります。 万が一このアプローチを採用する場合は、関連するすべてのユースケースを網羅していることを確認してください。 </SDKv3> --- # 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: <YOUR_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: <YOUR_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** トグルを有効にしてください。 <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ペイウォールのビュー数が多すぎる \{#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)をご参照ください。 ::: <details> <summary>フローの表示を始める前に(クリックして展開)</summary> 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)。 </details> オブザーバーモードでは、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<void> 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<void> 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<void> 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<bool> 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 でペイウォールとプロダクトを取得し、ユーザーの収益化を強化します。" --- <SDKv4> リモートコンフィグとカスタムペイウォールを表示する前に、それらに関する情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。フローおよびペイウォールビルダーでカスタマイズされたペイウォールの取得については、[フローとペイウォールを取得する](flutter-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を開始する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. [ペイウォールを作成し、プロダクトをペイウォールに組み込む](create-paywall)(Adapty ダッシュボード) 3. [プレースメントを作成し、ペイウォールをプレースメントに組み込む](create-placement)(Adapty ダッシュボード) 4. [Adapty SDK をインストールする](sdk-installation-flutter)(モバイルアプリ) </details> ## フローの情報を取得する \{#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` | <p>デフォルトでは、SDK はサーバーからデータを取得しようとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを受け取れるためです。</p><p></p><p>ただし、ユーザーがインターネット接続の不安定な環境にいると考えられる場合は、`.returnCacheDataElseLoad` の使用を検討してください。これはキャッシュが存在する場合にそのデータを返します。この場合、ユーザーは最新データを取得できないことがありますが、接続状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で安全に使用できます。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールを 2 層で保存しています。1 つは上述の定期更新されるキャッシュ、もう 1 つは[フォールバックペイウォール](flutter-use-fallback-paywalls)です。また、ペイウォールをより速く取得するために CDN を使用し、CDN に到達できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも確実に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5 秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p></p><p>なお、このメソッドは内部で複数のリクエストを行う場合があるため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトするケースがまれにあります。</p> | :::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つの割引フェーズを含めることができます。各フェーズオブジェクトには以下の便利なプロパティがあります:<br/>• `paymentMode`:`AdaptyPaymentMode.freeTrial`、`AdaptyPaymentMode.payAsYouGo`、`AdaptyPaymentMode.payUpFront`、`AdaptyPaymentMode.unknown` の値を持つ列挙型です。フリートライアルは `AdaptyPaymentMode.freeTrial` タイプになります。<br/>• `price`:割引価格を数値で表します。フリートライアルの場合は `0` になります。<br/>• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列です。例えば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。<br/>• `subscriptionPeriod`:オファー期間の個別の詳細をこのプロパティで取得することもできます。オファーに対しても前のセクションで説明したのと同じ方法で機能します。<br/>• `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` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。このオプションを推奨します。ユーザーが常に最新のデータを受け取れるためです。</p><p></p><p>ただし、ユーザーがネットワーク接続が不安定な環境にいることが多いと想定される場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合にそれを返すことを検討してください。この場合、最新のデータが届かない可能性はありますが、ネットワーク状況に関わらず読み込みを高速化できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを抑える目的で使用しても安全です。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p> | </SDKv4> <SDKv3> リモートコンフィグとカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズされたペイウォールの取得については、[ペイウォールビルダーのペイウォールと設定の取得](flutter-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. [ペイウォールを作成し、プロダクトをペイウォールに組み込む](create-paywall)(Adapty ダッシュボードで行います)。 3. [プレースメントを作成し、ペイウォールをプレースメントに組み込む](create-placement)(Adapty ダッシュボードで行います)。 4. [Adapty SDK をインストールする](sdk-installation-flutter)(モバイルアプリに導入します)。 </details> ## ペイウォール情報の取得 \{#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** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-remote-config-locale)の識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語を、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよびその推奨使用方法については、[ローカライゼーションとロケールコード](flutter-localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーがネットワークの不安定な環境にいることが多いと判断した場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在するときにキャッシュデータを返すことを検討してください。この場合、最新データを取得できないことがありますが、ネットワーク状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールを2層で保存します。1つは上記の定期更新されるキャッシュ、もう1つは[フォールバックペイウォール](flutter-use-fallback-paywalls)です。また、ペイウォールをより速く取得するためにCDNを使用し、CDNが利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新のペイウォールを取得できるように設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト時間を制限します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p></p><p>内部で複数のリクエストが実行される場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p> | プロダクト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つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下の便利なプロパティが含まれています:<br/>• `paymentMode`:`AdaptyPaymentMode.freeTrial`、`AdaptyPaymentMode.payAsYouGo`、`AdaptyPaymentMode.payUpFront`、`AdaptyPaymentMode.unknown` の値を持つ列挙型。無料トライアルは `AdaptyPaymentMode.freeTrial` タイプになります。<br/>• `price`:数値としての割引価格。無料トライアルの場合は `0` になります。<br/>• `localizedNumberOfPeriods`:オファーの長さをデバイスのロケールでローカライズした文字列。たとえば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。<br/>• `subscriptionPeriod`:オファー期間の個別の詳細をこのプロパティで取得することもできます。オファーに対しても前のセクションで説明したのと同じ方法で機能します。<br/>• `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** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語を、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよびその推奨される使用方法については、[ローカライズとロケールコード](flutter-localizations-and-locale-codes)をご覧ください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法はユーザーが常に最新のデータを取得できるため、推奨します。</p><p></p><p>ただし、ユーザーがインターネット接続の不安定な環境にいる場合は、`.returnCacheDataElseLoad` の使用を検討してください。これはキャッシュが存在する場合にキャッシュデータを返します。この場合、最新のデータが取得できないこともありますが、接続状況に関わらず読み込みが速くなります。キャッシュはセッション中に定期的に更新されるため、ネットワークリクエストを避ける目的でキャッシュを利用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ消去されます。</p> | </SDKv3> --- # File: present-remote-config-paywalls-flutter --- --- title: "Flutter SDKでリモートコンフィグでデザインされたペイウォールを表示する" description: "Adapty Flutter SDKでリモートコンフィグペイウォールを表示し、ユーザー体験をパーソナライズする方法を紹介します。" --- <SDKv4> リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコード上でレンダリングを実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、ペイウォールのビューをどのように表示するかはあなた次第です。リモートコンフィグ経由で設定されたカスタムペイウォールを表示するために、リモート設定を取得するメソッドを提供しています。 ## ペイウォールのリモートコンフィグを取得して表示する \{#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` オブジェクト。 | </SDKv4> <SDKv3> リモートコンフィグを使ってペイウォールをカスタマイズした場合は、ユーザーに表示するためのレンダリングをアプリのコードで実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、ペイウォールの見た目をどうするかはすべて自分で決められます。リモートコンフィグを取得するメソッドを用意しているので、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 ## ペイウォールのリモートコンフィグを取得して表示する \{#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) オブジェクト。 | </SDKv3> --- # 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** | <p>リクエストが成功した場合、レスポンスにはこのオブジェクトが含まれます。[AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) オブジェクトは、アプリ内のユーザーのアクセスレベル、サブスクリプション、および買い切り購入に関する包括的な情報を提供します。</p><p>アクセスレベルのステータスを確認して、ユーザーがアプリに必要なアクセス権を持っているかどうかを確かめてください。</p> | :::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\} <Details> <summary>オファーコードについて</summary> オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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アナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。 </Details> アプリ内でコード引き換えシートを表示するには: ```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** | <p>[`AdaptyProfile`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) オブジェクト。このモデルには、アクセスレベル、サブスクリプション、非サブスクリプション購入に関する情報が含まれています。</p><p>ユーザーがアプリにアクセスできるかどうかを確認するには、**アクセスレベルのステータス**を確認してください。</p> | :::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で行います。" --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+(最新版)" default> 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 | 必須 | <ul><li> iOS の場合: トランザクションの識別子。</li><li> Android の場合: 購入の文字列識別子 `purchase.getOrderId`。ここで、purchase は billing ライブラリの [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。</li></ul> | | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) オブジェクトの `variationId` プロパティを使用して取得できます。 | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x (legacy)" default> オブザーバーモードでは、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 | 必須 | <ul><li> iOS、StoreKit 1 の場合:[SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction) オブジェクト。</li><li> iOS、StoreKit 2 の場合:[Transaction](https://developer.apple.com/documentation/storekit/transaction) オブジェクト。</li><li> Android の場合:String 識別子(purchase は billing library の [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスで、その purchase.getOrderId)。</li></ul> | | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyPaywall-class.html) オブジェクトの `variationId` プロパティから取得できます。 | </TabItem> <TabItem value="old2" label="Adapty SDK up to 3.2.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> **トランザクションのレポート** - バージョン3.1.x以前は、App Storeのトランザクションを自動的に検知するため、手動でのレポートは不要です。 - バージョン3.2はオブザーバーモードをサポートしていません。 </TabItem> <TabItem value="kotlin" label="Android and Android-based cross-platforms" default> **トランザクションのレポート** `restorePurchases`を使って、[モバイルコードでの購入のリストア](flutter-restore-purchase)ページで説明しているように、Observer ModeでAdaptyにトランザクションを報告してください。 :::warning **トランザクションの報告を省略しないでください!** `restorePurchases`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: </TabItem> </Tabs> **ペイウォールとトランザクションの紐付け** 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) { } ``` </TabItem> </Tabs> --- # 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` で使用できるキー `<Key>` と値 `<Value>` の一覧は以下のとおりです。 | キー | 値 | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | 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)を確認するだけで、ユーザーのサブスクリプション状態を手軽に把握できます。 <details> <summary>サブスクリプションステータスを確認する前に(クリックして展開)</summary> - iOSの場合、[App Store Server Notifications](enable-app-store-server-notifications)を設定してください - Androidの場合、[リアルタイム デベロッパー通知(RTDN)](enable-real-time-developer-notifications-rtdn)を設定してください </details> ## アクセスレベルと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 | <p>[AdaptyProfile](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyProfile-class.html) オブジェクト。通常、ユーザーがアプリのプレミアムアクセスを持っているかどうかを判断するには、プロファイルのアクセスレベルのステータスのみを確認すれば十分です。</p><p></p><p>`.getProfile` メソッドは常に API へのクエリを試みるため、最新の結果を返します。何らかの理由(例:インターネット接続がない場合など)で Adapty SDK がサーバーから情報を取得できない場合は、キャッシュのデータが返されます。また、Adapty SDK は `AdaptyProfile` のキャッシュを定期的に更新し、情報をできる限り最新の状態に保つことも重要なポイントです。</p> | `.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の扱いには十分注意することをお勧めします。`<FirstName.LastName>` 形式のユーザー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** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライズ識別子です。このパラメータは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグからなる言語コードである必要があります。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合に返すことを検討してください。この場合、ユーザーが最新のデータを取得できないことがありますが、接続状態に関わらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的での使用は安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリーンアップした場合にのみ削除されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層で保存します。1つは上記の定期更新されるキャッシュ、もう1つはフォールバックオンボーディングです。また、CDN を使用してオンボーディングを高速に取得し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p>内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメータ | 説明 | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | 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** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライゼーション識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目のサブタグはリージョンを表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。このオプションを推奨するのは、ユーザーが常に最新のデータを取得できることが保証されるためです。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境にある場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合はキャッシュデータを返すことを検討してください。この場合、ユーザーが最新データを取得できないことがありますが、接続が不安定でも読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるためにキャッシュを使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時またはキャッシュを手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層で保存しています。1つは上記の定期更新されるキャッシュ、もう1つはフォールバックオンボーディングです。また、オンボーディングをより高速に取得するためにCDNを使用し、CDNが利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常にオンボーディングの最新バージョンを取得できるよう設計されています。</p> | --- # 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` に設定することでこの動作をカスタマイズできます。 <Tabs> <TabItem value="standalone" label="スタンドアロン画面" default> ```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 } ``` </TabItem> <TabItem value="embedded" label="埋め込みウィジェット"> ```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) { }, ) ``` </TabItem> </Tabs> ## セーフエリアのパディングを無効にする(Android) \{#disable-safe-area-paddings-android\} デフォルトでは、Androidデバイスにおいて、オンボーディングビューはステータスバーやナビゲーションバーなどのシステムUI要素を避けるため、セーフエリアのパディングを自動的に適用します。ただし、この動作を無効にしてレイアウトを完全に制御したい場合は、アプリにboolean型のリソースを追加することで対応できます。 1. `android/app/src/main/res/values` に移動します。`bools.xml` ファイルが存在しない場合は、新規作成してください。 2. 以下のリソースを追加します。 ```xml <resources> <bool name="adapty_onboarding_enable_safe_area_paddings">false</bool> </resources> ``` 変更はアプリ内のすべてのオンボーディングにグローバルに適用されます。 --- # 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を割り当てることができます。 <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ユーザーがカスタムボタン(**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); } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ### オンボーディングの読み込み完了 \{#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}'); } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ### オンボーディングを閉じる \{#closing-onboarding\} ユーザーが **Close** アクションが割り当てられたボタンをタップすると、オンボーディングは閉じられたとみなされます。 <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::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(); } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ### ペイウォールを開く \{#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<void> _openPaywall(String actionId) async { // Implement your paywall opening logic here } // Embedded widget onPaywallAction: (meta, actionId) { _openPaywall(actionId); } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ### ナビゲーションの追跡 \{#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` | フロー内のスクリーンの合計数 | <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } } ``` </Details> --- # 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)を参照してください。 <Details> <summary>各 params タイプのプロパティの形状(クリックして展開)</summary> ```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; } } ``` </Details> ## ユースケース \{#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<AdaptyPaywall> 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<AdaptyPaywall>(); late final StreamSubscription<AdaptyProfile> subscription; late final Timer timer; void resolve(Future<AdaptyPaywall> 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** をコピーします。 <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 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) に移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テスト対象のプロダクトが **Ready to Submit** になっていることを確認します。 <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. テーブルのプロダクト ID と Adapty ダッシュボードの [**Products**](https://app.adapty.io/products) タブのプロダクト ID を比較します。ID が一致しない場合は、テーブルからプロダクト ID をコピーし、Adapty ダッシュボードでそれを使って[プロダクトを作成](create-product)してください。 <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 3. プロダクトの販売状況を確認する \{#step-4-check-product-availability\} 1. **App Store Connect** に戻り、同じ **Subscriptions** セクションを開きます。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックしてプロダクト一覧を表示します。 3. テスト対象のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Availability** セクションまでスクロールし、必要な国と地域がすべて表示されていることを確認します。 <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 4. プロダクトの価格を確認する \{#step-5-check-product-prices\} 1. **App Store Connect** の **Monetization** → **Subscriptions** セクションに移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックします。 3. テスト対象のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Subscription Pricing** までスクロールし、**Current Pricing for New Subscribers** セクションを展開します。 <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 必要な価格がすべて表示されていることを確認します。 <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 5. アプリの有料ステータス、銀行口座、税務フォームがアクティブであることを確認する \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. [**App Store Connect**](https://appstoreconnect.apple.com/) のホームページで **Business** をクリックします。 <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 会社名を選択します。 <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. スクロールして、**Paid Apps Agreement**、**Bank Account**、**Tax forms** がいずれも **Active** になっていることを確認します。 <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 以上の手順を実施することで、`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<String, String>(); 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(<YOUR_OPTIONS>); 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: <BRANCH_IDENTITY_ID>, + ); - 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 はエラーやその他の重要な情報をログに記録し、アプリの動作状況を把握できるようにします。利用可能なレベルは以下のとおりです。<ul><li>error: エラーのみがログに記録されます。</li><li>warn: エラーと、重大なエラーではないが注意が必要な SDK からのメッセージがログに記録されます。</li><li>info: エラー、警告、および各モジュールのライフサイクルなどの重要な情報メッセージがログに記録されます。</li><li>verbose: 関数呼び出し、API クエリなど、デバッグ時に役立つ追加情報がすべてログに記録されます。</li></ul> | | **withObserverMode** | 任意 | <p>[オブザーバーモード](observer-vs-full-mode)を制御する真偽値です。購入とサブスクリプションの状態を自分で管理し、サブスクリプションイベントの送信と分析に Adapty を使用する場合は有効にしてください。</p><p>デフォルト値は `false` です。</p><p></p><p>🚧 オブザーバーモードで動作している場合、Adapty SDK はトランザクションをクローズしないため、自前で処理する必要があります。</p> | | **withCustomerUserId** | 任意 | 自社システムにおけるユーザーの識別子です。サブスクリプションおよび分析イベントに含めて送信し、イベントを正しいプロファイルに紐付けます。[**Profiles and Segments**](https://app.adapty.io/profiles/users) メニューで `customerUserId` によるユーザー検索も可能です。 | | **withIdfaCollectionDisabled** | 任意 | <p>IDFA の収集と共有を無効にするには `true` を設定します。</p><p>ユーザーの IP アドレス共有も無効になります。</p><p>デフォルト値は `false` です。</p><p>IDFA 収集の詳細については、[Analytics integration](analytics-integration#disable-collection-of-advertising-identifiers) セクションをご参照ください。</p> | | **withIpAddressCollectionDisabled** | 任意 | <p>ユーザーの IP アドレスの収集と共有を無効にするには `true` を設定します。</p><p>デフォルト値は `false` です。</p> | ### 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: <AdaptyUIObserver Implementation>, ); } 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_ # IOS - 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.661Z Total files: 44 --- # File: sdk-installation-ios --- --- title: "iOS SDKのインストールと設定" description: "サブスクリプションアプリ向けにiOSへAdapty SDKをインストールする手順ガイドです。" --- Adapty SDK は、モバイルアプリへのシームレスな統合を実現する 2 つの主要モジュールで構成されています。 - **Core Adapty**: Adapty をアプリで正常に動作させるために必要な必須 SDK です。 - **AdaptyUI**: [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合に必要なオプションモジュールです。ペイウォールビルダーは、クロスプラットフォームのペイウォールを簡単に作成できる、ノーコードのビジュアルエディターです。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を確認したいですか?ペイウォールの表示、購入処理などの基本的な機能を含む完全なセットアップを示す[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)をご覧ください。 ::: 完全な実装の手順については、以下の動画もご覧ください。 <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="iOS (SwiftUI)" default> <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/cSChHc8k2zA?si=KhNFhqXccIzYwTcm" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> </TabItem> <TabItem value="uikit" label="iOS (UIKit)" default> <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/WEUnlaAjSI0?si=sjXKVVb56tEHDKzJ" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> </TabItem> </Tabs> ## 必要要件 \{#requirements\} Adapty iOS SDK は iOS 15.0 以降が必要です。 :::important Xcode 26.4 以降でビルドする場合は、Adapty SDK 3.15.7 以上が必要です。 ::: :::info SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ::: ## Adapty SDK のインストール \{#install-adapty-sdk\} [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-iOS.svg?style=flat&logo=apple)](https://github.com/adaptyteam/AdaptySDK-iOS/releases) Adapty SDK は Swift Package Manager を使ってインストールします。Xcode で **File** -> **Add Package Dependency...** を選択してください。パッケージ依存関係の追加手順は Xcode のバージョンによって異なる場合があるため、必要に応じて Xcode のドキュメントを参照してください。 1. リポジトリURLを入力します: ``` https://github.com/adaptyteam/AdaptySDK-iOS.git ``` 2. バージョンを選択し(最新の安定バージョンを推奨)、**Add Package** をクリックします。 3. **Choose Package Products** ウィンドウで、必要なモジュールを選択します: - **Adapty**(コアモジュール) - **AdaptyUI**(オプション - ペイウォールビルダーを使用する場合のみ) :::note 注意: - SDK 3.x で [キッズモード](kids-mode) を有効にするには、**Adapty** の代わりに **Adapty_KidsMode** を選択してください。SDK 4.0 以降では通常のモジュールを選択し、キッズモードは `KidsMode` パッケージトレイトで有効化します。 - リストにある他のパッケージは選択しないでください – それらは必要ありません。 ::: 4. **Add Package** をクリックしてインストールを完了します。 5. **インストールの確認:** プロジェクトナビゲーターの **Package Dependencies** の下に「Adapty」(および選択した場合は「AdaptyUI」)が表示されていることを確認します。 :::important Adapty iOS SDK 4.0 はプレリリース版です。Swift Package Manager は **Up to Next Major Version**(`from:`)ルールではベータバージョンを解決しないため、正確なバージョンを指定する必要があります。Xcode では **Dependency Rule** を **Exact Version** に設定し、`4.0.0-beta.2` と入力してください。`Package.swift` では `.exact("4.0.0-beta.2")` を使用してください。詳しくは [Adapty iOS SDK を v4 へ移行する](migration-to-ios-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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers @main struct YourApp: App { init() { // Configure Adapty SDK let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard Adapty.logLevel = .verbose // recommended for development and the first production release let config = configurationBuilder.build() // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } var body: some Scene { WindowGroup { // Your content view } } } } ``` </TabItem> <TabItem value="swift" label="UIKit" default> ```swift showLineNumbers // In your AppDelegate class: // If you only use an AppDelegate, place the following code in the // application(_:didFinishLaunchingWithOptions:) method. // If you use a SceneDelegate, place the following code in the // scene(_:willConnectTo:options:) method. Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(logLevel: .verbose) // recommended for development and the first production release let config = configurationBuilder.build() try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` </TabItem> </Tabs> :::important `activate` が解決するまで、他の Adapty SDK メソッドを呼び出さないでください。完全な順序については、[iOS SDK の呼び出し順序](ios-sdk-call-order)を参照してください。 ::: 次に、アプリにペイウォールを設定します: - [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、まず以下の [AdaptyUI モジュールのアクティベート](#activate-adaptyui-module-of-adapty-sdk)を行い、その後[ペイウォールビルダークイックスタート](ios-quickstart-paywalls)に従ってください。 - 独自のペイウォール UI を構築する場合は、[カスタムペイウォールのクイックスタート](ios-quickstart-manual)を参照してください。 ## Adapty SDK の AdaptyUI モジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する予定があり、[AdaptyUI モジュールをインストール済み](sdk-installation-ios#install-adapty-sdk)の場合は、AdaptyUI も有効化する必要があります。 :::important コード内では、AdaptyUI を有効化する前に、Adapty のコアモジュールを先に有効化してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers title="Swift" @main struct YourApp: App { init() { // ...ConfigurationBuilder steps // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: config) try await AdaptyUI.activate() } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } // main body... } } ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift showLineNumbers title="UIKit" // AppDelegate のみを使用している場合は、以下のコードを // application(_:didFinishLaunchingWithOptions:) メソッドに記述してください。 // SceneDelegate を使用している場合は、以下のコードを // scene(_:willConnectTo:options:) メソッドに記述してください。 Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Adapty ダッシュボードから取得 .with(logLevel: .verbose) // 開発中は推奨 let config = configurationBuilder.build() try await Adapty.activate(with: config) try await AdaptyUI.activate() } catch { // アプリに適したエラー処理を行ってください print("Adapty activation failed: ", error) } } ``` </TabItem> </Tabs> :::tip AdaptyUI をアクティベートする際に、オプションとして[ペイウォールのデフォルトキャッシュ設定をオーバーライドする](#set-up-media-cache-configuration-for-adaptyui)ことができます。 ::: ## オプション設定 \{#optional-setup\} ### ログ記録 \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty は、何が起きているかを把握できるよう、エラーやその他の重要な情報をログに記録します。利用可能なログレベルは以下のとおりです: | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | エラーのみがログに記録されます | | `warn` | エラーと、重大なエラーを引き起こさないが注意が必要なSDKからのメッセージがログに記録されます | | `info` | エラー、警告、およびさまざまな情報メッセージがログに記録されます | | `verbose` | 関数呼び出し、APIクエリなど、デバッグ時に役立つ可能性のある追加情報がすべてログに記録されます | ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(logLevel: .verbose) // recommended for development ``` #### ログシステムのメッセージをリダイレクトする \{#redirect-the-logging-system-messages\} Adapty のログメッセージを自社システムに送信したり、ファイルに保存したりしたい場合は、`setLogHandler` メソッドを使用して、その中にカスタムのログ処理ロジックを実装してください。このハンドラーは、メッセージ内容と重要度レベルを含むログレコードを受け取ります。 ```swift showLineNumbers title="Swift" Adapty.setLogHandler { record in writeToLocalFile("Adapty \(record.level): \(record.message)") } ``` ### データポリシー \{#data-policies\} Adapty は、明示的に送信しない限りユーザーの個人データを保存しません。ただし、ストアや国のガイドラインに準拠するために、追加のデータセキュリティポリシーを実装することができます。 #### IDFA の収集と共有を無効にする \{#disable-idfa-collection-and-sharing\} Adapty モジュールを有効化する際に、`idfaCollectionDisabled` を `true` に設定すると、IDFA の収集と共有を無効にできます。 このパラメータを使用して、App Store レビューガイドラインに準拠したり、アプリで IDFA が不要な場合に App Tracking Transparency プロンプトの表示を回避したりできます。デフォルト値は `false` です。IDFA 収集の詳細については、[アナリティクス連携](analytics-integration#disable-collection-of-advertising-identifiers)セクションを参照してください。 ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(idfaCollectionDisabled: true) ``` #### IP 収集と共有を無効にする \{#disable-ip-collection-and-sharing\} Adaptyモジュールを有効化する際、`ipAddressCollectionDisabled`を`true`に設定すると、ユーザーのIPアドレスの収集と共有を無効にできます。デフォルト値は`false`です。 このパラメータは、ユーザーのプライバシー保護、GDPRやCCPAなどの地域データ保護規制への準拠、またはIPベースの機能がアプリに不要な場合の不必要なデータ収集削減に役立ちます。 ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(ipAddressCollectionDisabled: true) ``` #### AdaptyUI のペイウォールにおけるメディアキャッシュの設定 \{#media-cache-configuration-for-paywalls-in-adaptyui\} AdaptyUI の設定はオプションです。設定なしで AdaptyUI モジュールを有効化することもできます。ただし、設定を使用する場合は、すべてのパラメーターが必須となります。 ```swift showLineNumbers title="Swift" // Configure AdaptyUI let adaptyUIConfiguration = AdaptyUI.Configuration( mediaCacheConfiguration: .init( memoryStorageTotalCostLimit: 100 * 1024 * 1024, memoryStorageCountLimit: .max, diskStorageSizeLimit: 100 * 1024 * 1024 ) ) // Activate AdaptyUI AdaptyUI.activate(configuration: adaptyUIConfiguration) ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :-------------------------- | :------- | :----------------------------------------------------------- | | memoryStorageTotalCostLimit | 必須 | ストレージの合計コスト上限(バイト単位)。 | | memoryStorageCountLimit | 必須 | メモリストレージのアイテム数上限。 | | diskStorageSizeLimit | 必須 | ディスク上のストレージファイルサイズ上限(バイト単位)。0は上限なしを意味します。 | ### トランザクション完了の動作 \{#transaction-finishing-behavior\} :::info この機能はSDKバージョン3.12.0以降で利用可能です。 ::: デフォルトでは、Adaptyは検証が成功した後にトランザクションを自動的に完了します。ただし、高度なトランザクション検証(サーバーサイドのレシート検証、不正検出、カスタムビジネスロジックなど)が必要な場合は、手動でトランザクションを完了するようにSDKを設定できます。 ```swift showLineNumbers title="Swift" let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(transactionsFinishBehavior: .manual) // .auto is the default ``` トランザクションの完了方法の詳細については、[ガイド](ios-transaction-management)を参照してください。 ### バックアップ復元時のデータ削除 \{#clear-data-on-backup-restore\} `clearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検知し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールなど、ローカルに保存されているすべてのSDKデータを削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```swift showLineNumbers let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") .with(clearDataOnBackup: true) // default – false ``` ## トラブルシューティング \{#troubleshooting\} #### Tuist での Swift 6 並行処理エラー \{#swift-6-concurrency-error-with-tuist\} [Tuist](https://tuist.dev/) でビルドすると、Swift 6 の厳格な並行処理コンパイルエラーが発生することがあります。典型的な症状としては、`AdaptyUIBuilderLogic` での `@Sendable` 属性の不一致や、同様のクロスモジュールの Sendability エラーなどが挙げられます。 これは、TuistがSPMパッケージからXcodeプロジェクトを生成する際に`swift-tools-version: 6.0`の設定を保持しないために発生します。その結果、一部のAdaptyターゲット(`Adapty`、`AdaptyUI`、`AdaptyUIBuilder`)がSwift 5のルールでコンパイルされ、他のターゲットがSwift 6を使用するため、モジュール間で`@Sendable`の不一致が生じます。 **修正方法**: Adapty SDK **3.15.5**以降にアップグレードしてください。Swift言語バージョンが混在していても、この問題が解消されます。 **回避策**: アップグレードできない場合は、TuistのコンフィグレーションでAdaptyの3つのターゲットすべてにSwift 6を明示的に設定してください: ```swift showLineNumbers targetSettings: [ "Adapty": .init().swiftVersion("6"), "AdaptyUI": .init().swiftVersion("6"), "AdaptyUIBuilder": .init().swiftVersion("6"), ] ``` --- # File: ios-quickstart-paywalls --- --- title: "iOS SDKでFlow Builderを使ってアプリ内課金を有効にする" description: "Adapty Flow Builderでアプリ内課金を有効にするためのクイックスタートガイド。" --- アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**フロー**](adapty-flow-builder) – ノーコードのフロービルダーで作成した、プロダクトをユーザーに提示するための画面シーケンス。SDKは`getFlow`を使って取得します。独自のコードでUIを構築したい場合は、代わりにペイウォールを使用してください — [ペイウォールを手動で実装する](ios-quickstart-manual)を参照。 - [**プレースメント**](placements) – アプリ内でフローをどこで・いつ表示するか(`main`、`onboarding`、`settings`など)。ダッシュボードでフローをプレースメントに紐付け、コード内ではプレースメントIDで取得します。これにより、A/B テストの実施や、ユーザーごとに異なるフローの表示が簡単に行えます。 Adapty では、アプリ内での購入を有効にする方法を3つ提供しています。アプリの要件に応じて、いずれかを選択してください。 | 実装方法 | 複雑さ | 使用する場面 | |---|---|---| | Adapty フロービルダー | ✅ 簡単 | [ノーコードビルダーで購入対応済みのフローを作成します](quickstart-paywalls)。Adapty が自動的にレンダリングし、購入フロー・レシート検証・サブスクリプション管理をすべて裏側で処理します。 | | 手動作成のペイウォール | 🟡 普通 | アプリコードでペイウォール UI を実装しますが、プロダクトラインナップの柔軟性を保つために Adapty からフローオブジェクトを取得します。[ガイド](ios-quickstart-manual)をご覧ください。 | | オブザーバーモード | 🔴 難しい | 独自の購入処理インフラが既にあり、それを引き続き使用したい場合に選択します。オブザーバーモードには Adapty における制限事項があります。[こちらの記事](observer-vs-full-mode)をご覧ください。 | :::important **以下の手順は、Adapty フロービルダーで作成したフローを実装する方法を説明しています。** ペイウォールの UI を自分でビルドしたい場合は、[ペイウォールを手動で実装する](ios-quickstart-manual)を参照してください。 ::: Adapty フロービルダーで作成したフローを表示するには、アプリのコードで以下の作業を行うだけです。 1. **フローを取得する**: Adapty からフローを取得します。 2. **表示する(購入処理は Adapty が担当)**: アプリにビューを表示します。 3. **ボタンアクションを処理する**: ユーザーの操作に対するアプリの応答を関連付けます。たとえば、ユーザーがボタンをタップしたときにリンクを開いたり、フローを閉じたりします。 ## 始める前に \{#before-you-start\} 始める前に、以下の手順を完了してください: 1. Adapty ダッシュボードで[アプリを App Store に接続する](initial_ios)。 2. Adapty で[プロダクトを作成する](create-product)。 3. [フローを作成してプロダクトを追加する](create-paywall)。 4. [プレースメントを作成してフローを追加する](create-placement)。 5. アプリのコードに [Adapty SDK をインストールして有効化する](sdk-installation-ios)。このガイドでは Adapty iOS SDK v4 の API を使用します。 ## 1. フローを取得する \{#1-get-the-flow\} フローはダッシュボードで設定されたプレースメントに関連付けられています。プレースメントを使うと、オーディエンスごとに異なるフローを表示したり、[A/B テスト](ab-tests)を実施したりすることができます。 Adapty フロービルダーで作成したフローを取得するには、以下の手順を行います。 1. `getFlow` メソッドを使って[プレースメント](placements) ID から `flow` オブジェクトを取得し、ビュー設定が含まれているか確認します。 2. `getFlowConfiguration` メソッドを使ってビュー設定を取得します。ビュー設定には、フローを表示するために必要な UI 要素とスタイリング情報が含まれています。 ```swift func loadFlow() async { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } ``` ## 2. フローを表示する \{#display-the-flow\} フローの設定が完了したら、あとは数行のコードを追加するだけでフローを表示できます。 <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI" default> SwiftUI でフローを表示する際は、イベントの処理も必要です。`didFinishPurchase`、`didFailPurchase`、`didFinishRestore`、`didFailRestore`、`didReceiveError` は必須です。テスト時は、以下のスニペットのコードをそのままコピーしてイベントをログに記録できます。 :::tip フローは購入が成功しても自動的に閉じません。`didFinishPurchase` で表示バインディングを `false` に設定して閉じるか、何もしないでフローを次の画面に進めることができます。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didFinishPurchase: { product, purchaseResult in print("Purchase finished successfully") flowPresented = false // or do nothing to let the flow continue }, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in flowPresented = false print("Flow error: \(error)") } ) ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift func presentFlow(with config: AdaptyUI.FlowConfiguration) { let flowController = try AdaptyUI.flowController( with: config, delegate: self ) present(flowController, animated: true) } ``` `AdaptyFlowControllerDelegate` を実装してイベントを処理します。デフォルト実装がない4つのメソッドは最低限実装してください。購入が成功してもコントローラーは自動的に閉じないことに注意してください。`didFinishPurchase` で閉じるか、フローが次の画面に進むようにそのままにしてください。 ```swift extension YourViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) // or do nothing to let the flow continue } } func flowController(_ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError) { print("Purchase failed: \(error)") } func flowController(_ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile) { print("Restore finished successfully") } func flowController(_ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError) { print("Restore failed: \(error)") } } ``` </TabItem> </Tabs> :::info フローの表示方法の詳細については、[ガイド](ios-present-paywalls)をご参照ください。 ::: ## 3. ボタンアクションの処理 \{#handle-button-actions\} ユーザーがボタンをタップすると、iOS SDK は購入・復元・フローのクローズ・リンクの開閉を自動的に処理します。 ただし、カスタムまたは事前定義された ID を持つボタンについては、コード側でアクションを処理する必要があります。また、デフォルトの動作をオーバーライドしたい場合もあるでしょう。 たとえば、閉じるボタンの処理方法を以下に示します。UIKit では、`.close` が発火した際に SDK が自動的にコントローラーを閉じます。カスタムの動作が必要な場合のみオーバーライドしてください。SwiftUI では、`isPresented` バインディングを自分で `false` に設定する必要があります。 :::tip ボタンの[アクション](handle-paywall-actions)や[イベント](ios-handling-events)の処理方法についてはガイドをご覧ください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI" default> ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow when the user taps close default: break } }, didFinishPurchase: { product, purchaseResult in flowPresented = false }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift extension YourViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didPerform action: AdaptyUI.Action) { switch action { case .close: controller.dismiss(animated: true) // default behavior — override only if needed default: break } } } ``` </TabItem> </Tabs> ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: フローをアプリで表示する準備ができました。[サンドボックスモードで購入をテスト](test-purchases-in-sandbox)して、テスト購入が正常に完了できることを確認してください。 次に、適切なユーザーにフローを表示したり有料機能へのアクセスを付与したりするために、[ユーザーのアクセスレベルを確認](ios-check-subscription-status)する必要があります。 ## 完全なコード例 \{#full-example\} このガイドのすべての手順をアプリに統合する方法を以下に示します。 <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI" default> ```swift struct ContentView: View { @State private var flowPresented = false @State private var flowConfiguration: AdaptyUI.FlowConfiguration? @State private var isLoading = false @State private var hasInitialized = false var body: some View { VStack { if isLoading { ProgressView("Loading...") } else { Text("Your App Content") } } .task { guard !hasInitialized else { return } await initializeFlow() hasInitialized = true } .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFinishPurchase: { product, purchaseResult in print("Purchase finished successfully") flowPresented = false // or do nothing to let the flow continue }, didFailPurchase: { product, error in print("Purchase failed: \(error)") }, didFinishRestore: { profile in print("Restore finished successfully") }, didFailRestore: { error in print("Restore failed: \(error)") }, didReceiveError: { error in print("Flow error: \(error)") flowPresented = false } ) } private func initializeFlow() async { isLoading = true defer { isLoading = false } await loadFlow() flowPresented = true } private func loadFlow() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return } flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) } catch { print("Failed to load: \(error)") } } } ``` </TabItem> <TabItem value="uikit" label="UIKit" default> ```swift class ViewController: UIViewController { private var flowConfiguration: AdaptyUI.FlowConfiguration? override func viewDidLoad() { super.viewDidLoad() Task { await initializeFlow() } } private func initializeFlow() async { do { flowConfiguration = try await loadFlow() if let flowConfiguration { await MainActor.run { presentFlow(with: flowConfiguration) } } } catch { print("Error initializing: \(error)") } } private func loadFlow() async throws -> AdaptyUI.FlowConfiguration? { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") guard flow.hasViewConfiguration else { print("Flow doesn't have a view configuration") return nil } return try await AdaptyUI.getFlowConfiguration(forFlow: flow) } private func presentFlow(with config: AdaptyUI.FlowConfiguration) { guard let flowController = try? AdaptyUI.flowController( with: config, delegate: self ) else { return } present(flowController, animated: true) } } extension ViewController: AdaptyFlowControllerDelegate { func flowController(_ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) // or do nothing to let the flow continue } } func flowController(_ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError) { print("Purchase failed for \(product.vendorProductId): \(error)") guard error.adaptyErrorCode != .paymentCancelled else { return } let message = switch error.adaptyErrorCode { case .paymentNotAllowed: "Purchases are not allowed on this device." default: "Purchase failed. Please try again." } let alert = UIAlertController(title: "Purchase Error", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) } func flowController(_ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile) { print("Restore finished successfully") controller.dismiss(animated: true) } func flowController(_ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError) { print("Restore failed: \(error)") } func flowController(_ controller: AdaptyFlowController, didReceiveError error: AdaptyUIError) { print("Flow error: \(error)") controller.dismiss(animated: true) } } ``` </TabItem> </Tabs> --- # File: ios-check-subscription-status --- --- title: "iOS SDKでサブスクリプションステータスを確認する" description: "AdaptyでiOSアプリのサブスクリプションステータスを確認する方法を学びます。" --- ユーザーが有料コンテンツにアクセスできるか、ペイウォールを表示するかを判断するには、プロファイルの[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態にアクセスして、ユーザーにペイウォールを表示するか有料機能へのアクセスを許可するかを判断する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ペイウォールまたは有料コンテンツを表示するかどうかを決める際は、プロファイルの[アクセスレベル](access-level)を確認します。方法は2つあります: - 最新のプロファイルデータが即座に必要な場合(アプリ起動時など)や強制的に更新したい場合は `getProfile` を呼び出す。 - **プロファイルの自動更新**を設定して、サブスクリプションステータスが変わるたびにローカルコピーを自動更新する。 :::important デフォルトでは、`premium` アクセスレベルがAdaptyにすでに存在します。アクセスレベルを複数設定する必要がない場合は、`premium` をそのまま使用できます。 ::: ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得する最も簡単な方法は、`getProfile` メソッドを使ってプロファイルにアクセスすることです: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> </Tabs> ### サブスクリプション更新を受け取る \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取りたい場合: 1. 任意の型で `AdaptyDelegate` プロトコルに準拠し、`didLoadLatestProfile` メソッドを実装します。ユーザーのサブスクリプションステータスが変わるたびに、Adaptyがこのメソッドを自動的に呼び出します。以下の例では、サブスクリプションのワークフローやユーザープロファイルの処理を支援する `SubscriptionManager` 型を使用しています。この型は依存性注入で渡したり、UIKitアプリのシングルトンとして設定したり、アプリのメイン構造体からSwiftUI環境に追加したりできます。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存して、追加のネットワークリクエストなしにアプリ全体で使用できるようにします。 ```swift class SubscriptionManager: AdaptyDelegate { nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { let hasAccess = profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false // Update UI, unlock content, etc. } } // Set delegate after Adapty activation Adapty.delegate = subscriptionManager ``` :::note Adaptyはアプリ起動時に `didLoadLatestProfile` を自動的に呼び出し、デバイスがオフラインの場合でもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールのロジックを連携させる \{#connect-profile-with-paywall-logic\} ペイウォールを表示するか有料機能へのアクセスを許可するかを即座に判断したい場合、ユーザーのプロファイルを直接確認できます。このアプローチは、アプリ起動時、プレミアムセクションへの入場時、特定コンテンツを表示する前などのシナリオで役立ちます。 <Tabs> <TabItem value="swiftui" label="SwiftUI" default> ```swift private func checkAccessLevel() async -> Bool { do { let profile = try await Adapty.getProfile() return profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false } catch { print("Error checking access level: \(error)") return false } } // In your initialization logic: let hasAccess = await checkAccessLevel() if !hasAccess { paywallPresented = true // Show paywall if no access } ``` </TabItem> <TabItem value="uikit" label="UIKit"> ```swift private func checkAccessLevel() async throws -> Bool { let profile = try await Adapty.getProfile() return profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false } // In your initialization logic: let hasAccess = try await checkAccessLevel() if !hasAccess { presentPaywall(with: paywallConfiguration) } ``` </TabItem> </Tabs> ## 次のステップ \{#next-steps\} サブスクリプションステータスの追跡方法がわかったところで、[ユーザープロファイルの操作方法](ios-quickstart-identify)を確認して、既存の認証システムや有料アクセスの共有設定と適切に連携していることを確かめましょう。 独自の認証システムがない場合でも、Adaptyがユーザーを管理しますので問題はありません。ただし、Adaptyが匿名ユーザーをどのように扱うかについては[ガイド](ios-quickstart-identify)を参照することをおすすめします。 --- # File: ios-quickstart-identify --- --- title: "iOS SDKでのユーザー識別" description: "アプリ内サブスクリプション管理のためのAdaptyセットアップ クイックスタートガイド。" --- :::important このガイドは、独自の認証システムをお持ちの方を対象としています。ここでは、既存の認証システムに合わせてAdaptyのユーザープロファイルを管理する方法を説明します。 ::: ユーザーの購入履歴をどのように管理するかは、アプリの認証モデルによって異なります。 - バックエンド認証を使用せず、ユーザーデータを保存しないアプリの場合は、[匿名ユーザーに関するセクション](#anonymous-users)を参照してください。 - バックエンド認証を使用している(または使用予定の)アプリの場合は、[識別済みユーザーに関するセクション](#identified-users)を参照してください。 **主要な概念**: - **プロファイル**はSDKが動作するために必要なエンティティです。Adaptyが自動的に作成します。 - プロファイルは匿名 **(カスタマーユーザーIDなし)** または識別済み **(カスタマーユーザーIDあり)** のどちらかになります。 - **カスタマーユーザーID**を提供することで、Adaptyのプロファイルと社内の認証システムを紐付けられます。 匿名ユーザーと識別済みユーザーの違いは次のとおりです。 | | 匿名ユーザー | 識別済みユーザー | |-------------------------|---------------------------------------------------|-------------------------------------------------------------------------| | **購入管理** | ストアレベルの購入復元 | カスタマーユーザーIDを通じたデバイス間での購入履歴の維持 | | **プロファイル管理** | 再インストールのたびに新しいプロファイルが作成される | セッションとデバイスをまたいで同一プロファイルを使用 | | **データの永続性** | 匿名ユーザーのデータはアプリインストールに紐付く | 識別済みユーザーのデータはアプリインストールをまたいで保持される | ## 匿名ユーザー \{#anonymous-users\} バックエンド認証を使用していない場合、**アプリコード内で認証処理を実装する必要はありません**。 1. アプリの初回起動時にSDKが有効化されると、Adaptyは**ユーザーの新しいプロファイルを作成します**。 2. ユーザーがアプリ内で何かを購入すると、その購入は**ユーザーのAdaptyプロファイルとストアアカウントに紐付けられます**。 3. ユーザーがアプリを**再インストール**したり、**新しいデバイス**にインストールしたりすると、Adaptyは有効化時に**新しい匿名プロファイルを作成します**。 4. ユーザーがアプリ内で以前に購入を行っていた場合、デフォルトではSDKの有効化時にApp Storeから購入履歴が自動的に同期されます。 :::note バックアップからの復元は再インストールとは動作が異なります。デフォルトでは、ユーザーがバックアップから復元した場合、SDKはキャッシュデータを保持し、新しいプロファイルを作成しません。この動作は`clearDataOnBackup`設定で変更できます。[詳細はこちら](sdk-installation-ios#clear-data-on-backup-restore)。 ::: 匿名ユーザーの場合、インストールのたびに新しいプロファイルが作成されますが、Adaptyのアナリティクスで[新規インストールとして扱う基準を設定できる](general#4-installs-definition-for-analytics)ため、問題ありません。 匿名ユーザーの場合、インストール数は**デバイスID**でカウントする必要があります。この場合、再インストールを含め、デバイスでのアプリインストールが1件としてカウントされます。 ## 識別済みユーザー \{#identified-users\} アプリ内でユーザーを識別する方法は2つあります。 - [**ログイン/サインアップ時:**](#during-loginsignup) アプリ起動後にユーザーがサインインする場合、認証時にカスタマーユーザーIDを指定して`identify()`を呼び出します。 - [**SDK有効化時:**](#during-the-sdk-activation) アプリ起動時にカスタマーユーザーIDが既にわかっている場合は、`activate()`を呼び出す際に送信します。 :::important デフォルトでは、Adaptyが別のカスタマーユーザーIDに現在紐付いているカスタマーユーザーIDから購入を受け取った場合、アクセスレベルは共有されます。つまり、両方のプロファイルが有料アクセスを持つことになります。この設定を変更して、一方のプロファイルから他方へ有料アクセスを移行したり、共有を完全に無効にしたりすることもできます。詳細は[こちらの記事](general#6-sharing-paid-access-between-user-accounts)を参照してください。 ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(たとえば、アプリへのログイン後やサインアップ後)、`identify`メソッドを使用してカスタマーユーザーIDを設定します。 - **このカスタマーユーザーIDを以前使用したことがない**場合、Adaptyは自動的に現在のプロファイルに紐付けます。 - **このカスタマーユーザーIDでユーザーを以前識別したことがある**場合、AdaptyはそのカスタマーユーザーIDに紐付いたプロファイルに切り替えます。 :::important カスタマーユーザーIDはユーザーごとに一意である必要があります。パラメーター値をハードコードすると、すべてのユーザーが同一として扱われます。 ::: 他のSDKメソッドを呼び出す前に、必ず`identify`を`await`してください。並列呼び出しを行うと`#3006 profileWasChanged`が発生するか、匿名プロファイルが対象になります。詳細は[iOS SDKの呼び出し順序](ios-sdk-call-order)を参照してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") // Unique for each user } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // User IDs must be unique for each user Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> </Tabs> ### SDK有効化時 \{#during-the-sdk-activation\} SDKを有効化する時点でカスタマーユーザーIDが既にわかっている場合は、`identify`を別途呼び出す代わりに、`activate`メソッドで送信できます。 カスタマーユーザーIDがわかっているにもかかわらず、有効化後にのみ設定した場合、有効化時にAdaptyが新しい匿名プロファイルを作成し、`identify`を呼び出した後に既存のプロファイルへ切り替えることになります。 既存のカスタマーユーザーID(以前使用したもの)でも新しいものでも渡すことができます。新しいものを渡した場合、有効化時に作成された新しいプロファイルが自動的にそのカスタマーユーザーIDに紐付けられます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスのダッシュボードに影響しません。これはインストール数がデバイスIDに基づいてカウントされるためです。 デバイスIDはデバイス上のストアからのアプリの単一インストールを表し、アプリの再インストール後にのみ再生成されます。 初回インストールか再インストールかに関わらず、また既存のカスタマーユーザーIDを使用するかどうかにも依存しません。 プロファイルの作成(SDKの有効化またはログアウト時)、ログイン、または再インストールなしのアプリアップグレードでは、追加のインストールイベントは発生しません。 デバイスではなくユニークユーザーに基づいてインストールをカウントしたい場合は、**App settings**で[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // Place in the app main struct for SwiftUI or in AppDelegate for UIKit let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // Place in the app main struct for SwiftUI or in AppDelegate for UIKit let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` </TabItem> </Tabs> ### ユーザーのログアウト \{#log-users-out\} ユーザーをログアウトさせるボタンがある場合は、`logout`メソッドを使用します。 :::important ユーザーをログアウトすると、そのユーザーの新しい匿名プロファイルが作成されます。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.logout() } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.logout { error in if error == nil { // successful logout } } ``` </TabItem> </Tabs> :::info ユーザーをアプリに再ログインさせるには、`identify`メソッドを使用します。 ::: ### ログインなしでの購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリにログインする前後どちらでも購入できる場合、ログイン後もアクセスが維持されるようにする必要があります。 1. ログアウト状態のユーザーが購入を行うと、Adaptyはその購入を匿名プロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルへの切り替えを行います。 - 新しいカスタマーユーザーIDの場合(たとえば、登録前に購入が行われた場合)、AdaptyはカスタマーユーザーIDを現在のプロファイルに割り当て、購入履歴がすべて維持されます。 - 既存のカスタマーユーザーIDの場合(カスタマーユーザーIDがすでにプロファイルに紐付いている場合)、プロファイル切り替え後に実際のアクセスレベルを取得する必要があります。識別後すぐに[`getProfile`](ios-check-subscription-status)を呼び出すか、データが自動的に同期されるよう[プロファイルの更新をリッスンする](ios-check-subscription-status)ことができます。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内決済のロジックを実装できました!アプリのマネタイズがうまくいくことを願っています。 Adaptyをさらに活用するために、以下のトピックもご覧ください。 - [**テスト**](test-purchases-in-sandbox): すべてが期待どおりに動作するか確認する - [**オンボーディング**](ios-onboardings): オンボーディングでユーザーを引き込みリテンションを高める - [**インテグレーション**](configuration): マーケティングアトリビューションおよびアナリティクスサービスとわずか1行のコードで連携する - [**カスタムプロファイル属性の設定**](setting-user-attributes): ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/B テストを実施したり異なるユーザーに異なるペイウォールを表示したりする --- # File: adapty-sdk-integration-skill --- --- title: "SDKインテグレーションスキルを使ってAdaptyをiOSアプリに統合する" description: "adapty-sdk-integrationスキルを使用して、AIコーディングツールでAdapty SDKをiOSアプリにエンドツーエンドで統合します。" --- :::important このスキルはベータ版です。途中で止まったり、予期しない動作をした場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor)を参照してください。AIツールが各ステップを適切なドキュメントとともに進められるように案内します。 ::: [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 --- --- title: "AIアシスタントを使ってAdaptyをiOSアプリに組み込む" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使ってAdaptyをiOSアプリに組み込むためのステップバイステップガイドです。" --- このガイドでは、AIコーディングツールを使ってAdaptyをiOSアプリに段階的に組み込む方法を説明します。正しいAdaptyドキュメントを正しい順序でAIに渡すことがポイントです。 For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## 始める前に:ダッシュボードのセットアップ \{#before-you-start-dashboard-setup\} AdaptyはSDKコードを書く前に、ダッシュボードでいくつかの設定が必要です。インタラクティブなLLMスキルを使うか、ダッシュボードから手動で設定することができます。 ### スキルを使う方法(推奨) \{#skill-approach-recommended\} Adapty CLIスキルを使うと、LLMがアプリ、プロダクト、アクセスレベル、ペイウォール、プレースメントを直接設定できます。ダッシュボードを各ステップで開く必要はありません。[ストアの接続](integrate-payments)だけはダッシュボードで行う必要があります。 ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` スキルを追加したら、エージェントで `/adapty-cli` を実行してください。ストアの接続のためにダッシュボードを開くタイミングも含め、各ステップをガイドしてくれます。 ### ダッシュボードを使う方法 \{#dashboard-approach\} すべてを手動で設定したい場合は、コードを書く前に以下の準備が必要です。LLMはダッシュボードの値を自動で調べることはできないので、自分で確認して提供する必要があります。 1. **アプリストアに接続する**: Adapty ダッシュボードで **App settings → General** を開きます。購入機能を動かすために必須の設定です。 [App Store に接続する](integrate-payments) 2. **公開SDKキーをコピーする**: Adapty ダッシュボードで **App settings → General** を開き、**API keys** セクションを確認します。コード上では、`Adapty.activate("YOUR_PUBLIC_SDK_KEY")` に渡す文字列です。 3. **プロダクトを少なくとも1つ作成する**: Adapty ダッシュボードの **Products** ページで作成します。コードからプロダクトを直接参照することはありません — Adaptlyはフローやペイウォールを通じてプロダクトを配信します。 [プロダクトを追加する](quickstart-products) 4. **フローまたはペイウォールとプレースメントを作成する**: Adapty ダッシュボードでフロー(またはUIを自分で作る場合はペイウォール)を作成し、**Placements** ページでプレースメントに割り当てます。コード上では、`Adapty.getFlow("YOUR_PLACEMENT_ID")` に渡すプレースメントIDが該当します。 [フローを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**: Adapty ダッシュボードの **Products** ページで各プロダクトに設定します。コード上では、`profile.accessLevels["premium"]` で確認する文字列です。ほとんどのアプリではデフォルトの `premium` アクセスレベルで十分です。プロダクトによって(たとえば `basic` プランと `pro` プラン)ユーザーがアクセスできる機能が異なる場合は、コーディングを始める前に[追加のアクセスレベルを作成](assigning-access-level-to-a-product)してください。 :::tip 5つすべてが揃ったら、コードを書く準備完了です。LLMに「公開SDKキーはX、プレースメントIDはY」と伝えておくと、正確な初期化コードとペイウォール取得コードを生成してもらえます。 ::: ### 後から設定するもの \{#set-up-when-ready\} コーディングを始めるためには必須ではありませんが、組み込みが進んだ段階で必要になります。 - **A/B テスト**: **Placements** ページで設定します。コードの変更は不要です。 [A/B テスト](ab-tests) - **フローやプレースメントの追加**: 別のプレースメントIDで `getFlow` を追加で呼び出します。 - **アナリティクス連携**: **Integrations** ページで設定します。連携ごとに設定方法が異なります。[アナリティクス連携](analytics-integration)と[アトリビューション連携](attribution-integration)を参照してください。 ## AdaptyドキュメントをLLMに渡す \{#feed-adapty-docs-to-your-llm\} ### Context7を使う(推奨) \{#use-context7-recommended\} [Context7](https://context7.com)は、LLMが最新のAdaptyドキュメントに直接アクセスできるようにするMCPサーバーです。質問内容に応じて適切なドキュメントを自動で取得するため、URLを手動で貼り付ける手間がありません。 Context7は**Cursor**、**Claude Code**、**Windsurf**、その他のMCP対応ツールで動作します。セットアップするには以下を実行してください。 ``` npx ctx7 setup ``` このコマンドがエディタを自動検出してContext7サーバーを設定します。手動でセットアップする場合は、[Context7 GitHubリポジトリ](https://github.com/upstash/context7)を参照してください。 設定後は、プロンプト内でAdaptyライブラリを参照してください。 ``` Use the adaptyteam/adapty-docs library to look up how to install the iOS SDK ``` :::warning Context7を使えばドキュメントのURLを手動で貼り付ける必要はなくなりますが、実装の順序は重要です。すべてが正しく動くよう、以下の[実装ウォークスルー](#implementation-walkthrough)をステップごとに進めてください。 ::: ### プレーンテキストのドキュメントを使う \{#use-plain-text-docs\} AdaptyのドキュメントはプレーンテキストのMarkdownとして取得できます。URLの末尾に `.md` を付けるか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例: [adapty-cursor.md](https://adapty.io/docs/ja/adapty-cursor.md) 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステージには、「LLMに送る内容」ブロックがあり、貼り付け用の `.md` リンクが含まれています。 まとめて多くのドキュメントが必要な場合は、以下の[インデックスファイルとプラットフォーム別のサブセット](#plain-text-doc-index-files)を参照してください。 ## 実装ウォークスルー \{#implementation-walkthrough\} このガイドの残りの部分では、実装の順序に沿ってAdaptyの組み込みを進めていきます。各ステージには、LLMに送るドキュメント、完了時に確認できる内容、よくある問題が記載されています。 ### 組み込みを計画する \{#plan-your-integration\} コードに入る前に、LLMにプロジェクトを分析させて実装計画を立ててもらいましょう。AIツールにプランニングモード(CursorやClaude Codeのプランモードなど)があれば、コードを書く前にプロジェクト構造とAdaptyドキュメントの両方を確認させるために活用してください。 購入処理にどのアプローチを使うかをLLMに伝えてください — これによって参照すべきガイドが変わります。 - [**Adapty Flow Builder**](adapty-flow-builder): Adaptのノーコードビルダーでフローを作成し、SDKが自動でレンダリングします。 - [**手動作成のペイウォール**](ios-quickstart-manual): 独自のペイウォールUIをコードで構築しますが、プロダクトの取得と購入処理にはAdaptyを使います。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラをそのまま維持し、アナリティクスと連携のみAdaptyを使います。 どれを選べばよいかわからない場合は、[クイックスタートの比較表](ios-quickstart-paywalls)をご覧ください。 ### SDKをインストールして設定する \{#install-and-configure-the-sdk\} XcodeのSwift Package ManagerでAdapty SDKパッケージをインストールし、公開SDKキーで有効化します。これが基盤となるステップで、これなしには他の機能は動きません。 **ガイド:** [Adapty SDKのインストールと設定](sdk-installation-ios) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-ios.md ``` :::tip[チェックポイント] - **期待される結果:** アプリがビルドして起動する。XcodeコンソールにAdaptyの有効化ログが表示される。 - **注意点:** "Public API key is missing" → App settingsで取得した実際のキーがプレースホルダーと置き換えられているか確認する。 ::: ### フローまたはペイウォールを表示して購入を処理する \{#show-flows-or-paywalls-and-handle-purchases\} プレースメントIDでフローまたはペイウォールを取得して表示し、購入イベントを処理します。必要なガイドは購入の処理方法によって異なります。 進めながらサンドボックスで都度購入をテストしてください — 最後まで待たずに行いましょう。セットアップ手順は[サンドボックスでの購入テスト](test-purchases-in-sandbox)を参照してください。 <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Flow Builder" default> **ガイド:** - [Flow Builderで購入を有効にする(クイックスタート)](ios-quickstart-paywalls) - [フローとその設定を取得する](get-pb-paywalls) - [フローを表示する](ios-present-paywalls) - [フローのイベントを処理する](ios-handling-events) - [ボタンアクションに対応する](handle-paywall-actions) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-quickstart-paywalls.md - https://adapty.io/docs/ja/get-pb-paywalls.md - https://adapty.io/docs/ja/ios-present-paywalls.md - https://adapty.io/docs/ja/ios-handling-events.md - https://adapty.io/docs/ja/handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される結果:** 設定したプロダクトがフローに表示される。プロダクトをタップするとサンドボックスの購入ダイアログが表示される。 - **注意点:** フローが空または `getFlow` エラー → プレースメントIDがダッシュボードと完全に一致しているか、プレースメントにオーディエンスが割り当てられているか確認する。 ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](ios-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products) - [リモートコンフィグで設計されたペイウォールを表示する](present-remote-config-paywalls) - [購入を行う](making-purchases) - [購入を復元する](restore-purchase) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products.md - https://adapty.io/docs/ja/present-remote-config-paywalls.md - https://adapty.io/docs/ja/making-purchases.md - https://adapty.io/docs/ja/restore-purchase.md ``` :::tip[チェックポイント] - **期待される結果:** カスタムペイウォールにAdaptyから取得したプロダクトが表示される。プロダクトをタップするとサンドボックスの購入ダイアログが表示される。 - **注意点:** プロダクト配列が空 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、プレースメントにオーディエンスがあるか確認する。 ::: </TabItem> <TabItem value="observer" label="Observer mode"> **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードを実装する](implement-observer-mode) - [オブザーバーモードでトランザクションを報告する](report-transactions-observer-mode) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/observer-vs-full-mode.md - https://adapty.io/docs/ja/implement-observer-mode.md - https://adapty.io/docs/ja/report-transactions-observer-mode.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローでサンドボックス購入を行った後、Adaptのダッシュボード **Event Feed** にトランザクションが表示される。 - **注意点:** イベントが表示されない → Adaptにトランザクションを報告しているか、App Store Server Notificationsが設定されているか確認する。 ::: </TabItem> </Tabs> ### サブスクリプションのステータスを確認する \{#check-subscription-status\} 購入後、ユーザープロファイルでアクティブなアクセスレベルを確認して、プレミアムコンテンツへのアクセスを制限します。 **ガイド:** [サブスクリプションのステータスを確認する](ios-check-subscription-status) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックス購入後、`profile.accessLevels["premium"]?.isActive` が `true` を返す。 - **注意点:** 購入後も `accessLevels` が空 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているか確認する。 ::: ### ユーザーを識別する \{#identify-users\} アプリのユーザーアカウントをAdaptyのプロファイルに紐付けて、デバイスをまたいで購入が引き継がれるようにします。 :::important アプリに認証機能がない場合はこのステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](ios-quickstart-identify) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/ios-quickstart-identify.md ``` :::tip[チェックポイント] - **期待される結果:** `Adapty.identify("your-user-id")` を呼び出した後、ダッシュボードの **Profiles** セクションにカスタムユーザーIDが表示される。 - **注意点:** 匿名プロファイルへのアトリビューションを避けるため、`identify` はアクティベーション後、ペイウォール取得前に呼び出す。 ::: ### リリースの準備をする \{#prepare-for-release\} サンドボックスで組み込みが動作したら、すべてが本番環境に対応しているかリリースチェックリストを確認しましょう。 **ガイド:** [リリースチェックリスト](release-checklist) LLMに送る内容: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ja/release-checklist.md ``` :::tip[チェックポイント] - **期待される結果:** すべてのチェックリスト項目が確認済み:ストア接続、サーバー通知、購入フロー、アクセスレベルチェック、プライバシー要件。 - **注意点:** App Store Server Notificationsが未設定 → **App settings → iOS SDK** で設定しないと、イベントがダッシュボードに表示されません。 ::: ## プレーンテキストのドキュメントインデックスファイル \{#plain-text-doc-index-files\} 個別ページを超えてLLMに広いコンテキストを提供したい場合、Adaptyドキュメント全体をリスト化または統合したインデックスファイルを提供しています。 - [`llms.txt`](https://adapty.io/docs/ja/llms.txt): すべてのページを `.md` リンク付きでリスト化しています。LLMがウェブサイトにアクセスしやすくするための[新興標準](https://llmstxt.org/)です。一部のAIエージェント(ChatGPTなど)では、`llms.txt` をダウンロードしてチャットにファイルとしてアップロードする必要があります。 - [`llms-full.txt`](https://adapty.io/docs/ja/llms-full.txt): Adaptyドキュメントサイト全体を1つのファイルにまとめたものです。非常に大きいため、全体像が必要な場合のみ使用してください。 - iOS専用の [`ios-llms.txt`](https://adapty.io/docs/ja/ios-llms.txt) と [`ios-llms-full.txt`](https://adapty.io/docs/ja/ios-llms-full.txt): サイト全体と比べてトークンを節約できる、プラットフォーム別のサブセットです。 --- # File: get-pb-paywalls --- --- title: "フローとペイウォールを取得する - iOS" description: "iOSアプリでAdaptyからフローとペイウォールを取得する方法。" --- <SDKv4> <MethodPromo method="getFlow" /> [フローまたはペイウォールビルダーのペイウォールを設計](adapty-paywall-builder)したら、それをモバイルアプリに表示できます。最初のステップは、以下の説明に従って、プレースメントに関連付けられたフローまたはペイウォールとそのビュー設定を取得することです。 :::tip Adapty SDK をモバイルアプリに統合した実例を見たいですか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示す[サンプルアプリ](sample-apps)をご確認ください。 ::: <details> <summary>始める前に</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成し、プロダクトを組み込み](create-paywall)ます。 3. Adapty ダッシュボードで[プレースメントを作成し、フロー/ペイウォールを組み込み](create-placement)ます。 4. モバイルアプリに [Adapty SDK](sdk-installation-ios) をインストールします。 </details> ## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} フロービルダーまたはペイウォールビルダーを使ってフローやペイウォールをデザインした場合、それをモバイルアプリのコードでレンダリングしてユーザーに表示することを心配する必要はありません。このようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてIDを取得し、ビュー設定を準備した上で、モバイルアプリに表示する必要があります。 フローまたはペイウォールとその[ビュー設定](get-pb-paywalls#fetch-the-view-configuration)は、できるだけ早い段階で取得してください。表示する直前ではなく、理想的にはずっと前に取得しましょう。ビュー設定を取得した時点で、SDKはバックグラウンドで画像のダウンロードとキャッシュを開始します。早く取得するほど、ダウンロードが完了するまでの時間が長く確保できます。フローまたはペイウォールを表示する頃には、設定と画像がすでにキャッシュ済みで表示できる状態になっています。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します: <Tabs> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") // the requested flow/paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow/paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュデータを返します。この方法を推奨するのは、ユーザーが常に最新のデータを受け取れるためです。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を利用していると想定される場合は、`.returnCacheDataElseLoad` を使用することを検討してください。これにより、キャッシュが存在する場合はキャッシュデータを返します。この場合、最新のデータが取得できないことがありますが、通信環境に左右されずに読み込み時間を短縮できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けたい場面での使用も安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールや手動でのクリアを行った場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2つの層で保存しています。1つは上記の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。また、CDN を使用してペイウォールをより高速に取得し、CDN に接続できない場合のスタンドアロンフォールバックサーバーも用意しています。このシステムは、常にペイウォールの最新バージョンを取得しつつ、インターネット接続が不安定な場合でも信頼性を確保するよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>まれに、内部で複数のリクエストが発生する場合があるため、`loadTimeout` に指定した時間よりわずかに遅くタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------- | | Flow | プレースメント、識別子(`id`、`variationId`)、名前、リモートコンフィグ、およびフローにビュー設定が含まれるかどうかを示す `hasViewConfiguration` フラグを含む `AdaptyFlow` オブジェクトです。プリロード、カスタム UI、またはプログラムによるチェック用に実際のプロダクトを取得するには、`getPaywallProducts(flow:)` を呼び出してください。 | ## ビュー設定の取得 \{#fetch-the-view-configuration\} フローまたはペイウォールを取得したら、`flow.hasViewConfiguration` を使ってビュー設定が含まれているかどうかを確認します。このフラグは、Adapty ダッシュボードでプレースメントがどのように設計されたかを示します。 - **`true`** — プレースメントが **Flow Builder**(フロー)または **Paywall Builder**(ペイウォール)で設計されています。Adapty が UI をレンダリングします。以降の手順に従い、ビュー設定を取得して[フローまたはペイウォールを表示](ios-present-paywalls)してください。 - **`false`** — プレースメントはビルダー UI を持たないカスタムペイウォールです。 `getFlowConfiguration` メソッドを使用してビュー設定を読み込みます。 ```swift showLineNumbers guard flow.hasViewConfiguration else { // handle as remote config paywall return } let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow) ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :----------------------- | :------------- | :---------- | | **forFlow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | | **locale** | <p>任意</p><p>デフォルト: `nil`</p> | [ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子。`-` で区切られた1つまたは2つのサブタグを持つ言語コードで指定します(例: `en`、`pt-br`)。詳細は[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウトを制限する値です。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。内部で複数のリクエストが発生する場合があるため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。 | | **products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために、`AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡すと、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **systemRequestsHandler** | 任意 | フローのアクションによってトリガーされるシステムの権限リクエストやレビューリクエストを処理する、`AdaptySystemRequestsHandler` に準拠したオブジェクト。フローにそのようなアクションが含まれる場合にのみ必要です。 | | **assetsResolver** | 任意 | フロー/ペイウォール内の画像や動画を上書きする `[String: AdaptyCustomAsset]` 辞書。詳細は[アセットのカスタマイズ](#customize-assets)を参照してください。 | | **timerResolver** | 任意 | 開発者が定義したタイマーの終了日時を提供する、`AdaptyTimerResolver` に準拠したオブジェクト。詳細は[開発者定義タイマーの設定](#set-up-developer-defined-timers)を参照してください。 | 読み込みが完了したら、[フロー/ペイウォールを表示](ios-present-paywalls)します。 ## デフォルトオーディエンスのフローまたはペイウォールを取得して高速化する \{#get-a-flow-or-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、フローやペイウォールはほぼ瞬時に取得されるため、このプロセスの高速化を特に気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が不安定な場合は、フローやペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、何も表示しないよりもスムーズなユーザー体験を提供するために、デフォルトのフローまたはペイウォールを表示したいと思うかもしれません。 これに対処するために、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けのフローまたはペイウォールを取得します。ただし、推奨されるアプローチは `getFlow` メソッドでフローまたはペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)セクションをご覧ください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現在と将来)で別々のペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないペイウォールで問題が発生することを許容するかのどちらかを選択することになります。 - **ターゲティングの喪失**: すべてのユーザーに **All Users** オーディエンス向けに設計された同じペイウォールが表示されるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを許容してでもフローやペイウォールの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。それ以外の場合は、[上記](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)で説明した `getFlow` を使用してください。 ::: ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成した際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方式はユーザーが常に最新のデータを受け取れるため、こちらをお勧めします。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定だと思われる場合は、`.returnCacheDataElseLoad` を使用すると、キャッシュが存在する場合にそれを返すことができます。この場合、ユーザーが最新データを取得できないことがありますが、接続状況に関わらず読み込みが速くなります。キャッシュはセッション中でも定期的に更新されるため、ネットワークリクエストを避ける目的でのキャッシュ使用は安全です。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ削除されます。</p> | ## アセットのカスタマイズ \{#customize-assets\} ペイウォール/フローの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には事前定義済みのID(`hero_image`と`hero_video`)が割り当てられています。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定する](custom-media)必要があります。 たとえば、次のようなことができます。 - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 - 動画が読み込まれる前にプレイヤーがレイアウトスペースを確保できるよう、動画のピクセル解像度を指定する(アスペクト比 = `width / height`)。スキップするには `nil` を渡す。 カスタムアセットをシンプルな辞書で提供する方法の例を以下に示します: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image and a known resolution "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!), resolution: CGSize(width: 1080, height: 1920) ) ), ] let flowConfig = try await AdaptyUI.getFlowConfiguration( forFlow: flow, assetsResolver: customAssets ) ``` :::note アセットが見つからない場合、ペイウォール/フローはデフォルトの外観にフォールバックします。 ::: ## 開発者定義タイマーの設定 \{#set-up-developer-defined-timers\} モバイルアプリでカスタムタイマーを使用するには、`AdaptyTimerResolver` プロトコルに準拠したオブジェクトを作成します。このオブジェクトは、各カスタムタイマーのレンダリング方法を定義します。必要であれば、このプロトコルにすでに準拠している `[String: Date]` ディクショナリを直接使用することもできます。以下に例を示します: ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリは各タイマーを正しい値で動的に更新できます。例えば: - `CUSTOM_TIMER_NY`: 元日など、タイマーの終了までの残り時間。 - `CUSTOM_TIMER_6H`: ユーザーがペイウォールを開いてから始まった6時間のうち、残りの時間。 </SDKv4> <SDKv3> [Adapty ダッシュボード](adapty-paywall-builder)のペイウォールビルダーで[ペイウォールのビジュアルデザインを作成](adapty-paywall-builder)したら、それをモバイルアプリに表示できます。最初のステップは、以下の説明に従ってプレースメントに関連付けられたペイウォールとそのビュー設定を取得することです。 このトピックはペイウォールビルダーでカスタマイズされたペイウォールに関するものです。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォール用のペイウォールとプロダクトの取得](fetch-paywalls-and-products)を参照してください。 :::tip Adapty SDK をモバイルアプリに統合した実際の例を見たい方は、[サンプルアプリ](sample-apps)をご覧ください。ペイウォールの表示、購入処理、その他の基本的な機能を含む完全なセットアップを確認できます。 ::: <details> <summary>モバイルアプリでペイウォールを表示する前に</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加する](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加する](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-ios) をインストールする。 </details> ## ペイウォールビルダーで作成したペイウォールを取得する \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーを使ってペイウォールをデザインした](adapty-paywall-builder)場合、ユーザーに表示するためのレンダリングコードをアプリに書く必要はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてペイウォールのIDを取得し、ビュー設定を取得してから、アプリ内に表示する必要があります。 最適なパフォーマンスを確保するために、ペイウォールとその[ビュー設定](get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します: <Tabs> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値を使用します。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子です。このパラメータは、マイナス(**-**)で区切られた1つまたは2つのサブタグで構成された言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードの詳細と推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるようになるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーの通信環境が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合はキャッシュデータを返すことを検討してください。この設定では最新データが取得できないことがありますが、通信が不安定な環境でも読み込みが速くなります。キャッシュはセッション中に定期的に更新されるため、ネットワークリクエストを減らす目的でキャッシュを利用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリアによってのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存します。1つは上記の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより速く取得するために CDN を使用し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、通信環境が悪い場合でも常にペイウォールの最新バージョンを確実に取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルのフォールバックが返されます。</p><p>内部的に複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅くタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------- | | Paywall | プロダクトIDのリスト、ペイウォール識別子、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーで **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、ビュー設定が含まれているかどうかを確認してください。ビュー設定が存在する場合は、そのペイウォールがペイウォールビルダーで作成されたことを意味します。これにより、ペイウォールの表示方法が決まります。ビュー設定がある場合はペイウォールビルダーのペイウォールとして扱い、ない場合は[リモートコンフィグのペイウォールとして処理してください](present-remote-config-paywalls)。 `getPaywallConfiguration` メソッドを使って、ビュー設定を読み込みます。 ```swift showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, products: products ) // use loaded configuration } catch { // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------------- | :---------- | | **paywall** | 必須 | 対象のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。 | | **products** | 任意 | 画面上でのプロダクト表示タイミングを最適化するために、`AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡した場合、AdaptyUI が自動的に必要なプロダクトを取得します。 | :::note 複数の言語を使用している場合は、[ペイウォールビルダーのローカライゼーションを追加する方法](add-paywall-locale-in-adapty-paywall-builder)と、ロケールコードを正しく使用する方法を[こちら](localizations-and-locale-codes)でご確認ください。 ::: 読み込みが完了したら、[ペイウォールを表示](ios-present-paywalls)してください。 ## デフォルトオーディエンス向けペイウォールを取得してより速く表示する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ瞬時に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合は、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を提供することを検討するとよいでしょう。 この問題に対処するために、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の [ペイウォール情報の取得](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder) セクションをご覧ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)に対して異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがレンダリングされないペイウォールに遭遇するリスクを許容するかのどちらかを選択しなければなりません。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 これらのデメリットを受け入れてでもペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` を使用してください。 ::: ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` :::note `getPaywallForDefaultAudience` メソッドは iOS SDK バージョン 2.11.2 以降で利用可能です。 ::: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよび推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境にある場合は、`.returnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュデータを返すため、最新データが得られない場合もありますが、接続状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを減らす目的で安全に利用できます。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ削除されます。</p> | ## アセットのカスタマイズ \{#customize-assets\} ペイウォールの画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、`hero_image` と `hero_video` という定義済みIDがあります。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズできます。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のようなことができます。 - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty iOS SDK をバージョン 3.7.0 以上にアップデートしてください。 ::: カスタムアセットをシンプルな辞書形式で提供する方法の例を示します: ```swift showLineNumbers let customAssets: [String: AdaptyCustomAsset] = [ // Show a local image using a custom ID "custom_image": .image( .uiImage(value: UIImage(named: "image_name")!) ), // Show a local preview image while a remote main image is loading "hero_image": .image( .remote( url: URL(string: "https://example.com/image.jpg")!, preview: UIImage(named: "preview_image") ) ), // Show a local video with a preview image "hero_video": .video( .file( url: Bundle.main.url(forResource: "custom_video", withExtension: "mp4")!, preview: .uiImage(value: UIImage(named: "video_preview")!) ) ), ] let paywallConfig = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall, assetsResolver: customAssets ) ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの外観にフォールバックします。 ::: ## デベロッパー定義タイマーの設定 \{#set-up-developer-defined-timers\} モバイルアプリでカスタムタイマーを使用するには、`AdaptyTimerResolver` プロトコルに準拠したオブジェクトを作成します。このオブジェクトは、各カスタムタイマーのレンダリング方法を定義します。`[String: Date]` ディクショナリはすでにこのプロトコルに準拠しているため、直接使用することもできます。以下に例を示します。 ```swift showLineNumbers @MainActor struct AdaptyTimerResolverImpl: AdaptyTimerResolver { func timerEndAtDate(for timerId: String) -> Date { switch timerId { case "CUSTOM_TIMER_6H": Date(timeIntervalSinceNow: 3600.0 * 6.0) // 6 hours case "CUSTOM_TIMER_NY": Calendar.current.date(from: DateComponents(year: 2025, month: 1, day: 1)) ?? Date(timeIntervalSinceNow: 3600.0) default: Date(timeIntervalSinceNow: 3600.0) // 1 hour } } } ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は、Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリは各タイマーを正しい値で動的に更新できます。例えば: - `CUSTOM_TIMER_NY`: 元日など、タイマー終了までの残り時間。 - `CUSTOM_TIMER_6H`: ユーザーがペイウォールを開いてから始まった6時間のうち、残り時間。 </SDKv3> --- # File: ios-present-paywalls --- --- title: "フローとペイウォールの表示 - iOS" description: "iOSアプリでユーザーにフローとペイウォールを表示します。" --- <SDKv4> <MethodPromo method="getFlow" label="フローとペイウォールの表示" /> フローまたはペイウォールを作成した場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングを気にする必要はありません。フローやペイウォールには、表示する内容とその表示方法の両方が含まれています。 以下で使用する `AdaptyUI.FlowConfiguration` オブジェクトの取得方法については、[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 ## SwiftUI でフローとペイウォールを表示する \{#present-flows-and-paywalls-in-swiftui\} ### モーダルビューとして表示する \{#present-as-a-modal-view\} フローまたはペイウォールをデバイス画面にモーダルビューとして表示するには、SwiftUI の `.flow` モディファイアを使用します。最小限の呼び出しには、`isPresented`、`flowConfiguration`、および5つの必須コールバックが必要です。 ```swift showLineNumbers title="SwiftUI" .flow( isPresented: $flowPresented, flowConfiguration: <AdaptyUI.FlowConfiguration>, didFinishPurchase: { _, _ in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { _, _ in /* handle the error */ }, didFinishRestore: { _ in /* check access level and dismiss */ }, didFailRestore: { _ in /* handle the error */ }, didReceiveError: { _ in flowPresented = false } ) ``` より細かい制御が必要な場合は、`didPerformAction` などのオプションコールバックを追加してボタンのタップを処理できます: ```swift showLineNumbers title="SwiftUI" @State var flowPresented = false // ensure that you manage this variable state and set it to `true` at the moment you want to show the flow or paywall var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: <AdaptyUI.FlowConfiguration>, didPerformAction: { action in switch action { case .close: flowPresented = false default: // Handle other actions break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) } ``` パラメーター: | パラメーター | 必須 | 説明 | |:--------------------------------------|:---------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | フローまたはペイウォール画面の表示を管理するバインディング。 | | **flowConfiguration** | 必須 | フローまたはペイウォールの視覚的な詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。`AdaptyUI.getFlowConfiguration(forFlow:)` メソッドを使用します。詳しくは[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **didFinishPurchase** | 必須 | `Adapty.makePurchase()` が正常に完了したときに呼び出されます。フローは自動的に閉じません。ここでプレゼンテーションバインディングを `false` に設定するか、何もしてフローを購入後も継続させてください。 | | **didFailPurchase** | 必須 | `Adapty.makePurchase()` が失敗したときに呼び出されます。 | | **didFinishRestore** | 必須 | `Adapty.restorePurchases()` が正常に完了したときに呼び出されます。 | | **didFailRestore** | 必須 | `Adapty.restorePurchases()` が失敗したときに呼び出されます。 | | **didReceiveError** | 必須 | レンダリングエラーまたはフロースクリプトのランタイムエラー(例:JavaScript 例外、`AdaptyUIError` コード `4105`)が発生したときに呼び出されます。レンダリングエラーの場合は [Adapty サポートにお問い合わせ](mailto:support@adapty.io)ください。 | | **fullScreen** | オプション | フローまたはペイウォールをフルスクリーンモードで表示するか、シートとして表示するかを決定します。デフォルトは `true` です。 | | **didAppear** | オプション | フローまたはペイウォールビューが表示されたときに呼び出されます。 | | **didDisappear** | オプション | フローまたはペイウォールビューが閉じられたときに呼び出されます。 | | **didPerformAction** | オプション | ユーザーがボタンをクリックしたときに呼び出されます。`close` と `openURL` の2つのアクション ID が事前定義されており、それ以外はカスタムでビルダー内で設定できます。 | | **didSelectProduct** | オプション | ユーザーまたはシステムによって購入するプロダクトが選択されたときに呼び出されます。 | | **didStartPurchase** | オプション | ユーザーが購入プロセスを開始したときに呼び出されます。 | | **didFinishWebPaymentNavigation** | オプション | Web 支払いのナビゲーションが完了したときに呼び出されます。 | | **didStartRestore** | オプション | ユーザーが復元プロセスを開始したときに呼び出されます。 | | **didFailLoadingProducts** | オプション | プロダクトの読み込み中にエラーが発生したときに呼び出されます。`true` を返すと再読み込みを試みます。 | | **didPartiallyLoadProducts** | オプション | プロダクトが部分的に読み込まれたときに呼び出されます。 | | **showAlertItem** | オプション | フローまたはペイウォールの上にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | オプション | アラートビューをレンダリングするための関数。 | | **placeholderBuilder** | オプション | フローまたはペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。デフォルトは `ProgressView` です。 | iOS でのパラメーターの詳細については、[iOS - イベントの処理](ios-handling-events)をご参照ください。 ### 非モーダルビューとして表示する \{#present-as-a-non-modal-view\} フローやペイウォールを、アプリのナビゲーションフロー内のナビゲーション先またはインラインビューとして表示することもできます。SwiftUI のビュー内で `AdaptyFlowView` を直接使用してください: ```swift showLineNumbers title="SwiftUI" AdaptyFlowView( flowConfiguration: <AdaptyUI.FlowConfiguration>, didFinishPurchase: { product, purchaseResult in // Dismiss the view, or do nothing to let the flow continue }, didFailPurchase: { product, error in // Handle purchase failure }, didFinishRestore: { profile in // Handle successful restore }, didFailRestore: { error in // Handle restore failure }, didReceiveError: { error in // Handle the error (rendering or JS exception from the flow script). } ) ``` ## UIKitでフローとペイウォールを表示する \{#present-flows-and-paywalls-in-uikit\} デバイスの画面にフローまたはペイウォールを表示するには、次の手順を行います。 1. `AdaptyUI.flowController(with:delegate:)` メソッドを使用して、表示したいビジュアルフローを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualFlow = try AdaptyUI.flowController( with: <AdaptyUI.FlowConfiguration>, delegate: <AdaptyFlowControllerDelegate> ) ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :---------- | | **flowConfiguration** | 必須 | フローまたはペイウォールのビジュアル詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。`AdaptyUI.getFlowConfiguration(forFlow:)` メソッドを使用します。詳細は [フローとペイウォールの取得](get-pb-paywalls) を参照してください。 | | **delegate** | 必須 | フローおよびペイウォールのイベントを受け取る `AdaptyFlowControllerDelegate`。詳細は [フロー&ペイウォールイベントの処理](ios-handling-events) を参照してください。 | 戻り値: | オブジェクト | 説明 | | :---------------------- | :------------------------------------------------------- | | **AdaptyFlowController** | リクエストされたフローまたはペイウォール画面を表すオブジェクト。 | 2. オブジェクトが正常に作成されたら、デバイスの画面に表示できます。 ```swift showLineNumbers title="Swift" present(visualFlow, animated: true) ``` :::tip リアルワールドの例でAdapty SDKをモバイルアプリに統合する方法を確認したい場合は、[サンプルアプリ](sample-apps)をご覧ください。ペイウォールの表示、購入、その他の基本機能など、完全なセットアップを実演しています。 ::: </SDKv4> <SDKv3> ペイウォールビルダーでペイウォールをカスタマイズした場合、モバイルアプリのコードでレンダリングしてユーザーに表示することを心配する必要はありません。このようなペイウォールには、ペイウォール内に何を表示するか、またどのように表示するかの両方が含まれています。 `AdaptyUI.PaywallConfiguration` オブジェクトの取得方法については、[ペイウォールビルダーのペイウォールとその設定を取得する](get-pb-paywalls)を参照してください。 ## SwiftUI でペイウォールを表示する \{#present-paywalls-in-swiftui\} ### モーダルビューとして表示する \{#present-as-a-modal-view\} ビジュアルペイウォールをデバイス画面にモーダルビューとして表示するには、SwiftUI の `.paywall` モディファイアを使用します: ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false // ensure that you manage this variable state and set it to `true` at the moment you want to show the paywall var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywallConfiguration: <AdaptyUI.PaywallConfiguration>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishPurchase: { product, profile in paywallPresented = false }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } ) } ``` Parameters: | パラメータ | 必須 | 説明 | |:----------------------------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | ペイウォール画面を表示するかどうかを管理するバインディング。 | | **paywallConfiguration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:)` メソッドを使用してください。詳細は[ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls)を参照してください。 | | **didFailPurchase** | 必須 | `Adapty.makePurchase()` が失敗したときに呼び出されます。 | | **didFinishRestore** | 必須 | `Adapty.restorePurchases()` が正常に完了したときに呼び出されます。 | | **didFailRestore** | 必須 | `Adapty.restorePurchases()` が失敗したときに呼び出されます。 | | **didFailRendering** | 必須 | インターフェースのレンダリング中にエラーが発生した場合に呼び出されます。この場合は[Adapty サポートにお問い合わせ](mailto:support@adapty.io)ください。 | | **fullScreen** | 任意 | ペイウォールをフルスクリーンモードで表示するか、モーダルとして表示するかを決定します。デフォルトは `true` です。 | | **didAppear** | 任意 | ペイウォールビューが表示されたときに呼び出されます。 | | **didDisappear** | 任意 | ペイウォールビューが閉じられたときに呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをクリックしたときに呼び出されます。ボタンによってアクション ID が異なります。`close` と `openURL` の 2 つのアクション ID があらかじめ定義されており、それ以外はカスタムでビルダーで設定できます。 | | **didSelectProduct** | 任意 | プロダクトが(ユーザーまたはシステムによって)購入対象として選択された場合に呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始したときに呼び出されます。 | | **didFinishPurchase** | 任意 | `Adapty.makePurchase()` が正常に完了したときに呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | Web 決済のナビゲーションが終了したときに呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始したときに呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生したときに呼び出されます。`true` を返すと再読み込みを試みます。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれたときに呼び出されます。 | | **showAlertItem** | 任意 | ペイウォールの上にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングするための関数。 | | **placeholderBuilder** | 任意 | ペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。 | イベントのパラメータについては、[iOS - イベントの処理](ios-handling-events) を参照してください。 ### ノンモーダルビューとして表示する \{#present-as-a-non-modal-view\} ペイウォールをナビゲーションの遷移先やインラインビューとして、アプリのナビゲーションフロー内に表示することもできます。SwiftUI のビューで `AdaptyPaywallView` を直接使用してください。 ```swift showLineNumbers title="SwiftUI" AdaptyPaywallView( paywallConfiguration: <AdaptyUI.PaywallConfiguration>, didFailPurchase: { product, error in // Handle purchase failure }, didFinishRestore: { profile in // Handle successful restore }, didFailRestore: { error in // Handle restore failure }, didFailRendering: { error in // Handle rendering error } ) ``` ## UIKit でペイウォールを表示する \{#present-paywalls-in-uikit\} デバイス画面にビジュアルペイウォールを表示するには、次の手順を行います。 1. `.paywallController(for:products:viewConfiguration:delegate:)` メソッドを使用して、表示したいビジュアルペイウォールを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( with: <paywall configuration object>, delegate: <AdaptyPaywallControllerDelegate> ) ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :---------- | | **paywall configuration** | 必須 | ペイウォールのビジュアル情報を含む `AdaptyUI.PaywallConfiguration` オブジェクトです。`AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` メソッドを使用してください。詳細は[ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls)を参照してください。 | | **delegate** | 必須 | ペイウォールイベントを受け取るための `AdaptyPaywallControllerDelegate` です。詳細は[ペイウォールイベントの処理](ios-handling-events)を参照してください。 | 戻り値: | オブジェクト | 説明 | | :---------------------- | :--------------------------------------------------- | | **AdaptyPaywallController** | リクエストされたペイウォール画面を表すオブジェクト | 2. オブジェクトの作成に成功したら、デバイスの画面に表示できます。 ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::tip 実際の統合例を確認したい場合は、[サンプルアプリ](sample-apps)をご覧ください。ペイウォールの表示、購入処理などの基本的な機能を含む、完全なセットアップが確認できます。 ::: </SDKv3> --- # File: handle-paywall-actions --- --- title: "フローアクションへの応答 - iOS" description: "iOS アプリでペイウォールやオンボーディングフローのボタンアクションを処理し、ユーザー入力を扱う方法。" --- <SDKv4> Adapty のフロービルダーまたはペイウォールビルダーを使用してフローやペイウォールを構築する場合、ボタンを適切に設定することが重要です。 1. [ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよび既存アクションをコードで処理する方法を説明します。 :::warning **フロー/ペイウォールのクローズと URL オープンのみ自動処理されます。** その他のボタンアクションはすべて、アプリコード側で適切な処理を実装する必要があります。 ::: :::note iOS SDKは、`AdaptySystemRequestsHandler`を通じて、プッシュ通知やカメラアクセスなどのシステム権限リクエストに応答できます。フローはまだこれらのリクエストをトリガーしないため、現時点では対応不要です。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローまたはペイウォールを閉じるボタンを追加するには: 1. ビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで `close` アクションのハンドラーを実装します。 :::info iOS SDK では、`close` アクションはデフォルトでフローまたはペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるフローを閉じると別のフローが開くようにすることもできます。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false // dismiss the flow or paywall default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` ## フローとペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: フローまたはペイウォールにリンクを開くボタン(例:**Terms of use** や **Privacy policy**)を追加するには: 1. ビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 2. アプリのコードに、受け取ったURLをブラウザで開く `openURL` アクションのハンドラーを実装します。 :::info iOS SDK では、`openURL` アクションはデフォルトでURLを開く動作をします。ただし、必要に応じてコード内でこの動作を上書きすることができます。 ::: ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case let .openURL(url): UIApplication.shared.open(url, options: [:]) // default behavior default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` ## カスタムアクションを処理する \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ビルダーでボタンを追加し、**Custom** アクションを割り当て、ID を設定します。 2. アプリのコードに、作成したアクション ID に対応するハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます。 ```swift .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case let .custom(id): if id == "openNewPaywall" { // Display another flow or paywall } default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) ``` </SDKv4> <SDKv3> Adapty ペイウォールビルダーを使ってペイウォールを構築する場合、ボタンを適切に設定することが重要です: 1. [ペイウォールビルダーにボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、コード内でカスタムアクションおよび既存アクションを処理する方法を説明します。 :::warning **購入、復元、ペイウォールのクローズ、URL のオープンのみ自動的に処理されます。** その他のボタンアクションは、アプリのコードで適切に対応を実装する必要があります。 ::: ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info iOS SDK では、`close` アクションはデフォルトでペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコードでこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じることで別のペイウォールを開くようにすることも可能です。 ::: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case .close: controller.dismiss(animated: true) // default behavior break } } ``` ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: ペイウォールにリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info iOS SDKでは、`openUrl`アクションはデフォルトでURLを開く動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。 ::: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case let .openURL(url): UIApplication.shared.open(url, options: [:]) // default behavior break } } ``` ## アプリへのログイン \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコードで、ユーザーを識別する `login` アクションのハンドラーを実装します。 ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case .login: // Show a login screen let loginVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginViewController") controller.present(loginVC, animated: true) } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当てて、IDを設定します。 2. アプリのコードで、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のペイウォールを表示するボタンを追加できます: ```swift func paywallController(_ controller: AdaptyPaywallController, didPerform action: AdaptyUI.Action) { switch action { case let .custom(id): if id == "openNewPaywall" { // Display another paywall } } break } } ``` </SDKv3> --- # File: ios-handling-events --- --- title: "フローとペイウォールのイベントを処理する - iOS" description: "iOSアプリでフローおよびペイウォールのイベントを処理する方法。" --- <SDKv4> :::important このガイドでは、購入・復元・プロダクト選択・ペイウォール表示に関するイベント処理について説明します。また、ボタン操作(ペイウォールを閉じる、リンクを開くなど)の実装も必要です。詳しくは[ボタン操作の処理に関するガイド](handle-paywall-actions)をご覧ください。 ::: フローとペイウォールは、購入や購入の復元に追加のコードは不要です。ただし、アプリが反応できるイベントをいくつか生成します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や購入関連アクションの通知が含まれます。以下で、これらのイベントへの対応方法を説明します。 :::tip Adapty SDK をモバイルアプリに組み込む実際の例を見たいですか?ペイウォールの表示、購入、その他の基本的な機能を含む完全なセットアップを示す[サンプルアプリ](sample-apps)をぜひご確認ください。 ::: ## SwiftUI でのイベント処理 \{#handling-events-in-swiftui\} モバイルアプリ内のフローまたはペイウォール画面で発生するプロセスを制御・監視するには、SwiftUI の `.flow` モディファイアを使用します。 ```swift showLineNumbers title="Swift" @State var flowPresented = false var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false case let .openURL(url): // handle opening the URL (incl. for terms and privacy) default: // handle other actions } }, didSelectProduct: { product in /* Handle the event */ }, didStartPurchase: { product in /* Handle the event */ }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false }, didFailLoadingProducts: { error in // Return `true` to retry loading return false } ) } ``` クロージャのパラメーターは必要なものだけ登録すれば、不要なものは省略できます。 | パラメーター | 必須 | 説明 | |:------------------------------------------|:---------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | フローまたはペイウォール画面の表示を管理するバインディング。 | | **flowConfiguration** | 必須 | フローまたはペイウォールのビジュアル詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。詳細は[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **didFinishPurchase** | 必須 | `Adapty.makePurchase()` が正常に完了したときに呼び出されます。フローは自動的に閉じないため、ここでプレゼンテーションバインディングを `false` に設定するか、何もせずにフローを購入後も継続させてください。 | | **didFailPurchase** | 必須 | `Adapty.makePurchase()` が失敗したときに呼び出されます。 | | **didFinishRestore** | 必須 | `Adapty.restorePurchases()` が正常に完了したときに呼び出されます。 | | **didFailRestore** | 必須 | `Adapty.restorePurchases()` が失敗したときに呼び出されます。 | | **didReceiveError** | 必須 | フローでレンダリングエラーまたはフロースクリプトのランタイムエラー(例:JavaScript の例外、`AdaptyUIError` コード `4105`)が発生したときに呼び出されます。レンダリングエラーの場合は[Adapty サポートにお問い合わせください](mailto:support@adapty.io)。 | | **placeholderBuilder** | 任意 | フローまたはペイウォールの読み込み中にプレースホルダービューをレンダリングする関数。デフォルトは `ProgressView`。 | | **fullScreen** | 任意 | フローまたはペイウォールをフルスクリーンモードで表示するか、シートとして表示するかを決定します。デフォルトは `true`。 | | **didAppear** | 任意 | フローまたはペイウォールのビューが画面に表示されたときに呼び出されます。 | | **didDisappear** | 任意 | フローまたはペイウォールのビューが閉じられたときに呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをクリックしたときに呼び出されます。`close` と `openURL` の2つのアクション ID が事前定義されており、それ以外はビルダーで設定できるカスタムアクションです。 | | **didSelectProduct** | 任意 | ユーザーまたはシステムによって購入するプロダクトが選択されたときに呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始したときに呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | ウェブ決済のナビゲーションが完了したときに呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始したときに呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生したときに呼び出されます。`true` を返すと読み込みを再試行します。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれたときに呼び出されます。 | | **showAlertItem** | 任意 | フローまたはペイウォールの上にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングする関数。 | ## UIKit でのイベント処理 \{#handling-events-in-uikit\} UIKit アプリでは、`AdaptyFlowControllerDelegate` プロトコルを通じてイベントを処理します。`AdaptyFlowController` と `AdaptyFlowControllerDelegate` のセットアップ方法については、[フローとペイウォールの表示 - iOS](ios-present-paywalls) を参照してください。 このプロトコルには13のメソッドが宣言されており、そのうち4つはデフォルト実装がなく、準拠する際に必ず実装する必要があります:`didFinishPurchase`、`didFailPurchase`、`didFinishRestoreWith`、`didFailRestoreWith`です。残りのメソッドはデフォルトの何もしない実装を持っており、カスタム動作が必要な場合にオーバーライドできます。メソッドは以下に目的別にグループ化されています。 ### ライフサイクル \{#lifecycle\} ```swift showLineNumbers title="Swift" func flowControllerDidAppear(_ controller: AdaptyFlowController) { } func flowControllerDidDisappear(_ controller: AdaptyFlowController) { } ``` これらはフローまたはペイウォールのビューが表示・非表示になったときに呼び出されます。 ### ユーザーアクション \{#user-actions\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didPerform action: AdaptyUI.Action ) { } ``` `AdaptyUI.Action` のケース: - `.close` — デフォルトの動作はコントローラーを閉じます。コントローラーを画面に残したり、追加のクリーンアップ処理を行う場合はオーバーライドしてください。 - `.openURL(url:)` — デフォルトの動作は `UIApplication.shared.open(...)` でURLを開きます。 - `.custom(id:)` — ビルダーでカスタムアクションIDが設定されたボタンがタップされたときに発火します。 ### プロダクト選択 \{#product-selection\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didSelectProduct product: AdaptyPaywallProduct ) { } ``` ユーザーまたはシステムによってプロダクトが購入対象として選択されたときに呼び出されます。プロダクトにはオファーの全情報が含まれており(v4 ではエリジビリティが自動で判定されるため、`AdaptyPaywallProductWithoutDeterminingOffer` という独立した型は存在しません)。 ### 購入イベント \{#purchase-events\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didStartPurchase product: AdaptyPaywallProduct ) { } func flowController( _ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) // or do nothing to let the flow continue } } func flowController( _ controller: AdaptyFlowController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` `didFinishPurchase` と `didFailPurchase` にはデフォルトの実装がないため、必ず実装する必要があります。購入が成功してもコントローラーは自動的に閉じられません。適切なタイミングで `controller.dismiss(animated:)` を呼び出すか、複数画面のフローで購入後も続けて進む場合はそのまま何もしなくても構いません。 ### リストアイベント \{#restore-events\} ```swift showLineNumbers title="Swift" func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { } func flowController( _ controller: AdaptyFlowController, didFinishRestoreWith profile: AdaptyProfile ) { } func flowController( _ controller: AdaptyFlowController, didFailRestoreWith error: AdaptyError ) { } ``` `didFinishRestoreWith` と `didFailRestoreWith` にはデフォルト実装がありません。コントローラーを閉じる前に、返された `AdaptyProfile` に目的のアクセスレベルが含まれているかどうかを確認してください。 ### フローエラーとプロダクト読み込みエラー \{#flow-errors-and-product-loading-errors\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didReceiveError error: AdaptyUIError ) { } func flowController( _ controller: AdaptyFlowController, didFailLoadingProductsWith error: AdaptyError ) -> Bool { // Return `true` to retry product loading; default returns `false`. return false } func flowController( _ controller: AdaptyFlowController, didPartiallyLoadProducts failedIds: [String] ) { } ``` `didReceiveError` は、レンダリングエラーおよびフロースクリプトのランタイムエラー(JavaScript例外、`AdaptyUIError` コード `4105`)で発生します。レンダリングエラーが発生した場合は、[Adapty サポートにお問い合わせください](mailto:support@adapty.io)。読み込みエラーの場合は、`didFailLoadingProductsWith` から `true` を返すことでリトライできます。一時的なネットワーク障害に有効です。 ### Web支払いナビゲーション \{#web-payment-navigation\} ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, error: AdaptyError? ) { } ``` Webの支払いナビゲーションが完了した際(成功・失敗を問わず)に呼び出されます。 </SDKv4> <SDKv3> :::important このガイドでは、購入・復元・プロダクト選択・ペイウォール表示のイベント処理について説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の処理も実装する必要があります。詳しくは[ボタン操作のハンドリングに関するガイド](handle-paywall-actions)をご覧ください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定されたペイウォールは、購入や復元のために追加のコードは必要ありません。ただし、アプリが応答できるいくつかのイベントが生成されます。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連アクションの通知が含まれます。これらのイベントへの応答方法については、以下をご覧ください。 このガイドは、Adapty SDK v3.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。 :::tip Adapty SDK がモバイルアプリにどのように統合されるか、実際の例を見てみたいですか?[サンプルアプリ](sample-apps)では、ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを確認できます。 ::: ## SwiftUI でのイベント処理 \{#handling-events-in-swiftui\} モバイルアプリ内のペイウォール画面で発生するプロセスを制御・監視するには、SwiftUI の `.paywall` モディファイアを使用してください: ```swift showLineNumbers title="Swift" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywall: paywall, viewConfiguration: viewConfig, didPerformAction: { action in switch action { case .close: paywallPresented = false case let .openURL(url): // handle opening the URL (incl. for terms and privacy) default: // handle other actions } }, didSelectProduct: { /* Handle the event */ }, didStartPurchase: { /* Handle the event */ }, didFinishPurchase: { product, info in /* Handle the event */ }, didFailPurchase: { product, error in /* Handle the event */ }, didStartRestore: { /* Handle the event */ }, didFinishRestore: { /* Handle the event */ }, didFailRestore: { /* Handle the event */ }, didFailRendering: { error in paywallPresented = false }, didFailLoadingProducts: { error in return false } ) } ``` 必要なクロージャパラメータだけを登録し、不要なものは省略できます。この場合、未使用のクロージャパラメータは作成されません。 | パラメータ | 必須 | 説明 | |:----------------------------------|:---------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **isPresented** | 必須 | ペイウォール画面の表示を管理するバインディング。 | | **paywallConfiguration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.paywallConfiguration(for:products:viewConfiguration:observerModeResolver:tagResolver:timerResolver:)` メソッドを使用してください。詳細は [ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls) を参照してください。 | | **didFailPurchase** | 必須 | エラー(支払い不可、ネットワークエラー、無効なプロダクトなど)によって購入が失敗した場合に呼び出されます。ユーザーによるキャンセルや保留中の支払いでは呼び出されません。 | | **didFinishRestore** | 必須 | 購入が正常に完了したときに呼び出されます。 | | **didFailRestore** | 必須 | 購入の復元に失敗したときに呼び出されます。 | | **didFailRendering** | 必須 | インターフェースのレンダリング中にエラーが発生した場合に呼び出されます。この場合は [Adapty サポートにお問い合わせください](mailto:support@adapty.io)。 | | **fullScreen** | 任意 | ペイウォールをフルスクリーンモードで表示するか、モーダルとして表示するかを指定します。デフォルトは `true` です。 | | **didAppear** | 任意 | ペイウォールビューが画面に表示されたときに呼び出されます。また、ユーザーがペイウォール内の [ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button) をタップしてインアプリブラウザでウェブペイウォールが開いたときにも呼び出されます。 | | **didDisappear** | 任意 | ペイウォールビューが閉じられたときに呼び出されます。また、ペイウォールからインアプリブラウザで開いた [ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button) が画面から消えたときにも呼び出されます。 | | **didPerformAction** | 任意 | ユーザーがボタンをクリックしたときに呼び出されます。ボタンごとにアクション ID が異なります。`close` と `openURL` の 2 つのアクション ID は事前定義されており、その他はビルダーで設定できるカスタムのものです。 | | **didSelectProduct** | 任意 | プロダクトが(ユーザーまたはシステムによって)購入のために選択された場合に呼び出されます。 | | **didStartPurchase** | 任意 | ユーザーが購入プロセスを開始したときに呼び出されます。 | | **didFinishPurchase** | 任意 | 購入が正常に完了したときに呼び出されます。 | | **didFinishWebPaymentNavigation** | 任意 | 購入のために [ウェブペイウォール](web-paywall) を開こうとした後(成功・失敗を問わず)に呼び出されます。 | | **didStartRestore** | 任意 | ユーザーが復元プロセスを開始したときに呼び出されます。 | | **didFailLoadingProducts** | 任意 | プロダクトの読み込み中にエラーが発生したときに呼び出されます。読み込みを再試行する場合は `true` を返してください。 | | **didPartiallyLoadProducts** | 任意 | プロダクトが部分的に読み込まれたときに呼び出されます。 | | **showAlertItem** | 任意 | ペイウォールの上部にアラートアイテムの表示を管理するバインディング。 | | **showAlertBuilder** | 任意 | アラートビューをレンダリングするための関数。 | | **placeholderBuilder** | 任意 | ペイウォールの読み込み中にプレースホルダービューをレンダリングするための関数。 | ## UIKit でのイベント処理 \{#handling-events-in-uikit\} モバイルアプリのペイウォール画面で発生するプロセスを制御・監視するには、`AdaptyPaywallControllerDelegate` のメソッドを実装します。 ### ユーザー生成イベント \{#user-generated-events\} #### プロダクトの選択 \{#product-selection\} ユーザーが購入するプロダクトを選択すると、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer ) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController(_ controller: AdaptyPaywallController, didStartPurchase product: AdaptyPaywallProduct) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> オブザーバーモードでは呼び出されません。詳細については、[iOS - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 #### ウェブペイウォールを使用して購入を開始した \{#started-purchase-using-a-web-paywall\} ユーザーが[ウェブペイウォール](web-paywall)を使って購入プロセスを開始すると、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, shouldContinueWebPaymentNavigation product: AdaptyPaywallProduct ) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### 購入成功またはキャンセル \{#successful-or-canceled-purchase\} 購入が成功した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFinishPurchase product: AdaptyPaywallProductWithoutDeterminingOffer, purchaseResult: AdaptyPurchaseResult ) { } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Cancelled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "cancelled" } } ``` </Details> この場合は、ペイウォール画面を閉じることをお勧めします。 オブザーバーモードでは呼び出されません。詳細については、[iOS - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode) を参照してください。 #### 購入失敗 \{#failed-purchase\} 購入がエラーにより失敗した場合、このメソッドが呼び出されます。対象となるのは、StoreKit のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、システムエラーです。なお、ユーザーによるキャンセルは `didFinishPurchase` がキャンセル結果として呼び出され、このメソッドはトリガーされません。保留中の支払いについても同様です。 ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFailPurchase product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ``` </Details> オブザーバーモードでは呼び出されません。詳細は [iOS - オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode) をご覧ください。 #### Webペイウォールによる購入の失敗 \{#failed-purchase-using-a-web-paywall\} `Adapty.openWebPaywall()` が失敗した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFailWebPaymentNavigation product: AdaptyPaywallProduct, error: AdaptyError ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ``` </Details> #### 購入の復元に成功した場合 \{#successful-restore\} 購入の復元が成功した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" func paywallController( _ controller: AdaptyPaywallController, didFinishRestoreWith profile: AdaptyProfile ) { } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ``` </Details> 推奨する方法は、必要な `accessLevel` がある場合にスクリーンを閉じることです。確認方法については、[サブスクリプションのステータス](subscription-status)をご参照ください。 #### 復元の失敗 \{#failed-restore\} 購入の復元に失敗した場合、このメソッドが呼び出されます: ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailRestoreWith error: AdaptyError ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> ### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクトの配列を渡さなかった場合、AdaptyUI はサーバーから必要なオブジェクトを自動的に取得します。この操作が失敗した場合、AdaptyUI は以下のメソッドを呼び出してエラーを通知します: ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailLoadingProductsWith error: AdaptyError ) -> Bool { return true } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> `true` を返すと、AdaptyUI は 2 秒後にリクエストを再試行します。 #### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生した場合、このメソッドで通知されます: ```swift showLineNumbers title="Swift" public func paywallController( _ controller: AdaptyPaywallController, didFailRenderingWith error: AdaptyError ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ``` </Details> 通常、このようなエラーは発生しないはずですので、もし見かけた場合はお知らせください。 </SDKv3> --- # File: ios-use-fallback-paywalls --- --- title: "iOS - フォールバックを使用する" description: "ユーザーがオフラインの場合や Adapty サーバーが利用できない場合の処理方法" --- スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} 1. フォールバック JSON ファイルをプロジェクトバンドルに追加します。XCode で **File** メニューを開き、**Add Files to "YourProjectName"** を選択してください。 2. 対象のフロー、ペイウォール、またはオンボーディングを取得する**前に** `.setFallback` メソッドを呼び出してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { if let urlPath = Bundle.main.url(forResource: fileName, withExtension: "json") { try await Adapty.setFallback(fileURL: urlPath) } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers if let url = Bundle.main.url(forResource: "ios_fallback", withExtension: "json") { Adapty.setFallback(fileURL: url) } ``` </TabItem> </Tabs> パラメーター: | パラメーター | 説明 | | :---------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **fileURL** | フォールバック設定ファイルへのパス。 | --- # File: localizations-and-locale-codes --- --- title: "iOS SDKでローカライゼーションとロケールコードを使用する" description: "iOSアプリでグローバルなユーザーにリーチするために、アプリのローカライゼーションとロケールコードを管理します。" --- ## これが重要な理由 \{#why-this-is-important\} ロケールコードが関係するシナリオはいくつかあります。たとえば、アプリの現在のローカライゼーションに対応する正しいペイウォールを取得しようとする場合などです。 ロケールコードは複雑で、プラットフォームによって異なることがあります。そのため、Adaptyがサポートするすべてのプラットフォームに対して独自の内部標準を設けています。ただし、コードが複雑であるため、サーバーに何を送信しているのか、そして次に何が起こるのかを正確に把握することが重要です。これにより、期待通りの結果を常に受け取ることができます。 ## Adaptyのロケールコード標準 \{#locale-code-standard-at-adapty\} ロケールコードについて、Adaptyはわずかに変更した [BCP 47標準](https://en.wikipedia.org/wiki/IETF_language_tag) を使用しています。各コードはハイフンで区切られた小文字のサブタグで構成されています。例:`en`(英語)、`pt-br`(ポルトガル語(ブラジル))、`zh`(簡体字中国語)、`zh-hant`(繁体字中国語)。 ## ロケールコードのマッチング \{#locale-code-matching\} Adaptyがクライアント側SDKからロケールコード付きの呼び出しを受け取り、ペイウォールの対応するローカライゼーションを検索する際、以下の処理が行われます: 1. 受信したロケール文字列が小文字に変換され、すべてのアンダースコア(`_`)がハイフン(`-`)に置き換えられます 2. 完全に一致するロケールコードのローカライゼーションを検索します 3. 一致するものが見つからない場合、最初のハイフンの前の部分文字列(`pt-br`の場合は`pt`)を取り出し、一致するローカライゼーションを検索します 4. それでも一致するものが見つからない場合、デフォルトの`en`ローカライゼーションを返します これにより、`'pt_BR'`を送信したiOSデバイス、`pt-BR`を送信したAndroidデバイス、`pt-br`を送信した別のデバイスは、すべて同じ結果を受け取ります。 ## ローカライゼーションの実装:推奨方法 \{#implementing-localizations-recommended-way\} ローカライゼーションについて検討しているなら、すでにプロジェクト内のローカライズされた文字列ファイルを扱っているでしょう。その場合、各ローカライゼーションに対応するファイルに、意図したAdaptyロケールコードをキーと値のペアとして配置することをお勧めします。そして、次のようにSDKを呼び出す際にそのキーの値を取得します: ```swift showLineNumbers // 1. Modify your Localizable.strings files /* Localizable.strings - Spanish */ adapty_paywalls_locale = "es"; /* Localizable.strings - Portuguese (Brazil) */ adapty_paywalls_locale = "pt-br"; // 2. Extract and use the locale code let locale = NSLocalizedString("adapty_paywalls_locale", comment: "") // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` これにより、アプリのすべてのユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。 ## ローカライゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} ロケールコードをすべてのローカライゼーションに明示的に定義しなくても、類似した(ただし同一ではない)結果を得ることができます。その場合、プラットフォームが提供する他のオブジェクトからロケールコードを抽出することになります。例: ```swift showLineNumbers let locale = Locale.current.identifier // pass locale code to AdaptyUI.getViewConfiguration or Adapty.getPaywall method ``` いくつかの理由から、このアプローチは推奨しません: 1. iOSでは、優先言語と現在のロケールは同一ではありません。ローカライゼーションを正しく選択したい場合、Appleのロジックに依存するか(ローカライズされた文字列ファイルを使用する推奨アプローチでは自動的に機能します)、それを再現する必要があります。 2. Adaptyのサーバーが何を受け取るかを予測するのが難しいです。たとえばiOSでは、デバイスから`ar_OM@numbers='latn'`のようなロケールを取得してサーバーに送信することがあります。この場合、期待していた`ar-om`ローカライゼーションではなく、`ar`が返ってくる可能性があり、意図しない結果になることがあります。 このアプローチを使用する場合は、関連するすべてのユースケースを網羅していることを確認してください。 --- # File: ios-troubleshoot-paywall-builder --- --- title: "Troubleshoot Paywall Builder in iOS SDK" description: "Troubleshoot Paywall Builder in iOS SDK" --- このガイドでは、iOS SDK でAdapty ペイウォールビルダーを使用して作成したペイウォールに関する一般的な問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: `getPaywallConfiguration` メソッドがペイウォール設定を取得できない。 **原因**: ペイウォールビルダーでデバイス表示が有効になっていない。 **解決策**: ペイウォールビルダーの **Show on device** トグルを有効にしてください。 <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ペイウォールの表示回数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールの表示回数が想定の2倍になっている。 **原因**: コード内で `logShowFlow`(iOS SDK v4+)/ `logShowPaywall` を呼び出している可能性があります。ペイウォールビルダーやフロービルダーで作成したペイウォール・フローを使用している場合、アナリティクスは自動的に記録されるため、このメソッドを呼び出すと表示回数が重複します。 **解決策**: ペイウォールビルダーまたはフロービルダーを使用している場合は、コード内で `logShowFlow`(iOS SDK v4+)/ `logShowPaywall` を呼び出していないことを確認してください。 ## その他の問題 \{#other-issues\} **問題**: 上記に該当しないペイウォールビルダー関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](ios-sdk-migration-guides)を参照し、SDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで修正されています。 --- # File: ios-present-paywall-builder-paywalls-in-observer-mode --- --- title: "iOS SDKのObserverモードでPaywall Builderのペイウォールを表示する" description: "オブザーバーモードでPBペイウォールを表示して、より詳細なインサイトを得る方法を学びます。" --- ペイウォールビルダーを使用してペイウォールをカスタマイズした場合、それをユーザーに表示するためにモバイルアプリのコードでレンダリングする必要はありません。このようなペイウォールには、ペイウォール内に表示する内容とその表示方法の両方が含まれています。 :::warning このセクションは[オブザーバーモード](observer-vs-full-mode)専用です。オブザーバーモードで作業していない場合は、[iOS - ペイウォールビルダーのペイウォールを表示する](ios-present-paywalls)を参照してください。 ::: <SDKv4> <details> <summary>フローの表示を始める前に(クリックして展開)</summary> 1. Adapty と [App Store の初期連携](initial_ios)を設定します。 2. Adapty SDK をインストールして設定します。`observerMode` パラメーターを `true` に設定してください。[iOS SDK インストールガイド](sdk-installation-ios#activate-adapty-module-of-adapty-sdk)を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. [ビルダーでフローまたはペイウォールを設定](create-paywall)し、プロダクトを割り当てます。 5. [プレースメントを作成し、フローまたはペイウォールを割り当てます](create-placement)。 6. モバイルアプリのコードで[フローとその設定を取得](get-pb-paywalls)します。 </details> <p> </p> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> 1. `AdaptyObserverModeResolver` オブジェクトを実装します。プロトコルは SDK v3 と同じです — オブザーバーモード自体はフローとペイウォールのレンダリング間で変わりません: ```swift showLineNumbers title="Swift" func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // call onStartPurchase / onFinishPurchase to notify AdaptyUI about the purchase progress } func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, onFinishRestore: @escaping () -> Void) { // call onStartRestore / onFinishRestore to notify AdaptyUI about the restore progress } ``` 2. リゾルバーを `observerModeResolver:` パラメーターとして渡し、フロー設定オブジェクトを作成します: ```swift showLineNumbers title="Swift" do { let flowConfiguration = try await AdaptyUI.getFlowConfiguration( forFlow: flow, observerModeResolver: <AdaptyObserverModeResolver> ) } catch { // handle the error } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :----------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------- | | **forFlow** | required | `Adapty.getFlow(placementId:)` で取得した `AdaptyFlow` オブジェクト。[フローとペイウォールの取得](get-pb-paywalls)を参照してください。 | | **observerModeResolver** | required | 上記で実装した `AdaptyObserverModeResolver`。 | 3. `AdaptyUI.flowController(with:delegate:)` を使ってフローコントローラーを初期化します: ```swift showLineNumbers title="Swift" import AdaptyUI let visualFlow = try AdaptyUI.flowController( with: flowConfiguration, delegate: <AdaptyFlowControllerDelegate> ) ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | | :------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------- | | **flowConfiguration** | required | フローのビジュアル詳細を含む `AdaptyUI.FlowConfiguration` オブジェクト。[フローとペイウォールの取得](get-pb-paywalls) を参照。 | | **delegate** | required | フローイベントをリッスンするための `AdaptyFlowControllerDelegate`。[フロー&ペイウォールイベントの処理](ios-handling-events) を参照。 | 戻り値: | オブジェクト | 説明 | | :------------------- | :----------------------------------------------------- | | AdaptyFlowController | リクエストされたフロー画面を表すオブジェクト。 | 4. コントローラーを表示します: ```swift showLineNumbers title="Swift" present(visualFlow, animated: true) ``` :::warning [購入トランザクションにペイウォールを紐付ける](report-transactions-observer-mode)のを忘れずに。これを行わないと、Adapty は購入元のペイウォールを特定できません。 ::: </TabItem> <TabItem value="swiftui" label="SwiftUI" default> SwiftUI では、リゾルバを使ってフロー設定を取得し、`.flow` モディファイアに渡します。 ```swift showLineNumbers title="SwiftUI" @State var flowPresented = false @State var flowConfiguration: AdaptyUI.FlowConfiguration? var body: some View { Text("Hello, AdaptyUI!") .flow( isPresented: $flowPresented, flowConfiguration: flowConfiguration, didPerformAction: { action in switch action { case .close: flowPresented = false default: break } }, didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didReceiveError: { error in flowPresented = false } ) .task { flowConfiguration = try? await AdaptyUI.getFlowConfiguration( forFlow: flow, observerModeResolver: <AdaptyObserverModeResolver> ) } } ``` `getFlowConfiguration`の`observerModeResolver:`パラメーターは、レンダリングされたフローがカスタム購入ロジックを尊重するようにするものです。このモディファイア自体はフルモードと同じコールバックを使用します。 :::warning [購入トランザクションにペイウォールを関連付ける](report-transactions-observer-mode)ことを忘れないでください。そうしないと、Adaptyは購入元のペイウォールを特定できません。 ::: </TabItem> </Tabs> </SDKv4> <SDKv3> <Tabs groupId="current-os" queryString> <TabItem value="sdk3" label="Paywall Builder (SDK 3.x)" default> <details> <summary>ペイウォールを表示する前に(クリックして展開)</summary> 1. Adapty の初期連携を設定します。[Google Play との連携](initial-android)および[App Store との連携](initial_ios)をご参照ください。 2. SDK をインストールして設定します。`observerMode` パラメータを `true` に設定してください。フレームワーク別の手順は [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk) をご参照ください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. Adapty ダッシュボードで[ペイウォールを設定してプロダクトを割り当て](create-paywall)、ペイウォールビルダーでカスタマイズします。 5. Adapty ダッシュボードで[プレースメントを作成してペイウォールを割り当て](create-placement)ます。 6. モバイルアプリのコードで[ペイウォールビルダーのペイウォールとその設定を取得](get-pb-paywalls)します。 </details> <p> </p> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> 1. `AdaptyObserverModeResolver` オブジェクトを実装します: ```swift showLineNumbers title="Swift" func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, onFinishRestore: @escaping () -> Void) { // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore } ``` `observerMode(didInitiatePurchase:onStartPurchase:onFinishPurchase:)` イベントは、ユーザーが購入を開始したことを通知します。このコールバックに応じて、カスタム購入フローを起動できます。 `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)` イベントは、ユーザーが復元を開始したことを通知します。このコールバックに応じて、カスタム復元フローを起動できます。 また、購入またはリストアのプロセスをAdaptyUIに通知するために、以下のコールバックを必ず呼び出してください。これは、ローダーの表示など、ペイウォールの適切な動作に必要です。 | コールバック | 説明 | | :----------------- | :------------------------------------------------------------------------------- | | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | | onStartRestore() | 復元が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishRestore() | 復元が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | 2. ペイウォール設定オブジェクトを作成します: ```swift showLineNumbers title="Swift" do { let paywallConfiguration = try AdaptyUI.getPaywallConfiguration( forPaywall: <paywall object>, observerModeResolver: <AdaptyObserverModeResolver> ) } catch { // handle the error } ``` リクエストパラメータ: | パラメータ | 必須 / 任意 | 説明 | | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall** | required | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **ObserverModeResolver** | required | 前のステップで実装した `AdaptyObserverModeResolver` オブジェクト。 | 3. `.paywallController(for:products:viewConfiguration:delegate:)` メソッドを使用して、表示したいビジュアルペイウォールを初期化します: ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( with: <paywall configuration object>, delegate: <AdaptyPaywallControllerDelegate> ) ``` リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall Configuration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクトです。`AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` メソッドを使用してください。詳細は [ペイウォールビルダーのペイウォールとその設定を取得する](get-pb-paywalls) をご参照ください。 | | **Delegate** | 必須 | ペイウォールイベントを受け取るための `AdaptyPaywallControllerDelegate` です。詳細は [ペイウォールイベントの処理](ios-handling-events) をご参照ください。 | 戻り値: | オブジェクト | 説明 | | :---------------------- | :--------------------------------- | | AdaptyPaywallController | リクエストされたペイウォール画面を表すオブジェクト | オブジェクトが正常に作成されたら、次のように表示できます: ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::warning [購入トランザクションにペイウォールを関連付ける](report-transactions-observer-mode)ことを忘れないでください。関連付けを行わないと、Adapty は購入元のペイウォールを特定できません。 ::: </TabItem> <TabItem value="swiftui" label="SwiftUI" default> デバイス画面にビジュアルペイウォールを表示するには、SwiftUI の `.paywall` モディファイアを使用します: ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywallConfiguration: <paywall configuration object>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } ) } ``` (empty input — nothing to translate) | パラメータ | 必須/任意 | 説明 | | :----------------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall Configuration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyUI.PaywallConfiguration` オブジェクト。`AdaptyUI.getPaywallConfiguration(forPaywall:locale:)` メソッドを使用してください。詳細は [ペイウォールビルダーのペイウォールとその設定を取得する](get-pb-paywalls) をご参照ください。 | | **Products** | 任意 | `AdaptyPaywallProduct` オブジェクトの配列を指定すると、画面上のプロダクト表示タイミングを最適化できます。`nil` を渡した場合、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **TagResolver** | 任意 | カスタムタグとその解決済みの値のディクショナリを定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツに合わせて特定の文字列に動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグのトピックをご参照ください。 | | **ObserverModeResolver** | 任意 | 前のステップで実装した `AdaptyObserverModeResolver` オブジェクト | クロージャパラメーター: | クロージャパラメーター | 説明 | | :--------------------- | :-------------------------------------------------------------------------------- | | **didFinishRestore** | Adapty.restorePurchases() が成功した場合、このコールバックが呼び出されます。 | | **didFailRestore** | Adapty.restorePurchases() が失敗した場合、このコールバックが呼び出されます。 | | **didFailRendering** | インターフェースのレンダリング中にエラーが発生した場合、このコールバックが呼び出されます。 | その他のクロージャーパラメーターについては、[iOS - イベントの処理](ios-handling-events) トピックを参照してください。 :::warning [購入トランザクションにペイウォールを関連付ける](report-transactions-observer-mode) ことを忘れないでください。そうしないと、Adapty は購入元のペイウォールを特定できません。 ::: </TabItem> </Tabs> </TabItem> <TabItem value="sdk2" label="Legacy Paywall Builder (SDK up to 2.x)" default> <details> <summary>ペイウォールの表示を始める前に(クリックして展開)</summary> 1. Adapty と [Google Play の初期連携](initial-android)および [App Store の初期連携](initial_ios)を設定します。 1. Adapty SDK をインストールして設定します。`observerMode` パラメーターを `true` に設定してください。各フレームワーク向けの手順は [iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk)、[Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk) を参照してください。 2. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 3. Adapty ダッシュボードで[ペイウォールを設定してプロダクトを割り当て](create-paywall)、ペイウォールビルダーを使ってカスタマイズします。 4. Adapty ダッシュボードで[プレースメントを作成してペイウォールを割り当て](create-placement)ます。 5. モバイルアプリのコードで [Paywall Builder のペイウォールとその設定を取得](get-pb-paywalls)します。 </details> <p> </p> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> 1. `AdaptyObserverModeDelegate` オブジェクトを実装します: ```swift showLineNumbers title="Swift" func paywallController(_ controller: AdaptyPaywallController, didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } ``` `paywallController(_:didInitiatePurchase:onStartPurchase:onFinishPurchase:)` イベントは、ユーザーが購入を開始したことを通知します。このイベントに応答して、独自の購入フローを起動できます。 また、購入プロセスをAdaptyUIに通知するために、以下のコールバックを呼び出すことを忘れないでください。これは、ローダーの表示など、ペイウォールが正しく動作するために必要です: | コールバック | 説明 | | :--------------- | :---------------------------------------------------------------- | | onStartPurchase | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | 2. `.paywallController(for:products:viewConfiguration:delegate:observerModeDelegate:)` メソッドを使用して、表示したいビジュアルペイウォールを初期化します。 ```swift showLineNumbers title="Swift" import AdaptyUI let visualPaywall = AdaptyUI.paywallController( for: <paywall object>, products: <paywall products array>, viewConfiguration: <LocalizedViewConfiguration>, delegate: <AdaptyPaywallControllerDelegate> observerModeDelegate: <AdaptyObserverModeDelegate> ) ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :----------------------- | :------- | :----------------------------------------------------------- | | **Paywall** | 必須 | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **Products** | 任意 | 画面上のプロダクト表示タイミングを最適化するために、`AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡した場合、AdaptyUI が自動的に必要なプロダクトを取得します。 | | **ViewConfiguration** | 必須 | ペイウォールのビジュアル詳細を含む `AdaptyUI.LocalizedViewConfiguration` オブジェクト。`AdaptyUI.getViewConfiguration(paywall:locale:)` メソッドを使用してください。詳細は [ペイウォールビルダーのペイウォールと設定の取得](get-pb-paywalls) を参照してください。 | | **Delegate** | 必須 | ペイウォールイベントをリッスンするための `AdaptyPaywallControllerDelegate`。詳細は [ペイウォールイベントの処理](ios-handling-events) を参照してください。 | | **ObserverModeDelegate** | 必須 | 前のステップで実装した `AdaptyObserverModeDelegate` オブジェクト。 | | **TagResolver** | 任意 | カスタムタグとその解決済みの値の辞書を定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツ向けに特定の文字列へ動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | 戻り値: | オブジェクト | 説明 | | :---------------------- | :------------------------------------- | | AdaptyPaywallController | リクエストされたペイウォール画面を表すオブジェクト | オブジェクトが正常に作成されたら、次のように表示できます: ```swift showLineNumbers title="Swift" present(visualPaywall, animated: true) ``` :::warning 購入トランザクションに[ペイウォールを関連付ける](report-transactions-observer-mode)ことを忘れないでください。関連付けを行わないと、Adapty は購入元のペイウォールを特定できません。 ::: </TabItem> <TabItem value="swiftui" label="SwiftUI" default> デバイス画面にビジュアルペイウォールを表示するには、SwiftUI の `.paywall` モディファイアを使用します: ```swift showLineNumbers title="SwiftUI" @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, paywall: <paywall object>, configuration: <LocalizedViewConfiguration>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false }, observerModeDidInitiatePurchase: { product, onStartPurchase, onFinishPurchase in // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase }, ) } ``` (empty input — nothing to translate) | パラメータ | 必須/任意 | 説明 | | :---------------- | :------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Paywall** | 必須 | 対象のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクトです。 | | **Product** | 任意 | 画面上のプロダクト表示タイミングを最適化するために `AdaptyPaywallProduct` オブジェクトの配列を指定します。`nil` を渡した場合、AdaptyUI が必要なプロダクトを自動的に取得します。 | | **Configuration** | 必須 | ペイウォールの視覚的な詳細を含む `AdaptyUI.LocalizedViewConfiguration` オブジェクトです。`AdaptyUI.getViewConfiguration(paywall:locale:)` メソッドを使用してください。詳細は [ペイウォールビルダーのペイウォールとその設定の取得](get-pb-paywalls) を参照してください。 | | **TagResolver** | 任意 | カスタムタグとその解決済みの値の辞書を定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツに応じた文字列に動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグに関するトピックを参照してください。 | Closure parameters: | クロージャのパラメータ | 説明 | | :---------------------------------- | :-------------------------------------------------------------------------------- | | **didFinishRestore** | Adapty.restorePurchases() が成功した場合、このコールバックが呼び出されます。 | | **didFailRestore** | Adapty.restorePurchases() が失敗した場合、このコールバックが呼び出されます。 | | **didFailRendering** | インターフェースのレンダリング中にエラーが発生した場合、このコールバックが呼び出されます。 | | **observerModeDidInitiatePurchase** | ユーザーが購入を開始したときにこのコールバックが呼び出されます。 | 他のクロージャパラメータについては、[iOS - イベントの処理](ios-handling-events)トピックをご参照ください。 :::warning 必ず[購入トランザクションにペイウォールを関連付ける](report-transactions-observer-mode)ようにしてください。関連付けを行わないと、Adaptyは購入元のペイウォールを特定できません。 ::: </TabItem> </Tabs> </TabItem> </Tabs> </SDKv3> --- # File: ios-quickstart-manual --- --- title: "iOS SDKのカスタムペイウォールで購入を有効にする" description: "Adapty SDKをカスタムiOSペイウォールに統合してアプリ内課金を有効にします。" --- このガイドでは、Adaptyをカスタムペイウォールに統合する方法を説明します。ペイウォールの実装を完全にコントロールしながら、Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を行います。 :::important **このガイドはカスタムペイウォールを実装する開発者向けです。** 購入を最も簡単に有効にしたい場合は、[Adapty フローBuilder](ios-quickstart-paywalls)を使用してください。フローBuilderを使えば、ノーコードのビジュアルエディターでフローを作成でき、Adaptyが購入ロジックをすべて自動的に処理します。アプリを再公開せずにさまざまなデザインをテストできます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトのセットアップ \{#set-up-products\} アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります: - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定。Adaptyでは、プロダクトを取得する唯一の方法がペイウォールですが、この設計によりアプリコードを変更せずにプロダクト、価格、オファーを変更できます。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings`など)。ダッシュボードでプレースメントにペイウォールを設定し、コード内でプレースメントIDを使ってリクエストします。これにより、A/B テストの実施やユーザーごとに異なるペイウォールの表示が簡単になります。 カスタムペイウォールを使用する場合でも、これらの概念を理解しておくことが重要です。基本的に、アプリで販売するプロダクトを管理するための仕組みです。 カスタムペイウォールを実装するには、**ペイウォール**を作成して**プレースメント**に追加する必要があります。この設定によりプロダクトを取得できるようになります。ダッシュボードで何をする必要があるかを理解するには、[こちら](quickstart)のクイックスタートガイドに従ってください。 ### ユーザーの管理 \{#manage-users\} バックエンド認証の有無にかかわらず作業できます。 ただし、Adapty SDKは匿名ユーザーと識別済みユーザーを異なる方法で処理します。[識別クイックスタートガイド](ios-quickstart-identify)を読んで、その詳細を理解し、ユーザーを適切に処理していることを確認してください。 ## ステップ1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、次の手順が必要です: 1. `getFlow`メソッドに[プレースメント](placements)IDを渡して`flow`オブジェクトを取得します。 2. `getPaywallProducts`メソッドを使ってこのフローのプロダクト配列を取得します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift func loadPaywall() async { do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let products = try await Adapty.getPaywallProducts(flow: flow) // Use products to build your custom paywall UI } catch { // Handle the error } } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift func loadPaywall() { Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): Adapty.getPaywallProducts(flow: flow) { result in switch result { case let .success(products): // Use products to build your custom paywall UI case let .failure(error): // Handle the error } } case let .failure(error): // Handle the error } } } ``` </TabItem> </Tabs> ## ステップ2. 購入を受け付ける \{#step-2-accept-purchases\} ユーザーがカスタムペイウォールのプロダクトをタップしたら、選択したプロダクトを引数に`makePurchase`メソッドを呼び出します。これにより購入フローが処理され、更新されたプロファイルが返されます。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift func purchaseProduct(_ product: AdaptyPaywallProduct) async { do { let purchaseResult = try await Adapty.makePurchase(product: product) switch purchaseResult { case .userCancelled: // User canceled the purchase break case .pending: // Purchase is pending (e.g., awaiting parental approval) break case let .success(profile, transaction): // Purchase successful, profile updated break } } catch { // Handle the error } } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift func purchaseProduct(_ product: AdaptyPaywallProduct) { Adapty.makePurchase(product: product) { result in switch result { case let .success(purchaseResult): switch purchaseResult { case .userCancelled: // User canceled the purchase break case .pending: // Purchase is pending (e.g., awaiting parental approval) break case let .success(profile, transaction): // Purchase successful, profile updated break } case let .failure(error): // Handle the error } } } ``` </TabItem> </Tabs> ## ステップ3. 購入を復元する \{#step-3-restore-purchases\} Appleは、サブスクリプションのあるすべてのアプリに対して、ユーザーが購入を復元できる手段を提供することを求めています。Apple IDでログインした際に購入は自動的に復元されますが、それでもアプリに復元ボタンを実装する必要があります。 ユーザーが復元ボタンをタップしたら`restorePurchases`メソッドを呼び出します。これにより購入履歴がAdaptyと同期され、更新されたプロファイルが返されます。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift func restorePurchases() async { do { let profile = try await Adapty.restorePurchases() // Restore successful, profile updated } catch { // Handle the error } } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift func restorePurchases() { Adapty.restorePurchases { result in switch result { case let .success(profile): // Restore successful, profile updated case let .failure(error): // Handle the error } } } ``` </TabItem> </Tabs> ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールはアプリに表示する準備ができました。[サンドボックスモードで購入をテスト](test-purchases-in-sandbox)して、ペイウォールからテスト購入を完了できることを確認してください。 次に、[ユーザーが購入を完了したかどうかを確認](ios-check-subscription-status)して、ペイウォールを表示するか有料機能へのアクセスを許可するかを判断してください。 --- # File: fetch-paywalls-and-products --- --- title: "iOS SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "AdaptyのiOS SDKでペイウォールとプロダクトを取得し、ユーザーの収益化を向上させます。" --- <SDKv4> リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。**Flow Builder** または **Paywall Builder** でカスタマイズされたフローやペイウォールの取得方法については、<InlineTooltip tooltip="フローとペイウォールのアプリ内での取得方法に関するガイド">[iOS](get-pb-paywalls)、[Android](android-get-pb-paywalls)、[React Native](react-native-get-pb-paywalls)、[Flutter](flutter-get-pb-paywalls)、および [Unity](unity-get-pb-paywalls)</InlineTooltip>をご覧ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでフローとプロダクトの取得を開始する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[フローまたはペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに[Adapty SDK をインストール](sdk-installation-ios)する。 </details> ## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)は App Store と Google Play 両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはフローやペイウォールに統合され、モバイルアプリの特定のプレースメントに表示できます。 プロダクトを表示するには、`getFlow` メソッドを使って[プレースメント](placements)のいずれかから `AdaptyFlow` を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードすべきIDはプレースメントIDのみです。フローはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変更される可能性があります。アプリはこれらの変更を動的に処理する必要があります。つまり、今日フローが2つのプロダクトを返し、明日3つを返す場合でも、コードを変更せずにすべてを表示できなければなりません。 ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") // the requested flow } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。この設定を推奨します。ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用することを検討してください。キャッシュが存在する場合はキャッシュデータを返します。この場合、最新データが得られないことがありますが、接続状況にかかわらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために活用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はフローとペイウォールを 2 つのレイヤーで保存しています。上記の定期更新されるキャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、フローとペイウォールをより速く取得するために CDN を使用し、CDN が利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。</p> | | **loadTimeout** | デフォルト: 5 秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p></p><p>まれに、内部で複数のリクエストが行われるため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトする場合があります。</p> | :::note v4 では、`locale` パラメータは `getFlow` から移動し、`getFlowConfiguration`(AdaptyUI でレンダリングする場合のみ使用)に設定するようになりました。カスタムペイウォールの場合、利用可能なすべてのロケールは `flow.remoteConfigs` にまとめて返されるため、ユーザーのデバイスまたはアプリの設定に合ったロケールを選んでください。 ::: プロダクトIDをハードコードしないでください!フローはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特典(無料トライアルなど)は随時変更される可能性があります。こうしたシナリオに対応できるようコードを作成してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはそれら2つを表示します。しかし後に3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できる必要があります。ハードコードが必要なのはプレースメントIDだけです。 レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | `AdaptyFlow` オブジェクト。プレースメント、識別子(`id`、`variationId`)、名前、設定済みロケールごとのエントリを含む `remoteConfigs` 配列、および `hasViewConfiguration` フラグを保持します。フローのプロダクトを取得するには `getPaywallProducts(flow:)` を呼び出してください。 | ## プロダクトを取得する \{#fetch-products\} フローを取得したら、そのフローに対応するプロダクトの配列を取得できます: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let products = try await Adapty.getPaywallProducts(flow: flow) // the requested products array } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallProducts(flow: flow) { result in switch result { case let .success(products): // the requested products array case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他いくつかのプロパティを含みます。 | 独自のペイウォールデザインを実装する場合、[`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |---|---| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用してください。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づきます。 | | **Price** | ローカライズされた価格を表示するには、`product.localizedPrice` を使用してください。このローカライズはデバイスのロケール情報に基づきます。また、`product.price` で価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.currencySymbol` を使用してください。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.localizedSubscriptionPeriod` を使用してください。このローカライズはデバイスのロケールに基づきます。サブスクリプション期間をプログラムで取得するには、`product.subscriptionPeriod` を使用してください。そこから `unit` 列挙型にアクセスして期間の長さ(day、week、month、year、または unknown)を取得できます。`numberOfUnits` の値で期間単位の数を取得できます。たとえば、四半期ごとのサブスクリプションの場合、`unit` プロパティには `.month`、`numberOfUnits` プロパティには `3` が表示されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれていることを示すバッジやインジケーターを表示するには、`product.subscriptionOffer` プロパティを確認してください。このオブジェクトには以下の便利なプロパティがあります:<br/>• `offerType`:`introductory`、`promotional`、`winBack` の値を持つ列挙型。無料トライアルや初期割引サブスクリプションは `introductory` タイプになります。<br/>• `price`:割引価格を数値で表したもの。無料トライアルの場合は `0` を確認してください。<br/>• `localizedPrice`:ユーザーのロケールに合わせてフォーマットされた割引価格。<br/>• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列。たとえば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。<br/>• `subscriptionPeriod`:オファー期間の個別の詳細はこのプロパティで取得することもできます。オファーに対してもサブスクリプション期間と同様に機能します。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | :::note v4では、`getPaywallProducts(flow:)` が返すすべてのプロダクトにオファーの適格性情報が含まれています。v3にあった `getPaywallProductsWithoutDeterminingOffer` の個別呼び出しは削除されました。 ::: ## デフォルトオーディエンスフローでフロー取得を高速化する \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ瞬時に取得されるため、この処理を高速化することを特に気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が不安定な場合、フローの取得に想定以上の時間がかかることがあります。そのような状況では、何も表示しないよりもデフォルトフローを表示して、スムーズなユーザー体験を確保したい場合があるでしょう。 これに対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けのフローを取得します。ただし、推奨されるアプローチは `getFlow` メソッドを使用してフローを取得することである点を理解しておくことが重要です。詳細は上記の[フロー情報の取得](fetch-paywalls-and-products#fetch-flow-information)セクションを参照してください。 :::warning `getFlow` の使用を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるフローを表示する必要がある場合、課題に直面する可能性があります。現在の(レガシー)バージョンに対応したフローを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないフローで問題に遭遇することを許容するかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じフローを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくターゲティングを含む)が失われます。 これらのデメリットを受け入れてでもフローの取得を高速化したい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。それ以外の場合は、[上記](fetch-paywalls-and-products#fetch-flow-information)の `getFlow` を使用してください。 ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let flow = try await Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") // the requested flow } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getFlowForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(flow): // the requested flow case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方式はユーザーが常に最新のデータを取得できるため、推奨しています。</p><p></p><p>ただし、ユーザーがネットワークの不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュされたデータを返します。この場合、最新のデータが届かない可能性はありますが、ネットワーク状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために活用しても安全です。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリアした場合にのみ削除されます。</p> | </SDKv4> <SDKv3> リモートコンフィグとカスタムペイウォールを表示する前に、それらに関する情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズされたペイウォールの取得方法については、<InlineTooltip tooltip="アプリでペイウォールビルダーのペイウォールを取得するガイド">[iOS](get-pb-paywalls)、[Android](android-get-pb-paywalls)、[React Native](react-native-get-pb-paywalls)、[Flutter](flutter-get-pb-paywalls)、[Unity](unity-get-pb-paywalls)</InlineTooltip>を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を開始する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトをペイウォールに追加](create-paywall)してください。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールをプレースメントに追加](create-placement)してください。 4. モバイルアプリに [Adapty SDK をインストール](sdk-installation-ios)してください。 </details> ## ペイウォール情報の取得 \{#fetch-paywall-information\} Adapty では、[プロダクト](product)はApp StoreとGoogle Playの両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはペイウォールに統合されており、モバイルアプリの特定のプレースメントで表示できます。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)のいずれかから[ペイウォール](paywalls)を取得する必要があります。 :::important **プロダクト ID をハードコードしないでください。** ハードコードするのはプレースメント ID のみにしてください。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更に動的に対応する必要があります。今日は 2 つのプロダクトを返すペイウォールが明日は 3 つを返すことになっても、コードを変更せずにすべて表示できるようにしてください。 ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語を表し、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードの詳細とその推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを取得できるからです。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を使用していると思われる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在すればそれを返すことを検討してください。この場合、ユーザーは最新のデータを取得できないことがありますが、インターネット接続が不安定な場合でも読み込み時間が短縮されます。キャッシュは定期的に更新されるため、ネットワークリクエストを避けるためにセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップによってのみ消去されます。</p><p></p><p>Adapty SDK はペイウォールを2つの層に保存します:上記の定期的に更新されるキャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより速く取得するために CDN を使用し、CDN が到達不能な場合に備えてスタンドアローンのフォールバックサーバーも使用しています。このシステムは、インターネット接続が限られている状況でも信頼性を確保しながら、常に最新バージョンのペイウォールを取得できるように設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p></p><p>まれに、このメソッドが `loadTimeout` で指定した時間よりもわずかに遅くタイムアウトすることがあります。これは、処理内部で複数のリクエストが実行される場合があるためです。</p> | プロダクトIDをハードコードしないでください!ペイウォールはリモートで設定されるため、利用可能なプロダクト、プロダクト数、特典(無料トライアルなど)は随時変更される可能性があります。これらのシナリオに対応できるよう、コードを実装してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはその2つのプロダクトを表示する必要があります。その後3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できなければなりません。ハードコードが必要なのはプレースメントIDのみです。 レスポンスのパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォールの識別子、リモートコンフィグなどのプロパティを含む [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) オブジェクト。 | ## プロダクトを取得する \{#fetch-products\} ペイウォールを取得したら、それに対応するプロダクトの配列をクエリできます: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let products = try await Adapty.getPaywallProducts(paywall: paywall) // the requested products array } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallProducts(paywall: paywall) { result in switch result { case let .success(products): // 取得したプロダクトの配列 case let .failure(error): // エラーを処理する } } ``` </TabItem> </Tabs> レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトのリストで、プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティを含みます。 | 独自のペイウォールデザインを実装する際、[`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。以下によく使われるプロパティを示しますが、利用可能なすべてのプロパティの詳細はリンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **タイトル** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **価格** | ローカライズされた価格を表示するには、`product.localizedPrice` を使用します。このローカライズはデバイスのロケール情報に基づいています。`product.price` を使用すると価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.currencySymbol` を使用します。 | | **サブスクリプション期間** | 期間(週、月、年など)を表示するには、`product.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づいています。サブスクリプション期間をプログラムで取得するには、`product.subscriptionPeriod` を使用します。そこから `unit` 列挙型にアクセスして長さ(day、week、month、year、または unknown)を取得できます。`numberOfUnits` の値は期間単位の数を返します。たとえば四半期サブスクリプションの場合、unit プロパティには `.month`、numberOfUnits プロパティには `3` が表示されます。 | | **初回オファー** | サブスクリプションに初回オファーが含まれているかをバッジなどで表示するには、`product.subscriptionOffer` プロパティを確認します。このオブジェクト内には以下の便利なプロパティが含まれています。<br/>• `offerType`: `introductory`、`promotional`、`winBack` の値を持つ列挙型。無料トライアルや初期割引サブスクリプションは `introductory` タイプになります。<br/>• `price`: 割引後の価格(数値)。無料トライアルの場合は `0` になります。<br/>• `localizedPrice`: ユーザーのロケールに合わせてフォーマットされた割引価格。<br/>• `localizedNumberOfPeriods`: オファーの期間をデバイスのロケールでローカライズした文字列。たとえば3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。<br/>• `subscriptionPeriod`: オファー期間の詳細を個別に取得する場合はこのプロパティを使用します。前のセクションで説明したのと同じ方法でオファーに対しても機能します。<br/>• `localizedSubscriptionPeriod`: ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## iOS での初回オファー適格性の確認 \{#check-intro-offer-eligibility-on-ios\} デフォルトでは、`getPaywallProducts` メソッドが初回オファー、プロモーションオファー、ウィンバックオファーの適格性を確認します。SDK がオファーの適格性を判定する前にプロダクトを表示する必要がある場合は、代わりに `getPaywallProductsWithoutDeterminingOffer` メソッドを使用してください。 :::note 初期プロダクトを表示した後は、必ず通常の `getPaywallProducts` メソッドを呼び出して、正確なオファー適格性情報でプロダクトを更新してください。 ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let products = try await Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) // the requested products array without subscriptionOffer } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallProductsWithoutDeterminingOffer(paywall: paywall) { result in switch result { case let .success(products): // subscriptionOfferなしでリクエストしたプロダクト配列 case let .failure(error): // エラーを処理する } } ``` </TabItem> </Tabs> ## デフォルトオーディエンスのペイウォールでペイウォールの取得を高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ瞬時に取得されるため、このプロセスを高速化することを特に意識する必要はありません。しかし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を提供したい場合があるでしょう。 この問題を解決するために、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](fetch-paywalls-and-products#fetch-paywall-information)セクションをご覧ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)で異なるペイウォールを表示する必要がある場合、課題が生じることがあります。現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがペイウォールを正しく表示できないリスクを受け入れるかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、カスタム属性に基づくものを含む)が失われます。 これらのデメリットを許容してでもペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products#fetch-paywall-information)で説明した `getPaywall` を使用してください。 ::: <Tabs group="current-os"> <TabItem value="swift" label="Swift"> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID") // the requested paywall } catch { // handle the error } ``` </TabItem> <TabItem value="callback" label="Swift-Callback"> ```swift showLineNumbers Adapty.getPaywallForDefaultAudience(placementId: "YOUR_PLACEMENT_ID", locale: "en") { result in switch result { case let .success(paywall): // the requested paywall case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> :::note `getPaywallForDefaultAudience` メソッドは iOS SDK バージョン 2.11.2 以降で利用できます。 ::: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメータは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードです。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードと推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーがネットワークの不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在すればそれを返すことも検討してください。この場合、最新データが取得できないことがありますが、接続状況に左右されず読み込みが速くなります。キャッシュはセッション中も定期的に更新されるため、ネットワークリクエストを減らす目的で安全に使用できます。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動でのクリア時にのみ削除されます。</p> | </SDKv3> --- # File: present-remote-config-paywalls --- --- title: "iOS SDKでリモートコンフィグ設計のペイウォールをレンダリングする" description: "Adaptyでリモートコンフィグペイウォールを表示してユーザー体験をパーソナライズする方法を解説します。" --- <SDKv4> リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリング処理をアプリのコードに実装する必要があります。リモートコンフィグは柔軟にカスタマイズできるため、ペイウォールに何を含めるか、どのように表示するかはすべて開発者次第です。Adapty はリモートコンフィグを取得するメソッドを提供しており、カスタムペイウォールを自由に表示できます。 [iOS で初回オファーの対象ユーザーを確認する](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios)ことを忘れずに、対象ユーザーの場合の処理もペイウォールに組み込んでください。 ## フローのリモートコンフィグを取得して表示する \{#get-flow-remote-config-and-present-it\} v4 では、フローは設定済みロケールごとに 1 つの `AdaptyRemoteConfig` エントリを `remoteConfigs` 配列に持ちます。ユーザーの設定に合ったロケールを選択し、必要な値を読み取ってください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let config = flow.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow.remoteConfigs.first let headerText = config?.dictionary?["header_text"] as? String } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") { result in let flow = try? result.get() let config = flow?.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow?.remoteConfigs.first let headerText = config?.dictionary?["header_text"] as? String } ``` </TabItem> </Tabs> 必要な値をすべて取得したら、それらを組み合わせて見栄えの良いページをレンダリングしましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、どのデバイスでもシームレスで使いやすい体験を提供してください。 :::warning 以下で説明する[ペイウォール表示イベントの記録](present-remote-config-paywalls#track-paywall-view-events)を必ず行ってください。これにより、Adapty アナリティクスがファネルや A/B テストの情報を取得できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入する際は、フローのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細は[購入処理](making-purchases)を参照してください。 [フォールバックペイウォールというバックアップペイウォールを作成する](fallback-paywalls)ことをおすすめします。インターネット接続がない場合やキャッシュが利用できない場合でも、このバックアップが表示されるためスムーズな体験が維持されます。 ## ペイウォール表示イベントのトラッキング \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見たタイミングを把握しているのが開発者だけのため、手動での記録が必要です。 ペイウォール表示イベントを記録するには、`.logShowFlow(flow)` を呼び出すだけです。ファネルや A/B テストのペイウォール指標に反映されます。 :::important [フロービルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示している場合は、`.logShowFlow(flow)` を呼び出す必要はありません。それらの場合、Adapty が自動的に表示をトラッキングします。 ::: ```swift showLineNumbers try await Adapty.logShowFlow(flow) ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :-------- | :------- |:-----------------------------------------------------------------------------------------| | **flow** | 必須 | `Adapty.getFlow(placementId:)` で取得した `AdaptyFlow` オブジェクト。 | </SDKv4> <SDKv3> リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリング処理をアプリのコードに実装する必要があります。リモートコンフィグは柔軟にカスタマイズできるため、ペイウォールに何を含めるか、どのように表示するかはすべて開発者次第です。Adapty はリモートコンフィグを取得するメソッドを提供しており、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 [iOS で初回オファーの対象ユーザーを確認する](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios)ことを忘れずに、対象ユーザーの場合の処理もペイウォールに組み込んでください。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") let headerText = paywall.remoteConfig?.dictionary?["header_text"] as? String } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID") { result in let paywall = try? result.get() let headerText = paywall?.remoteConfig?.dictionary?["header_text"] as? String } ``` </TabItem> </Tabs> 必要な値をすべて取得したら、それらを組み合わせて見栄えの良いページをレンダリングしましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインにして、どのデバイスでもシームレスで使いやすい体験を提供してください。 :::warning 以下で説明する[ペイウォール表示イベントの記録](present-remote-config-paywalls#track-paywall-view-events)を必ず行ってください。これにより、Adapty アナリティクスがファネルや A/B テストの情報を取得できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入する際は、ペイウォールのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細は[購入処理](making-purchases)を参照してください。 [フォールバックペイウォールというバックアップペイウォールを作成する](fallback-paywalls)ことをおすすめします。インターネット接続がない場合やキャッシュが利用できない場合でも、このバックアップが表示されるためスムーズな体験が維持されます。 ## ペイウォール表示イベントのトラッキング \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見たタイミングを把握しているのが開発者だけのため、手動での記録が必要です。 ペイウォール表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールを表示している場合は、`.logShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```swift showLineNumbers Adapty.logShowPaywall(paywall) ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- |:-----------------------------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://swift.adapty.io/documentation/adapty/adaptypaywall) オブジェクト。 | </SDKv3> --- # File: making-purchases --- --- title: "iOS SDKでモバイルアプリの購入を行う" description: "Adaptyを使用したアプリ内課金とサブスクリプションの処理に関するガイド。" --- モバイルアプリ内でペイウォールを表示することは、ユーザーにプレミアムコンテンツやサービスへのアクセスを提供するための重要なステップです。ただし、[ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしている場合に限り、ペイウォールを表示するだけで購入処理が完結します。 ペイウォールビルダーを使用しない場合は、購入を完了してコンテンツをアンロックするために `.makePurchase()` という別のメソッドを使用する必要があります。このメソッドは、ユーザーがペイウォールで操作を行い、目的のトランザクションを進めるための窓口となります。 ペイウォールにユーザーが購入しようとしているプロダクトに対して有効なプロモーションオファーがある場合、Adaptyは購入時に自動的にそれを適用します。 :::warning 初回オファーが自動的に適用されるのは、ペイウォールビルダーで設定されたペイウォールを使用している場合のみです。 それ以外の場合は、[iOS での初回オファーの利用資格を確認](fetch-paywalls-and-products#check-intro-offer-eligibility-on-ios)する必要があります。この手順を省略すると、リリース時にアプリが審査で却下される可能性があります。また、初回オファーの対象ユーザーに通常価格が請求される可能性もあります。 ::: 一つのステップも省略せずに[初期設定](quickstart)を完了していることを確認してください。設定が完了していないと、購入の検証ができません。 ## 購入を行う \{#make-purchase\} :::note **[ペイウォールビルダー](adapty-paywall-builder)を使用していますか?** 購入は自動的に処理されます。このステップはスキップできます。 **ステップバイステップのガイドが必要ですか?** 完全なコンテキストとエンドツーエンドの実装手順については、[クイックスタートガイド](ios-implement-paywalls-manually)をご覧ください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let purchaseResult = try await Adapty.makePurchase(product: product) switch purchaseResult { case .userCancelled: // Handle the case where the user canceled the purchase case .pending: // Handle deferred purchases (e.g., the user will pay offline with cash) case let .success(profile, transaction): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // Grant access to the paid features } } } catch { // Handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.makePurchase(product: product) { result in switch result { case let .success(purchaseResult): switch purchaseResult { case .userCancelled: // Handle the case where the user canceled the purchase case .pending: // Handle deferred purchases (e.g., the user will pay offline with cash) case let .success(profile, transaction): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // Grant access to the paid features } } case let .failure(error): // Handle the error } } ``` </TabItem> </Tabs> リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- | :-------------------------------------------------------------------------------------------------- | | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://swift.adapty.io/documentation/adapty/adaptypaywallproduct) オブジェクト。 | レスポンスパラメーター: | パラメーター | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>リクエストが成功した場合、レスポンスにはこのオブジェクトが含まれます。[AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクトは、アプリ内でのユーザーのアクセスレベル、サブスクリプション、非サブスクリプション購入に関する包括的な情報を提供します。</p><p>ユーザーがアプリへの必要なアクセス権を持っているかどうかを確認するために、アクセスレベルのステータスをチェックしてください。</p> | :::warning **注意:** Apple の StoreKit バージョンが v2.0 未満、かつ Adapty SDK バージョンが v2.9.0 未満の場合は、代わりに [Apple App Store 共有シークレット](app-store-connection-configuration#step-5-enter-app-store-shared-secret)を提供する必要があります。このメソッドは現在 Apple によって非推奨とされています。 ::: ## App Store からのアプリ内課金 \{#in-app-purchases-from-the-app-store\} ユーザーが App Store で購入を開始し、トランザクションがアプリに引き継がれる場合、2つの選択肢があります: - **トランザクションを即座に処理する:** `shouldAddStorePayment` で `true` を返します。これにより、Apple の購入システム画面がすぐに表示されます。 - **後処理のためにプロダクトオブジェクトを保存する:** `shouldAddStorePayment` で `false` を返し、後で保存したプロダクトを使って `makePurchase` を呼び出します。購入をトリガーする前にユーザーにカスタム画面を表示したい場合に便利です。 完全なコード例を以下に示します: ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. The Apple purchase system screen will show automatically. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` when the timing is appropriate func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## iOS でオファーコードを利用する \{#redeem-offer-codes-in-ios\} <Details> <summary>オファーコードについて</summary> オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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アナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。 </Details> アプリ内でコード引き換えシートを表示するには: ```swift showLineNumbers Adapty.presentCodeRedemptionSheet() ``` :::danger 確認された問題として、一部のアプリでオファーコード引き換えシートが正常に動作しない場合があります。ユーザーを直接 App Store にリダイレクトすることをお勧めします。 そのためには、以下の形式の URL を開く必要があります: `https://apps.apple.com/redeem?ctx=offercodes&id={apple_app_id}&code={code}` ::: --- # File: restore-purchase --- --- title: "iOS SDKでのアプリ内購入の復元" description: "シームレスなユーザー体験を確保するために、Adaptyで購入を復元する方法を学びましょう。" --- 購入の復元とは、ユーザーが以前に購入したコンテンツ(サブスクリプションやアプリ内課金など)に、再度課金されることなくアクセスを取り戻せる機能です。アプリをアンインストール・再インストールした場合や、新しいデバイスに移行した場合でも、以前の購入内容に改めて支払うことなくアクセスできるため、特に便利な機能です。 :::note [ペイウォールビルダー](adapty-paywall-builder)で構築されたペイウォールでは、追加のコードなしに購入が自動的に復元されます。その場合は、この手順をスキップできます。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしていない場合に購入を復元するには、`.restorePurchases()` メソッドを呼び出してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.restorePurchases() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.restorePurchases { [weak self] result in switch result { case let .success(profile): if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // successful access restore } case let .failure(error): // handle the error } } ``` </TabItem> </Tabs> レスポンスパラメーター: | パラメーター | 説明 | |---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>[`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクト。このモデルには、アクセスレベル、サブスクリプション、および非サブスクリプション購入に関する情報が含まれます。</p><p>ユーザーがアプリへのアクセス権を持っているかどうかを確認するには、**アクセスレベルのステータス**を確認してください。</p> | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: ios-transaction-management --- --- title: "iOS SDKにおける高度なトランザクション管理" description: "Adapty SDKを使用してiOSアプリでトランザクションを手動で完了する方法を説明します。" --- :::note 高度なトランザクション管理は、Adapty iOS SDK バージョン3.12以降でサポートされています。 ::: Adaptyの高度なトランザクション管理を使用すると、トランザクションの処理、検証、完了をより細かく制御できます。 高度なトランザクション管理には、連携して動作する3つのオプション機能が含まれています。 | 機能 | 目的 | |-------------------------------------------------------------|----------| | [`appAccountToken`](#assign-appaccounttoken) | Appleのトランザクションを内部ユーザーIDに紐付ける | | [`jwsTransaction`](#access-the-jws-representation) | バリデーション用にAppleの署名済みトランザクションペイロードを提供する | | [手動完了](#control-transaction-finishing-behavior) | バックエンドが成功を確認した後にのみトランザクションを完了できる | これらのツールを組み合わせることで、AdaptyがバックエンドとのトランザクションSync機能を維持しながら、堅牢なカスタムバリデーションフローを構築できます。 :::important ほとんどのアプリにはこの機能は不要です。 デフォルトでは、AdaptyはStoreKitトランザクションを自動的に検証・完了します。 このガイドは、独自のバックエンドバリデーションを実行する場合や、購入ライフサイクルを完全に制御したい場合にのみ使用してください。 ::: ## `appAccountToken`を設定する \{#assign-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:))は、App Storeのトランザクションを内部ユーザーIDに紐付けるための**UUID**です。 StoreKitはこのトークンをすべてのトランザクションに関連付けるため、バックエンドでApp Storeのデータとユーザーを照合できます。 ユーザーごとに生成した安定したUUIDを使用し、デバイスをまたいで同じアカウントに対して再利用してください。 これにより、購入とApp Storeの通知が正しく紐付けられます。 トークンは2つの方法で設定できます。SDK初期化時またはユーザーを識別するときです。 :::important `appAccountToken`は必ず`customerUserId`と一緒に渡す必要があります。 トークンのみを渡した場合、トランザクションに含まれません。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } // Or when identifying a user: do { try await Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: <APP_ACCOUNT_TOKEN>) Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } // Or when identifying a user: Adapty.identify("YOUR_USER_ID", withAppAccountToken: <APP_ACCOUNT_TOKEN>) { error in if let error { // handle the error } } ``` </TabItem> </Tabs> ## JWS表現にアクセスする \{#access-the-jws-representation\} 購入を行うと、結果にはAppleのトランザクションが[JWSコンパクトシリアライゼーション形式](https://developer.apple.com/documentation/storekit/verificationresult/jwsrepresentation-21vgo)で含まれます。 この値をバックエンドに転送して、独自のバリデーションやログ記録に活用できます。 ```swift let result = try await Adapty.makePurchase(product: paywallProduct) let jwsRepresentation = result.jwsTransaction ``` ## トランザクション完了の動作を制御する \{#control-transaction-finishing-behavior\} デフォルトでは、AdaptyはバリデーションAfterにStoreKitトランザクションを自動的に完了します。 バックエンドが成功を確認するまで完了を遅らせたい場合は、完了動作を手動に設定してください。 このモードでは: - Adaptyは引き続き購入を検証し、バックエンドとSyncします。 - `finish()`を明示的に呼び出すまで、トランザクションは未完了のままです。 ```swift var configBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_API_KEY") .with(transactionFinishBehavior: .manual) try await Adapty.activate(with: configBuilder.build()) ``` 手動トランザクション完了を使用する場合、未完了のトランザクションを処理するために`onUnfinishedTransaction`デリゲートメソッドを実装する必要があります。 ```swift showLineNumbers title="Swift" extension YourApp: AdaptyDelegate { func onUnfinishedTransaction(_ transaction: AdaptyUnfinishedTransaction) async { // Perform your custom validation logic here // When ready, finish the transaction await transaction.finish() } } ``` 現在の未完了トランザクションをすべて取得するには、`getUnfinishedTransactions()`メソッドを使用してください。 ```swift let unfinishedTransactions = try await Adapty.getUnfinishedTransactions() ``` --- # File: implement-observer-mode --- --- title: "iOS SDK でオブザーバーモードを実装する" description: "iOS SDK で Adapty のオブザーバーモードを実装し、ユーザーのサブスクリプションイベントを追跡する方法を説明します。" --- 独自の購入インフラを持っており、まだ Adapty への完全な移行を検討していない場合は、[オブザーバーモード](observer-vs-full-mode)を活用できます。基本的な使い方では、オブザーバーモードによって高度なアナリティクスや、アトリビューション・分析システムとのシームレスな連携が可能になります。 これで十分な場合は、以下の 2 つだけ対応すれば OK です: 1. Adapty SDK を設定する際に `observerMode` パラメータを `true` にしてオブザーバーモードを有効化する。 2. 既存の購入インフラから Adapty へ[トランザクションを報告する](report-transactions-observer-mode)。 ペイウォールや A/B テストも利用したい場合は、以下に説明する追加のセットアップが必要です。 ## オブザーバーモードのセットアップ \{#observer-mode-setup\} 購入やサブスクリプションのステータス管理を自分で行い、サブスクリプションイベントの送信やアナリティクスのために Adapty を使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作している場合、Adapty SDK はトランザクションをクローズしません。そのため、トランザクションの処理はご自身で行ってください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers @main struct YourApp: App { init() { // Configure Adapty SDK let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(observerMode: true) let config = configurationBuilder.build() // Activate Adapty SDK asynchronously Task { do { try await Adapty.activate(with: configurationBuilder) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } var body: some Scene { WindowGroup { // Your content view } } } } ``` </TabItem> <TabItem value="swift" label="UIKit" default> ```swift showLineNumbers Task { do { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "YOUR_PUBLIC_SDK_KEY") // Get from Adapty dashboard .with(observerMode: true) let config = configurationBuilder.build() try await Adapty.activate(with: config) } catch { // Handle error appropriately for your app print("Adapty activation failed: ", error) } } ``` </TabItem> </Tabs> パラメータ: | パラメータ | 説明 | | --------------------------- | ------------------------------------------------------------ | | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御する真偽値です。デフォルト値は `false` です。 | ## オブザーバーモードで Adapty のペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adapty のペイウォールや A/B テスト機能も使用したい場合は可能ですが、オブザーバーモードでは追加のセットアップが必要です。上記の手順に加えて、以下を行ってください: 1. [リモートコンフィグペイウォール](present-remote-config-paywalls)は通常どおり表示する。ペイウォールビルダーのペイウォールについては、[iOS](ios-present-paywall-builder-paywalls-in-observer-mode) 向けの専用セットアップガイドに従う。 3. 購入トランザクションに[ペイウォールを紐付ける](report-transactions-observer-mode)。 --- # File: report-transactions-observer-mode --- --- title: "iOS SDKのObserverモードでトランザクションをレポートする" description: "iOS SDKのAdapty Observerモードで購入トランザクションをレポートし、ユーザーインサイトと収益追跡を行います。" --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+(現行版)" default> Observerモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡できません。アプリストアからトランザクションを手動でレポートする必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を行うことが重要です。 `reportTransaction`を使用して、Adaptyが認識できるよう各トランザクションを明示的にレポートしてください。 :::warning **トランザクションのレポートをスキップしないでください!** `reportTransaction`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションをレポートする際に`variationId`を含めてください。これにより、購入がトリガーとなったペイウォールとリンクされ、正確なペイウォールアナリティクスが確保されます。 ```swift showLineNumbers do { // every time when calling transasction.finish() try await Adapty.reportTransaction(transaction, withVariationId: <YOUR_PAYWALL_VARIATION_ID>) } catch { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- | ------------------------------------------------------------ | | **transaction** | 必須 | <ul><li> StoreKit 1の場合:SKPaymentTransaction。</li><li> StoreKit 2の場合:Transaction。</li></ul> | | **variationId** | 任意 | ペイウォールバリアントの一意のID。[AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall)オブジェクトの`variationId`プロパティから取得できます。 | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x(旧バージョン)" default> Observerモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡できません。アプリストアからトランザクションをレポートするか、リストアする必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を行うことが重要です。 `reportTransaction`を使用して、トランザクションデータをAdaptyに送信してください。 :::warning **トランザクションのレポートをスキップしないでください!** `reportTransaction`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションをレポートする際に`withVariationId`を含めてください。これにより、購入がトリガーとなったペイウォールとリンクされ、正確なペイウォールアナリティクスが確保されます。 ```swift showLineNumbers do { // every time when calling transasction.finish() try await Adapty.reportTransaction(transaction, withVariationId: <YOUR_PAYWALL_VARIATION_ID>) } catch { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- | ------------------------------------------------------------ | | **transaction** | 必須 | <ul><li> StoreKit 1の場合:SKPaymentTransaction。</li><li> StoreKit 2の場合:Transaction。</li></ul> | | **variationId** | 任意 | ペイウォールバリアントの一意のID。[AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall)オブジェクトの`variationId`プロパティから取得できます。 | </TabItem> <TabItem value="old2" label="Adapty SDK 3.2.x以前(旧バージョン)" default> **トランザクションのレポート** - 3.1.x以前のバージョンはApp Storeのトランザクションを自動的に監視するため、手動でのレポートは不要です。 - バージョン3.2はObserverモードをサポートしていません。 **トランザクションとペイウォールの関連付け** Adapty SDKは購入のソースを判断できません。購入の処理はお客様側で行うためです。そのため、Observerモードでペイウォールやおよび/またはA/Bテストを使用する場合は、アプリストアから受け取ったトランザクションをモバイルアプリのコード内で対応するペイウォールに関連付ける必要があります。アプリをリリースする前にこの設定を正しく行うことが重要です。そうしないと、アナリティクスにエラーが発生します。 ```swift let variationId = paywall.variationId // There are two overloads: for StoreKit 1 and StoreKit 2 Adapty.setVariationId(variationId, forPurchasedTransaction: transactionId) { error in if error == nil { // successful binding } } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | variationId | 必須 | バリアントの文字列識別子。[AdaptyPaywall](https://swift.adapty.io/documentation/adapty/adaptypaywall)オブジェクトの`variationId`プロパティを使用して取得できます。 | | transactionId | 必須 | <p>StoreKit 1の場合:[SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction)オブジェクト。</p><p>StoreKit 2の場合:[Transaction](https://developer.apple.com/documentation/storekit/transaction)オブジェクト。</p> | </TabItem> </Tabs> --- # File: ios-troubleshoot-purchases --- --- title: "iOSのSDKにおける購入のトラブルシューティング" description: "iOSのSDKにおける購入のトラブルシューティング" --- このガイドでは、iOS SDKで手動購入を実装する際によく発生する問題の解決方法を説明します。 ## オブザーバーモードでのAdaptyError.cantMakePayments \{#adaptyer-ror-cant-make-payments-in-observer-mode\} **問題**: オブザーバーモードで`makePurchase`を使用すると、`AdaptyError.cantMakePayments`が発生する。 **原因**: オブザーバーモードでは、Adaptyの`makePurchase`メソッドではなく、自分側で購入を処理する必要があります。 **解決策**: 購入に`makePurchase`を使用している場合は、オブザーバーモードをオフにしてください。`makePurchase`を使用するか、オブザーバーモードで自分側で購入を処理するか、どちらか一方を選択する必要があります。詳細は[オブザーバーモードの実装](implement-observer-mode)を参照してください。 ## makePurchasesCompletionHandlersが見つからない \{#not-found-makepurchasescompletionhandlers\} **問題**: `makePurchasesCompletionHandlers`が見つからないというエラーが発生している。 **原因**: これは通常、サンドボックステストに関連する問題です。 **解決策**: 新しいサンドボックスユーザーを作成して再試行してください。これにより、サンドボックス関連の購入完了ハンドラーの問題が解決されることがよくあります。 ## その他の問題 \{#other-issues\} **問題**: 上記で取り上げていない購入関連のその他の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](ios-sdk-migration-guides)を使用してSDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: ios-web-paywall --- --- title: "iOS SDKでウェブペイウォールを実装する" description: "App Storeの手数料や審査なしで決済を受け付けるウェブペイウォールを設定します。" --- :::important 始める前に、[ダッシュボードでウェブペイウォールを設定](web-paywall)済みであること、および Adapty SDK バージョン 3.6.1 以降がインストールされていることを確認してください。 ::: ## ウェブペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールを利用している場合は、SDK メソッドを使ってウェブペイウォールを処理する必要があります。`.openWebPaywall` メソッドは次の処理を行います。 1. 特定のユーザーに表示されたペイウォールとリダイレクト先のウェブページを Adapty が紐付けるための一意の URL を生成します。 2. ユーザーがアプリに戻ったタイミングを検知し、短い間隔で `.getProfile` を呼び出して、プロファイルのアクセス権が更新されたかどうかを確認します。 これにより、決済が成功してアクセス権が更新された場合、アプリ内でほぼ即座にサブスクリプションが有効化されます。 ```swift showLineNumbers title="Swift" do { try await Adapty.openWebPaywall(for: product) } catch { print("Failed to open web paywall: \(error)") } ``` :::note `openWebPaywall` メソッドには2つのバージョンがあります。 1. `openWebPaywall(product)` はペイウォールごとに URL を生成し、プロダクトのデータも URL に追加します。 2. `openWebPaywall(paywall)` はペイウォールごとに URL を生成しますが、プロダクトのデータは URL に追加しません。Adapty のペイウォールに設定されたプロダクトとウェブペイウォールのプロダクトが異なる場合に使用してください。 ::: ## エラーを処理する \{#handle-errors\} | エラー | 説明 | 推奨される対処法 | |-----------------------------------------|------------------------------------------------------|---------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | ペイウォールにウェブ購入 URL が設定されていない | Adapty ダッシュボードでペイウォールが正しく設定されているか確認してください | | AdaptyError.productWithoutPurchaseUrl | プロダクトにウェブ購入 URL が設定されていない | Adapty ダッシュボードでプロダクトの設定を確認してください | | AdaptyError.failedOpeningWebPaywallUrl | ブラウザで URL を開くことができなかった | デバイスの設定を確認するか、別の購入方法を提供してください | | AdaptyError.failedDecodingWebPaywallUrl | URL 内のパラメーターを正しくエンコードできなかった | URL パラメーターが有効かつ適切にフォーマットされているか確認してください | ## 実装例 \{#implementation-example\} ```swift showLineNumbers title="Swift" class SubscriptionViewController: UIViewController { var paywall: AdaptyPaywall? @IBAction func purchaseButtonTapped(_ sender: UIButton) { guard let paywall = paywall, let product = paywall.products.first else { return } Task { await offerWebPurchase(for: product) } } func offerWebPurchase(for paywallProduct: AdaptyPaywallProduct) async { do { // Attempt to open web paywall try await Adapty.openWebPaywall(for: paywallProduct) } catch let error as AdaptyError { switch error { case .paywallWithoutPurchaseUrl, .productWithoutPurchaseUrl: showAlert(message: "Web purchase is not available for this product.") case .failedOpeningWebPaywallUrl: showAlert(message: "Could not open web browser. Please try again.") default: showAlert(message: "An error occurred: \(error.localizedDescription)") } } catch { showAlert(message: "An unexpected error occurred.") } } // Helper methods private func showAlert(message: String) { /* ... */ } } ``` :::note ユーザーがアプリに戻った後は、プロファイルの更新を反映するために UI をリフレッシュしてください。`AdaptyDelegate` がプロファイル更新イベントを受信して処理します。 ::: ## アプリ内ブラウザでウェブペイウォールを開く \{#open-web-paywalls-in-an-in-app-browser\} :::important アプリ内ブラウザでのウェブペイウォール表示は、Adapty SDK v3.15 以降でサポートされています。 ::: デフォルトでは、ウェブペイウォールは外部ブラウザで開きます。 シームレスなユーザー体験を提供するために、アプリ内ブラウザでウェブペイウォールを開くことができます。これにより、アプリを切り替えることなく、アプリ内でウェブ購入ページを表示してトランザクションを完了できます。 この機能を有効にするには、`in` パラメーターを `.inAppBrowser` に設定します。 ```swift showLineNumbers title="Swift" do { try await Adapty.openWebPaywall(for: product, in: .inAppBrowser) // default – .externalBrowser } catch { print("Failed to open web paywall: \(error)") } ``` --- # File: identifying-users --- --- title: "iOS SDKでユーザーを識別する" description: "Adaptyでユーザーを識別し、パーソナライズされたサブスクリプション体験を向上させましょう。" --- Adaptyはすべてのユーザーに対して内部プロファイルIDを作成します。ただし、独自の認証システムがある場合は、独自のCustomer User IDを設定してください。[Profiles](profiles-crm)セクションでCustomer User IDによるユーザー検索が可能で、[サーバーサイドAPI](getting-started-with-server-side-api)でも使用できます。このIDはすべてのインテグレーションに送信されます。 ## 設定時にCustomer User IDを設定する \{#set-customer-user-id-on-configuration\} 設定時にユーザーIDが利用可能な場合は、`.activate()`メソッドの`customerUserId`パラメーターとして渡してください: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID") Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` </TabItem> </Tabs> :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## 設定後にCustomer User IDを設定する \{#set-customer-user-id-after-configuration\} SDKの設定時にユーザーIDがない場合は、`.identify()`メソッドを使っていつでも後から設定できます。最も一般的なユースケースは、登録や認証の後、ユーザーが匿名ユーザーから認証済みユーザーに切り替わるタイミングです。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.identify("YOUR_USER_ID") } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.identify("YOUR_USER_ID") { error in if let error { // handle the error } } ``` </TabItem> </Tabs> リクエストパラメーター: - **Customer User ID**(必須): 文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信 ユーザーが再度ログインするなど、Adaptyのサーバーにすでにそのユーザーの情報が存在する場合があります。このような場合、Adapty SDKは自動的に新しいユーザーへ切り替えます。匿名ユーザーにカスタム属性やサードパーティネットワークからのアトリビューションなどのデータを渡していた場合は、識別済みユーザーに対してそのデータを再送信してください。 また、新しいユーザーのデータが異なる可能性があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得することが重要です。 ::: ## ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()`メソッドを呼び出すことで、いつでもユーザーをログアウトできます: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { try await Adapty.logout() } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.logout { error in if error == nil { // successful logout } } ``` </TabItem> </Tabs> その後、`.identify()`メソッドを使ってユーザーをログインできます。 ## appAccountTokenを設定する \{#set-appaccounttoken\} [`appAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:))は、AppleのStoreKit 2がアプリのインストールやデバイスをまたいでユーザーを識別するためのUUIDです。 Adapty iOS SDK 3.10.2以降、SDKの設定時またはユーザーの識別時に`appAccountToken`を渡せるようになりました: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) do { try await Adapty.activate(with: configurationBuilder.build()) } catch { // handle the error } // Or when identifying a user: do { try await Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers // During configuration: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(customerUserId: "YOUR_USER_ID", withAppAccountToken: UUID()) Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } // Or when identifying a user: Adapty.identify("YOUR_USER_ID", withAppAccountToken: UUID()) { error in if let error { // handle the error } } ``` </TabItem> </Tabs> その後、`.identify()`メソッドを使ってユーザーをログインできます。 ## デバイスをまたいでユーザーを検出する \{#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: setting-user-attributes --- --- title: "iOS SDKでユーザー属性を設定する" description: "Adaptyでユーザー属性を設定し、より効果的なオーディエンスのセグメンテーションを実現する方法を学びましょう。" --- アプリのユーザーに対して、メールアドレスや電話番号などの任意の属性を設定できます。設定した属性は、ユーザーの[セグメント](segments)の作成や、CRMでの確認に利用できます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") .with(phoneNumber: "+18888888888") .with(firstName: "John") .with(lastName: "Appleseed") .with(gender: .other) .with(birthday: Date()) do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(email: "email@email.com") .with(phoneNumber: "+18888888888") .with(firstName: "John") .with(lastName: "Appleseed") .with(gender: .other) .with(birthday: Date()) Adapty.updateProfile(params: builder.build()) { error in if error != nil { // handle the error } } ``` </TabItem> </Tabs> `updateProfile` メソッドで以前に設定した属性はリセットされません。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 使用できるキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters.Builder` で使用できるキー `<Key>` と値 `<Value>` の一覧は以下のとおりです。 | キー | 値 | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | 列挙型。使用できる値: `female`、`male`、`other` | | birthday | Date | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定できます。カスタム属性は通常、アプリの使用状況に関連したものです。たとえば、フィットネスアプリなら週あたりの運動回数、語学学習アプリならユーザーの習熟度などが考えられます。カスタム属性をセグメントで活用して、ターゲットを絞ったペイウォールやオファーを作成したり、どのプロダクト指標が収益に最も影響するかをアナリティクスで分析したりできます。 ```swift showLineNumbers do { builder = try builder.with(customAttribute: "value1", forKey: "key1") } catch { // handle key/value validation error } ``` 既存のキーを削除するには、`.withRemoved(customAttributeForKey:)` メソッドを使用します。 ```swift showLineNumbers do { builder = try builder.withRemoved(customAttributeForKey: "key2") } catch { // handle error } ``` 事前にどのカスタム属性が設定されているかを確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning `customAttributes` の値は最新でない場合があります。ユーザー属性は異なるデバイスからいつでも送信される可能性があるため、最後の同期後にサーバー上の属性が変更されている場合があります。 ::: ### 制限事項 \{#limits\} - ユーザーあたりのカスタム属性は最大30個まで - キー名は最大30文字。キー名に使用できる文字は英数字と以下の記号です: `_` `-` `.` - 値は文字列または浮動小数点数で、50文字以内 --- # File: subscription-status --- --- title: "iOS SDK でサブスクリプションのステータスを確認する" description: "Adapty でユーザーのサブスクリプションステータスを追跡・管理して、顧客維持率を向上させましょう。" --- Adapty を使えば、サブスクリプションのステータス管理が簡単になります。プロダクト ID をコードに手動で埋め込む必要はなく、アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプションステータスをスムーズに把握できます。 サブスクリプションのステータス確認を始める前に、[App Store サーバー通知](enable-app-store-server-notifications)を設定してください。 ## アクセスレベルと AdaptyProfile オブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは [AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクトのプロパティです。アプリ起動時([ユーザーを識別する](identifying-users#set-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更が発生したときに更新することをおすすめします。こうすることで、都度リクエストを送ることなくプロファイルオブジェクトを活用できます。 プロファイルの更新通知を受け取るには、以下の[サブスクリプションステータスの更新をリッスンする](subscription-status#listening-for-subscription-status-updates)セクションで説明している方法でプロファイルの変更を監視してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()` メソッドを使用します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() if profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get() { // check the access profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive ?? false { // grant access to premium features } } } ``` </TabItem> </Tabs> レスポンスパラメーター: | パラメーター | 説明 | | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Profile | <p>[AdaptyProfile](https://swift.adapty.io/documentation/adapty/adaptyprofile) オブジェクト。通常、ユーザーがプレミアムアクセスを持っているかどうかを判断するには、プロファイルのアクセスレベルのステータスだけを確認すれば十分です。</p><p></p><p>`.getProfile` メソッドは常に API へのクエリを試みるため、最新の結果を返します。何らかの理由(インターネット接続がないなど)で Adapty SDK がサーバーから情報を取得できない場合は、キャッシュのデータが返されます。また、Adapty SDK は `AdaptyProfile` キャッシュを定期的に更新し、情報をできる限り最新の状態に保ちます。</p> | `.getProfile()` メソッドはユーザープロファイルを返し、そこからアクセスレベルのステータスを取得できます。アプリごとに複数のアクセスレベルを設定することも可能です。たとえばニュースアプリで複数のトピックのサブスクリプションを独立して販売する場合、「sports」や「science」といったアクセスレベルを作成できます。ただし、ほとんどの場合はアクセスレベルは 1 つで十分なので、デフォルトの「premium」アクセスレベルをそのまま使用できます。 デフォルトの「premium」アクセスレベルを確認する例を示します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let profile = try await Adapty.getProfile() let isPremium = profile.accessLevels["premium"]?.isActive ?? false // grant access to premium features } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers Adapty.getProfile { result in if let profile = try? result.get(), profile.accessLevels["premium"]?.isActive ?? false { // grant access to premium features } } ``` </TabItem> </Tabs> ### サブスクリプションステータスの更新をリッスンする \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adapty はイベントを発火します。 Adapty からのメッセージを受け取るには、追加の設定が必要です。 ```swift showLineNumbers Adapty.delegate = self // To receive subscription updates, extend `AdaptyDelegate` with this method: nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { // handle any changes to subscription state } ``` Adapty はアプリ起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDK に実装されたキャッシュはプロファイルのサブスクリプションステータスを保持します。これにより、サーバーが利用できない場合でも、キャッシュされたデータからプロファイルのサブスクリプションステータス情報を取得できます。 ただし、キャッシュから直接データをリクエストすることはできません。SDK は 1 分ごとにサーバーに問い合わせて、プロファイルに関する更新や変更を確認します。新しいトランザクションなどの変更があった場合は、サーバーとの同期を維持するためにキャッシュデータへ反映されます。 --- # File: ios-deal-with-att --- --- title: "iOSのATTについて" description: "iOSでAdaptyを使い始めて、サブスクリプションの設定と管理を効率化しましょう。" --- アプリでAppTrackingTransparencyフレームワークを使用しており、ユーザーにアプリトラッキングの許可リクエストを表示している場合は、[認証ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/)をAdaptyに送信する必要があります。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="Swift-Callback" default> ```swift showLineNumbers if #available(iOS 14, macOS 11.0, *) { let builder = AdaptyProfileParameters.Builder() .with(appTrackingTransparencyStatus: .authorized) Adapty.updateProfile(params: builder.build()) { [weak self] error in if error != nil { // handle the error } } } ``` </TabItem> </Tabs> :::warning この値は変更されたタイミングでできるだけ早く送信することを強くお勧めします。そうすることで、設定済みのインテグレーションにデータがタイムリーに送信されます。 ::: --- # File: kids-mode --- --- title: "iOS SDKのキッズモード" description: "Apple のポリシーに準拠するためのキッズモードを簡単に有効化できます。iOS SDKではIDFAや広告データは収集されません。" --- <SDKv4> iOS アプリが子ども向けの場合、[Apple](https://developer.apple.com/kids/) のポリシーに従う必要があります。Adapty SDK を使用している場合、いくつかの簡単な手順でポリシーに準拠した設定を行い、App Store の審査を通過できます。 ## 必要な設定内容 \{#whats-required\} Adapty SDK で以下の収集を無効にする設定が必要です。 - [IDFA(広告識別子)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) - [IPアドレス](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) また、カスタマーユーザー ID の使い方にも注意が必要です。`<FirstName.LastName>` 形式のユーザー 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\} SDK 4.0 以降、Kids Mode は `KidsMode` という名前の Swift パッケージトレイトになりました。このトレイトを有効にすると、SDK 全体で IDFA と AdSupport がコンパイルから除外されます。通常の **Adapty** および **AdaptyUI** モジュールと、通常の `import Adapty` / `import AdaptyUI` ステートメントはそのまま使用できます。 :::note `KidsMode` トレイトは SDK バージョン 4.0 以降で使用できます。SDK 4.0 以降、SDK は Swift Package Manager 経由でのみインストールされます。CocoaPods はサポートされなくなりました。 ::: <Tabs> <TabItem value="xcode" label="Xcode" default> 1. [Adapty SDKをインストールします](sdk-installation-ios)。通常通り、**Adapty** と **AdaptyUI** モジュールを選択してください。 2. Xcode 26.4以降では、プロジェクト設定を開き、**Package Dependencies** ビューに移動して、AdaptySDK-iOS の依存関係に対して **KidsMode** トレイトを有効にします。 :::note Xcode 26.4より前のバージョンでは、XcodeプロジェクトのUIからトレイトを有効にすることができません。その場合は、`KidsMode`トレイトを有効にしてAdaptyに依存するローカルSwiftパッケージを小さく作成し(**Package.swift**タブを参照)、アプリターゲットがそのパッケージに依存するようにしてください。 ::: </TabItem> <TabItem value="spm" label="Package.swift"> `Package.swift`でAdaptyを依存関係として追加する場合は、パッケージ宣言内でトレイトを有効にしてください。トレイトを使用するには`swift-tools-version` 6.1以降が必要です。 ```swift showLineNumbers title="Package.swift" .package( url: "https://github.com/adaptyteam/AdaptySDK-iOS.git", from: "4.0.0", traits: ["KidsMode"] ) ``` </TabItem> </Tabs> </SDKv4> <SDKv3> iOS アプリが子ども向けの場合、[Apple](https://developer.apple.com/kids/) のポリシーに従う必要があります。Adapty SDK を使用している場合、いくつかの簡単な手順でポリシーに準拠した設定を行い、アプリストアの審査を通過できます。 ## 必要な設定 \{#whats-required\} Adapty SDK で以下の収集を無効化するよう設定する必要があります: - [IDFA(広告識別子)](https://en.wikipedia.org/wiki/Identifier_for_Advertisers) - [IPアドレス](https://www.ftc.gov/system/files/ftc_gov/pdf/p235402_coppa_application.pdf) さらに、カスタムユーザー ID の使い方には注意が必要です。`<FirstName.LastName>` 形式のユーザー ID は、メールアドレスと同様に個人情報の収集とみなされる可能性があります。キッズモードでは、ランダム化または匿名化された識別子(ハッシュ化された ID やデバイス生成の UUID など)を使用して、コンプライアンスを確保することがベストプラクティスです。 ## キッズモードを有効にする \{#enabling-kids-mode\} ### Adapty ダッシュボードでの設定変更 \{#updates-in-the-adapty-dashboard\} Adapty ダッシュボードでは、IPアドレスの収集を無効にする必要があります。[App settings](https://app.adapty.io/settings/general) に移動し、**Collect users' IP address** の下にある **Disable IP address collection** をクリックしてください。 ### モバイルアプリのコードを更新する \{#updates-in-your-mobile-app-code\} ポリシーに準拠するため、ユーザーのIDFAおよびIPアドレスの収集を無効にしてください。 <Tabs> <TabItem value="spm" label="Swift Package Manager" default> Swift Package Managerを使用している場合、SDKのインストール時にXcodeで **Adapty_KidsMode** モジュールを選択することでキッズモードを有効にできます。 Xcodeで **File** -> **Add Package Dependency...** に進んでください。なお、パッケージ依存関係の追加手順はXcodeのバージョンによって異なる場合があるため、必要に応じてXcodeのドキュメントを参照してください。 1. リポジトリURLを入力します: ``` https://github.com/adaptyteam/AdaptySDK-iOS.git ``` 2. バージョンを選択し(最新の安定版を推奨)、**Add Package** をクリックします。 3. **Choose Package Products** ウィンドウで、必要なモジュールを選択します: - **Adapty_KidsMode**(コアモジュール) - **AdaptyUI_KidsMode**(オプション - ペイウォールビルダーを使用する場合のみ) 他のパッケージは不要です。 4. **Add Package** をクリックしてインストールを完了します。 5. コードの中で、`import Adapty` の代わりに `import Adapty_KidsMode`、`import AdaptyUI` の代わりに `import AdaptyUI_KidsMode` と記述してください: ```swift ``` </TabItem> <TabItem value="cocoapods" label="CocoaPods"> 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 ``` </TabItem> </Tabs> </SDKv3> --- # File: get-onboardings --- --- title: "オンボーディングとその設定を取得する" description: "Adapty でオンボーディングを取得する方法を説明します。" --- :::tip **SDK v4 以降**では、オンボーディングのより強力な代替手段として[フロー](get-pb-paywalls)を構築できます。オンボーディングが WebView 内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫した iOS のルック&フィール、高速な読み込み、WebView ランタイムへの依存がなくなります。詳しくは[フローとペイウォールの取得](get-pb-paywalls)および[フローとペイウォールの表示](ios-present-paywalls)をご覧ください。 ::: Adapty ダッシュボードのビルダーで[オンボーディングのビジュアル部分をデザイン](design-onboarding)したら、モバイルアプリに表示できます。このプロセスの最初のステップは、プレースメントに関連付けられたオンボーディングとそのビュー設定を取得することです。詳細は以下をご覧ください。 始める前に、以下を確認してください。 1. [Adapty iOS、Android、React Native、または Flutter SDK](installation-of-adapty-sdks) バージョン 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## オンボーディングの取得 \{#fetch-onboarding\} [オンボーディング](onboardings)をノーコードビルダーで作成すると、アプリが取得・表示する必要のあるコンテナとして保存されます。このコンテナは、表示するコンテンツ、表示方法、ユーザーの操作(クイズの回答やフォームの入力など)の処理方法といった、すべての体験を管理します。また、コンテナは分析イベントを自動的に追跡するため、別途ビュートラッキングを実装する必要はありません。 パフォーマンスを最大限に発揮するため、ユーザーに表示する前に画像が十分にダウンロードされるよう、早めにオンボーディングの設定を取得してください。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```swift showLineNumbers do { let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // the requested onboarding } catch { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライズ識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成された言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードおよび推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。このオプションを推奨します。ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合はキャッシュデータを返すことを検討してください。この場合、最新データが取得できないことがありますが、接続状況に関わらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、ネットワークリクエストを減らす目的でセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層構造で保存します。上述の定期更新キャッシュとフォールバックオンボーディングです。また、オンボーディングをより高速に取得するためにCDNを使用し、CDNが利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>内部的に複数のリクエストで構成される場合があるため、稀にこのメソッドが `loadTimeout` で指定した時間をわずかに超えてタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | [`AdaptyOnboarding`](https://swift.adapty.io/documentation/adapty/adaptyonboarding) オブジェクト。オンボーディングの識別子と設定、リモートコンフィグ、その他のプロパティを含みます。 | ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ瞬時にフェッチされるため、このプロセスの高速化を心配する必要はありません。ただし、オーディエンスやオンボーディングが多数存在し、ユーザーのインターネット接続が弱い場合、オンボーディングのフェッチに予想以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないのではなく、デフォルトのオンボーディングを表示することで、スムーズなユーザー体験を確保したい場合があるでしょう。 `getOnboardingForDefaultAudience` メソッドを使用することで、指定したプレースメントの **All Users** オーディエンス向けオンボーディングを取得できます。ただし、推奨されるアプローチは `getOnboarding` メソッドでオンボーディングを取得することであり、詳細は上記の[オンボーディングの取得](#fetch-onboarding)セクションをご覧ください。 :::warning `getOnboardingForDefaultAudience` の代わりに `getOnboarding` の使用を検討してください。前者には以下の重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のある設計が必要になるか、古いバージョンが正しく表示されない可能性を受け入れる必要があります。 - **パーソナライズなし**: 「すべてのユーザー」オーディエンスのコンテンツのみを表示するため、国、アトリビューション、カスタム属性に基づいたターゲティングができません。 取得の高速化がこれらのデメリットを上回るユースケースの場合は、以下に示すように `getOnboardingForDefaultAudience` を使用してください。それ以外の場合は、[上記](#fetch-onboarding)で説明している `getOnboarding` を使用してください。 ::: ```swift showLineNumbers Adapty.getOnboardingForDefaultAudience(placementId: "YOUR_PLACEMENT_ID") { result in switch result { case let .success(onboarding): // the requested onboarding case let .failure(error): // handle the error } } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライズの識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードである必要があります。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードとその推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるよう、このオプションを推奨します。</p><p></p><p>ただし、ユーザーがインターネット接続の不安定な環境を使用していると思われる場合は、`.returnCacheDataElseLoad` の使用を検討してください。これにより、キャッシュが存在する場合はキャッシュされたデータを返します。この場合、ユーザーは最新のデータを取得できないことがありますが、インターネット接続の品質に関わらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、ネットワークリクエストを避けるためにセッション中に使用しても安全です。</p><p></p><p>なお、キャッシュはアプリの再起動後も保持され、アプリのアンインストール時または手動でクリーンアップした場合にのみ消去されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層構造で保存します。上記の定期更新されるキャッシュと、フォールバックオンボーディングです。また、オンボーディングをより速く取得するためにCDNを使用し、CDNに到達できない場合に備えてスタンドアロンのフォールバックサーバーも使用しています。このシステムは、インターネット接続が不安定な場合でも信頼性を確保しながら、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | --- # File: ios-present-onboardings --- --- title: "iOS SDKでオンボーディングを表示する" description: "iOSでオンボーディングを表示してコンバージョンと収益を向上させる方法をご紹介します。" --- :::tip **SDK v4以降**では、オンボーディングのより強力な代替手段として[フロー](get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされます。これにより、よりスムーズなアニメーション、一貫したiOSのルック&フィール、高速な読み込み、WebViewランタイムへの依存がなくなるといったメリットが得られます。始めるには、[フローとペイウォールの取得](get-pb-paywalls)および[フローとペイウォールの表示](ios-present-paywalls)をご覧ください。 ::: ビルダーでオンボーディングをカスタマイズした場合、モバイルアプリのコードでレンダリングを意識する必要はありません。このようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [Adapty iOS SDK](sdk-installation-ios) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## Swiftでのオンボーディングの表示 \{#present-onboardings-in-swift\} デバイス画面にビジュアルオンボーディングを表示するには、以下の手順に従ってください。 1. `.getOnboardingConfiguration` メソッドを使用して、オンボーディングのビュー設定を取得します。 2. `.onboardingController` メソッドを使用して、表示したいビジュアルオンボーディングを初期化します。 リクエストパラメーター: | パラメータ | 必須/任意 | 説明 | |:-----------------------------|:---------|:------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onboarding configuration** | 必須 | すべてのオンボーディングプロパティを含む `AdaptyUI.OnboardingConfiguration` オブジェクト。`AdaptyUI.getOnboardingConfiguration` メソッドを使用して取得します。 | | **delegate** | 必須 | オンボーディングイベントを受け取るための `AdaptyOnboardingControllerDelegate`。 | 戻り値: | オブジェクト | 説明 | |:-------------------------------|:--------------------------------------------------------| | **AdaptyOnboardingController** | リクエストされたオンボーディング画面を表すオブジェクト | 3. オブジェクトが正常に作成されたら、デバイスの画面に表示できます: ```swift showLineNumbers title="Swift" import Adapty import AdaptyUI // 0. Get an onboarding if you haven't done it yet let onboarding = try await Adapty.getOnboarding(placementId: "YOUR_PLACEMENT_ID") // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Create Onboarding View Controller let onboardingController = try AdaptyUI.onboardingController( with: configuration, delegate: <AdaptyOnboardingControllerDelegate> ) // 3. Present it to the user present(onboardingController, animated: true) ``` ## SwiftUIでオンボーディングを表示する \{#present-onboardings-in-swiftui\} SwiftUIでデバイス画面にビジュアルオンボーディングを表示するには: ```swift showLineNumbers title="SwiftUI" // 1. Obtain the onboarding view configuration: let configuration = try AdaptyUI.getOnboardingConfiguration(forOnboarding: onboarding) // 2. Display the Onboarding View within your view hierarchy AdaptyOnboardingView( configuration: configuration, placeholder: { Text("Your Placeholder View") }, onCloseAction: { action in // hide the onboarding view }, onError: { error in // handle the error } ) ``` ## スプラッシュ画面とオンボーディング間のスムーズなトランジションを追加する \{#add-smooth-transitions-between-the-splash-screen-and-onboarding\} デフォルトでは、スプラッシュ画面とオンボーディングの間に、オンボーディングが完全に読み込まれるまでローディング画面が表示されます。ただし、トランジションをよりスムーズにしたい場合は、スプラッシュ画面を延長したり、別のコンテンツを表示したりするようにカスタマイズできます。 そのためには、プレースホルダー(オンボーディングの読み込み中に表示されるもの)を定義します。プレースホルダーを定義すると、オンボーディングはバックグラウンドで読み込まれ、準備ができ次第自動的に表示されます。 <Tabs> <TabItem value="swift" label="UIKit"> ```swift showLineNumbers extension YourOnboardingManagerClass: AdaptyOnboardingControllerDelegate { func onboardingsControllerLoadingPlaceholder( _ controller: AdaptyOnboardingController ) -> UIView? { // instantiate and return the UIView which will be presented while onboarding is being loaded } } ``` </TabItem> <TabItem value="swiftui" label="SwiftUI"> ```swift showLineNumbers AdaptyOnboardingView( configuration: configuration, placeholder: { // define your placeholder view, which will be presented while onboarding is being loaded }, // the rest of the implementation ) ``` </TabItem> </Tabs> ## オンボーディングでのリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディングでのリンクの開き方のカスタマイズは、Adapty SDK v3.15.1 以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、アプリを切り替えることなくウェブページを表示できるため、シームレスなユーザー体験が提供されます。 外部ブラウザでリンクを開くようにしたい場合は、`externalUrlsPresentation` パラメータを `.externalBrowser` に設定することでこの動作をカスタマイズできます: ```swift showLineNumbers let configuration = try AdaptyUI.getOnboardingConfiguration( forOnboarding: onboarding, externalUrlsPresentation: .externalBrowser // default – .inAppBrowser ) ``` --- # File: ios-handling-onboarding-events --- --- title: "iOS SDKでオンボーディングイベントを処理する" description: "AdaptyでiOSのオンボーディング関連イベントを処理します。" --- :::tip **SDK v4 以降**、オンボーディングのより強力な代替手段として[フロー](get-pb-paywalls)を構築できます。オンボーディングは WebView 内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫した iOS のルック&フィール、高速な読み込み、WebView ランタイムへの依存がなくなります。はじめるには、[フロー&ペイウォールの取得](get-pb-paywalls)と[フロー&ペイウォールの表示](ios-present-paywalls)をご覧ください。 ::: 始める前に、以下を確認してください: 1. [Adapty iOS SDK](sdk-installation-ios) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ビルダーで設定したオンボーディングは、アプリが応答できるイベントを生成します。これらのイベントへの応答方法については、以下をご覧ください。 モバイルアプリ内のオンボーディング画面で発生するプロセスを制御・監視するには、`AdaptyOnboardingControllerDelegate` のメソッドを実装してください。 ## カスタムアクション \{#custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加し、IDを割り当てることができます。 <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> その後、このIDをコードで使用してカスタムアクションとして処理できます。たとえば、ユーザーが**Login**や**Allow notifications**などのカスタムボタンをタップすると、デリゲートメソッド`onboardingController`が`.custom(id:)`ケースでトリガーされ、`actionId`パラメータはビルダーの**Action ID**になります。`"allowNotifications"`のように独自のIDを作成できます。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onCustomAction action: AdaptyOnboardingsCustomAction) { if action.actionId == "allowNotifications" { // Request notification permissions } } func onboardingController(_ controller: AdaptyOnboardingController, didFailWithError error: AdaptyUIError) { // Handle errors } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ## オンボーディングを閉じる \{#closing-onboarding\} ユーザーが **Close** アクションが割り当てられたボタンをタップすると、オンボーディングは閉じられたとみなされます。 <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important ユーザーがオンボーディングを閉じたときの動作は、アプリ側で管理する必要があります。たとえば、オンボーディング自体の表示を停止する処理が必要です。 ::: 例: ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onCloseAction action: AdaptyOnboardingsCloseAction) { controller.dismiss(animated: true) } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ## ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。ペイウォールが閉じられた後に開きたい場合は、[`AdaptyOnboardingsCloseAction`](#closing-onboarding) を処理してペイウォールをイベントデータに依存せず開く、というより簡単な方法があります。 ::: オンボーディングでペイウォールをシームレスに扱うには、アクション ID をペイウォールのプレースメント ID と同じにするのがおすすめです。こうすることで、`AdaptyOnboardingsOpenPaywallAction` の後にプレースメント ID を使ってすぐにペイウォールを取得して表示できます。 注意: 画面上に表示できるビュー(ペイウォールまたはオンボーディング)は一度に1つだけです。オンボーディングの上にペイウォールを表示した場合、バックグラウンドのオンボーディングをプログラムで操作することはできません。オンボーディングを閉じようとすると、代わりにペイウォールが閉じられ、オンボーディングがそのまま表示された状態になります。これを避けるため、ペイウォールを表示する前に必ずオンボーディングビューを閉じてください。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onPaywallAction action: AdaptyOnboardingsOpenPaywallAction) { // Dismiss onboarding before presenting the flow controller.dismiss(animated: true) { Task { do { // Get the flow using the placement ID from the action let flow = try await Adapty.getFlow(placementId: action.actionId) // Get the flow configuration let flowConfiguration = try await AdaptyUI.getFlowConfiguration( forFlow: flow ) // Create and present the flow controller let flowController = try AdaptyUI.flowController( with: flowConfiguration, delegate: self ) // Present the flow from the root view controller if let rootVC = UIApplication.shared.windows.first?.rootViewController { rootVC.present(flowController, animated: true) } } catch { // Handle any errors that occur during flow loading print("Failed to present flow: \(error)") } } } } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ## オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、次のメソッドが呼び出されます: ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, didFinishLoading action: OnboardingsDidFinishLoadingAction) { // Handle loading completion } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ## ナビゲーションのトラッキング \{#tracking-navigation\} `onAnalyticsEvent` メソッドは、オンボーディングフロー中にさまざまなアナリティクスイベントが発生したときに呼び出されます。 `event` オブジェクトは次のいずれかの型になります。 |型 | 説明 | |------------|-------------| | `onboardingStarted` | オンボーディングが読み込まれたとき | | `screenPresented` | いずれかの画面が表示されたとき | | `screenCompleted` | 画面が完了したとき。オプションの `elementId`(完了した要素の識別子)とオプションの `reply`(ユーザーからの応答)を含む。ユーザーが画面を終了するアクションを実行したときにトリガーされます。 | | `secondScreenPresented` | 2番目の画面が表示されたとき | | `userEmailCollected` | 入力フィールドからユーザーのメールアドレスが収集されたときにトリガーされます | | `onboardingCompleted` | ユーザーが `final` IDを持つ画面に到達したときにトリガーされます。このイベントが必要な場合は、[最後の画面に `final` IDを割り当ててください](design-onboarding)。 | | `unknown` | 認識されないイベント型。`name`(不明なイベントの名前)と `meta`(追加のメタデータ)を含む | 各イベントには、以下の情報を含む `meta` が付与されます: | フィールド | 説明 | |------------|-------------| | `onboardingId` | オンボーディングフローの一意の識別子 | | `screenClientId` | 現在の画面の識別子 | | `screenIndex` | フロー内での現在の画面の位置 | | `screensTotal` | フロー内の画面の総数 | アナリティクスイベントをトラッキングに利用する例を以下に示します: ```swift func onboardingController(_ controller: AdaptyOnboardingController, onAnalyticsEvent event: AdaptyOnboardingsAnalyticsEvent) { switch event { case .onboardingStarted(let meta): // Track onboarding start trackEvent("onboarding_started", meta: meta) case .screenPresented(let meta): // Track screen presentation trackEvent("screen_presented", meta: meta) case .screenCompleted(let meta, let elementId, let reply): // Track screen completion with user response trackEvent("screen_completed", meta: meta, elementId: elementId, reply: reply) case .onboardingCompleted(let meta): // Track successful onboarding completion trackEvent("onboarding_completed", meta: meta) case .unknown(let meta, let name): // Handle unknown events trackEvent(name, meta: meta) // Handle other cases as needed } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } } ``` </Details> --- # File: ios-onboarding-input --- --- title: "iOS SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用して、iOSアプリでオンボーディングのデータを保存・活用します。" --- :::tip **SDK v4以降**、オンボーディングのより強力な代替として[フロー](get-pb-paywalls)を構築できます。オンボーディングがWebView内で動作するのに対し、フローはデバイス上でネイティブにレンダリングされるため、スムーズなアニメーション、iOSらしい一貫したルック&フィール、高速な読み込み、WebViewランタイムへの依存がないといったメリットがあります。まずは[フローとペイウォールの取得](get-pb-paywalls)および[フローとペイウォールの表示](ios-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`onStateUpdatedAction` メソッドが呼び出されます。フィールドの種類をコード内で保存したり処理したりできます。 例えば: ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // ユーザーの設定や回答を保存する switch action.params { case .select(let params): // 単一選択を処理する case .multiSelect(let params): // 複数選択を処理する case .input(let params): // テキスト入力を処理する case .datePicker(let params): // 日付選択を処理する } } ``` `action` オブジェクトには以下が含まれます: | パラメーター | 説明 | |----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `elementId` | 入力要素の一意の識別子。保存時に質問と回答を関連付けるために使用できます。 | | `params` | typeおよびvalueプロパティを含む、ユーザーの入力データオブジェクト。 | | `params.type` | 入力要素のタイプ。以下のいずれかを指定できます:<br/>• `"select"` - 選択肢から1つを選択<br/>• `"multiSelect"` - 選択肢から複数を選択<br/>• `"input"` - テキスト入力フィールド<br/>• `"datePicker"` - 日付の選択 | | `params.value` | ユーザーが選択または入力した値。構造はタイプによって異なります:<br/>• `select`:`id`、`value`、`label`を持つオブジェクト<br/>• `multiSelect`:`id`、`value`、`label`を持つオブジェクトの配列<br/>• `input`:`type`、`value`を持つオブジェクト<br/>• `datePicker`:`day`、`month`、`year`を持つオブジェクト | <Details> <summary>保存されたデータの例(実装によって異なる場合があります)</summary> ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ``` </Details> ## ユースケース \{#use-cases\} ### ユーザープロファイルへのデータ付加 \{#enrich-user-profiles-with-data\} 入力データをユーザープロファイルとすぐに紐付け、同じ情報を二度聞かなくて済むようにするには、アクションの処理時に入力データを使って[ユーザープロファイルを更新](setting-user-attributes)する必要があります。 たとえば、IDが`name`のテキストフィールドでユーザーに名前を入力してもらい、その値をユーザーのファーストネームとして設定したい場合や、`email`フィールドでメールアドレスを入力してもらいたい場合、アプリのコードは次のようになります。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Store user preferences or responses switch action.params { case .input(let params): // Handle text input let builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field switch action.elementId { case "name": builder.with(firstName: params.value.value) case "email": builder.with(email: params.value.value) default: break } // Delegate methods are synchronous; kick off the async update in a Task. Task { do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } } default: break } } ``` ### オンボーディングの回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングのクイズを活用すると、ユーザーがオンボーディングを完了した後に表示するペイウォールもカスタマイズできます。 たとえば、スポーツ経験についてユーザーに質問し、ユーザーグループごとに異なるCTAやプロダクトを表示することができます。 1. オンボーディングビルダーに[クイズを追加](onboarding-quizzes)し、各選択肢にわかりやすいIDを設定します。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](setting-user-attributes)します。 ```swift showLineNumbers func onboardingController(_ controller: AdaptyOnboardingController, onStateUpdatedAction action: AdaptyOnboardingsStateUpdatedAction) { // Handle quiz responses and set custom attributes switch action.params { case .select(let params): // Handle quiz selection let builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes switch action.elementId { case "experience": // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) try? builder.with(customAttribute: params.value.value, forKey: "experience") default: break } // Delegate methods are synchronous; kick off the async update in a Task. Task { do { try await Adapty.updateProfile(params: builder.build()) } catch { // handle the error } } default: break } } ``` 3. カスタム属性値ごとに[セグメント](segments)を作成します。 4. [プレースメント](placements)を作成し、作成した各セグメントに対して[オーディエンス](audience)を追加します。 5. アプリのコード内でプレースメントの[ペイウォールを表示](ios-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[このボタンのアクションへの応答](ios-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: ios-sdk-call-order --- --- title: "iOS SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的な #2002 エラーを防ぎます。" --- `Adapty.activate()` が完了するまで、他のAdapty SDKメソッドを呼び出してはいけません。解決されるまで、SDKには状態がありません。`activate()` の前または並行して発行された呼び出しはすべて [`#2002 notActivated`](ios-sdk-error-handling#network-errors) で失敗します。 アプリがユーザー認証を行い、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `Adapty.identify()` を呼び出してください。`identify` が解決するまでユーザーアクションメソッドを呼び出さないでください。`identify` と競合する呼び出しは [`#3006 profileWasChanged`](ios-sdk-error-handling#general-errors) で失敗するか、アクティベーション時に作成された匿名プロファイルに対して実行されます。これが起きると、アトリビューション、`appsflyer_id` などのMMP ID、インストールの帰属が識別済みプロファイルに転送されないことがあります。アプリがユーザー認証を行わない場合は、`identify` をスキップして匿名プロファイルのまま使用してください。 MMP・アナリティクスSDK(AppsFlyer、Adjust、Branch、PostHog)も同じルールに従います。それらを先に初期化し、UIDコールバックを待ってから `Adapty.activate` を呼び出してください。そうしないと、MMP IDが短命な匿名プロファイルに紐づき、識別済みプロファイルに常に転送されるとは限りません。AppsFlyerの詳細については、[AppsFlyer](appsflyer) を参照してください。 ## 正しい順序 \{#the-correct-order\} どのパスを取るかは、カスタマーユーザーIDをいつ知るか、そしてMMPまたはアナリティクスSDKを使用するかどうかの2点によって決まります。 - **ステップ2と5**:すべてのアプリで必須です。SDKをアクティベートし、その後SDKメソッドを呼び出します。 - **ステップ1と3**:MMPまたはアナリティクスSDK(AppsFlyer、Adjust、Branch、PostHog)を統合する場合のみ必要です。 - **ステップ4**:アプリがユーザー認証を行い、起動後にカスタマーユーザーIDを収集する場合のみ必要です。 アプリ起動時にカスタマーユーザーIDがある場合は、`activate()` に直接渡してください(ステップ2a)。このパスでは匿名プロファイルが作成されないため、ステップ4は不要です。 | ステップ | 呼び出し | タイミング | 備考 | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | MMPまたはアナリティクスSDKの初期化(AppsFlyer、Adjust、PostHog、Branch) | アプリ起動時、最初に | MMPのUIDコールバック(例:`getAppsFlyerUID`)を待ってください。 | | 2a | `Adapty.activate(with: config)` に `customerUserId` をconfigに設定して呼び出す | アプリ起動時、ステップ1の後、カスタマーユーザーIDがある場合 | 推奨。匿名プロファイルは一切作成されません。 | | 2b | `Adapty.activate(with: config)` に `customerUserId` を設定せずに呼び出す | アプリ起動時、ステップ1の後、カスタマーユーザーIDがない場合(または収集しない場合) | Adaptyが匿名プロファイルを作成します。 | | 3 | 各MMPに対して `Adapty.setIntegrationIdentifier(...)` を呼び出す | ステップ2の後、ユーザーアクション呼び出しの前 | MMP IDが正しいプロファイルに紐づくために必要です。 | | 4 | `try await Adapty.identify("YOUR_USER_ID")` | ステップ3の後(またはMMPがない場合はステップ2の後)、ステップ5の前 — 認証ありのパス2bのみ | 必ず `await` してください。`identify` 中の並行呼び出しは `#3006 profileWasChanged` を発生させます。 | | 5 | `getPaywall`、`getPaywallProducts`、`restorePurchases`、`makePurchase`、`updateAttribution`、`updateProfile` | `identify` を呼び出す場合はステップ4の後、それ以外はステップ3の後(またはMMPがない場合はステップ2の後) | これらの呼び出しには安定したプロファイルが必要です。 | :::important これらのステップを省略すると、リターンユーザーのプレミアムアクセスの喪失、プロファイルへの `appsflyer_id` の欠落、間違ったオーディエンスに対してペイウォールが返される問題が発生します。 ::: ## Web2appとWebファネルのインストール \{#web2app-and-web-funnel-installs\} ユーザーがWebチェックアウト(Stripe、Paddle、FunnelFox)で購入し、その後ネイティブアプリをインストールする場合、デバイスで最初に `activate()` が呼ばれると新しい匿名プロファイルが作成されます。このプロファイルはWebプロファイルとリンクされていません。アプリ起動前にカスタマーユーザーIDを解決できる場合(認証フローやインストールリファラーから)、`activate()` に直接渡してください。そうしないと、`identify("YOUR_USER_ID")` を呼び出してから `restorePurchases` を実行するまで、Web購入はデバイスから見えません。 各Webチェックアウトで送信するメタデータについては、以下を参照してください: - [Stripe](stripe) - [Paddle](paddle) --- # File: ios-optimize-paywall-fetching --- --- title: "iOS SDKでペイウォールのフェッチを最適化する" description: "AdaptyのペイウォールをiOSで確実にフェッチする:タイミング、キャッシュ、フォールバックのパターン。" --- iOSで信頼性の高いペイウォールフェッチを実現するには、3つの要件を満たす必要があります。高速なレンダリング、オーディエンスターゲットに合ったペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバックです。以下のルールでは、それを実現するためのタイミング、キャッシュ、フォールバックのパターンを説明します。 :::tip 以下のルールは、`Adapty.activate()` と `Adapty.identify()` がすでに解決済みであることを前提としています。[iOS SDKのコール順序](ios-sdk-call-order)を参照してください。 ::: ## ルールと注意点 \{#rules-and-pitfalls\} | 推奨事項 | 避けるべき事項 | 理由 | |---|---|---| | 表示しようとしているプレースメントをフェッチする。 | 起動時にすべてのプレースメントを並列でプリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、バースト中に画面が真っ暗になる。 | | アトリビューションが解決される時間を確保してから `getPaywall` をフェッチする(例:`activate` から1〜2秒後、または `onProfileUpdate` が発火した後)。 | `App.init()` で `getPaywall` を呼び出す。 | アトリビューションがまだ取得されていない。ペイウォールはデフォルトのオーディエンスに対して解決され、セグメントやASAパーソナライゼーションが静かにバイパスされる。 | | `loadTimeout` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無期限に待機する。 | タイムアウトなしでは、接続が悪いユーザーはネットワークが解決するまで空白の画面を見続けるか、アプリを閉じてしまう。 | `fetchPolicy` と `loadTimeout` パラメーターのリファレンスについては[ペイウォールとプロダクトのフェッチ](fetch-paywalls-and-products)を、適切なプレースメントの選択については[プレースメント](placements)を参照してください。 ## 接続が悪い環境向けの調整 \{#tune-for-poor-connectivity\} 接続が安定しない市場(農村部、移動中、ルーティングの問題が多い地域)向けには: - 最初のフェッチを除くすべてのフェッチで `fetchPolicy: .returnCacheDataElseLoad` を設定する。 - Adapty ダッシュボードですべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeout` を3〜5秒に設定し、タイムアウトが発生した場合はフォールバックを受け入れる。 - ペイウォールの表示を `getProfile()` に依存させない。`getPaywall` は独立して呼び出すことで、プロファイルの取得が遅くてもUIをブロックしないようにする。 --- # File: ios-show-aa-targeted-paywall --- --- title: "iOS SDK の初回起動時に AA ターゲティングのペイウォールを表示する" description: "AdaptyProfile.appliedAttributionSources を使って、iOS で Apple Ads のアトリビューションを待ってからペイウォールをリクエストする方法。" --- Apple Ads(AA)のアトリビューションは、`Adapty.activate()` の後に非同期で届きます。`getPaywall` を早いタイミングで呼び出すと、アトリビューションがまだ反映されていないことが多く、Adapty はデフォルトのオーディエンスに対してプレースメントを解決してしまいます — つまり AA セグメントのペイウォールが適用されません。`AdaptyProfile.appliedAttributionSources` を使うと、AA アトリビューションがプロファイルに適用されたタイミングをアプリが検知できるため、AA セグメントが正しく解決されるまでペイウォールのリクエストを待機させられます。 ## はじめる前に \{#before-you-start\} 必要なもの: - Adapty iOS SDK **3.17.1** 以降。 - Adapty でアプリの Apple Ads を設定済みであること。詳しくは [Apple Ads](apple-search-ads) を参照してください。 ## 仕組み \{#how-it-works\} `Adapty.activate()` の後、SDK はバックグラウンドで Apple から Apple Ads のアトリビューションをリクエストし、その結果を Adapty のバックエンドに転送します。AA がプロファイルのアクティブなアトリビューションソースになると、SDK は更新された `AdaptyProfile` を配信します。この `appliedAttributionSources` 配列には `.appleAds` が含まれています。 配列が空の場合、以下のいずれかを意味します: - このプロファイルの Apple Ads アトリビューションがまだ処理されていない。 - アトリビューションが届いていない。 配列が空でも `getPaywall` の呼び出し自体は安全です — Adapty は現在のプロファイル状態に一致するオーディエンス(通常はデフォルトのオーディエンス)に対してリクエストを解決します。 :::important この待機処理は**初回起動時のみ**適用されます。Apple Ads のアトリビューションが一度記録されると、プロファイルに永続的に保存されます。2 回目以降の起動では、キャッシュされたプロファイルにすでに `.appleAds` が `appliedAttributionSources` に含まれているため、`didLoadLatestProfile` はその値ですぐに発火し、`getPaywall` は遅延なく Apple Ads セグメントのペイウォールを返します。 ::: ## 実装 \{#implementation\} 初回起動時は、プロファイル内の `.appleAds` を監視しながら、厳格なタイムアウトを設定してください — Apple Ads のアトリビューションが届かない場合でも、ユーザーにはペイウォールを表示する必要があります。 1. **SDK を有効化します。** [iOS SDK のインストールと設定](sdk-installation-ios) を参照してください。 2. **`AdaptyDelegate` に準拠して `didLoadLatestProfile` を実装することでプロファイルの更新を購読します。** デリゲートをまだ設定していない場合は、[サブスクリプションのアップデートを監視する](ios-check-subscription-status#listen-to-subscription-updates) を参照してください。 3. **`appliedAttributionSources` に `.appleAds` が含まれているか監視します。** 含まれている場合にペイウォールをリクエストすると、Adapty は AA セグメントのバリアントを返します: ```swift extension <YourAdaptyDelegateImpl>: AdaptyDelegate { nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { if profile.appliedAttributionSources.contains(where: { $0 == .appleAds }) { // load paywall via Adapty.getPaywall(placementId:) } } } ``` 4. **購読と並行して 3〜5 秒のタイマーを開始します。** タイマーが先に発火した場合は、`.appleAds` が現れなくてもペイウォールをリクエストします: どちらのパスが先に発火しても、その時点でペイウォールを読み込み、もう一方のパスはスキップします。ペイウォールが 2 回フェッチされないよう、単一の状態フラグ(例:`hasLoadedPaywall`)を使って重複を排除してください。ネットワークリクエストが失敗してもユーザーが詰まらないよう、プレースメントに [フォールバックペイウォール](fallback-paywalls) を設定してください。 ## 完全なサンプル \{#complete-example\} 以下の実装は、アトリビューションとタイムアウトを競争させ、デフォルトのオーディエンスのペイウォールを並行してプリフェッチし、適切なペイウォールを返します。呼び出し元は単一の非同期関数を await するだけで、呼び出し側でデリゲートや状態フラグを管理する必要はありません。 `ProfileObserver` は `AdaptyDelegate` からプロファイルの更新を公開する再利用可能なシングルトンです。`PaywallLoader.getPaywallOrDefault` は structured concurrency の `TaskGroup` を使って競争を実行します: - タイムアウト内にアトリビューションが届いた場合、`getPaywall(placementId:)` を通じてセグメント化されたペイウォールを返します。 - `timeout` が先に経過した場合、`getPaywallForDefaultAudience(placementId:)` を通じてプリフェッチ済みのデフォルトオーディエンスのペイウォールを返します。 ```swift title="PaywallLoader.swift" /// Demonstrates how to fetch a paywall that depends on attribution being applied, /// falling back to the default-audience paywall if attribution doesn't arrive in time. /// /// Stateless and self-contained: every call kicks off its own default-audience /// prefetch and races it against attribution + segmented fetch. enum PaywallLoader { static func getPaywallOrDefault( placementId: String, timeout: TimeInterval ) async throws -> AdaptyPaywall { struct TimedOut: Error {} // Kick off the default-audience request immediately so it has the full // `timeout` window to load. We'll either cancel it on success or await // its result on timeout — never a duplicate network call. let defaultPaywallTask = Task { try await Adapty.getPaywallForDefaultAudience(placementId: placementId) } do { // Race two child tasks: whichever finishes first wins. let result = try await withThrowingTaskGroup(of: AdaptyPaywall.self) { group in // 1. Wait for attribution, then ask Adapty for the segmented paywall. group.addTask { await waitForAttribution() return try await Adapty.getPaywall(placementId: placementId) } // 2. Time-bomb: throws `TimedOut` after `timeout` seconds. group.addTask { try await Task.sleep(nanoseconds: UInt64(timeout * 1_000_000_000)) throw TimedOut() } guard let value = try await group.next() else { throw CancellationError() } group.cancelAll() // stop the loser (sleeper or the attribution wait). return value } // Segmented paywall won — we no longer need the default-audience prefetch. defaultPaywallTask.cancel() return result } catch is TimedOut { // Attribution didn't apply in time — return the prefetched default // (instant if already done, otherwise we await the in-flight request). return try await defaultPaywallTask.value } } /// Suspends until a profile with the desired attribution source is observed. /// `@Published.values` emits the current profile immediately on subscription, /// so this returns on the first iteration if attribution is already applied. @MainActor private static func waitForAttribution() async { for await profile in ProfileObserver.shared.$profile.values { if profile?.appliedAttributionSources.contains(.appleAds) == true { return } } } } @MainActor final class ProfileObserver: AdaptyDelegate { static let shared = ProfileObserver() @Published private(set) var profile: AdaptyProfile? nonisolated func didLoadLatestProfile(_ profile: AdaptyProfile) { Task { @MainActor [weak self] in self?.profile = profile } } } ``` `Adapty.activate()` の完了後、一度だけ `ProfileObserver` を `AdaptyDelegate` に接続します: ```swift Adapty.delegate = ProfileObserver.shared ``` スプラッシュスクリーンから呼び出します: ```swift do { let paywall = try await PaywallLoader.getPaywallOrDefault( placementId: "YOUR_PLACEMENT_ID", timeout: 5 ) // present the paywall } catch { // handle the error or show a fallback paywall } ``` 他の目的(例:[サブスクリプションのアップデートを監視する](ios-check-subscription-status#listen-to-subscription-updates))のために既に `AdaptyDelegate` を使用している場合は、`Adapty.delegate = ProfileObserver.shared` を設定する代わりに、既存のデリゲートから `ProfileObserver.shared` に `didLoadLatestProfile` を転送してください。 --- # File: ios-test --- --- title: "iOSSDKのテストとリリース" description: "AdaptyでiOSアプリのサブスクリプション状態を確認する方法を学びましょう。" --- AdaptyのSDKをiOSアプリに実装したら、すべてが正しく設定されており、購入が期待どおりに動作することをテストしましょう。これには、SDKの統合と実際の購入の両方のテストが含まれます。 ## アプリをテストする \{#test-your-app\} サンドボックステストやTestFlightの検証を含むアプリ内課金の包括的なテストについては、[テストガイド](test-purchases-in-sandbox)をご覧ください。 ## リリースの準備 \{#prepare-for-release\} アプリをストアに申請する前に、[リリースチェックリスト](release-checklist)に従って以下を確認してください: - ストア接続とサーバー通知が設定されている - 購入が完了し、Adaptyに報告されている - アクセスが正しく解除および復元される - プライバシーおよびレビュー要件が満たされている --- # File: InvalidProductIdentifiers --- --- title: "Code-1000 noProductIDsFound エラーの修正" description: "Adapty でサブスクリプションを管理する際の無効なプロダクト識別子エラーを解決します。" --- 1000 コードエラー `noProductIDsFound` は、ペイウォールでリクエストしたプロダクトが App Store に登録されているにもかかわらず、購入可能な状態でないことを示します。このエラーには `InvalidProductIdentifiers` の警告が伴う場合があります。エラーなしに警告だけが表示される場合は、無視して問題ありません。 `noProductIDsFound` エラーが発生している場合は、以下の手順で解決してください。 ## ステップ 1. Bundle ID を確認する \{#step-2-check-bundle-id\} 1. [App Store Connect](https://appstoreconnect.apple.com/apps) を開きます。アプリを選択し、**General** → **App Information** セクションに進みます。 2. **General Information** サブセクションで **Bundle ID** をコピーします。 <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 4. App Store Connect の **App information** ページに戻り、**Apple ID** をコピーします。 5. Adapty ダッシュボードの [**App settings** -> **iOS SDK**](https://app.adapty.io/settings/ios-sdk) ページで、**Apple app ID** フィールドにその ID を貼り付けます。 ## ステップ 2. プロダクトを確認する \{#step-2-check-products\} 1. **App Store Connect** を開き、左側のメニューから [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) に移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テスト対象のプロダクトが **Ready to Submit** になっていることを確認してください。なっていない場合は、[App Store のプロダクト](app-store-products)ページの手順に従ってください。 <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. テーブルに表示されているプロダクト ID と、Adapty ダッシュボードの [**Products**](https://app.adapty.io/products) タブに登録されているプロダクト ID を照合してください。ID が一致しない場合は、テーブルからプロダクト ID をコピーして、Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 3. プロダクトの利用可能地域を確認する \{#step-4-check-product-availability\} 1. **App Store Connect** に戻り、同じ **Subscriptions** セクションを開きます。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックして、プロダクト一覧を表示します。 3. テスト対象のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Availability** セクションまでスクロールし、必要な国と地域がすべて一覧に含まれていることを確認してください。 <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 4. プロダクトの価格を確認する \{#step-5-check-product-prices\} 1. 再び **App Store Connect** の **Monetization** → **Subscriptions** セクションに移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックします。 3. テスト対象のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Subscription Pricing** までスクロールし、**Current Pricing for New Subscribers** セクションを展開します。 <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 必要な価格がすべて一覧に含まれていることを確認してください。 <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 5. アプリの有料ステータス、銀行口座、税務フォームがアクティブであることを確認する \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. [**App Store Connect**](https://appstoreconnect.apple.com/) のホームページで **Business** をクリックします。 <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 会社名を選択します。 <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 下にスクロールして、**Paid Apps Agreement**、**Bank Account**、**Tax forms** がすべて **Active** になっていることを確認します。 <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 以上の手順を実行することで、`InvalidProductIdentifiers` の警告を解消し、プロダクトをストアで公開できるようになります。 ## ステップ 6. プロダクトがスタックしている場合は再作成する \{#step-6-recreate-the-product-if-its-stuck\} ステップ 1〜5 がすべて問題なく通過している場合(`Approved` ステータス、Bundle ID の一致、有効な API キーなど)でも、SDK が `1000 noProductIDsFound` を返し続けることがあります。この場合、プロダクトが Apple のレジストリでスタックしている可能性があります。App Store Connect の UI 上にはプロダクトが存在していても、StoreKit のルックアップパスに公開されていない状態になることがあります。 App Store Connect でプロダクトを削除し、同じプロダクト ID で再作成してください。再作成後、反映されるまで最大 24 時間かかる場合があります。 --- # File: cantMakePayments --- --- title: "Code-1003 cantMakePayment エラーの修正" description: "Adapty でサブスクリプションを管理する際に発生する支払いエラーを解決します。" --- 1003エラー(`cantMakePayments`)は、このデバイスでアプリ内課金ができないことを示しています。 `cantMakePayments`エラーが発生している場合、通常は以下のいずれかの原因が考えられます: - デバイスの制限:このエラーはAdaptyとは無関係です。以下の解決方法を参照してください。 - オブザーバーモードの設定:`makePurchase`メソッドとオブザーバーモードは同時に使用できません。以下のセクションを参照してください。 ## 問題:デバイスの制限 \{#issue-device-restrictions\} | 問題 | 解決方法 | |-----------------------------|---------------------------------------------------------| | スクリーンタイムの制限 | [スクリーンタイム](https://support.apple.com/en-us/102470)でアプリ内課金の制限を無効にする | | アカウントの停止 | Appleサポートに連絡してアカウントの問題を解決する | | 地域の制限 | 対応地域のApp Storeアカウントを使用する | ## 問題:オブザーバーモードとmakePurchaseの併用 \{#issue-using-both-observer-mode-and-makepurchase\} 購入処理に`makePurchase`を使用している場合、オブザーバーモードを使用する必要はありません。[オブザーバーモード](observer-vs-full-mode)が必要なのは、購入ロジックを自分で実装する場合のみです。 したがって、`makePurchase`を使用している場合は、SDK有効化コードからオブザーバーモードの有効化を安全に削除できます。 --- # File: migration-to-ios-sdk-v4 --- --- title: "Adapty iOS SDK v4.0への移行" description: "ペイウォールAPIをフローAPIに置き換えてAdapty iOS SDK v4.0に移行します。フロービルダーとペイウォールビルダーの両方に対応しています。" --- Adapty iOS SDK 4.0ではフローが導入され、それに合わせてペイウォールAPIの名称が変更されました。新しいAPIはフロービルダーと既存のペイウォールビルダーの両方で動作します。Adapty ダッシュボード側での設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId:locale:)` | `Adapty.getFlow(placementId:)` | | `AdaptyUI.getPaywallConfiguration(forPaywall:)` | `AdaptyUI.getFlowConfiguration(forFlow:locale:)` | | `Adapty.getPaywallProducts(paywall:)` | `Adapty.getPaywallProducts(flow:)` | | `Adapty.logShowPaywall(_:)` | `Adapty.logShowFlow(_:)` | | `AdaptyPaywallController` | `AdaptyFlowController` | | `AdaptyPaywallControllerDelegate` | `AdaptyFlowControllerDelegate` | | `AdaptyUI.paywallController(with:delegate:)` | `AdaptyUI.flowController(with:delegate:)` | | `.paywall()` (SwiftUI modifier) | `.flow()` | | `AdaptyPaywallView` | `AdaptyFlowView` | | `didFailRenderingWith:` / `didFailRendering:` | `didReceiveError:` | | `didFinishPurchase`(オプション、成功時に自動で閉じる) | `didFinishPurchase`(必須、自動では閉じない) | | `Adapty_KidsMode` / `AdaptyUI_KidsMode` パッケージプロダクト | `KidsMode` パッケージトレイト | | `Adapty.updateAttribution(_:source:)` (`source: String`) | `Adapty.updateAttribution(_:source:)` (`source: AdaptyAttributionSource`) | | `Adapty.setIntegrationIdentifier(key:value:)` | `Adapty.setIntegrationIdentifier(_:)` (`AdaptyIntegrationIdentifier`) | ## iOS 最小バージョン \{#minimum-ios-version\} Adapty iOS SDK 4.0 では、最小デプロイメントターゲットが iOS 13.0 から **iOS 15.0** に引き上げられました。アップグレードの前に、プロジェクトの iOS Deployment Target を 15.0 以上に設定してください。 ## インストール:CocoaPods のサポート終了 \{#installation-cocoapods-no-longer-supported\} Adapty iOS SDK 4.0 では CocoaPods のサポートが廃止されました。SDK のインストールには [Swift Package Manager](sdk-installation-ios#install-adapty-sdk) をご利用ください。 プロジェクトで引き続き CocoaPods を使用している場合は、`Podfile` から `Adapty` および `AdaptyUI` の pod を削除し、`pod install` を実行してクリーンアップした後、Xcode の **File → Add Package Dependency** から `https://github.com/adaptyteam/AdaptySDK-iOS.git` を使ってパッケージを追加してください。 ## キッズモード: 専用プロダクトからパッケージトレイトへ \{#kids-mode-separate-products-replaced-by-a-package-trait\} v3 では、[キッズモード](kids-mode)を有効にするには、専用の **Adapty_KidsMode** および **AdaptyUI_KidsMode** パッケージプロダクトを選択し、import 文をリネームする必要がありました。v4.0 ではこれらのプロダクトが削除されました。キッズモードは、通常の Adapty パッケージ上の `KidsMode` という Swift パッケージトレイトとなり、有効にすると SDK 全体で IDFA および AdSupport がコンパイル時に除外されます。 移行手順: 1. **Choose Package Products** ウィンドウで、**Adapty_KidsMode** および **AdaptyUI_KidsMode** の代わりに、通常の **Adapty** および **AdaptyUI** プロダクトを選択します。 2. `KidsMode` トレイトを有効にします。Xcode 26.4 以降をお使いの場合は、プロジェクトの **Package Dependencies** ビューで AdaptySDK-iOS 依存関係に対して有効にしてください。`Package.swift` で Adapty を依存関係として追加する場合(`swift-tools-version` 6.1 以降が必要)は、そちらで有効にします: ```swift showLineNumbers title="Package.swift" .package( url: "https://github.com/adaptyteam/AdaptySDK-iOS.git", from: "4.0.0", traits: ["KidsMode"] ) ``` 3. インポートを通常のモジュールに戻します: ```diff showLineNumbers - import Adapty_KidsMode - import AdaptyUI_KidsMode + import Adapty + import AdaptyUI ``` :::note Xcode 26.4 より前のバージョンでは、UI からプロジェクトにトレイトを有効化できません。その場合は、`KidsMode` トレイトを有効にした Adapty に依存するローカルの Swift パッケージを作成し、アプリターゲットがそのパッケージに依存するように設定してください。 ::: ## 削除された API \{#removed-apis\} - **`Adapty.getPaywallProductsWithoutDeterminingOffer(paywall:)`** — 削除されました。すべてのプロダクトにオファー情報が含まれるようになったため、個別の対象資格確認パスは不要になりました。 - **`AdaptyPaywallProductWithoutDeterminingOffer`** — 削除されました。以前このタイプを渡していたコールバック(`didSelectProduct` など)は、今後 `AdaptyPaywallProduct` を渡すようになります。 ## App Store プロモートアプリ内課金の一時的な削除 \{#app-store-promoted-in-app-purchases-temporarily-removed\} StoreKit 2 への移行の一環として、Adapty iOS SDK 4.0 では App Store プロモートアプリ内課金のサポートが削除されました。`shouldAddStorePayment(for:)` デリゲートメソッドおよびそれが受け取る `AdaptyDeferredProduct` 型は、4.0 では使用できません。 :::warning この削除は一時的なものです — プロモートアプリ内課金のサポートは、今後の 4.x リリースで復活する予定です。アプリがプロモートアプリ内課金に依存している場合は、サポートが戻るまで iOS SDK 3.x をご利用ください。 ::: ## ペイウォールの取得 \{#fetching-paywalls\} ### getPaywall + getPaywallConfiguration → getFlow + getFlowConfiguration 返却される型は `AdaptyPaywall` / `AdaptyUI.PaywallConfiguration` から `AdaptyFlow` / `AdaptyUI.FlowConfiguration` に変わります。`locale` パラメータはフェッチ呼び出しから `getFlowConfiguration` に移動します。 ```diff showLineNumbers - let paywall = try await Adapty.getPaywall(placementId: "YOUR_PLACEMENT_ID", locale: "en") - let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall) + let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") + let flowConfiguration = try await AdaptyUI.getFlowConfiguration(forFlow: flow, locale: "en") ``` ### getPaywallProducts(paywall:) → getPaywallProducts(flow:) `getPaywallProducts` は、`Adapty.getFlow` によって返された `AdaptyFlow` を受け取るようになりました: ```diff showLineNumbers - let products = try await Adapty.getPaywallProducts(paywall: paywall) + let products = try await Adapty.getPaywallProducts(flow: flow) ``` ## ペイウォールの表示を記録する \{#tracking-paywall-views\} ### logShowPaywall(_:) → logShowFlow(_:) `logShowPaywall` は `logShowFlow` にリネームされ、`AdaptyPaywall` の代わりに `AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリアントに対して記録されるため、既存のファネルや A/B テストの指標はダッシュボードの変更なしに引き続き機能します。 ```diff showLineNumbers - try await Adapty.logShowPaywall(paywall) + try await Adapty.logShowFlow(flow) ``` v3と同様に、[Flow Builder](adapty-flow-builder)や[Paywall Builder](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示する際には、このメソッドを呼び出す必要はありません。これらのビューはAdaptyが自動的にトラッキングします。 ## didFinishPurchaseが必須になりました \{#didfinishpurchase-is-now-required\} v3では、`didFinishPurchase`はオプションでした。実装しなかった場合、購入成功後にペイウォールが自動的に閉じられていました。v4.0では、この自動クローズのデフォルト実装が削除されました。これにより、購入成功後もフローを継続できます。たとえば、フローの残りのスクリーンを表示し続けることが可能です。購入後の動作はご自身で決定してください。スクリーンを閉じるか、何もせずにフローを継続させるかを選べます。 - **UIKit**: `AdaptyFlowControllerDelegate` の準拠者は `didFinishPurchase` を実装する必要があります。デフォルト実装は廃止されました。 - **SwiftUI**: `.flow(...)` および `AdaptyFlowView(...)` の `didFinishPurchase` クロージャが必須になりました。`didFailPurchase` および `didFinishRestore` と同様です。 v3 の動作を維持するには、自分で画面を閉じてください: ```swift showLineNumbers title="Swift" func flowController( _ controller: AdaptyFlowController, didFinishPurchase product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if !purchaseResult.isPurchaseCancelled { controller.dismiss(animated: true) } } ``` ## UIKit \{#uikit\} ### AdaptyPaywallController → AdaptyFlowController コントローラーの型とファクトリーメソッドの名前を変更します: ```diff showLineNumbers - let controller = try AdaptyUI.paywallController( - with: paywallConfiguration, - delegate: self - ) + let controller = try AdaptyUI.flowController( + with: flowConfiguration, + delegate: self + ) ``` ### AdaptyPaywallControllerDelegate → AdaptyFlowControllerDelegate プロトコル名を変更し、すべてのメソッドシグネチャを更新してください。`didSelectProduct` が削除された `AdaptyPaywallProductWithoutDeterminingOffer` の代わりに `AdaptyPaywallProduct` を受け取るようになった点、および `didFinishPurchase` は[実装が必須になった](#didfinishpurchase-is-now-required)点(デフォルト実装がなくなりました)に注意してください。 ```diff showLineNumbers - class YourClass: AdaptyPaywallControllerDelegate { + class YourClass: AdaptyFlowControllerDelegate { - func paywallControllerDidAppear(_ controller: AdaptyPaywallController) { } + func flowControllerDidAppear(_ controller: AdaptyFlowController) { } - func paywallControllerDidDisappear(_ controller: AdaptyPaywallController) { } + func flowControllerDidDisappear(_ controller: AdaptyFlowController) { } - func paywallController(_ controller: AdaptyPaywallController, - didPerform action: AdaptyUI.Action) { } + func flowController(_ controller: AdaptyFlowController, + didPerform action: AdaptyUI.Action) { } - func paywallController(_ controller: AdaptyPaywallController, - didSelectProduct product: AdaptyPaywallProductWithoutDeterminingOffer) { } + func flowController(_ controller: AdaptyFlowController, + didSelectProduct product: AdaptyPaywallProduct) { } - func paywallController(_ controller: AdaptyPaywallController, - didStartPurchase product: AdaptyPaywallProduct) { } + func flowController(_ controller: AdaptyFlowController, + didStartPurchase product: AdaptyPaywallProduct) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishPurchase product: AdaptyPaywallProduct, - purchaseResult: AdaptyPurchaseResult) { } + func flowController(_ controller: AdaptyFlowController, + didFinishPurchase product: AdaptyPaywallProduct, + purchaseResult: AdaptyPurchaseResult) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailPurchase product: AdaptyPaywallProduct, - error: AdaptyError) { } + func flowController(_ controller: AdaptyFlowController, + didFailPurchase product: AdaptyPaywallProduct, + error: AdaptyError) { } - func paywallControllerDidStartRestore(_ controller: AdaptyPaywallController) { } + func flowControllerDidStartRestore(_ controller: AdaptyFlowController) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishRestoreWith profile: AdaptyProfile) { } + func flowController(_ controller: AdaptyFlowController, + didFinishRestoreWith profile: AdaptyProfile) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailRestoreWith error: AdaptyError) { } + func flowController(_ controller: AdaptyFlowController, + didFailRestoreWith error: AdaptyError) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailRenderingWith error: AdaptyUIError) { } + func flowController(_ controller: AdaptyFlowController, + didReceiveError error: AdaptyUIError) { } - func paywallController(_ controller: AdaptyPaywallController, - didFailLoadingProductsWith error: AdaptyError) -> Bool { } + func flowController(_ controller: AdaptyFlowController, + didFailLoadingProductsWith error: AdaptyError) -> Bool { } - func paywallController(_ controller: AdaptyPaywallController, - didPartiallyLoadProducts failedIds: [String]) { } + func flowController(_ controller: AdaptyFlowController, + didPartiallyLoadProducts failedIds: [String]) { } - func paywallController(_ controller: AdaptyPaywallController, - didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, - error: AdaptyError?) { } + func flowController(_ controller: AdaptyFlowController, + didFinishWebPaymentNavigation product: AdaptyPaywallProduct?, + error: AdaptyError?) { } } ``` ## SwiftUI \{#swiftui\} ### .paywall() モディファイア → .flow() \{#paywall-modifier--flow\} モディファイアの名前を変更し、設定パラメータ名を更新して、[必須となった](#didfinishpurchase-is-now-required) `didFinishPurchase` クロージャを追加します。 ```diff showLineNumbers @State var flowPresented = false // rename freely — the variable name is your choice var body: some View { Text("Hello, AdaptyUI!") - .paywall( + .flow( isPresented: $flowPresented, - paywallConfiguration: paywallConfiguration, + flowConfiguration: flowConfiguration, + didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, - didFailRendering: { error in flowPresented = false } + didReceiveError: { error in flowPresented = false } ) } ``` 名前が変更されたコールバックは、`didFailRendering` が対応していたのと同じレンダリングエラーに加え、フロースクリプトの新しいランタイムエラー(`AdaptyUIError` コード `4105` — `.jsException` の JavaScript 例外)にも対応します。既存のハンドラー本体はコードを変更する必要はありません。パラメーターの名前を変更するだけです。 ### AdaptyPaywallView → AdaptyFlowView ビューの名前を変更し、設定パラメータを更新し、[現在必須となった](#didfinishpurchase-is-now-required) `didFinishPurchase` クロージャを追加して、`didSelectProduct` クロージャを更新してください。このクロージャは、削除された `AdaptyPaywallProductWithoutDeterminingOffer` の代わりに `AdaptyPaywallProduct` を受け取るようになりました。 ```diff showLineNumbers - AdaptyPaywallView( - paywallConfiguration: paywallConfiguration, - didSelectProduct: { product: AdaptyPaywallProductWithoutDeterminingOffer in /* handle */ }, + AdaptyFlowView( + flowConfiguration: flowConfiguration, + didSelectProduct: { product: AdaptyPaywallProduct in /* handle */ }, + didFinishPurchase: { product, purchaseResult in /* dismiss, or do nothing to let the flow continue */ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, - didFailRendering: { error in /* handle the error */ } + didReceiveError: { error in /* handle the error */ } ) ``` ## AdaptyUI カスタムアセット \{#adaptyui-custom-assets\} ### AdaptyUICustomVideoAsset 既存のすべての呼び出し箇所に影響する変更が2点あります。 - `.player` が `AVQueuePlayer` の代わりに `AVPlayer` を受け取るようになりました。 - すべてのケースに末尾の `resolution: CGSize?` パラメータが追加されました。現在の動作を維持するには `nil` を渡してください。動画が読み込まれる前にプレイヤーがレイアウトスペースを確保できるよう(アスペクト比 = `width / height`)、実際のピクセルサイズを渡すこともできます。 ```diff showLineNumbers - case file(url: URL, preview: AdaptyUICustomImageAsset?) - case remote(url: URL, preview: AdaptyUICustomImageAsset?) - case player(item: AVPlayerItem, player: AVQueuePlayer, preview: AdaptyUICustomImageAsset?) + case file(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) + case remote(url: URL, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) + case player(item: AVPlayerItem, player: AVPlayer, preview: AdaptyUICustomImageAsset?, resolution: CGSize?) ``` ## アトリビューションと連携識別子 \{#attribution-and-integration-identifiers\} ### updateAttribution(_:source:) `source` パラメーターの型が `String` から新しい `AdaptyAttributionSource` 型に変更され、以前はネストされていた `AdaptyProfile.AttributionSource` がトップレベルの `AdaptyAttributionSource` に改名されました。定義済みのソースを使用するか、その他のソースには文字列リテラルを渡してください。`AdaptyAttributionSource` は `ExpressibleByStringLiteral` に準拠しているため、既存の文字列リテラルによる呼び出しはそのままコンパイルできます。 ```diff showLineNumbers - try await Adapty.updateAttribution(attribution, source: "adjust") + try await Adapty.updateAttribution(attribution, source: .adjust) ``` 定義済みソース: `.appleAds`、`.adjust`、`.appsflyer`、`.branch`、`.tenjin`。ソースを `String` 変数で保持している場合は、`AdaptyAttributionSource(rawValue: yourSource)` でラップしてください。 ### setIntegrationIdentifier(_:) \{#setintegrationidentifier\} `setIntegrationIdentifier(key:value:)` は、1つ以上の `AdaptyIntegrationIdentifier` 値を受け取る可変長引数メソッドに置き換えられました。生の文字列キーの代わりに、定義済みのファクトリーメソッドを使用してください: ```diff showLineNumbers - try await Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) + try await Adapty.setIntegrationIdentifier(.appsflyerId(uid)) ``` 1回の呼び出しで複数の識別子を設定できます: ```swift showLineNumbers try await Adapty.setIntegrationIdentifier( .appsflyerId(uid), .adjustDeviceId(adid) ) ``` 各古いキー文字列をそのファクトリーメソッドに置き換えます: | v3 キー | v4 ファクトリー | |---|---| | `"adjust_device_id"` | `.adjustDeviceId(_:)` | | `"airbridge_device_id"` | `.airbridgeDeviceId(_:)` | | `"amplitude_user_id"` | `.amplitudeUserId(_:)` | | `"amplitude_device_id"` | `.amplitudeDeviceId(_:)` | | `"appmetrica_device_id"` | `.appmetricaDeviceId(_:)` | | `"appmetrica_profile_id"` | `.appmetricaProfileId(_:)` | | `"appsflyer_id"` | `.appsflyerId(_:)` | | `"branch_id"` | `.branchId(_:)` | | `"facebook_anonymous_id"` | `.facebookAnonymousId(_:)` | | `"firebase_app_instance_id"` | `.firebaseAppInstanceId(_:)` | | `"mixpanel_user_id"` | `.mixpanelUserId(_:)` | | `"one_signal_subscription_id"` | `.oneSignalSubscriptionId(_:)` | | `"one_signal_player_id"` | `.oneSignalPlayerId(_:)` | | `"posthog_distinct_user_id"` | `.posthogDistinctUserId(_:)` | | `"pushwoosh_hwid"` | `.pushwooshHWID(_:)` | | `"tenjin_analytics_installation_id"` | `.tenjinAnalyticsInstallationId(_:)` | --- # File: migration-to-ios-315 --- --- title: "Adapty iOS SDK を v3.15 に移行する" description: "Adapty iOS SDK v3.15 に移行して、パフォーマンスの向上と新しいマネタイズ機能をご利用ください。" --- [オブザーバーモード](observer-vs-full-mode)で[ペイウォールビルダー](adapty-paywall-builder)を使用している場合、iOS SDK 3.15 以降では新しいメソッド `observerModeDidInitiateRestorePurchases(onStartRestore:onFinishRestore:)` を実装する必要があります。このメソッドにより、リストアロジックをより細かく制御できるようになり、カスタムフローで購入のリストアを処理できます。実装の詳細については、[オブザーバーモードでペイウォールビルダーのペイウォールを表示する](ios-present-paywall-builder-paywalls-in-observer-mode)を参照してください。 ```diff showLineNumbers func observerMode(didInitiatePurchase product: AdaptyPaywallProduct, onStartPurchase: @escaping () -> Void, onFinishPurchase: @escaping () -> Void) { // use the product object to handle the purchase // use the onStartPurchase and onFinishPurchase callbacks to notify AdaptyUI about the process of the purchase } + func observerModeDidInitiateRestorePurchases(onStartRestore: @escaping () -> Void, + onFinishRestore: @escaping () -> Void) { + // use the onStartRestore and onFinishRestore callbacks to notify AdaptyUI about the process of the restore + } ``` --- # File: migration-to-ios-sdk-34 --- --- title: "Adapty iOS SDK を v3.4 へ移行する" description: "Adapty iOS SDK v3.4 に移行して、パフォーマンスの向上と新しいマネタイズ機能を活用しましょう。" --- Adapty SDK 3.4.0 はメジャーリリースであり、お客様側での移行手順が必要な改善が含まれています。 ## Adapty SDK のアクティベーションを更新する \{#update-adapty-sdk-activation\} <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```diff showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") - Adapty.activate(with: configurationBuilder) { error in + Adapty.activate(with: configurationBuilder.build()) { error in // handle the error } ``` **フォールバックペイウォールファイルを更新する** 新しい SDK バージョンとの互換性を確保するために、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新されたフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換え](ios-use-fallback-paywalls)ます。 </TabItem> <TabItem value="swiftui" label="SwiftUI" default> ```diff showLineNumbers @main struct SampleApp: App { init() { let configurationBuilder = AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") Task { - try await Adapty.activate(with: configurationBuilder) + try await Adapty.activate(with: configurationBuilder.build()) } } var body: some Scene { WindowGroup { ContentView() } } } ``` **フォールバックペイウォールファイルを更新する** 新しい SDK バージョンとの互換性を確保するために、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新されたフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換え](ios-use-fallback-paywalls)ます。 </TabItem> </Tabs> --- # File: migration-to-ios330 --- --- title: "Adapty iOS SDK を v3.3 に移行する" description: "パフォーマンス向上と新しいマネタイゼーション機能のために Adapty iOS SDK v3.3 に移行します。" --- Adapty SDK 3.3.0 はメジャーリリースであり、いくつかの改善が加えられています。ただし、一部の移行手順が必要になる場合があります。 1. `Adapty.Configuration` を `AdaptyConfiguration` にリネームする。 2. `getViewConfiguration` メソッドを `getPaywallConfiguration` にリネームする。 3. SwiftUI から `didCancelPurchase` と `paywall` パラメータを削除し、`viewConfiguration` パラメータを `paywallConfiguration` にリネームする。 4. `AdaptyDelegate` メソッドから `defermentCompletion` パラメータを削除して、App Store からのプロモーション用アプリ内課金の処理方法を更新する。 5. `getProductsIntroductoryOfferEligibility` メソッドを削除する。 6. Adjust、AirBridge、Amplitude、AppMetrica、Appsflyer、Branch、Facebook Ads、Firebase と Google Analytics、Mixpanel、OneSignal、Pushwoosh のインテグレーション設定を更新する。 7. オブザーバーモードの実装を更新する。 <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/9Xs8d0lt_RY?si=xvWhUO2tlG1tKP5f" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen> </iframe> </div> ## Adapty.Configuration を AdaptyConfiguration にリネームする \{#rename-adaptyconfiguration-to-adaptyconfiguration\} 次のように Adapty iOS SDK の有効化コードを更新してください: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```diff showLineNumbers // In your AppDelegate class: let configurationBuilder = - Adapty.Configuration + AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) .with(customerUserId: "YOUR_USER_ID") .with(idfaCollectionDisabled: false) .with(ipAddressCollectionDisabled: false) Adapty.activate(with: configurationBuilder) { error in // handle the error } ``` </TabItem> <TabItem value="swiftui" label="SwiftUI" default> ```diff showLineNumbers @main struct SampleApp: App { init() let configurationBuilder = - Adapty.Configuration + AdaptyConfiguration .builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) // optional .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional Task { try await Adapty.activate(with: configurationBuilder) } } var body: some Scene { WindowGroup { ContentView() } } } ``` </TabItem> </Tabs> ## getViewConfiguration メソッドを getPaywallConfiguration にリネームする \{#rename-getviewconfiguration-method-to-getpaywallconfiguration\} ペイウォールの `viewConfiguration` を取得するメソッド名を次のように更新してください: ```diff showLineNumbers guard paywall.hasViewConfiguration else { // use your custom logic return } do { - let paywallConfiguration = try await AdaptyUI.getViewConfiguration( + let paywallConfiguration = try await AdaptyUI.getPaywallConfiguration( forPaywall: paywall ) // use loaded configuration } catch { // handle the error } ``` メソッドの詳細については、[ペイウォールビルダーで作成したペイウォールのビュー設定を取得する](get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をご覧ください。 ## SwiftUI のパラメータを変更する \{#change-parameters-in-swiftui\} SwiftUI に以下の変更が加えられています: 1. `didCancelPurchase` パラメータが削除されました。代わりに `didFinishPurchase` を使用してください。 2. `.paywall()` メソッドはペイウォールオブジェクトを受け付けなくなりました。 3. `paywallConfiguration` パラメータが `viewConfiguration` パラメータに置き換わりました。 次のようにコードを更新してください: ```diff showLineNumbers @State var paywallPresented = false var body: some View { Text("Hello, AdaptyUI!") .paywall( isPresented: $paywallPresented, - paywall: <paywall object>, - viewConfiguration: <LocalizedViewConfiguration>, + paywallConfiguration: <AdaptyUI.PaywallConfiguration>, didPerformAction: { action in switch action { case .close: paywallPresented = false default: // Handle other actions break } }, - didFinishPurchase: { product, profile in paywallPresented = false }, + didFinishPurchase: { product, purchaseResult in /* handle the result*/ }, didFailPurchase: { product, error in /* handle the error */ }, didFinishRestore: { profile in /* check access level and dismiss */ }, didFailRestore: { error in /* handle the error */ }, didFailRendering: { error in paywallPresented = false } - didCancelPurchase: { product in /* handle the result*/} ) } ``` ## App Store からのプロモーション用アプリ内課金の処理を更新する \{#update-handling-of-promotional-in-app-purchases-from-app-store\} 以下の例のように `AdaptyDelegate` メソッドから `defermentCompletion` パラメータを削除して、App Store からのプロモーション用アプリ内課金の処理方法を更新してください: ```swift showLineNumbers title="Swift" final class YourAdaptyDelegateImplementation: AdaptyDelegate { nonisolated func shouldAddStorePayment(for product: AdaptyDeferredProduct) -> Bool { // 1a. // Return `true` to continue the transaction in your app. // 1b. // Store the product object and return `false` to defer or cancel the transaction. false } // 2. Continue the deferred purchase later on by passing the product to `makePurchase` func continueDeferredPurchase() async { let storedProduct: AdaptyDeferredProduct = // get the product object from the 1b. do { try await Adapty.makePurchase(product: storedProduct) } catch { // handle the error } } } ``` ## getProductsIntroductoryOfferEligibility メソッドを削除する \{#remove-getproductsintroductoryoffereligibility-method\} Adapty iOS SDK 3.3.0 より前は、ユーザーが対象かどうかに関わらず、プロダクトオブジェクトには常にオファーが含まれていました。そのため、オファーを使用する前に資格を手動で確認する必要がありました。 現在は、ユーザーが対象の場合にのみプロダクトオブジェクトにオファーが含まれます。つまり、資格を確認する必要はなくなりました。オファーが存在する場合、そのユーザーは対象です。 対象外のユーザーのオファーを確認したい場合は、`sk1Product` および `sk2Product` を参照してください。 ## サードパーティインテグレーション SDK の設定を更新する \{#update-third-party-integration-sdk-configuration\} Adapty iOS SDK 3.3.0 から、`updateAttribution` メソッドの公開 API が更新されました。以前は `[AnyHashable: Any]` 辞書を受け付けており、各サービスのアトリビューションオブジェクトをそのまま渡すことができました。現在は `[String: any Sendable]` が必要なため、渡す前にアトリビューションオブジェクトを変換する必要があります。 Adapty iOS SDK 3.3.0 以降でインテグレーションが正常に動作するよう、以下のセクションに従って各インテグレーションの SDK 設定を更新してください。 ### Adjust 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Adjust インテグレーションの SDK 設定](adjust#connect-your-app-to-adjust)をご確認ください。 <Tabs groupId="current-os" queryString> <TabItem value="v5" label="Adjust 5.x+" default> ```diff showLineNumbers class AdjustModuleImplementation { - func updateAdjustAttribution() { - Adjust.attribution { attribution in - guard let attributionDictionary = attribution?.dictionary()?.toSendableDict() else { return } - - Adjust.adid { adid in - guard let adid else { return } - - Adapty.updateAttribution(attributionDictionary, source: .adjust, networkUserId: adid) { error in - // handle the error - } - } - } - } + func updateAdjustAdid() { + Adjust.adid { adid in + guard let adid else { return } + + Adapty.setIntegrationIdentifier(key: "adjust_device_id", value: adid) + } + } + + func updateAdjustAttribution() { + Adjust.attribution { attribution in + guard let attribution = attribution?.dictionary() else { + return + } + + Adapty.updateAttribution(attribution, source: "adjust") + } + } } ``` </TabItem> <TabItem value="v4" label="Adjust 4.x" default> ```diff showLineNumbers class YourAdjustDelegateImplementation { // Find your implementation of AdjustDelegate // and update adjustAttributionChanged method: func adjustAttributionChanged(_ attribution: ADJAttribution?) { - if let attribution = attribution?.dictionary()?.toSendableDict() { - Adapty.updateAttribution(attribution, source: .adjust) + if let attribution = attribution?.dictionary() { + Adapty.updateAttribution(attribution, source: "adjust") } } } ``` </TabItem> </Tabs> ### AirBridge 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AirBridge インテグレーションの SDK 設定](airbridge#connect-your-app-to-airbridge)をご確認ください。 ```diff showLineNumbers import AirBridge - let builder = AdaptyProfileParameters.Builder() - .with(airbridgeDeviceId: AirBridge.deviceUUID()) - - Adapty.updateProfile(params: builder.build()) + do { + try await Adapty.setIntegrationIdentifier( + key: "airbridge_device_id", + value: AirBridge.deviceUUID() + ) + } catch { + // handle the error + } ``` ### Amplitude 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Amplitude インテグレーションの SDK 設定](amplitude#sdk-configuration)をご確認ください。 ```diff showLineNumbers import Amplitude - let builder = AdaptyProfileParameters.Builder() - .with(amplitudeUserId: Amplitude.instance().userId) - .with(amplitudeDeviceId: Amplitude.instance().deviceId) - - Adapty.updateProfile(params: builder.build()) + do { + try await Adapty.setIntegrationIdentifier( + key: "amplitude_user_id", + value: Amplitude.instance().userId + ) + try await Adapty.setIntegrationIdentifier( + key: "amplitude_device_id", + value: Amplitude.instance().deviceId + ) + } catch { + // handle the error + } ``` ### AppMetrica 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppMetrica インテグレーションの SDK 設定](appmetrica#sdk-configuration)をご確認ください。 ```diff showLineNumbers import AppMetricaCore - if let deviceID = AppMetrica.deviceID { - let builder = AdaptyProfileParameters.Builder() - .with(appmetricaDeviceId: deviceID) - .with(appmetricaProfileId: "YOUR_ADAPTY_CUSTOMER_USER_ID") - - Adapty.updateProfile(params: builder.build()) - } + if let deviceID = AppMetrica.deviceID { + do { + try await Adapty.setIntegrationIdentifier( + key: "appmetrica_device_id", + value: deviceID + ) + try await Adapty.setIntegrationIdentifier( + key: "appmetrica_profile_id", + value: "YOUR_ADAPTY_CUSTOMER_USER_ID" + ) + } catch { + // handle the error + } + } ``` ### AppsFlyer 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppsFlyer インテグレーションの SDK 設定](appsflyer#connect-your-app-to-appsflyer)をご確認ください。 ```diff showLineNumbers class YourAppsFlyerLibDelegateImplementation { // Find your implementation of AppsFlyerLibDelegate // and update onConversionDataSuccess method: func onConversionDataSuccess(_ conversionInfo: [AnyHashable : Any]) { let uid = AppsFlyerLib.shared().getAppsFlyerUID() - Adapty.updateAttribution( - conversionInfo.toSendableDict(), - source: .appsflyer, - networkUserId: uid - ) + Adapty.setIntegrationIdentifier(key: "appsflyer_id", value: uid) + Adapty.updateAttribution(conversionInfo, source: "appsflyer") } } ``` ### Branch 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Branch インテグレーションの SDK 設定](branch#connect-your-app-to-branch)をご確認ください。 ```diff showLineNumbers class YourBranchImplementation { func initializeBranch() { // Pass the attribution you receive from the initializing method of Branch iOS SDK to Adapty. Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in - if let data = data?.toSendableDict() { - Adapty.updateAttribution(data, source: .branch) - } + if let data { + Adapty.updateAttribution(data, source: "branch") + } } } } ``` ### Facebook Ads 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Facebook Ads インテグレーションの SDK 設定](facebook-ads#connect-your-app-to-facebook-ads)をご確認ください。 ```diff showLineNumbers import FacebookCore - let builder = AdaptyProfileParameters.Builder() - .with(facebookAnonymousId: AppEvents.shared.anonymousID) - - do { - try Adapty.updateProfile(params: builder.build()) - } catch { - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "facebook_anonymous_id", + value: AppEvents.shared.anonymousID + ) + } catch { + // handle the error + } ``` ### Firebase と Google Analytics 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Firebase と Google Analytics インテグレーションの SDK 設定](firebase-and-google-analytics)をご確認ください。 ```diff showLineNumbers import FirebaseCore import FirebaseAnalytics FirebaseApp.configure() - if let appInstanceId = Analytics.appInstanceID() { - let builder = AdaptyProfileParameters.Builder() - .with(firebaseAppInstanceId: appInstanceId) - Adapty.updateProfile(params: builder.build()) { error in - // handle error - } - } + if let appInstanceId = Analytics.appInstanceID() { + do { + try await Adapty.setIntegrationIdentifier( + key: "firebase_app_instance_id", + value: appInstanceId + ) + } catch { + // handle the error + } + } ``` ### Mixpanel 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Mixpanel インテグレーションの SDK 設定](mixpanel#sdk-configuration)をご確認ください。 ```diff showLineNumbers import Mixpanel - let builder = AdaptyProfileParameters.Builder() - .with(mixpanelUserId: Mixpanel.mainInstance().distinctId) - - do { - try await Adapty.updateProfile(params: builder.build()) - } catch { - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "mixpanel_user_id", + value: Mixpanel.mainInstance().distinctId + ) + } catch { + // handle the error + } ``` ### OneSignal 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[OneSignal インテグレーションの SDK 設定](onesignal#sdk-configuration)をご確認ください。 ```diff showLineNumbers // PlayerID (pre-v5 OneSignal SDK) // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { - let params = AdaptyProfileParameters.Builder() - .with(oneSignalPlayerId: playerId) - .build() - - Adapty.updateProfile(params:params) { error in - // check error - } + Task { + try await Adapty.setIntegrationIdentifier( + key: "one_signal_player_id", + value: playerId + ) + } } } // SubscriptionID (v5+ OneSignal SDK) OneSignal.Notifications.requestPermission({ accepted in - let id = OneSignal.User.pushSubscription.id - - let builder = AdaptyProfileParameters.Builder() - .with(oneSignalSubscriptionId: id) - - Adapty.updateProfile(params: builder.build()) + Task { + try await Adapty.setIntegrationIdentifier( + key: "one_signal_subscription_id", + value: OneSignal.User.pushSubscription.id + ) + } }, fallbackToSettings: true) ``` ### Pushwoosh 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Pushwoosh インテグレーションの SDK 設定](pushwoosh#sdk-configuration)をご確認ください。 ```diff showLineNumbers - let params = AdaptyProfileParameters.Builder() - .with(pushwooshHWID: Pushwoosh.sharedInstance().getHWID()) - .build() - - Adapty.updateProfile(params: params) { error in - // handle the error - } + do { + try await Adapty.setIntegrationIdentifier( + key: "pushwoosh_hwid", + value: Pushwoosh.sharedInstance().getHWID() + ) + } catch { + // handle the error + } ``` ## オブザーバーモードの実装を更新する \{#update-observer-mode-implementation\} ペイウォールとトランザクションを紐付ける方法を更新してください。以前は `setVariationId` メソッドを使用して `variationId` を割り当てていました。現在は、新しい `reportTransaction` メソッドを使用してトランザクションを記録する際に `variationId` を直接含めることができます。最終的なコード例については、[オブザーバーモードでペイウォールを購入トランザクションに関連付ける](report-transactions-observer-mode)をご確認ください。 :::warning `reportTransaction` メソッドを使用してトランザクションを必ず記録してください。この手順を省略すると、Adapty はトランザクションを認識できず、アクセスレベルの付与、アナリティクスへの反映、インテグレーションへの送信が行われません。この手順は必須です! ::: ```diff showLineNumbers - let variationId = paywall.variationId - - // There are two overloads: for StoreKit 1 and StoreKit 2 - Adapty.setVariationId(variationId, forPurchasedTransaction: transaction) { error in - if error == nil { - // successful binding - } - } + do { + // every time when calling transaction.finish() + try await Adapty.reportTransaction(transaction, withVariationId: <YOUR_PAYWALL_VARIATION_ID>) + } catch { + // handle the error + } ``` --- # File: migration-to-ios-sdk-v3 --- --- title: "Adapty iOS SDK を v3.0 に移行する" description: "パフォーマンスの向上と新しいマネタイズ機能のために、Adapty iOS SDK v3.0 に移行しましょう。" --- Adapty SDK v3.0 では、新しい [Adapty ペイウォールビルダー](adapty-paywall-builder)をサポートしています。これはペイウォールをノーコードで作成できる使いやすいツールの最新バージョンです。高い柔軟性と豊富なデザイン機能により、ペイウォールの効果と収益性をさらに高めることができます。 :::info AdaptyUI ライブラリは非推奨となり、現在は AdaptySDK の一部として含まれています。 ::: ## Swift Package Manager で Adapty SDK v3.x を再インストールする \{#reinstall-adapty-sdk-v3x-via-swift-package-manager\} 1. AdaptyUI SDK のパッケージ依存関係をプロジェクトから削除してください。今後は不要です。 2. すでに追加済みであっても、Adapty SDK の依存関係を再追加する必要があります。Xcode で **File** -> **Add Package Dependency...** を開いてください。パッケージ依存関係の追加方法は Xcode のバージョンによって異なる場合があります。必要に応じて Xcode のドキュメントをご参照ください。 3. リポジトリ URL `https://github.com/adaptyteam/AdaptySDK-iOS.git` を入力してください。 4. バージョンを選択し、**Add package** ボタンをクリックしてください。 5. 必要なモジュールを選択してください: 1. **Adapty** は必須モジュールです。 2. **AdaptyUI** は [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なオプションモジュールです。 6. Xcode がプロジェクトにパッケージ依存関係を追加します。インポートするには、**Choose Package Products** ウィンドウで **Add package** ボタンを再度クリックしてください。パッケージが **Packages** リストに表示されます。 ## CocoaPods で Adapty SDK v3.x を再インストールする \{#reinstall-adapty-sdk-v3x-via-cocoapods\} 1. `Podfile` に Adapty を追加してください。必要なモジュールを選択してください: 1. **Adapty** は必須モジュールです。 2. **AdaptyUI** は [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なオプションモジュールです。 2. ```shell showLineNumbers title="Podfile" pod 'Adapty', '~> 3.2.0' pod 'AdaptyUI', '~> 3.2.0' # optional module needed only for Paywall Builder ``` 3. 次を実行してください: ```sh showLineNumbers title="Shell" pod install ``` これにより、アプリ用の `.xcworkspace` ファイルが作成されます。以後のアプリ開発にはこのファイルを使用してください。 Adapty および AdaptyUI SDK モジュールを有効化してください。v3.0 以前は AdaptyUI を有効化していませんでしたが、**AdaptyUI の有効化を追加**することを忘れないでください。パラメーターに変更はないため、そのまま使用してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers // In your AppDelegate class: let configurationBuilder = AdaptyConfiguration .Builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) .with(customerUserId: "YOUR_USER_ID") .with(idfaCollectionDisabled: false) .with(ipAddressCollectionDisabled: false) Adapty.activate(with: configurationBuilder) { error in // handle the error } // Only if you are going to use AdaptyUI AdaptyUI.activate() ``` </TabItem> <TabItem value="swiftui" label="SwiftUI" default> ```swift title="" showLineNumbers @main struct SampleApp: App { init() let configurationBuilder = AdaptyConfiguration .Builder(withAPIKey: "PUBLIC_SDK_KEY") .with(observerMode: false) // optional .with(customerUserId: "YOUR_USER_ID") // optional .with(idfaCollectionDisabled: false) // optional .with(ipAddressCollectionDisabled: false) // optional Adapty.activate(with: configurationBuilder) { error in // handle the error } // Only if you are going to use AdaptyUI AdaptyUI.activate() } var body: some Scene { WindowGroup { ContentView() } } } ``` </TabItem> </Tabs> --- # End of Documentation _Generated on: 2026-07-24T13:00:57.682Z_ _Successfully processed: 44/44 files_ # KMP - 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.684Z Total files: 48 --- # File: kmp-sdk-overview --- --- title: "Kotlin Multiplatform SDK 概要" description: "Adapty Kotlin Multiplatform SDK とその主な機能について学びましょう。" --- [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-KMP.svg?style=flat&logo=kotlin)](https://github.com/adaptyteam/AdaptySDK-KMP/releases) ようこそ!アプリ内課金をもっと簡単にするお手伝いをします 🚀 Adapty Kotlin Multiplatform SDK は、アプリ内課金の煩わしさを取り除き、あなたが本来得意とすること――素晴らしいアプリの開発――に集中できるよう設計されています。以下の機能を標準で提供します: - 購入処理、レシート検証、サブスクリプション管理をすぐに利用可能 - アプリのアップデートなしにペイウォールの作成とテストが可能 - ゼロ設定で詳細な購入分析を提供 — コホート、LTV、チャーン、ファネル分析を含む - アプリセッションやデバイスをまたいでユーザーのサブスクリプション状態を常に最新に保つ - たった1行のコードでマーケティングアトリビューションや分析サービスとアプリを連携 :::note コードに入る前に、Adapty と Google Play Console を連携し、ダッシュボードでプロダクトを設定する必要があります。まずは[クイックスタートガイド](quickstart)ですべての設定を完了させてください。 ::: ## はじめる \{#get-started\} 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. インテグレーションガイドで扱う内容は次のとおりです: 1. [SDK のインストールと設定](sdk-installation-kotlin-multiplatform):SDK をプロジェクトの依存関係として追加し、コードで有効化します。 2. [フローを通じて購入を有効化](kmp-quickstart-paywalls):ユーザーがプロダクトを購入できるよう購入フローを設定します。独自の UI を構築する場合は、代わりに[ペイウォールを手動で実装する](kmp-quickstart-manual)を参照してください。 3. [サブスクリプション状態の確認](kmp-check-subscription-status):ユーザーのサブスクリプション状態を自動的に確認し、有料コンテンツへのアクセスを管理します。 4. [ユーザーの識別(任意)](kmp-quickstart-identify):ユーザーを Adapty のプロファイルに関連付けて、デバイスをまたいでデータを一貫して保存します。 ### 実際の動作を確認する \{#see-it-in-action\} 全体の流れを確認したいですか?以下のリソースをご活用ください: - **サンプルアプリ**:完全なセットアップを示す[サンプル例](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)をご覧ください - **動画チュートリアル**:以下のステップバイステップ実装動画でご確認ください <iframe width="560" height="315" src="https://www.youtube.com/embed/JfwJvwnloNw?si=HskPxRk4WGkF_u9s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ## 主要なコンセプト \{#main-concepts\} コードに入る前に、Adapty を動かす主要なコンセプトを理解しておきましょう。 Adapty のアプローチの優れた点は、アプリにハードコードするのはプレースメントのみという点です。プロダクト、ペイウォールのデザイン、価格、オファーなど、その他すべては Adapty ダッシュボードからアプリのアップデートなしに柔軟に管理できます: 1. [**プロダクト**](product) — アプリ内で購入できるもの全般。サブスクリプション、消耗型アイテム、永続アクセスが含まれます。 2. **フローまたはペイウォール** — プレースメントに紐づいた、設定を持つプロダクトのまとまり。2つの種類があります: - **[フロー](adapty-flow-builder)** — フロービルダーで構築されたビジュアルなノーコードインターフェース。Adapty が UI をレンダリングし、購入処理も行います。 - **[ペイウォール](paywalls)** — ビジュアル設定なし。自分のコードで UI を構築し、`makePurchase` を自分で呼び出します。[ペイウォールを手動で実装する](kmp-quickstart-manual)を参照してください。 SDK のコードでは、どちらも同じ `getFlow` メソッドで取得します。 3. [**プレースメント**](placements) — ユーザージャーニーの中でフローやペイウォールを表示したい戦略的なポイント。プレースメントは収益化戦略の「どこで」「いつ」を表します。一般的なプレースメントの例: - `main` — 主要なペイウォールの表示場所 - `onboarding` — ユーザーのオンボーディングフロー中に表示 - `settings` — アプリの設定からアクセス可能 最初のインテグレーションでは `main` や `onboarding` といった基本的なものから始め、その後[アプリ内でユーザーが購入意欲を持ちやすい他の場所](choose-meaningful-placements)を検討してみましょう。 4. [**プロファイル**](profiles-crm) — ユーザーがプロダクトを購入すると、プロファイルに**アクセスレベル**が付与され、有料機能へのアクセス制御に使用します。 --- # File: sdk-installation-kotlin-multiplatform --- --- title: "Adapty Kotlin Multiplatform SDKのインストールと設定" description: "Kotlin MultiplatformアプリにAdapty SDKをインストールおよび設定する方法。" --- Adapty SDKは、モバイルアプリへのシームレスな統合を実現する2つの主要モジュールで構成されています。 - **Core Adapty**: Adapty がアプリで正しく機能するために必要な、必須の SDK です。 - **AdaptyUI** (`io.adapty:adapty-kmp-ui`): Compose Multiplatform レンダリングレイヤー(`view.present()`)で [Adapty ペイウォールビルダー](adapty-paywall-builder) を使用する場合に必要なモジュールです。プロジェクトで Compose Multiplatform を使用しない場合は、代わりにコアモジュールの [`createNativePaywallView`](kmp-present-paywalls#without-compose-multiplatform) と [`createNativeOnboardingView`](kmp-present-onboardings#without-compose-multiplatform) を使用できます。 :::tip Adapty SDK がモバイルアプリにどのように統合されるか、実際の例を確認したいですか?ペイウォールの表示、購入処理、その他の基本的な機能を含む完全なセットアップを示す[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)をご覧ください。 ::: 完全な実装のウォークスルーについては、こちらの動画もご参照ください: <iframe width="560" height="315" src="https://www.youtube.com/embed/JfwJvwnloNw?si=HskPxRk4WGkF_u9s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> ## 動作要件 \{#requirements\} Adapty Kotlin Multiplatform SDK は Xcode 16.2 以降に対応しています。 :::info SDK v3.17 以降、Adapty SDK はデフォルトで Google Play Billing Library v8.0.0 を使用します。 ::: :::info SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ::: ## GradleでAdapty SDKをインストールする \{#install-adapty-sdk-via-gradle\} Android・iOSアプリの両方で、GradleによるAdapty SDKのインストールが必要です。 依存関係の設定方法を選んでください: - 標準のGradle:**モジュールレベル**の `build.gradle` に依存関係を追加する - プロジェクトで `.gradle.kts` ファイルを使用している場合は、**モジュールレベル**の `build.gradle.kts` に依存関係を追加する - バージョンカタログを使用している場合は、`libs.versions.toml` ファイルに依存関係を追加し、`build.gradle.kts` でそれを参照する :::important Adapty Kotlin Multiplatform SDK 4.0 はプレリリース版です。Gradle は動的バージョン範囲(`+` や `latest.release` など)ではプレリリースバージョンを自動選択しないため、`io.adapty:adapty-kmp:4.0.0-beta.1` や `libs.versions.toml` での `adapty-kmp = "4.0.0-beta.1"` のように、バージョンを明示的に指定する必要があります。詳しくは [Adapty Kotlin Multiplatform SDK を v4 へ移行する](migration-to-kmp-sdk-v4) を参照してください。 ::: <Tabs> <TabItem value="module-level build.gradle" label="module-level build.gradle" default> ```kotlin showLineNumbers kotlin { sourceSets { commonMain { dependencies { implementation libs.adapty.kmp } } } } ``` </TabItem> <TabItem value="module-level build.gradle.kts" label="module-level build.gradle.kts" default> ```kotlin showLineNumbers kotlin { sourceSets { val commonMain by getting { dependencies { implementation(libs.adapty.kmp) } } } } ``` </TabItem> <TabItem value="version-catalog" label="バージョンライブラリ" default> ```toml showLineNumbers // libs.versions.toml [versions] .. adapty-kmp = "<the latest SDK version>" [libraries] .. adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" } // build.gradle.kts kotlin { sourceSets { val commonMain by getting { dependencies { implementation(libs.adapty.kmp) } } } } ``` </TabItem> </Tabs> :::note Mavenに関連するエラーが発生した場合は、Gradleスクリプトに `mavenCentral()` が含まれているか確認してください。 <details> <summary>追加方法の手順</summary> プロジェクトの `settings.gradle` に `dependencyResolutionManagement` がない場合は、トップレベルの `build.gradle` の repositories の末尾に以下を追加してください: ```groovy showLineNumbers title="top-level build.gradle" allprojects { repositories { ... mavenCentral() } } ``` `dependencyResolutionManagement` がある場合は、`settings.gradle` の `dependencyResolutionManagement` セクション内の `repositories` に以下を追加してください: ```groovy showLineNumbers title="settings.gradle" dependencyResolutionManagement { ... repositories { ... google() mavenCentral() } } ``` </details> ::: ## Adapty SDK を有効化する \{#activate-adapty-sdk\} ### 基本的なセットアップ \{#basic-setup\} 初期化はできるだけ早い段階で追加してください。通常は、両プラットフォーム共通のKotlinコードに記述します。 :::note Adapty SDKはアプリ内で一度だけ有効化すれば十分です。 ::: ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` :::important `activate`の完了を待ってから、他のAdapty SDKメソッドを呼び出してください。完全な順序については、[Kotlin Multiplatform SDKの呼び出し順序](kmp-sdk-call-order)を参照してください。 ::: **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"`を置き換えます。 :::info - Adaptyの初期化にはPublic SDKキーを使用してください。Secretキーは[サーバーサイドAPI](getting-started-with-server-side-api)専用です。 - SDKキーはアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 ::: 次に、アプリにペイウォールを設定します: - [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、まず以下で[AdaptyUI モジュールを有効化](#activate-adaptyui-module-of-adapty-sdk)してから、[ペイウォールビルダークイックスタート](kmp-quickstart-paywalls)に進んでください。 - 独自のペイウォール UI を作成する場合は、[カスタムペイウォールのクイックスタート](kmp-quickstart-manual)を参照してください。 ## AdaptyUI モジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [Adapty ペイウォールビルダー](kmp-present-paywalls)を使用するために **AdaptyUI** モジュールを有効化する場合は、設定で `.withActivateUI(true)` を指定してください。 :::info important コード内では、AdaptyUI を有効化する前に、コアの Adapty モジュールを先に有効化する必要があります。 ::: ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withActivateUI(true) // true for activating the AdaptyUI module .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` ## Proguard の設定(Android) \{#configure-proguard-android\} 本番環境でアプリを公開する前に、Proguard の設定に `-keep class com.adapty.** { *; }` を追加する必要がある場合があります。 ## オプション設定 \{#optional-setup\} ### ログ \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty は、何が起きているかを把握できるよう、エラーやその他の重要な情報をログに記録します。以下のログレベルが利用できます。 | Level | Description | | :----------------------- | :------------------------------------------------------------------------------------------------------------------------ | | `AdaptyLogLevel.ERROR` | エラーのみがログに記録されます。 | | `AdaptyLogLevel.WARN` | エラーと、重大なエラーは引き起こさないが注意が必要なSDKからのメッセージがログに記録されます。 | | `AdaptyLogLevel.INFO` | エラー、警告、および各種情報メッセージがログに記録されます。デフォルト値。 | | `AdaptyLogLevel.VERBOSE` | 関数呼び出し、APIクエリなど、デバッグ時に役立つ可能性のある追加情報がログに記録されます。 | | `AdaptyLogLevel.DEBUG` | 内部デバッグデータを含む、最も詳細な情報がログに記録されます。 | アプリでAdaptyを設定する前に、ログレベルを設定できます。 ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withLogLevel(AdaptyLogLevel.VERBOSE) // recommended for development .build() ``` ### データポリシー \{#data-policies\} #### IPアドレスの収集と共有を無効にする \{#disable-ip-address-collection-and-sharing\} Adaptyモジュールを有効化する際に、`ipAddressCollectionDisabled` を `true` に設定すると、ユーザーのIPアドレスの収集と共有を無効にできます。デフォルト値は `false` です。 このパラメータは、ユーザーのプライバシーを強化したい場合、GDPRやCCPAなどの地域のデータ保護規制に準拠したい場合、またはIPベースの機能がアプリに不要なときに不要なデータ収集を減らしたい場合にご利用ください。 ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withIpAddressCollectionDisabled(true) .build() ``` #### 広告IDの収集と共有を無効にする \{#disable-advertising-id-collection-and-sharing\} Adaptyモジュールを有効化する際に、`appleIdfaCollectionDisabled`(iOS)または`googleAdvertisingIdCollectionDisabled`(Android)を`true`に設定すると、広告識別子の収集を無効にできます。デフォルト値は`false`です。 App Store/Play Storeのポリシーへの準拠、App Tracking Transparencyプロンプトの表示回避、または広告IDに基づくアドバタイジングアトリビューションや分析がアプリに不要な場合に、このパラメーターを使用してください。 ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withGoogleAdvertisingIdCollectionDisabled(true) // Android only .withAppleIdfaCollectionDisabled(true) // iOS only .build() ``` #### AdaptyUI のメディアキャッシュ設定 \{#set-up-media-cache-configuration-for-adaptyui\} デフォルトでは、AdaptyUI はパフォーマンスを向上させ、ネットワーク使用量を削減するために、メディア(画像や動画など)をキャッシュします。カスタム設定を指定することで、キャッシュの設定を変更できます。 `mediaCache` を使用して、デフォルトのキャッシュ設定を上書きできます。 ```kotlin val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withMediaCacheConfiguration( AdaptyConfig.MediaCacheConfiguration( memoryStorageTotalCostLimit = 200 * 1024 * 1024, // 200 MB memoryStorageCountLimit = Int.MAX_VALUE, diskStorageSizeLimit = 200 * 1024 * 1024 // 200 MB ) ) .build() ``` ### ローカルアクセスレベルの有効化(Android) \{#enable-local-access-levels-android\} デフォルトでは、Android では[ローカルアクセスレベル](local-access-levels)が無効になっています。有効にするには、`withLocalAccessLevelAllowed` を `true` に設定します: ```kotlin title="Kotlin" showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withGoogleLocalAccessLevelAllowed(true) .build() ``` ### バックアップ復元時のデータ削除 \{#clear-data-on-backup-restore\} `withAppleClearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検出し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールなど、ローカルに保存されているすべてのSDKデータを削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```swift showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withAppleClearDataOnBackup(true) .build() ``` ## トラブルシューティング \{#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` ファイルのルートの `<manifest>` タグに tools が含まれていることを確認してください: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. `<application>` でバックアップ属性を上書きする \{#2-override-backup-attributes-in-application\} 同じ `AndroidManifest.xml` ファイルで、`<application>` タグを更新して、アプリが最終的な値を提供し、マニフェストマージャーにライブラリの値を置き換えるよう指示します: ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` いずれかの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" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Android 11以前**(従来のフルバックアップコンテンツ形式を使用): ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> :::important Kotlin Multiplatform プロジェクトでは、APK/AAB を生成する Android アプリケーションモジュール(例: `androidApp` または `app`)にこれらの変更を適用してください: - マニフェスト: `androidApp/src/main/AndroidManifest.xml` - バックアップルール XML: `androidApp/src/main/res/xml/` ::: #### Android で別のアプリから戻った後に購入が失敗する \{#purchases-fail-after-returning-from-another-app-in-android\} 購入フローを開始するアクティビティが非デフォルトの `launchMode` を使用している場合、ユーザーが Google Play、銀行アプリ、またはブラウザから戻ってきたときに、Android がアクティビティを誤って再生成または再利用することがあります。これにより、購入結果が失われたり、キャンセル済みとして処理される場合があります。 購入が正常に機能するよう、購入フローを開始するアクティビティには `standard` または `singleTop` のランチモードのみを使用し、それ以外のモードは避けてください。 `AndroidManifest.xml` で、購入フローを開始するアクティビティが `standard` または `singleTop` に設定されていることを確認してください。 ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` --- # File: kmp-quickstart-paywalls --- --- title: "Kotlin Multiplatform SDKでFlow Builderを使ったアプリ内課金の有効化" description: "AdaptyのFlow Builderでアプリ内課金を有効化するためのクイックスタートガイド。" --- このガイドでは、Adapty Kotlin Multiplatform SDK v4(ベータ版)の API を使用しています。v3 をお使いの場合は、対応するメソッド名について[移行ガイド](migration-to-kmp-sdk-v4)を参照してください。 アプリ内課金を有効にするには、3 つの重要な概念を理解する必要があります: - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**フロー**](adapty-flow-builder) – ノーコードのフロービルダーで作成した、プロダクトをユーザーに提示する画面シーケンス。SDKは`getFlow`で取得します。独自のコードでUIを構築したい場合はペイウォールを使用してください([ペイウォールを手動で実装する](kmp-quickstart-manual)を参照)。 - [**プレースメント**](placements) – アプリのどこでいつフローを表示するかを指定します(`main`、`onboarding`、`settings`など)。ダッシュボードでフローをプレースメントに紐付け、コードからはプレースメントIDで取得します。これにより、A/B テストの実施や異なるユーザーへの異なるフローの表示が簡単にできます。 Adapty では、アプリで購入を有効にする方法を3つ提供しています。アプリの要件に応じて、いずれかを選択してください。 | 実装方法 | 複雑さ | 使用するタイミング | |---|---|---| | Adapty フロービルダー | ✅ 簡単 | [ノーコードビルダーで購入対応フローを完全に作成します](quickstart-paywalls)。Adapty が自動的にレンダリングし、購入フロー全体、レシート検証、サブスクリプション管理をすべて裏側で処理します。 | | 手動作成ペイウォール | 🟡 中程度 | ペイウォールの UI はアプリのコードで実装しますが、プロダクトの柔軟性を維持するためにフローオブジェクトは Adapty から取得します。[ガイド](kmp-quickstart-manual)を参照してください。 | | オブザーバーモード | 🔴 難しい | すでに独自の購入処理インフラがあり、それを引き続き使用したい場合に選択します。オブザーバーモードには Adapty における制限がある点に注意してください。[記事](observer-vs-full-mode)を参照してください。 | :::important **以下の手順は、Adapty フロービルダーで作成したフローを実装する方法を示しています。** ペイウォールのUIを自分でビルドしたい場合は、[ペイウォールを手動で実装する](kmp-quickstart-manual)を参照してください。 ::: Adapty フロービルダーで作成したフローを表示するには、アプリのコード内で以下の操作だけ行えば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-kotlin-multiplatform)。 :::tip これらの手順を最も素早く完了するには、[クイックスタートガイド](quickstart)に従うか、[Developer CLI](developer-cli-quickstart)を使用してフローとプレースメントを作成してください。 ::: ## 1. フローを取得する \{#1-get-the-flow\} フローはダッシュボードで設定したプレースメントに紐付けられています。プレースメントを使うと、オーディエンスごとに異なるフローを表示したり、[A/B テスト](ab-tests)を実施したりできます。 Adapty フロービルダーで作成したフローを取得するには、次の手順を行います。 1. `getFlow` メソッドを使って、[プレースメント](placements) ID から `flow` オブジェクトを取得します。 2. `createFlowView` メソッドを使って、フローのビューを作成します。ビューにはフローを表示するために必要な UI 要素とスタイリングが含まれています。フローにビューが設定されていない場合、`createFlowView` はエラーを返すため、`onError` でハンドリングしてください。 :::important ビューを取得するには、フロービルダーで **Show on device** トグルをオンにする必要があります。オンにしていない場合、`createFlowView` はエラーを返し、フローは表示されません。 ::: ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // the flow has no view configured, or view creation failed } } .onError { error -> // handle the error } ``` ## 2. フローを表示する \{#display-the-flow\} フローを取得したら、数行のコードを追加するだけで表示できます。 デバイス画面にビジュアルフローを表示するには、まずビューを作成する必要があります。そのために、`AdaptyUI.createFlowView()` メソッドを呼び出します: ```kotlin showLineNumbers AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // handle the error } ``` ビューが正常に作成されたら、デバイスの画面に表示できます。各ビューは一度しか使用できません。`dismiss()` を呼び出した後、再度フローを表示するには `createFlowView` を呼び出してください。 :::tip フローの表示方法の詳細については、[ガイド](kmp-present-paywalls)をご覧ください。 ::: ## 3. ボタンアクションを処理する \{#handle-button-actions\} ユーザーがフロー内のボタンをクリックすると、Kotlin Multiplatform SDK は購入、復元、フローのクローズ、リンクの開封を自動的に処理します。 ただし、カスタムまたは事前定義された ID を持つボタンは、コードでアクションを処理する必要があります。また、デフォルトの動作を上書きしたい場合もあります。 例えば、以下はクローズボタンのデフォルト動作です。コードに追加する必要はありませんが、必要な場合にどのように実装するかを確認できます。 デフォルトでは、購入が完了してもフローは開いたままになります。購入完了後にフローを閉じたい場合は、`flowViewDidFinishPurchase` コールバック内でビューを閉じてください。 :::tip ボタンの[アクション](kmp-handle-paywall-actions)と[イベント](kmp-handling-events)の処理方法については、ガイドをご覧ください。 ::: ```kotlin showLineNumbers AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } else -> Unit } } override fun flowViewDidFinishPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) { mainUiScope.launch { view.dismiss() } } } }) ``` ## 次のステップ \{#next-steps\} ペイウォールをアプリに表示する準備ができました。[App Storeサンドボックス](test-purchases-in-sandbox)または[Google Play Store](testing-on-android)でテスト購入を行い、ペイウォールからテスト購入が完了できることを確認してください。 次に、[ユーザーのアクセスレベルを確認](kmp-check-subscription-status)して、適切なユーザーにペイウォールを表示したり、有料機能へのアクセスを付与したりするようにしてください。 ## 完全な例 \{#full-example\} 以下は、これらのステップをアプリにまとめて統合する方法です。 ```kotlin showLineNumbers // Set up the observer for handling flow events AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } else -> Unit } } override fun flowViewDidFinishPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { if (purchaseResult !is AdaptyPurchaseResult.UserCanceled) { mainUiScope.launch { view.dismiss() } } } }) // Get and display the flow Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // the flow has no view configured — use custom logic } } .onError { error -> // handle the error } ``` --- # File: kmp-check-subscription-status --- --- title: "Kotlin Multiplatform SDKでサブスクリプションのステータスを確認する" description: "AdaptyでKotlin Multiplatformアプリのサブスクリプションステータスを確認する方法を学びましょう。" --- ユーザーが有料コンテンツにアクセスできるかどうか、またはペイウォールを表示するかどうかを判断するには、プロファイル内の[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態にアクセスして、ペイウォールを表示するか有料機能へのアクセスを許可するかを判断する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ペイウォールや有料コンテンツをユーザーに表示するかどうかを決める際には、プロファイル内の[アクセスレベル](access-level)を確認します。方法は2つあります。 - アプリ起動時など、最新のプロファイルデータがすぐに必要な場合や強制的に更新したい場合は、`getProfile` を呼び出す。 - **プロファイルの自動更新**を設定して、サブスクリプションのステータスが変わるたびに自動的に更新されるローカルコピーを保持する。 ### プロファイルを取得する \{#get-profile\} サブスクリプションのステータスを確認するもっとも簡単な方法は、`getProfile` メソッドを使ってプロファイルにアクセスすることです。 ```kotlin showLineNumbers Adapty.getProfile() .onSuccess { profile -> // check the access } .onError { error -> // handle the error } ``` ### サブスクリプションの更新を監視する \{#listen-to-subscription-updates\} アプリ内でプロファイルの更新を自動的に受け取るには、次のようにします。 1. `Adapty.setOnProfileUpdatedListener()` を使ってプロファイルの変更を監視する。ユーザーのサブスクリプションステータスが変わるたびに、Adaptyが自動的にこのメソッドを呼び出します。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存しておくと、追加のネットワークリクエストなしにアプリ全体で利用できます。 ```kotlin showLineNumbers class SubscriptionManager { private var currentProfile: AdaptyProfile? = null init { // Listen for profile updates Adapty.setOnProfileUpdatedListener { profile -> currentProfile = profile // Update UI, unlock content, etc. } } // Use stored profile instead of calling getProfile() fun hasAccess(): Boolean { return currentProfile?.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true } } ``` :::note Adaptyはアプリ起動時にプロファイル更新リスナーを自動的に呼び出し、デバイスがオフラインでもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールのロジックを連携させる \{#connect-profile-with-paywall-logic\} ペイウォールの表示や有料機能へのアクセス許可をすぐに判断する必要がある場合は、ユーザーのプロファイルを直接確認できます。この方法は、アプリ起動時、プレミアムセクションへの遷移時、特定のコンテンツ表示前といったシナリオで役立ちます。 ```kotlin showLineNumbers private fun checkAccessAndShowPaywall() { // First, check if user has access Adapty.getProfile() .onSuccess { profile -> val hasAccess = profile.accessLevels?.get("YOUR_ACCESS_LEVEL")?.isActive == true if (!hasAccess) { // User doesn't have access, show paywall showPaywall() } else { // User has access, show premium content showPremiumContent() } } .onError { error -> // If we can't check access, show paywall as fallback showPaywall() } } private fun showPaywall() { // Get and display paywall using the KMP SDK Adapty.getPaywall("YOUR_PLACEMENT_ID") .onSuccess { paywall -> if (paywall.hasViewConfiguration) { val paywallView = AdaptyUI.createPaywallView(paywall = paywall) paywallView?.present() } else { // Handle remote config paywall or show custom UI handleRemoteConfigPaywall(paywall) } } .onError { error -> // Handle paywall loading error showError("Unable to load paywall") } } private fun showPremiumContent() { // Show your premium content here // This is where you unlock paid features } ``` ## 次のステップ \{#next-steps\} サブスクリプションのステータスを追跡する方法を理解したら、次は[ユーザープロファイルの操作](kmp-quickstart-identify)を学んで、ユーザーが購入済みのコンテンツに確実にアクセスできるようにしましょう。 --- # File: kmp-quickstart-identify --- --- title: "Kotlin Multiplatform SDKでユーザーを識別する" description: "KMPでアプリ内サブスクリプション管理のためにAdaptyをセットアップするためのクイックスタートガイド。" --- :::important このガイドは、独自の認証システムをお持ちの方を対象としています。ここでは、既存の認証システムと連携するように、Adaptyでユーザープロファイルを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回のインストールとしてカウントされます。 :::note バックアップからの復元は再インストールとは異なる動作をします。デフォルトでは、ユーザーがバックアップから復元した場合、SDKはキャッシュされたデータを保持し、新しいプロファイルは作成しません。この動作は`withAppleClearDataOnBackup`設定で変更できます。[詳細を確認する](sdk-installation-kotlin-multiplatform#clear-data-on-backup-restore)。 ::: ## 識別済みユーザー \{#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)をご覧ください。 ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(たとえば、アプリへのログインやサインアップ後など)、`identify`メソッドを使用してカスタマーユーザーIDを設定します。 - **このカスタマーユーザーIDを以前に使用したことがない**場合、Adaptyは自動的に現在のプロファイルにリンクします。 - **このカスタマーユーザーIDでユーザーを以前に識別したことがある**場合、AdaptyはそのカスタマーユーザーIDに関連付けられたプロファイルを使用するよう切り替えます。 :::important カスタマーユーザーIDは各ユーザーで一意である必要があります。パラメータの値をハードコードすると、すべてのユーザーが同一人物とみなされます。 ::: 他のSDKメソッドを呼び出す前に、`identify`の完了(`onSuccess`コールバック)を待ってください。同時に呼び出すと、匿名プロファイルに処理が行われる可能性があります。[Kotlin Multiplatform SDKでの呼び出し順序](kmp-sdk-call-order)を参照してください。 ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID") // Unique for each user .onSuccess { // successful identify } .onError { error -> // handle the error } ``` ### SDKアクティベーション時 \{#during-the-sdk-activation\} SDKをアクティベートする際にすでにカスタマーユーザーIDが分かっている場合、`identify`を別途呼び出す代わりに`activate`メソッドで渡すことができます。 カスタマーユーザーIDが分かっているにもかかわらず、アクティベーション後にのみ設定した場合、アクティベーション時にAdaptyが新しい匿名プロファイルを作成し、`identify`を呼び出した後にのみ既存のプロファイルに切り替わることになります。 既存のカスタマーユーザーID(以前に使用したもの)でも新しいものでも渡すことができます。新しいものを渡した場合、アクティベーション時に作成された新しいプロファイルが自動的にそのカスタマーユーザーIDにリンクされます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスのダッシュボードに影響しません。インストール数はデバイスIDに基づいてカウントされるためです。 デバイスIDは、デバイス上のストアからのアプリの単一のインストールを表し、アプリが再インストールされた場合にのみ再生成されます。 初回インストールか再インストールか、または既存のカスタマーユーザーIDが使用されているかどうかには依存しません。 プロファイルの作成(SDKのアクティベーション時またはログアウト時)、ログイン、またはアプリを再インストールせずにアップグレードしても、追加のインストールイベントは生成されません。 デバイスではなくユニークユーザーに基づいてインストール数をカウントしたい場合は、**App settings**に移動して[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```kotlin showLineNumbers AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("user123") // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. .build() ``` ### ユーザーのログアウト \{#log-users-out\} ユーザーのログアウトボタンがある場合は、`logout`メソッドを使用します。 :::important ユーザーをログアウトすると、そのユーザーのために新しい匿名プロファイルが作成されます。 ::: ```kotlin showLineNumbers Adapty.logout() .onSuccess { // successful logout } .onError { error -> // handle the error } ``` :::info ユーザーをアプリに再度ログインさせるには、`identify`メソッドを使用します。 ::: ### ログインなしでの購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリへのログイン前後の両方で購入できる場合、ログイン後もアクセスが維持されるように設定する必要があります。 1. ログアウト状態のユーザーが購入すると、Adaptyはその購入を匿名プロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルを使用するよう切り替わります。 - 新しいカスタマーユーザーIDの場合(たとえば、登録前に購入が行われた場合)、Adaptyは現在のプロファイルにカスタマーユーザーIDを割り当てるため、すべての購入履歴が維持されます。 - 既存のカスタマーユーザーIDの場合(カスタマーユーザーIDがすでにプロファイルにリンクされている場合)、プロファイルの切り替え後に実際のアクセスレベルを取得する必要があります。識別後すぐに[`getProfile`](kmp-check-subscription-status)を呼び出すか、[プロファイルの更新をリッスンする](kmp-check-subscription-status)ことでデータが自動的に同期されます。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内課金のロジックが実装できました!アプリの収益化がうまくいくことを願っています! Adaptyをさらに活用するために、以下のトピックも確認してください。 - [**テスト**](troubleshooting-test-purchases):すべてが期待どおりに動作することを確認する - [**インテグレーション**](configuration):マーケティングアトリビューションや分析サービスとわずか1行のコードで連携する - [**カスタムプロファイル属性の設定**](kmp-setting-user-attributes):ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/Bテストを実施したり、ユーザーに応じて異なるペイウォールを表示したりする --- # File: adapty-sdk-integration-skill-kmp --- --- title: "SDK統合スキルを使ってKotlin MultiplatformアプリにAdaptyを組み込む" description: "adapty-sdk-integrationスキルを使用して、AIコーディングツールでKotlin MultiplatformアプリにAdapty SDKをエンドツーエンドで統合します。" --- :::important このスキルはベータ版です。処理が止まったり予期しない動作をした場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor-kmp)を参照してください。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-kmp --- --- title: "AIアシスタンスを使ってAdaptyをKotlin Multiplatformアプリに統合する" description: "Cursor、Context7、ChatGPT、Claude、またはその他のAIツールを使用して、Kotlin MultiplatformアプリにAdaptyを統合するためのステップバイステップガイド。" --- このガイドでは、AIコーディングツールを使いながら、Kotlin MultiplatformアプリへのAdapty統合をステップバイステップで進めます。適切な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** に移動し、KMPアプリがApp StoreとGoogle Play両方を対象とする場合は両方接続してください。これは購入機能を動作させるために必要です。 [アプリストアを接続する](integrate-payments) 2. **Public SDK keyをコピーする**: Adapty ダッシュボードで **App settings → General** に移動し、**API keys** セクションを確認してください。コード上では、Adaptyの設定ビルダーに渡す文字列です。 3. **プロダクトを少なくとも1つ作成する**: Adapty ダッシュボードの **Products** ページで作成してください。コードからプロダクトを直接参照することはなく、Adaptyはペイウォール経由でプロダクトを配信します。 [プロダクトを追加する](quickstart-products) 4. **ペイウォールとプレースメントを作成する**: Adapty ダッシュボードの **Paywalls** ページでペイウォールを作成し、**Placements** ページでプレースメントに割り当ててください。コード上では、`Adapty.getPaywall("YOUR_PLACEMENT_ID")` に渡す文字列がプレースメントIDです。 [ペイウォールを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**: Adapty ダッシュボードの **Products** ページで各プロダクトに対して設定してください。コード上では `profile.accessLevels["premium"]?.isActive` で確認する文字列です。デフォルトの `premium` アクセスレベルはほとんどのアプリで使えます。プロダクトによってアクセスできる機能が異なる場合(例: `basic` プランと `pro` プラン)は、コーディングを始める前に[追加のアクセスレベルを作成](assigning-access-level-to-a-product)してください。 :::tip 5つすべて揃ったら、コードを書く準備ができています。LLMに「Public SDK keyは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サーバーです。質問内容に応じて必要なドキュメントを自動的に取得するため、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 Kotlin Multiplatform SDK ``` :::warning Context7を使えばドキュメントのリンクを手動で貼る手間は省けますが、実装の順序は重要です。以下の[実装ウォークスルー](#implementation-walkthrough)をステップごとに進めて、確実に動作させてください。 ::: ### プレーンテキストのドキュメントを使う \{#use-plain-text-docs\} AdaptyのドキュメントはどれもプレーンテキストのMarkdownで取得できます。URLの末尾に `.md` を付けるか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例: [adapty-cursor-kmp.md](https://adapty.io/docs/ja/adapty-cursor-kmp.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が自動的にレンダリングします。 - [**手動作成のペイウォール**](kmp-making-purchases): 自分でペイウォールUIをコードで作成しますが、プロダクトの取得と購入処理にはAdaptyを使います。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラをそのまま使い、Adaptyはアナリティクスと連携のみに使います。 どれを選べばいいか迷ったら、[クイックスタートの比較表](kmp-quickstart-paywalls)を参照してください。 ### SDKのインストールと設定 \{#install-and-configure-the-sdk\} GradleでAdapty SDKの依存関係を追加し、Public SDK keyで有効化してください。これがすべての基盤になります。 **ガイド:** [Adapty SDKのインストールと設定](sdk-installation-kotlin-multiplatform) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-kotlin-multiplatform.md ``` :::tip[チェックポイント] - **期待される結果:** アプリがビルドされ、起動します。Logcat(Android)またはXcodeコンソール(iOS)にAdaptyの有効化ログが表示されます。 - **注意点:** 「Public API key is missing」→ プレースホルダーをApp settingsの実際のキーに置き換えたか確認してください。 ::: ### ペイウォールの表示と購入処理 \{#show-paywalls-and-handle-purchases\} プレースメントIDでペイウォールを取得し、表示して、購入イベントを処理します。必要なガイドは購入の実装方法によって異なります。 進めながら都度サンドボックスで購入をテストしてください。最後まで待たないようにしましょう。設定方法は[サンドボックスでの購入テスト](test-purchases-in-sandbox)を参照してください。 <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **ガイド:** - [ペイウォールを使って購入を有効化する(クイックスタート)](kmp-quickstart-paywalls) - [ペイウォールビルダーのペイウォールと設定を取得する](kmp-get-pb-paywalls) - [ペイウォールを表示する](kmp-present-paywalls) - [ペイウォールのイベントを処理する](kmp-handling-events) - [ボタンアクションに対応する](kmp-handle-paywall-actions) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/kmp-quickstart-paywalls.md - https://adapty.io/docs/ja/kmp-get-pb-paywalls.md - https://adapty.io/docs/ja/kmp-present-paywalls.md - https://adapty.io/docs/ja/kmp-handling-events.md - https://adapty.io/docs/ja/kmp-handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される結果:** 設定したプロダクトとともにペイウォールが表示されます。プロダクトをタップするとサンドボックスの購入ダイアログが表示されます。 - **注意点:** ペイウォールが空または `getPaywall` エラーが出る → プレースメントIDがダッシュボードと完全に一致しているか、プレースメントにオーディエンスが設定されているか確認してください。 ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **ガイド:** - [カスタムペイウォールで購入を有効化する(クイックスタート)](kmp-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products-kmp) - [リモートコンフィグで設計したペイウォールをレンダリングする](present-remote-config-paywalls-kmp) - [購入を行う](kmp-making-purchases) - [購入を復元する](kmp-restore-purchase) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/kmp-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products-kmp.md - https://adapty.io/docs/ja/present-remote-config-paywalls-kmp.md - https://adapty.io/docs/ja/kmp-making-purchases.md - https://adapty.io/docs/ja/kmp-restore-purchase.md ``` :::tip[チェックポイント] - **期待される結果:** カスタムペイウォールにAdaptyから取得したプロダクトが表示されます。プロダクトをタップするとサンドボックスの購入ダイアログが表示されます。 - **注意点:** プロダクトの配列が空 → ダッシュボードのペイウォールにプロダクトが設定されているか、プレースメントにオーディエンスが設定されているか確認してください。 ::: </TabItem> <TabItem value="observer" label="Observer mode"> **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードを実装する](implement-observer-mode-kmp) - [オブザーバーモードでトランザクションを報告する](report-transactions-observer-mode-kmp) 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-kmp.md - https://adapty.io/docs/ja/report-transactions-observer-mode-kmp.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローでサンドボックス購入を行った後、トランザクションがAdaptyダッシュボードの **Event Feed** に表示されます。 - **注意点:** イベントが表示されない → Adaptyへのトランザクション報告が実装されているか、両ストアのサーバー通知が設定されているか確認してください。 ::: </TabItem> </Tabs> ### サブスクリプションのステータスを確認する \{#check-subscription-status\} 購入後、ユーザープロファイルのアクティブなアクセスレベルを確認してプレミアムコンテンツを制限します。 **ガイド:** [サブスクリプションのステータスを確認する](kmp-check-subscription-status) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/kmp-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックス購入後、`profile.accessLevels["premium"]?.isActive` が `true` を返します。 - **注意点:** 購入後に `accessLevels` が空 → ダッシュボードでプロダクトにアクセスレベルが設定されているか確認してください。 ::: ### ユーザーを識別する \{#identify-users\} アプリのユーザーアカウントをAdaptyプロファイルに紐付けて、デバイスをまたいで購入情報を引き継げるようにします。 :::important アプリに認証機能がない場合は、このステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](kmp-quickstart-identify) LLMに送る内容: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/kmp-quickstart-identify.md ``` :::tip[チェックポイント] - **期待される結果:** `Adapty.identify("your-user-id")` を呼び出した後、ダッシュボードの **Profiles** セクションにカスタムユーザーIDが表示されます。 - **注意点:** 匿名プロファイルへのアトリビューションを避けるため、`identify` はアクティベーション後、ペイウォールの取得前に呼び出してください。 ::: ### リリースの準備をする \{#prepare-for-release\} サンドボックスで統合の動作確認ができたら、リリースチェックリストを確認してすべて本番環境に対応しているか確認しましょう。 **ガイド:** [リリースチェックリスト](release-checklist) LLMに送る内容: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ja/release-checklist.md ``` :::tip[チェックポイント] - **期待される結果:** すべてのチェックリスト項目が確認済み:ストアの接続、サーバー通知、購入フロー、アクセスレベルの確認、プライバシー要件。 - **注意点:** サーバー通知が未設定 → **App 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つのファイルにまとめたものです。非常に大きいため、全体像が必要なときだけ使用してください。 - Kotlin Multiplatform専用の [`kmp-llms.txt`](https://adapty.io/docs/ja/kmp-llms.txt) と [`kmp-llms-full.txt`](https://adapty.io/docs/ja/kmp-llms-full.txt): サイト全体と比べてトークンを節約できるプラットフォーム別サブセットです。 --- # File: kmp-paywalls --- --- title: "フローとペイウォール - Kotlin Multiplatform" description: "Kotlin Multiplatformアプリで、Adapty Flow BuilderまたはPaywall Builderで作成したフローとペイウォールを表示・管理します。" --- ## ペイウォールを表示する \{#display-paywalls\} ### Adapty Flow Builder & Paywall Builder \{#adapty-flow-builder--paywall-builder\} <CustomDocCardList ids={['kmp-get-pb-paywalls', 'kmp-present-paywalls', 'kmp-handling-events', 'kmp-handle-paywall-actions']} /> :::tip Adapty ペイウォールビルダーのペイウォールをすぐに使い始めるには、[クイックスタートガイド](kmp-quickstart-paywalls)をご覧ください。 ::: ### ペイウォールを手動で実装する \{#implement-paywalls-manually\} <CustomDocCardList ids={['kmp-quickstart-manual', 'fetch-paywalls-and-products-kmp', 'present-remote-config-paywalls-kmp', 'kmp-making-purchases']} /> ペイウォールの実装と購入の手動処理に関するその他のガイドは、[カテゴリ](kmp-implement-paywalls-manually)をご覧ください。 ## 便利な機能 \{#useful-features\} <CustomDocCardList ids={['kmp-use-fallback-paywalls', 'kmp-web-paywalls']} /> --- # File: kmp-get-pb-paywalls --- --- title: "フローとペイウォールの取得 - Kotlin Multiplatform" description: "Kotlin MultiplatformアプリでAdaptyからフローとペイウォールを取得します。" --- <SDKv4> <MethodPromo method="getFlow" /> [フローまたはペイウォールビルダーのペイウォールを設計](adapty-paywall-builder)したら、モバイルアプリにそれを表示できます。最初のステップは、プレースメントに関連付けられたフローまたはペイウォールと、以下で説明するビュー設定を取得することです。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリにフローを表示する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成してプロダクトを追加する](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成してフロー/ペイウォールを追加する](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-kotlin-multiplatform) をインストールする。 </details> ## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} フロービルダーまたはペイウォールビルダーを使ってフローやペイウォールを作成した場合、モバイルアプリのコードでそれをレンダリングしてユーザーに表示する手間は必要ありません。こうしたフローやペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントからIDを取得し、ビュー設定を取得して、モバイルアプリ上で表示する処理は必要です。 最適なパフォーマンスを確保するには、フローまたはペイウォールとその[ビュー設定](kmp-get-pb-paywalls#fetch-the-view-configuration)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します: ```kotlin showLineNumbers Adapty.getFlow( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { flow -> // the requested flow/paywall }.onError { error -> // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` の使用を検討してください。これはキャッシュが存在する場合にキャッシュデータを返します。この場合、ユーザーが最新のデータを取得できないことがありますが、接続状況にかかわらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける用途では安全に使用できます。</p><p></p><p>キャッシュはアプリ再起動後も保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はフローとペイウォールをローカルに2つの層で保存します。上記の定期更新キャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、より高速な取得のために CDN を使用し、CDN に到達できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定する値です。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>まれに、内部で複数のリクエストが発生するため、`loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p><p>Kotlin Multiplatform の場合: `5.seconds` のような拡張関数で `Duration` を作成できます。`.seconds` は `kotlin.time.Duration.Companion.seconds` によって提供されます。</p> | レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------- | | Flow | プレースメント、識別子(`instanceIdentity`、`variationId`)、名前、ペイウォールのバリアント(`paywalls` — `AdaptyFlowPaywall` のリスト)、リモートコンフィグ(`remoteConfigs` — ロケールごとに1エントリのリスト)を含む `AdaptyFlow` オブジェクト。プリロード、カスタム UI、またはプログラムによる確認のために実際のプロダクトを取得するには、`getPaywallProducts(flow)` を呼び出してください。 | ## ビューの設定を取得する \{#fetch-the-view-configuration\} フローまたはペイウォールを取得したら、`createFlowView` メソッドを使ってビューの設定を読み込み、ビューを一度に作成します。確認が必要な別のフラグはありません。プレースメントが **Flow Builder**(フロー)または **Paywall Builder**(ペイウォール)で設計されている場合、`createFlowView` は表示準備の整ったビューを返します。プレースメントがビルダー UI のないカスタムペイウォールの場合、`createFlowView` は `AdaptyResult.Error` を返します。その場合は[リモートコンフィグペイウォールとして処理してください](present-remote-config-paywalls-kmp)。 :::important Flow Builderで **Show on device** トグルを必ず有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ```kotlin showLineNumbers AdaptyUI.createFlowView( flow = flow, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { view -> // use view }.onError { error -> // the flow has no view configured, or view creation failed } ``` | パラメータ | 必須/任意 | 説明 | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **flow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | | **loadTimeout** | 任意 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルのフォールバックが返されます。内部的に複数のリクエストで構成される場合があるため、指定した `loadTimeout` より若干遅れてタイムアウトすることがあります。`kotlin.time.Duration.Companion` の `5.seconds` などの拡張関数を利用できます。 | | **preloadProducts** | 任意 | `true` に設定すると、パフォーマンス向上のためにプロダクトを事前読み込みします。有効にすると、プロダクトが事前に読み込まれ、フローやペイウォールの表示にかかる時間が短縮されます。 | | **productPurchaseParams** | 任意 | [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) から [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/) へのマップです。フローやペイウォール内の個々のプロダクトに対して、パーソナライズドオファーやサブスクリプション更新パラメータなど、購入固有のパラメータを設定するために使用します。 | :::note 複数の言語を使用している場合は、[ビルダーのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の追加方法をご確認ください。 ::: 読み込みが完了したら、[フローまたはペイウォールを表示](kmp-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` をご利用ください。 ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。この方式では常に最新のデータをユーザーに提供できるため、こちらをお勧めします。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はそのデータを返します。この場合、ユーザーが受け取るデータが最新でない可能性はありますが、接続状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても問題ありません。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持されます。クリアされるのは、アプリのアンインストール時または手動でクリーンアップした場合のみです。</p> | ## アセットのカスタマイズ \{#customize-assets\} フローまたはペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、事前に定義されたID(`hero_image` と `hero_video`)があります。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のことができます: - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像を読み込んでいる間、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 カスタムアセットをマップ経由で提供する方法の例を示します。 :::info Kotlin Multiplatform SDK はローカルアセットのみをサポートしています。リモートコンテンツの場合は、カスタムアセットとして使用する前にアセットをダウンロードしてローカルにキャッシュしてください。 ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Map<String, AdaptyCustomAsset> = mapOf( // Load image from app resources (bundled with the app) // Files should be placed in commonMain/composeResources/files/ "hero_image" to AdaptyCustomAsset.localImageResource( path = heroImagePath ), // Or use image byte data "avatar" to AdaptyCustomAsset.localImageData( data = imageByteData ), // Load video from app resources "demo_video" to AdaptyCustomAsset.localVideoResource( path = demoVideoPath ), // Or use a video file from device storage "intro_video" to AdaptyCustomAsset.localVideoFile( path = "/path/to/local/video.mp4" ), // Apply custom brand colors "brand_primary" to AdaptyCustomAsset.color( colorHex = "#FF6B35" ), // Create gradient background "card_gradient" to AdaptyCustomAsset.linearGradient( colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"), stops = listOf(0.0f, 0.5f, 1.0f) ) ) // Use custom assets when creating the flow view AdaptyUI.createFlowView( flow = flow, customAssets = customAssets ).onSuccess { view -> // Present the flow with custom assets view.present() }.onError { error -> // Handle the error - the flow will fall back to default appearance } } ``` :::note アセットが見つからないか読み込みに失敗した場合、フローまたはペイウォールはビルダーで設定されたデフォルトの外観にフォールバックします。 ::: </SDKv4> <SDKv3> [Adapty ダッシュボードの新しいペイウォールビルダーでペイウォールのビジュアル部分をデザイン](adapty-paywall-builder)したら、モバイルアプリにそれを表示できます。最初のステップは、以下の説明に従って、プレースメントに紐付いたペイウォールとそのビュー設定を取得することです。 ペイウォールビルダーでカスタマイズしたペイウォールに関するトピックです。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォールのペイウォールとプロダクトの取得](fetch-paywalls-and-products-kmp)トピックをご参照ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールの表示を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加する](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加する](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-kotlin-multiplatform) をインストールする。 </details> ## ペイウォールビルダーで作成したペイウォールの取得 \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーを使ってペイウォールをデザインした](adapty-paywall-builder)場合、ユーザーに表示するためのレンダリングコードをアプリ内に書く必要はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントからペイウォールのIDを取得し、ビュー設定を取得した上で、モバイルアプリ内に表示する必要があります。 最適なパフォーマンスを確保するために、ペイウォールとその[ビュー設定](kmp-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します: ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードである必要があります。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードとその推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この設定を推奨します。ユーザーが常に最新のデータを受け取れるためです。</p><p></p><p>ただし、ユーザーが不安定なインターネット接続を使用していると考えられる場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュされたデータを返します。この場合、ユーザーは必ずしも最新のデータを受け取れるわけではありませんが、接続状況に関わらず高速な読み込みを体験できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても安全です。</p><p></p><p>アプリを再起動してもキャッシュは維持され、アプリの再インストールまたは手動でのクリア時にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存します: 上記の定期更新キャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールをより高速に取得するために CDN を使用し、CDN が利用できない場合に備えてスタンドアロンのフォールバックサーバーも使用しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p>なお、このメソッドは内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間より若干遅れてタイムアウトすることがあります。</p><p>Kotlin Multiplatform の場合: 拡張関数(例: `5.seconds`、`.seconds` は `import com.adapty.utils.seconds` から)または `TimeInterval.seconds(5)` を使って `TimeInterval` を作成できます。制限なしに設定する場合は `TimeInterval.INFINITE` を使用してください。</p> | レスポンスパラメーター: | パラメーター | 説明 | | :-------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | プロダクトIDのリスト、ペイウォール識別子、リモートコンフィグ、その他のプロパティを含む [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーの **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、`ViewConfiguration` が含まれているかどうかを確認してください。これが含まれている場合、そのペイウォールはペイウォールビルダーで作成されたことを示します。`ViewConfiguration` が存在する場合はペイウォールビルダーのペイウォールとして扱い、存在しない場合は[リモートコンフィグのペイウォールとして処理してください](present-remote-config-paywalls-kmp)。 `createPaywallView` メソッドを使用して、ビューの設定を読み込みます。 ```kotlin showLineNumbers if (paywall.hasViewConfiguration) { AdaptyUI.createPaywallView( paywall = paywall, loadTimeout = 5.seconds, preloadProducts = true ).onSuccess { paywallView -> // use paywallView }.onError { error -> // handle the error } } else { // use your custom logic } ``` | パラメーター | 必須/任意 | 説明 | | :--------------------------- | :------------- | :----------------------------------------------------------- | | **paywall** | 必須 | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **loadTimeout** | 任意 | このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルのフォールバックが返されます。なお、このメソッドは内部で複数のリクエストを行う場合があるため、`loadTimeout` で指定した時間よりわずかに遅くタイムアウトすることがあります。`kotlin.time.Duration.Companion` の `5.seconds` のような拡張関数を使用できます。 | | **preloadProducts** | 任意 | プロダクトを事前読み込みしてパフォーマンスを向上させるには `true` に設定します。有効にすると、プロダクトが事前に読み込まれ、ペイウォールの表示に要する時間が短縮されます。 | | **productPurchaseParams** | 任意 | [`AdaptyProductIdentifier`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-product-identifier/) から [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/) へのマップ。ペイウォール内の個々のプロダクトに対して、パーソナライズドオファーやサブスクリプション更新パラメーターなど、購入固有のパラメーターを設定するために使用します。 | :::note 複数の言語を使用している場合は、[ペイウォールビルダーのローカライゼーションの追加](add-paywall-locale-in-adapty-paywall-builder)方法をご確認ください。 ::: 読み込みが完了したら、[ペイウォールを表示](kmp-present-paywalls)してください。 ## デフォルトオーディエンス向けペイウォールを取得して表示を高速化する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ瞬時に取得されるため、この処理を高速化することを気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が遅い場合、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したい場合があるでしょう。 この問題に対処するには、`getPaywallForDefaultAudience` メソッドを使用することで、**All Users** オーディエンスに対して指定プレースメントのペイウォールを取得できます。ただし、推奨される方法は `getPaywall` メソッドによるペイウォールの取得であることを理解しておくことが重要です。詳しくは上記の [ペイウォール情報の取得](#fetch-paywall-designed-with-paywall-builder) セクションをご覧ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **潜在的な後方互換性の問題**: 異なるアプリバージョン(現在および将来)でそれぞれ異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在(レガシー)バージョンをサポートするペイウォールを設計するか、現在(レガシー)バージョンのユーザーがペイウォールを正常に表示できない可能性を許容するかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーに **All Users** オーディエンス向けに設計された同一のペイウォールが表示されます。つまり、国、マーケティングのアトリビューション、独自のカスタム属性などに基づいたパーソナライズされたターゲティングが失われます。 デフォルトオーディエンス向けのペイウォール取得を高速化するメリットを優先する場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` を使用してください。 ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子です。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードとその推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるようにするため、この設定を推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を利用していると考えられる場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合にキャッシュされたデータを返します。この場合、最新のデータが得られないことがありますが、インターネット接続が不安定であっても読み込み時間が短くなります。キャッシュは定期的に更新されるため、ネットワークリクエストを避けるためにセッション中に使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリア時にのみ削除されます。</p> | ## アセットのカスタマイズ \{#customize-assets\} ペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、あらかじめ定義されたID(`hero_image` と `hero_video`)があります。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のようなことができます: - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中に、ローカルのプレビュー画像を表示する。 - 動画を再生する前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty SDK をバージョン 3.7.0 以上にアップデートしてください。 ::: カスタムアセットをマップ経由で提供する方法の例を示します。 :::info Kotlin Multiplatform SDK はローカルアセットのみをサポートしています。リモートコンテンツを使用する場合は、カスタムアセットで使用する前にアセットをダウンロードしてローカルにキャッシュしてください。 ::: ```kotlin showLineNumbers // Import generated Res class for accessing resources viewModelScope.launch { // Get URIs for bundled resources using Res.getUri() val heroImagePath = Res.getUri("files/images/hero_image.png") val demoVideoPath = Res.getUri("files/videos/demo_video.mp4") // Or read image as byte data val imageByteData = Res.readBytes("files/images/avatar.png") // Create custom assets map val customAssets: Map<String, AdaptyCustomAsset> = mapOf( // Load image from app resources (bundled with the app) // Files should be placed in commonMain/composeResources/files/ "hero_image" to AdaptyCustomAsset.localImageResource( path = heroImagePath ), // Or use image byte data "avatar" to AdaptyCustomAsset.localImageData( data = imageByteData ), // Load video from app resources "demo_video" to AdaptyCustomAsset.localVideoResource( path = demoVideoPath ), // Or use a video file from device storage "intro_video" to AdaptyCustomAsset.localVideoFile( path = "/path/to/local/video.mp4" ), // Apply custom brand colors "brand_primary" to AdaptyCustomAsset.color( colorHex = "#FF6B35" ), // Create gradient background "card_gradient" to AdaptyCustomAsset.linearGradient( colors = listOf("#1E3A8A", "#3B82F6", "#60A5FA"), stops = listOf(0.0f, 0.5f, 1.0f) ) ) // Use custom assets when creating paywall view AdaptyUI.createPaywallView( paywall = paywall, customAssets = customAssets ).onSuccess { paywallView -> // Present the paywall with custom assets paywallView.present() }.onError { error -> // Handle the error - paywall will fall back to default appearance } } ``` :::note アセットが見つからない場合やロードに失敗した場合、ペイウォールはペイウォールビルダーで設定されたデフォルトの外観にフォールバックします。 ::: </SDKv3> --- # File: kmp-present-paywalls --- --- title: "フローとペイウォールの表示 - Kotlin Multiplatform" description: "Kotlin Multiplatformアプリでユーザーにフローとペイウォールを表示します。" --- <SDKv4> <MethodPromo method="getFlow" label="フローとペイウォールの表示" /> フローまたはペイウォールを作成した場合、それをモバイルアプリのコードでレンダリングしてユーザーに表示する方法を心配する必要はありません。フローまたはペイウォールには、表示する内容とその表示方法の両方が含まれています。 :::warning このガイドは、Adapty によってレンダリングされるフローと**新しいペイウォールビルダーのペイウォール**を対象としています。リモートコンフィグのペイウォールと [Observer モード](observer-vs-full-mode) では、処理方法が異なります。 - **リモートコンフィグペイウォール**を表示する場合は、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls-kmp)を参照してください。 - **オブザーバーモード**でフローを表示する場合は、[オブザーバーモードでフローを表示する](kmp-present-flows-in-observer-mode)を参照してください。 ::: 以下で使用する `flow` オブジェクトの取得方法については、[フローとペイウォールの取得](kmp-get-pb-paywalls)を参照してください。 Adapty Kotlin Multiplatform SDK では、フローとペイウォールを表示する方法が2つあります: - **Compose Multiplatform を使用する場合** - **Compose Multiplatform を使用しない場合** ## Compose Multiplatform の場合 \{#with-compose-multiplatform\} フローまたはペイウォールを表示するには、[`createFlowView`](kmp-get-pb-paywalls#fetch-the-view-configuration) メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。フローを再度表示する必要がある場合は、`createFlowView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用すると、エラーが発生する場合があります。 ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createFlowView(flow = flow).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### ダイアログを表示する \{#show-dialog\} Android でフローまたはペイウォールが表示されている場合は、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートがフロービューの背後に表示されるため、ユーザーには見えません。このメソッドを使用することで、すべてのプラットフォームでフローの上に正しくダイアログが表示されます。 ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { view.showDialog( title = "Close this screen?", content = "You will lose access to exclusive offers.", primaryActionTitle = "Stay", secondaryActionTitle = "Close" ).onSuccess { action -> if (action == AdaptyUIDialogActionType.SECONDARY) { // User confirmed - close the flow view.dismiss() } // If primary - do nothing, user stays }.onError { error -> // handle the error } } ``` ### iOSのプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのフローまたはペイウォールの表示スタイルを設定できます。このパラメータには `AdaptyUIIOSPresentationStyle.FULLSCREEN`(デフォルト)または `AdaptyUIIOSPresentationStyle.PAGESHEET` を指定できます。 ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createFlowView(flow = flow).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ## Compose Multiplatformを使わない場合 \{#without-compose-multiplatform\} :::note `createNativeFlowView` はコアモジュール `io.adapty:adapty-kmp` の一部です。Compose Multiplatform を使用しないプロジェクトでは、`io.adapty:adapty-kmp-ui` の依存関係は不要です。 ::: Compose Multiplatform を使わずにフローやペイウォールを埋め込むには、`createNativeFlowView` を呼び出してください。返された `AdaptyNativeFlowView` をレイアウトに追加します。 <Tabs> <TabItem value="android" label="Android"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val nativeView = AdaptyUI.createNativeFlowView( context = context, viewModelStoreOwner = activity, flow = flow, observer = myFlowObserver, ) // Embed in your Compose layout: AndroidView( factory = { nativeView.view }, modifier = Modifier.fillMaxSize() ) ``` デフォルトでは、埋め込みビューはセーフエリアのパディングを適用しません。レイアウト側でインセットを処理する必要があります。ビュー自体にパディングを適用させたい場合は、`createNativeFlowView` に `androidEnableSafeArea = true` を渡してください。このパラメータは Android 専用です。 </TabItem> <TabItem value="ios" label="iOS"> KMP インターフェースのデフォルトメソッドは Swift で `@required` になるため、Swift から直接 `AdaptyUIFlowsEventsObserver` を実装することはできません。まず `iosMain` でオープン基底クラスを宣言してください: ```kotlin showLineNumbers title="iosMain (Kotlin)" open class BaseFlowObserver : AdaptyUIFlowsEventsObserver ``` Swiftでサブクラスを作成し、必要なメソッドのみをオーバーライドします: ```swift showLineNumbers title="Swift" class MyFlowObserver: BaseFlowObserver { override func flowViewDidPerformAction(view: AdaptyUIFlowView, action: any AdaptyUIAction) { if action is AdaptyUIActionCloseAction { // remove nativeView from your view hierarchy } } } let nativeView = AdaptyUI.shared.createNativeFlowView( flow: flow, observer: MyFlowObserver() ) // nativeView.viewController is a UIViewController. // Add it to your SwiftUI view or UIKit hierarchy. ``` </TabItem> </Tabs> ### ビューの破棄 \{#dispose-the-view\} ビューをレイアウトから削除する際は `dispose()` を呼び出してください。これにより、イベントリスナーの登録が解除され、内部リソースが解放されます。 ```kotlin showLineNumbers title="Kotlin Multiplatform" nativeView.dispose() ``` ## カスタムタグ \{#custom-tags\} カスタムタグを使えば、シナリオごとに別々のフローやペイウォールを作成する手間を省けます。ユーザーデータに基づいて動的に変化する単一のフローを想像してみてください。たとえば、「こんにちは!」という汎用的な挨拶の代わりに、「こんにちは、John さん!」や「こんにちは、Ann さん!」といった個人に向けた挨拶を表示できます。 カスタムタグの活用例をいくつか紹介します: - フローやペイウォールにユーザーの名前やメールアドレスを表示する。 - 今日の曜日を表示して購買意欲を高める(例:「ハッピーサーズデー」)。 - 販売しているプロダクトに関するパーソナライズされた詳細情報を追加する(フィットネスプログラムの名前や VoIP アプリの電話番号など)。 カスタムタグを使うと、さまざまな状況に適応する柔軟なフローを作成でき、アプリのインターフェースをよりパーソナライズされた魅力的なものにできます。 :::warning 場合によっては、アプリがカスタムタグの置換内容を把握できないことがあります。特にユーザーが古いバージョンの AdaptyUI SDK を使用している場合がそれにあたります。これを防ぐため、未知のカスタムタグを含む行を置き換えるフォールバックテキストを必ず追加してください。これを設定しないと、ユーザーにタグがコード(`<USERNAME/>`)のまま表示されることがあります。 ::: フローやペイウォールでカスタムタグを使用するには、フロービューを作成する際にタグを渡します。 <Tabs> <TabItem value="standalone" label="With Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) AdaptyUI.createFlowView( flow = flow, customTags = customTags ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Without Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativeFlowView( context = context, viewModelStoreOwner = activity, flow = flow, observer = myFlowObserver, customTags = customTags, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativeFlowView( flow = flow, observer = myFlowObserver, customTags = customTags, ) ``` </TabItem> </Tabs> ## カスタムタイマー \{#custom-timers\} タイマーは、期間限定のスペシャルオファーやシーズンオファーを訴求するのに役立つツールです。ただし、このタイマーはオファーの有効期限やキャンペーンの期間とは連動していません。設定した値からゼロに向かってカウントダウンするだけのシンプルなスタンドアロンのカウントダウンです。タイマーがゼロに達しても何も起こらず、そのままゼロの状態が続きます。 タイマーの前後にテキストをカスタマイズして、「オファー終了まで:10:00 秒」のようなメッセージを作成できます。 フローまたはペイウォールでカスタムタイマーを使用するには、フロービューを作成する際に渡してください: <Tabs> <TabItem value="standalone" label="With Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) AdaptyUI.createFlowView( flow = flow, customTimers = customTimers ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Without Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativeFlowView( context = context, viewModelStoreOwner = activity, flow = flow, observer = myFlowObserver, customTimers = customTimers, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativeFlowView( flow = flow, observer = myFlowObserver, customTimers = customTimers, ) ``` </TabItem> </Tabs> </SDKv4> <SDKv3> ペイウォールビルダーを使ってペイウォールをカスタマイズした場合、モバイルアプリのコードでレンダリングしてユーザーに表示する手間はかかりません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このガイドは**新しいペイウォールビルダーのペイウォール**専用です。リモートコンフィグで設計されたペイウォールや [Observer mode](observer-vs-full-mode) では、ペイウォールの表示方法が異なります。 **リモートコンフィグのペイウォール**を表示する方法については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls-kmp)を参照してください。 ::: Adapty Kotlin Multiplatform SDKは、ペイウォールを表示する2つの方法を提供します: - **Compose Multiplatformを使用する場合** - **Compose Multiplatformを使用しない場合** ## Compose Multiplatform を使用する場合 \{#with-compose-multiplatform\} ペイウォールを表示するには、[`createPaywallView`](kmp-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) メソッドで作成した `view` の `view.present()` メソッドを使用します。各 `view` は一度しか使用できません。再度ペイウォールを表示する必要がある場合は、`createPaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用すると、エラーが発生することがあります。 ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createPaywallView(paywall = paywall).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### ダイアログを表示する \{#show-dialog\} Android でペイウォールが表示されている場合、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートはペイウォールの背面に表示されるため、ユーザーから見えなくなります。このメソッドを使用することで、すべてのプラットフォームでペイウォールの上に正しくダイアログを表示できます。 ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { view.showDialog( title = "Close paywall?", content = "You will lose access to exclusive offers.", primaryActionTitle = "Stay", secondaryActionTitle = "Close" ).onSuccess { action -> if (action == AdaptyUIDialogActionType.SECONDARY) { // User confirmed - close the paywall view.dismiss() } // If primary - do nothing, user stays }.onError { error -> // handle the error } } ``` ### iOS のプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのペイウォールの表示方法を設定できます。パラメータには `AdaptyUIIOSPresentationStyle.FULLSCREEN`(デフォルト)または `AdaptyUIIOSPresentationStyle.PAGESHEET` を指定できます。 ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createPaywallView(paywall = paywall).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ## Compose Multiplatformなしで使う \{#without-compose-multiplatform\} :::note `createNativePaywallView`はコア`io.adapty:adapty-kmp`モジュールの一部です。Compose Multiplatformを使用しないプロジェクトでは、`io.adapty:adapty-kmp-ui`依存関係は不要です。 ::: Compose Multiplatformなしでペイウォールを埋め込むには、`createNativePaywallView`を呼び出します。これはレイアウトに追加する`AdaptyNativePaywallView`を返します: <Tabs> <TabItem value="android" label="Android"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val nativeView = AdaptyUI.createNativePaywallView( context = context, viewModelStoreOwner = activity, paywall = paywall, observer = myPaywallObserver, ) // Embed in your Compose layout: AndroidView( factory = { nativeView.view }, modifier = Modifier.fillMaxSize() ) ``` </TabItem> <TabItem value="ios" label="iOS"> KMP インターフェースのデフォルトメソッドは Swift では `@required` になるため、Swift から直接 `AdaptyUIPaywallsEventsObserver` を実装することはできません。まず `iosMain` でオープン基底クラスを宣言してください: ```kotlin showLineNumbers title="iosMain (Kotlin)" open class BasePaywallObserver : AdaptyUIPaywallsEventsObserver ``` 次に、必要なメソッドだけをオーバーライドしてSwiftでサブクラスを作成します。 ```swift showLineNumbers title="Swift" class MyPaywallObserver: BasePaywallObserver { override func paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: any AdaptyUIAction) { if action is AdaptyUIActionCloseAction { // remove nativeView from your view hierarchy } } } let nativeView = AdaptyUI.shared.createNativePaywallView( paywall: paywall, observer: MyPaywallObserver() ) // nativeView.viewController is a UIViewController. // Add it to your SwiftUI view or UIKit hierarchy. ``` </TabItem> </Tabs> ### ビューの破棄 \{#dispose-the-view\} ビューをレイアウトから削除する際は `dispose()` を呼び出してください。これにより、イベントリスナーの登録が解除され、内部リソースが解放されます。 ```kotlin showLineNumbers title="Kotlin Multiplatform" nativeView.dispose() ``` ## カスタムタグ \{#custom-tags\} カスタムタグを使うと、シナリオごとに別々のペイウォールを作成しなくて済みます。ユーザーデータに基づいて動的に変化する1つのペイウォールを想像してみてください。たとえば、「こんにちは!」という汎用的な挨拶の代わりに、「こんにちは、John!」や「こんにちは、Ann!」のようにユーザーを名前で呼ぶことができます。 カスタムタグの活用例をいくつかご紹介します: - ペイウォールにユーザーの名前やメールアドレスを表示する。 - 売上アップのために現在の曜日を表示する(例:「ハッピーサーズデー」)。 - 販売しているプロダクトに関するパーソナライズされた詳細を追加する(フィットネスプログラムの名前や、VoIPアプリの電話番号など)。 カスタムタグを使用すると、さまざまな状況に適応する柔軟なペイウォールを作成でき、アプリのインターフェースをよりパーソナライズされた魅力的なものにできます。 :::warning アプリが カスタムタグの置換内容を認識できない場合があります—特にユーザーが古いバージョンの AdaptyUI SDK を使用している場合です。これを防ぐため、未知のカスタムタグを含む行を置き換えるフォールバックテキストを必ず追加してください。設定しないと、ユーザーにタグがコード(`<USERNAME/>`)としてそのまま表示される可能性があります。 ::: ペイウォールでカスタムタグを使用するには、ペイウォールビューを作成する際にカスタムタグを渡します: <Tabs> <TabItem value="standalone" label="With Compose Multiplatform" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) AdaptyUI.createPaywallView( paywall = paywall, customTags = customTags ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Without Compose Multiplatform"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativePaywallView( context = context, viewModelStoreOwner = activity, paywall = paywall, observer = myPaywallObserver, customTags = customTags, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTags = mapOf( "USERNAME" to "John", "DAY_OF_WEEK" to "Thursday" ) val nativeView = AdaptyUI.createNativePaywallView( paywall = paywall, observer = myPaywallObserver, customTags = customTags, ) ``` </TabItem> </Tabs> ## カスタムタイマー \{#custom-timers\} ペイウォールタイマーは、期間限定の特別オファーや季節オファーを宣伝するのに便利なツールです。ただし、このタイマーはオファーの有効期限やキャンペーンの期間とは連動していません。設定した値からゼロまでカウントダウンするだけのシンプルなタイマーです。タイマーがゼロになっても特に何も起こらず、ゼロのまま表示され続けます。 タイマーの前後にテキストをカスタマイズして、「オファー終了まで: 10:00 秒」のようなメッセージを作成できます。 ペイウォールでカスタムタイマーを使用するには、ペイウォールビューを作成する際に渡してください: <Tabs> <TabItem value="standalone" label="Compose Multiplatform を使用する場合" default> ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) AdaptyUI.createPaywallView( paywall = paywall, customTimers = customTimers ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` </TabItem> <TabItem value="native" label="Compose Multiplatform を使用しない場合"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativePaywallView( context = context, viewModelStoreOwner = activity, paywall = paywall, observer = myPaywallObserver, customTimers = customTimers, ) ``` ```kotlin showLineNumbers title="Kotlin Multiplatform (iOS)" val customTimers = mapOf( "CUSTOM_TIMER_NY" to LocalDateTime(2025, 1, 1, 0, 0, 0), "CUSTOM_TIMER_SALE" to LocalDateTime(2024, 12, 31, 23, 59, 59) ) val nativeView = AdaptyUI.createNativePaywallView( paywall = paywall, observer = myPaywallObserver, customTimers = customTimers, ) ``` </TabItem> </Tabs> </SDKv3> --- # File: kmp-handle-paywall-actions --- --- title: "フローアクションへの応答 - Kotlin Multiplatform" description: "Kotlin Multiplatformアプリでフローやペイウォールのボタンアクションを処理します。" --- <SDKv4> Adapty Flow Builder またはペイウォールビルダーを使用してフローやペイウォールを構築する場合、ボタンを適切に設定することが重要です。 1. [ビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクションIDを作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよび既存のアクションをコードで処理する方法を説明します。 :::warning **購入、リストア、フロー/ペイウォールのクローズ、リンクの開封は自動的に処理されます。** カスタムアクションなど、それ以外のボタンアクションはすべて、アプリコードで適切なレスポンス実装が必要です。 ::: ## AdaptyUIFlowsEventsObserverを設定する \{#set-up-the-adaptyuiflowseventsob-server\} フローのアクションを処理するには、`AdaptyUIFlowsEventsObserver`インターフェースを実装し、`AdaptyUI.setFlowsEventsObserver()`で設定する必要があります。これはアプリのライフサイクルの早い段階、通常はメインアクティビティまたはアプリの初期化時に行ってください。 ```kotlin // In your app initialization AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver()) ``` すべてのボタンアクションは、`AdaptyUIAction` シールドクラス(`CloseAction`、`AndroidSystemBackAction`、`OpenUrlAction`、`CustomAction`)として `flowViewDidPerformAction(view, action)` コールバックに渡されます。 :::warning `flowViewDidPerformAction` をオーバーライドすると、特定のアクションだけでなく**すべて**のアクションに対するデフォルト処理が置き換えられます。以下の例に示すように、動作を変更する意図がない限り、`CloseAction`(フローを閉じる)および `OpenUrlAction`(URLを開く)のデフォルト処理はそのまま残してください。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローまたはペイウォールを閉じるボタンを追加するには: 1. ビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、フローを閉じる `close` アクションのハンドラーを実装します。 :::info Kotlin Multiplatform SDK では、`CloseAction` はデフォルトでフローまたはペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるフローを閉じると別のフローが開くようにすることも可能です。 ::: ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } // default behavior is AdaptyUIAction.OpenUrlAction -> AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior else -> Unit } } } // Set up the observer AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver()) ``` [`createNativeFlowView`](kmp-present-paywalls#without-compose-multiplatform)を使用している場合、`view.dismiss()`を呼び出しても効果はありません。ビューはKMPスタックを通じて表示されるのではなく、レイアウトに埋め込まれているためです。代わりに、レイアウトからビューを削除し、`dispose()`を呼び出してください。 ## Android のシステムバックボタンを処理する \{#handle-the-android-system-back-button\} Android のシステムバックボタンを押す(またはバックジェスチャーを使用する)と、`AdaptyUIAction.AndroidSystemBackAction` が発行されます。デフォルトでは、このアクションは無視されます。フローは開いたままになり、ユーザーは **Close** ボタンやビルダーの `on_device_back` アクションなど、あなたが定義したパスを通じてフローを終了します。システムバックボタンでフローを閉じたい場合は、このアクションを自分で処理してください: ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } // default behavior is AdaptyUIAction.AndroidSystemBackAction -> mainUiScope.launch { view.dismiss() } // not handled by default is AdaptyUIAction.OpenUrlAction -> AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior else -> Unit } } } ``` ## フローとペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクのグループ(利用規約と購入履歴の復元など)を追加したい場合は、ビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: フローやペイウォールからリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには、ビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力してください。 デフォルトでは、SDKは受け取ったURLを`action.openIn`に応じて外部ブラウザまたはアプリ内ブラウザでネイティブに開くため、コードは不要です。確認ダイアログを先に表示するなど、カスタムロジックが必要な場合のみハンドラーをオーバーライドしてください。 ```kotlin class MyAdaptyUIFlowsEventsObserver( private val uriHandler: UriHandler ) : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.OpenUrlAction -> { // Show confirmation dialog before opening URL mainUiScope.launch { val selectedAction = view.showDialog( title = "Open URL?", content = action.url, primaryActionTitle = "Cancel", secondaryActionTitle = "Open" ).getOrNull() when (selectedAction) { AdaptyUIDialogActionType.PRIMARY -> { // User cancelled } AdaptyUIDialogActionType.SECONDARY -> { // User confirmed - open URL uriHandler.openUri(action.url) } else -> Unit } } } else -> Unit } } } // Set up the observer with UriHandler AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver(uriHandler)) ``` ## アプリにログインする \{#log-into-the-app\} アプリへのログインボタンを追加するには: 1. ビルダーでボタンを追加し、ID「login」の **Custom** アクションを割り当てます。 2. アプリのコードで、ユーザーを識別するカスタムアクションのハンドラーを実装します。 ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { if (action.action == "login") { // Handle login action - navigate to login screen // This depends on your app's navigation system // For example, in Compose Multiplatform: // navController.navigate("login") } } else -> Unit } } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには: 1. ビルダーでボタンを追加し、**Custom** アクションを割り当て、IDを設定します。 2. アプリのコードに、作成したアクション ID のハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます。 ```kotlin class MyAdaptyUIFlowsEventsObserver : AdaptyUIFlowsEventsObserver { override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { when (action.action) { "openNewFlow" -> { // Display another flow or paywall } } } else -> Unit } } } // Set up the observer AdaptyUI.setFlowsEventsObserver(MyAdaptyUIFlowsEventsObserver()) ``` </SDKv4> <SDKv3> :::warning **購入と復元のみ自動で処理されます。** ペイウォールを閉じる、リンクを開くなど、その他のボタンアクションはすべてアプリコード内で適切なレスポンスを実装する必要があります。 ::: Adaptyのペイウォールビルダーを使ってペイウォールを構築する場合、ボタンを正しく設定することが重要です: 1. [ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクションIDを作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよびあらかじめ用意されたアクションをコード内で処理する方法を説明します。 ## AdaptyUIPaywallsEventsObserverの設定 \{#set-up-the-adaptyuipaywallseventsObserver\} ペイウォールのアクションを処理するには、`AdaptyUIPaywallsEventsObserver` インターフェースを実装し、`AdaptyUI.setPaywallsEventsObserver()` で設定する必要があります。これはアプリのライフサイクルの早い段階、通常はメインアクティビティまたはアプリの初期化時に行ってください。 ```kotlin // In your app initialization AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info Kotlin Multiplatform SDK では、`CloseAction` と `AndroidSystemBackAction` はデフォルトでペイウォールを閉じる動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じることで別のペイウォールを開くといったことが可能です。 ::: ```kotlin class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver { override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { when (action) { AdaptyUIAction.CloseAction, AdaptyUIAction.AndroidSystemBackAction -> view.dismiss() } } } // Set up the observer AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` [`createNativePaywallView`](kmp-present-paywalls#without-compose-multiplatform) を使用している場合、`view.dismiss()` を呼び出しても効果はありません。このビューはレイアウトに埋め込まれており、KMP スタック経由で表示されているわけではないためです。代わりに、レイアウトからビューを削除し、`dispose()` を呼び出してください。 ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: ペイウォールからリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当てて、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info Kotlin Multiplatform SDK では、`OpenUrlAction` が開くべき URL を提供します。確認ダイアログを表示したり、アプリ独自の URL 処理方法を使用したりするなど、URL の開き方についてカスタムロジックを実装できます。 ::: ```kotlin class MyAdaptyUIPaywallsEventsObserver( private val uriHandler: UriHandler ) : AdaptyUIPaywallsEventsObserver { override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.OpenUrlAction -> { // Show confirmation dialog before opening URL mainUiScope.launch { val selectedAction = view.showDialog( title = "Open URL?", content = action.url, primaryActionTitle = "Cancel", secondaryActionTitle = "Open" ).getOrNull() when (selectedAction) { AdaptyUIDialogActionType.PRIMARY -> { // User cancelled } AdaptyUIDialogActionType.SECONDARY -> { // User confirmed - open URL uriHandler.openUri(action.url) } else -> Unit } } } } } } // Set up the observer with UriHandler AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver(uriHandler)) ``` ## アプリにログインする \{#log-into-the-app\} アプリにユーザーをログインさせるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、ID「login」の**カスタム**アクションを割り当てます。 2. アプリのコードで、ユーザーを識別するカスタムアクションのハンドラーを実装します。 ```kotlin class MyAdaptyUIObserver : AdaptyUIObserver { override fun paywallViewDidPerformAction(view: AdaptyUIView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { if (action.action == "login") { // Handle login action - navigate to login screen // This depends on your app's navigation system // For example, in Compose Multiplatform: // navController.navigate("login") } } } } } ``` ## カスタムアクションの処理 \{#handle-custom-actions\} ボタンを追加して任意のアクションを処理するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当て、ID を設定します。 2. アプリのコードで、作成したアクション ID に対するハンドラーを実装します。 例えば、別のサブスクリプションオファーや買い切り購入のセットがある場合、別のペイウォールを表示するボタンを追加できます: ```kotlin class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver { override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CustomAction -> { when (action.action) { "login" -> { // Handle login action - navigate to login screen // This depends on your app's navigation system // For example, in Compose Multiplatform: // navController.navigate("login") } } } } } } // Set up the observer AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` </SDKv3> --- # File: kmp-handling-events --- --- title: "フロー & ペイウォールイベントの処理 - Kotlin Multiplatform" description: "Kotlin Multiplatform アプリでフローおよびペイウォールイベントを処理します。" --- <SDKv4> :::important このガイドでは、購入・復元・プロダクト選択・フローのレンダリングに関するイベント処理について説明します。ボタン処理(フローを閉じる、リンクを開くなど)も別途実装する必要があります。詳細は[フローアクションの処理に関するガイド](kmp-handle-paywall-actions)をご覧ください。 ::: [Flow Builder](adapty-flow-builder) または [Paywall Builder](adapty-paywall-builder) で設定されたフローやペイウォールは、購入や復元のために追加コードは不要です。ただし、アプリが応答できるイベントが生成されます。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。 モバイルアプリのフロースクリーンで発生するプロセスを制御・監視するには、`AdaptyUIFlowsEventsObserver` インターフェースのメソッドを実装し、`AdaptyUI.setFlowsEventsObserver()` でオブザーバーを登録してください。一部のメソッドはよく使われるシナリオを自動的に処理するデフォルト実装が用意されているため、変更したいメソッドのみオーバーライドしてください。 ```kotlin showLineNumbers title="Kotlin" AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { // override only the methods you want to change }) ``` :::note これらのメソッドは、フローイベントに応答するカスタムロジックを追加する場所です。`view.dismiss()` を使用してフローを閉じたり、その他の必要なカスタム動作を実装したりできます。なお、`dismiss()` はサスペンド関数です。コールバック内では、オブザーバーの `mainUiScope` を使って起動してください:`mainUiScope.launch { view.dismiss() }`。 ::: ### ユーザー生成イベント \{#user-generated-events\} #### フローの表示と非表示 \{#flow-appearance-and-disappearance\} フローが表示または非表示になると、次のメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidAppear(view: AdaptyUIFlowView) { // Handle flow appearance // You can track analytics or update UI here } override fun flowViewDidDisappear(view: AdaptyUIFlowView) { // Handle flow disappearance // You can track analytics or update UI here } ``` :::note - iOS では、ユーザーがフロー内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップしてアプリ内ブラウザでウェブペイウォールが開いたときにも、`flowViewDidAppear` が呼び出されます。 - iOS では、フローからアプリ内ブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えたときにも、`flowViewDidDisappear` が呼び出されます。 ::: <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // Flow appeared { // No additional data } // Flow disappeared { // No additional data } ``` </Details> #### プロダクトの選択 \{#product-selection\} ユーザーが購入するプロダクトを選択すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidSelectProduct(view: AdaptyUIFlowView, productId: String) { // Handle product selection // You can update UI or track analytics here } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> #### 購入の開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidStartPurchase(view: AdaptyUIFlowView, product: AdaptyPaywallProduct) { // Handle purchase start // You can show loading indicators or track analytics here } ``` :::note [オブザーバーモード](kmp-present-flows-in-observer-mode)では、フローから開始された購入は`AdaptyUIObserverModeResolver`に配信されます。 ::: <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### 購入の成功、キャンセル、または保留 \{#successful-canceled-or-pending-purchase\} 購入が完了すると、このメソッドが呼び出されます。デフォルトでは何も行われません。購入後もフローは開いたままなので、ユーザーがアクセスを取得したら `view.dismiss()` を自分で呼び出してください。 ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFinishPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { when (purchaseResult) { is AdaptyPurchaseResult.Success -> { // Check if user has access to premium features if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) { mainUiScope.launch { view.dismiss() } } } AdaptyPurchaseResult.Pending -> { // Handle pending purchase (e.g., user will pay offline with cash) } AdaptyPurchaseResult.UserCanceled -> { // Handle user cancellation } } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Pending purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Pending" } } // User canceled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCanceled" } } ``` </Details> 購入が成功した場合は、フロー画面を閉じることをおすすめします。 #### 購入失敗 \{#failed-purchase\} エラーにより購入が失敗した場合、このメソッドが呼び出されます。これには、StoreKit/Google Play Billing のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、およびシステムエラーが含まれます。なお、ユーザーによるキャンセルは `flowViewDidFinishPurchase` をキャンセル結果で呼び出すため、このメソッドはトリガーされません。保留中の支払いもこのメソッドをトリガーしません。 ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFailPurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, error: AdaptyError ) { // Add your purchase failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ``` </Details> #### リストアの開始 \{#started-restore\} ユーザーがリストア処理を開始すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidStartRestore(view: AdaptyUIFlowView) { // Handle restore start // You can show loading indicators or track analytics here } ``` #### 購入の復元成功 \{#successful-restore\} 購入の復元が成功した場合、このメソッドが呼び出されます。デフォルトでは何も行いません — 復元後もフローは開いたままであり、明示的に閉じるまで表示され続けます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFinishRestore(view: AdaptyUIFlowView, profile: AdaptyProfile) { // Add your successful restore handling logic here // For example: show success message, update UI, or dismiss the flow // Check if user has access to premium features if (profile.accessLevels["premium"]?.isActive == true) { mainUiScope.launch { view.dismiss() } } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ``` </Details> 必要な `accessLevel` をユーザーが持っている場合は、画面を閉じることをおすすめします。確認方法については、[サブスクリプションのステータス](subscription-status)を参照してください。 #### 復元の失敗 \{#failed-restore\} `Adapty.restorePurchases()` が失敗した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFailRestore(view: AdaptyUIFlowView, error: AdaptyError) { // Add your restore failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> #### Webペイメントナビゲーションの完了 \{#web-payment-navigation-completion\} ユーザーが[ウェブペイウォール](web-paywall)を使用して購入プロセスを開始した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFinishWebPaymentNavigation( view: AdaptyUIFlowView, product: AdaptyPaywallProduct?, error: AdaptyError? ) { if (error != null) { // Handle web payment navigation error } else { // Handle successful web payment navigation } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // Successful web payment navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed web payment navigation { "product": null, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ``` </Details> ### データの取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} 初期化時にプロダクトを渡さなかった場合、AdaptyUI はサーバーから必要なオブジェクトを自動で取得します。この操作が失敗した場合、AdaptyUI は次のメソッドを呼び出してエラーを通知します。 ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidFailLoadingProducts(view: AdaptyUIFlowView, error: AdaptyError) { // Add your product loading failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> #### レンダリングエラーとランタイムエラー \{#rendering-and-runtime-errors\} インターフェースのレンダリング中にエラーが発生した場合、またはその他の購入以外のランタイムエラーが発生した場合、このメソッドによって報告されます。デフォルトでは、エラー発生時にフローが閉じられます。フローを開いたままにしたり、独自のハンドリングを追加したりするには、このメソッドをオーバーライドしてください: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) { // Handle the error // The default implementation dismisses the flow; // once you override this method, dismissal is up to you } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render flow interface", "details": { "underlyingError": "Invalid flow configuration" } } } ``` </Details> 通常の状況では、このようなエラーは発生しないはずです。もし遭遇した場合は、ぜひお知らせください。 #### アナリティクスイベント \{#analytics-events\} `flowViewDidReceiveAnalyticEvent` コールバックは、フローからのカスタムアナリティクスイベント用に予約されています。フローはまだこれらのイベントをコードに送出しないため、実装する必要はありません: ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidReceiveAnalyticEvent( view: AdaptyUIFlowView, name: String, paramsJsonString: String ) { // Reserved for custom analytic events from a flow } ``` ### ナビゲーション \{#navigation\} #### Android のシステムバックボタン \{#android-system-back-button\} デフォルトでは、Android のシステムバックボタンやバックジェスチャーでフローを閉じることはできません。デフォルトの `flowViewDidPerformAction` 実装は、`CloseAction` の場合のみフローを閉じ、`AndroidSystemBackAction` は無視します。そのため、ユーザーは **Close** ボタンやビルダーの `on_device_back` アクションなど、あなたが定義したパスを通じてフローを離れます。システムバックボタンでフローを閉じたい場合は、アクションを自分で処理してください。 ```kotlin showLineNumbers title="Kotlin" override fun flowViewDidPerformAction(view: AdaptyUIFlowView, action: AdaptyUIAction) { when (action) { is AdaptyUIAction.CloseAction -> mainUiScope.launch { view.dismiss() } // default behavior is AdaptyUIAction.AndroidSystemBackAction -> mainUiScope.launch { view.dismiss() } // not handled by default is AdaptyUIAction.OpenUrlAction -> AdaptyUI.openWebUrl(action.url, action.openIn) // default behavior else -> Unit } } ``` [フロー操作の処理に関するガイド](kmp-handle-paywall-actions)で、すべての操作の一覧をご確認ください。 </SDKv4> <SDKv3> [ペイウォールビルダー](adapty-paywall-builder)で設定されたペイウォールは、購入や復元を行うために追加のコードは必要ありません。ただし、アプリが応答できるいくつかのイベントが発生します。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。 :::warning このガイドは**新しいペイウォールビルダーのペイウォール**専用です。 ::: モバイルアプリのペイウォール画面で発生するプロセスを制御・監視するには、`AdaptyUIPaywallsEventsObserver` インターフェースのメソッドを実装します。一部のメソッドには、一般的なシナリオを自動的に処理するデフォルト実装が用意されています。 :::note これらのメソッドは、ペイウォールイベントへの応答としてカスタムロジックを追加する場所です。`view.dismiss()` でペイウォールを閉じたり、必要に応じてその他のカスタム動作を実装したりできます。 ::: ## ユーザー生成イベント \{#user-generated-events\} ### ペイウォールの表示と非表示 \{#paywall-appearance-and-disappearance\} ペイウォールが表示または非表示になったとき、以下のメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidAppear(view: AdaptyUIPaywallView) { // Handle paywall appearance // You can track analytics or update UI here } override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) { // Handle paywall disappearance // You can track analytics or update UI here } ``` :::note - iOSでは、ユーザーがペイウォール内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップしてインアプリブラウザでウェブペイウォールが開いた場合にも、`paywallViewDidAppear`が呼び出されます。 - iOSでは、ペイウォールからインアプリブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えた場合にも、`paywallViewDidDisappear`が呼び出されます。 ::: <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // Paywall appeared { // No additional data } // Paywall disappeared { // No additional data } ``` </Details> ### プロダクトの選択 \{#product-selection\} ユーザーが購入するプロダクトを選択すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) { // Handle product selection // You can update UI or track analytics here } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> ### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始すると、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) { // Handle purchase start // You can show loading indicators or track analytics here } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> ### 購入成功、キャンセル、または保留中 \{#successful-canceled-or-pending-purchase\} 購入が成功した場合、このメソッドが呼び出されます。デフォルトでは、ユーザーによってキャンセルされた場合を除き、自動的にペイウォールを閉じます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFinishPurchase( view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { when (purchaseResult) { is AdaptyPurchaseResult.Success -> { // Check if user has access to premium features if (purchaseResult.profile.accessLevels["premium"]?.isActive == true) { view.dismiss() } } AdaptyPurchaseResult.Pending -> { // Handle pending purchase (e.g., user will pay offline with cash) } AdaptyPurchaseResult.UserCanceled -> { // Handle user cancellation } } } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Pending purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Pending" } } // User canceled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCanceled" } } ``` </Details> 購入が成功した場合は、ペイウォール画面を閉じることをお勧めします。 ### 購入失敗 \{#failed-purchase\} 購入がエラーにより失敗した場合、このメソッドが呼び出されます。これには、StoreKit/Google Play Billing エラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、システムエラーが含まれます。なお、ユーザーによるキャンセルは、キャンセル結果として `paywallViewDidFinishPurchase` をトリガーします。また、保留中の支払いはこのメソッドをトリガーしません。 ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailPurchase( view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, error: AdaptyError ) { // Add your purchase failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ``` </Details> ### リストアの開始 \{#started-restore\} ユーザーがリストアプロセスを開始した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidStartRestore(view: AdaptyUIPaywallView) { // Handle restore start // You can show loading indicators or track analytics here } ``` ### 購入の復元に成功した場合 \{#successful-restore\} 購入の復元が成功した場合、以下のメソッドが呼び出されます。 ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) { // Add your successful restore handling logic here // For example: show success message, update UI, or dismiss paywall // Check if user has access to premium features if (profile.accessLevels["premium"]?.isActive == true) { view.dismiss() } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ``` </Details> ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることをお勧めします。確認方法については、[サブスクリプションのステータス](subscription-status)を参照してください。 ### 復元失敗時 \{#failed-restore\} `Adapty.restorePurchases()` が失敗した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your restore failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> ### ウェブ決済ナビゲーションの完了 \{#web-payment-navigation-completion\} ユーザーが[ウェブペイウォール](web-paywall)を使用して購入プロセスを開始した場合、このメソッドが呼び出されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFinishWebPaymentNavigation( view: AdaptyUIPaywallView, product: AdaptyPaywallProduct?, error: AdaptyError? ) { if (error != null) { // Handle web payment navigation error } else { // Handle successful web payment navigation } } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // Successful web payment navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed web payment navigation { "product": null, "error": { "code": "web_payment_failed", "message": "Web payment navigation failed", "details": { "underlyingError": "Network connection error" } } } ``` </Details> ## データの取得とレンダリング \{#data-fetching-and-rendering\} ### プロダクトの読み込みエラー \{#product-loading-errors\} 初期化時にプロダクトを渡さない場合、AdaptyUI はサーバーから必要なオブジェクトを自動的に取得します。この操作が失敗した場合、AdaptyUI は次のメソッドを呼び出してエラーを通知します。 ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your product loading failure handling logic here // For example: show error message, retry option, or custom error handling } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> ### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生した場合、このメソッドで報告されます: ```kotlin showLineNumbers title="Kotlin" override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) { // Handle rendering error // In a normal situation, such errors should not occur // If you come across one, please let us know } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ``` </Details> 通常の状況ではこのようなエラーは発生しないため、もし遭遇した場合はお知らせください。 </SDKv3> --- # File: kmp-use-fallback-paywalls --- --- title: "Kotlin Multiplatform - フォールバックペイウォールを使用する" description: "ユーザーがオフラインの場合やAdaptyサーバーが利用できない場合に対応する" --- スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} 1. フォールバック設定ファイルをアプリケーションに追加してください。 * ターゲットプラットフォームが Android の場合は、フォールバック設定ファイルを `android/app/src/main/assets/` フォルダに移動してください。 * ターゲットプラットフォームが iOS の場合は、フォールバック JSON ファイルをプロジェクトバンドルに追加してください。(**File** -> **Add Files to YourProjectName**) 2. ターゲットのフロー、ペイウォール、またはオンボーディングを取得する**前に**、`.setFallback` メソッドを呼び出してください。 3. ターゲットのプラットフォームに応じて、`assetId` パラメーターを設定してください。 * Android: `assets` ディレクトリからの相対ファイルパスを使用してください。 * iOS: 完全なファイル名を使用してください。 ```kotlin showLineNumbers Adapty.setFallback(assetId = "fallback.json") .onSuccess { // Fallback paywalls loaded successfully } .onError { error -> // Handle the error } ``` :::important `setFallback`は、SDKがターゲットのフロー、ペイウォール、またはオンボーディングを取得する前に実行する必要があります。 ::: パラメーター: | パラメーター | 説明 | | :---------- |:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **assetId** | フォールバック設定のファイル名(iOS)。 <br /> フォールバック設定ファイルのパス(`assets` ディレクトリからの相対パス)(Android)。 | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: kmp-localizations-and-locale-codes --- --- title: "Kotlin Multiplatform SDKでローカライゼーションとロケールコードを使用する" description: "Kotlin Multiplatformアプリでグローバルなユーザーに対応するため、アプリのローカライゼーションとロケールコードを管理する方法を説明します。" --- <SDKv4> ## これが重要な理由 \{#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. Adapty は完全に一致するロケールコードのローカライズを検索します 3. 一致するものが見つからない場合、Adapty は最初のハイフン前の部分文字列(`pt-br` に対する `pt`)を取り出して、一致するローカライズを検索します 4. それでも一致するものが見つからない場合、Adapty はデフォルトの `en` ローカライズを返します これにより、`'pt_BR'`、`pt-BR`、`pt-br` はすべて同じローカライズに解決されます。 ## ローカライゼーションの実装 \{#implementing-localizations\} SDK v4 では、フローを取得する際にロケールコードを渡す必要はありません。 - **フロービルダーおよびペイウォールビルダーのペイウォール**: Adapty はデバイスの設定とビルダーで設定したローカライゼーションをもとに、自動的にローカライゼーションを解決します。`createFlowView` でフローをレンダリングするだけで、ロケールコードは不要です。 - **カスタム(リモートコンフィグ)ペイウォール**: `getFlow` は設定済みのすべてのローカライゼーションを `flow.remoteConfigs` に返します。各エントリは `locale` コードと `dataMap` を持つ `AdaptyRemoteConfig` です。ユーザーに合ったエントリを独自のフォールバック処理で選択してください。 ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() // read your values from config?.dataMap } .onError { error -> // handle the error } ``` 上記のロケールコードマッチングルールは、Adapty が各リモートコンフィグに保存されている `locale` コードをどのように正規化するかを説明しています。 </SDKv4> <SDKv3> ## これが重要な理由 \{#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 を呼び出す際に、そのキーの値を取り出して使用します。例: ```kotlin showLineNumbers // 1. Add the Adapty locale code to your Compose Multiplatform resources /* composeResources/values/strings.xml (default — English) */ <string name="adapty_paywalls_locale">en</string> /* composeResources/values-es/strings.xml (Spanish) */ <string name="adapty_paywalls_locale">es</string> /* composeResources/values-pt-rBR/strings.xml (Portuguese — Brazil) */ <string name="adapty_paywalls_locale">pt-br</string> // 2. Extract and use the locale code suspend fun fetchPaywall() { val locale = getString(Res.string.adapty_paywalls_locale) Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = locale ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } } ``` このようにすることで、アプリの全ユーザーに対してどのローカライズが取得されるかを完全にコントロールできます。 Compose Multiplatform のリソースを使用していない場合でも、同じ考え方は他のどのローカライズライブラリにも適用できます(例:[moko-resources](https://github.com/icerockdev/moko-resources))。各ロケールのリソースバンドルに Adapty のロケールコードを文字列として保存し、SDK を呼び出す前にそれを読み込んでください。 ## ローカリゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} すべてのローカリゼーションにロケールコードを明示的に定義しなくても、同様の(ただし完全に同一ではない)結果を得ることができます。その場合、デバイスから直接ロケールコードを取得することになりますが、`commonMain` にはロケールの共通 API がないため、`expect`/`actual` 宣言が必要です。 ```kotlin showLineNumbers // commonMain expect fun currentLocaleTag(): String // androidMain actual fun currentLocaleTag(): String = Locale.getDefault().toLanguageTag() // iosMain actual fun currentLocaleTag(): String = NSLocale.currentLocale.localeIdentifier // commonMain — pass the locale code to Adapty suspend fun fetchPaywall() { Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = currentLocaleTag() ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } } ``` この方法はいくつかの理由からお勧めしません: 1. iOSでは、ユーザーの優先言語とデバイスの地域ロケールは同一ではありません。`NSLocale.currentLocale.localeIdentifier`は地域ロケールを返しますが、これはユーザーが実際にアプリで読む言語と異なる場合があります。ローカライズされた文字列ファイルを使用するiOSアプリは、Appleのresolveロジックによってこれらをうまく組み合わせるため、上記の推奨アプローチではそのまま動作します。 2. デバイスが何を返すか、そしてそれがAdaptyのローカライズと一致するかどうかを正確に予測するのは困難です。デバイスのロケールには、Adaptyで設定していない拡張子や地域コードが含まれる場合があり、その場合SDKは最初のサブタグへのフォールバック、最終的には`en`へのフォールバックを行います。 Should you decide to use this approach anyway — make sure you've covered all the relevant use cases. </SDKv3> --- # File: kmp-web-paywalls --- --- title: "Kotlin Multiplatform SDKでウェブペイウォールを実装する" description: "ストアの手数料や審査なしで課金できるウェブペイウォールを設定します。" --- :::important 始める前に、[ダッシュボードでウェブペイウォールを設定](web-paywall)し、Adapty SDK バージョン3.15以降をインストールしていることを確認してください。 ::: ## ウェブペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールを使用している場合は、SDK メソッドを使ってウェブペイウォールを処理する必要があります。`openWebPaywall` メソッドは以下を行います。 1. Adapty が特定のユーザーに表示されたペイウォールと、リダイレクト先のウェブページを紐づけるための一意の URL を生成します。 2. ユーザーがアプリに戻ったタイミングを検知し、短い間隔で `getProfile` をリクエストして、プロファイルのアクセス権が更新されたかどうかを確認します。 これにより、支払いが成功してアクセス権が更新された場合、アプリ内でほぼ即座にサブスクリプションが有効になります。 :::note ユーザーがアプリに戻った後、プロファイルの更新を反映するためにUIを更新してください。AdaptyはプロファイルのUpdateイベントを受信して処理します。 ::: ```kotlin showLineNumbers viewModelScope.launch { Adapty.openWebPaywall(product = product).onSuccess { // the web paywall was opened successfully }.onError { error -> // handle the error } } ``` :::note `openWebPaywall` メソッドには2つのバージョンがあります: 1. `openWebPaywall(product = product)` — ペイウォールごとにURLを生成し、プロダクトデータもURLに追加します。 2. `openWebPaywall(paywall = paywall)` — ペイウォールごとにURLを生成しますが、プロダクトデータはURLに追加しません。Adapty ペイウォールのプロダクトとウェブペイウォールのプロダクトが異なる場合に使用してください。 SDK v4 では、`paywall` パラメーターは `flowPaywall` パラメーターに置き換えられ、`flow.paywalls` 内のペイウォールバリアントの一つである `AdaptyFlowPaywall` を受け取ります。詳細は[移行ガイド](migration-to-kmp-sdk-v4)を参照してください。 ::: ## ウェブペイウォールをアプリ内ブラウザで開く \{#open-web-paywalls-in-an-in-app-browser\} デフォルトでは、ウェブペイウォールは外部ブラウザで開きます。 シームレスなユーザー体験を提供するために、ウェブペイウォールをアプリ内ブラウザで開くことができます。これにより、アプリを切り替えることなく、アプリ内でウェブ購入ページが表示され、ユーザーはそのまま取引を完了できます。 この機能を有効にするには、`openIn` パラメーターを `AdaptyWebPresentation.IN_APP_BROWSER` に設定します。 ```kotlin showLineNumbers viewModelScope.launch { Adapty.openWebPaywall( product = product, openIn = AdaptyWebPresentation.IN_APP_BROWSER // default – EXTERNAL_BROWSER ).onSuccess { // the web paywall was opened successfully }.onError { error -> // handle the error } } ``` --- # File: kmp-present-flows-in-observer-mode --- --- title: "Observerモードでフローを表示する - Kotlin Multiplatform" description: "Kotlin MultiplatformアプリでObserverモードのフローおよびペイウォールビルダーのペイウォールを表示し、独自のコードで購入を処理する方法を説明します。" --- ビルダーを使ってフローやペイウォールをカスタマイズした場合、モバイルアプリのコードでレンダリングしてユーザーに表示する方法を気にする必要はありません。このようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このセクションは[オブザーバーモード](observer-vs-full-mode)のみを対象としています。オブザーバーモードで作業していない場合は、[フローとペイウォールの表示](kmp-present-paywalls)のトピックを参照してください。 ::: :::info この機能を使用するには、Adapty Kotlin Multiplatform SDK 4.0(ベータ版)以降が必要です。以前はネイティブの iOS および Android SDK でのみ利用可能でした。アップグレードするには[移行ガイド](migration-to-kmp-sdk-v4)をご参照ください。 ::: <details> <summary>フローの表示を開始する前に(クリックして展開)</summary> 1. Adapty の初期連携を設定します([App Store との連携](initial_ios)および [Google Play との連携](initial-android))。 2. Adapty SDK をインストールして設定します。設定ビルダーで `withObserverMode(true)` を呼び出してください。[Kotlin Multiplatform SDK インストールガイド](sdk-installation-kotlin-multiplatform#activate-adapty-sdk)を参照してください。 3. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 4. [ビルダーでフローまたはペイウォールを設定](create-paywall)し、プロダクトを割り当てます。 5. [プレースメントを作成し、フローまたはペイウォールを割り当てます](create-placement)。 6. モバイルアプリのコードで[フローとその設定を取得](kmp-get-pb-paywalls)します。 </details> オブザーバーモードでは、SDKが代わりに購入処理を行うことはありません。ユーザーがAdaptyでレンダリングされたフローまたはペイウォールの購入ボタンや復元ボタンをタップすると、SDKはあなたの`AdaptyUIObserverModeResolver`を呼び出します。そちらで独自のコードを使って購入または復元を実行してください。 1. `AdaptyUIObserverModeResolver`インターフェースを実装します: ```kotlin showLineNumbers import com.adapty.kmp.AdaptyUIObserverModeResolver import com.adapty.kmp.models.AdaptyPaywallProduct import com.adapty.kmp.models.AdaptyUIFlowView class MyObserverModeResolver : AdaptyUIObserverModeResolver { override fun observerModeDidInitiatePurchase( view: AdaptyUIFlowView, product: AdaptyPaywallProduct, onStartPurchase: () -> Unit, onFinishPurchase: () -> Unit ) { onStartPurchase() // the view shows its loading indicator // make the purchase with your own code, // then report the transaction to Adapty and call: onFinishPurchase() // the view hides the loading indicator } override fun observerModeDidInitiateRestore( view: AdaptyUIFlowView, onStartRestore: () -> Unit, onFinishRestore: () -> Unit ) { onStartRestore() // restore purchases with your own code, then: onFinishRestore() } } ``` `observerModeDidInitiatePurchase` メソッドはユーザーが購入を開始したことを通知し、`observerModeDidInitiateRestore` はユーザーがリストアを開始したことを通知します。これに応じて、カスタムの購入またはリストアフローをトリガーしてください。 また、購入またはリストアのプロセスについて AdaptyUI に通知するため、以下のコールバックを呼び出すことを忘れないでください。これは、ローダーの表示など、フローが正しく動作するために必要です。 | コールバック | 説明 | | :----------------- | :------------------------------------------------------------------------------- | | onStartPurchase() | 購入が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishPurchase() | 購入が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | | onStartRestore() | 復元が開始されたことを AdaptyUI に通知するために呼び出すコールバックです。 | | onFinishRestore() | 復元が完了したことを AdaptyUI に通知するために呼び出すコールバックです。 | フローは、コード実行中は開いたまま維持されます。購入またはリストアが成功したら、自分でフローを閉じてください。 2. 画面を表示する前にリゾルバーを登録します: ```kotlin showLineNumbers import com.adapty.kmp.AdaptyUI AdaptyUI.setObserverModeResolver(MyObserverModeResolver()) ``` リゾルバーを登録しないと、フロービューは購入をコードに引き渡す手段がなく、ユーザーが購入ボタンをタップしても何も起こりません。 3. フローのビューを通常通り作成して表示します: [フローを取得してビューを作成](kmp-get-pb-paywalls)し、[表示します](kmp-present-paywalls)。追加のパラメーターは不要です。リゾルバーを登録すると、Adapty がレンダリングするすべてのフローやペイウォールの購入とリストアがそこを通じてルーティングされます。 :::warning [トランザクションを報告してペイウォールに関連付けること](report-transactions-observer-mode-kmp)を忘れないでください。これを行わないと、Adapty がトランザクションを認識できず、購入元のペイウォールを特定できません。 ::: --- # File: kmp-troubleshoot-paywall-builder --- --- title: "Kotlin Multiplatform SDK でのペイウォールビルダーのトラブルシューティング" description: "Kotlin Multiplatform SDK でのペイウォールビルダーのトラブルシューティング" --- このガイドでは、Kotlin Multiplatform SDK で Adapty ペイウォールビルダーを使用して作成したペイウォールに関する一般的な問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: `createPaywallView` メソッドがペイウォールビューの作成に失敗する、またはペイウォールにビュー設定がない。 **原因**: ペイウォールビルダーでデバイス表示が有効になっていない。 **解決策**: ペイウォールビルダーで **Show on device** トグルを有効にしてください。また、`AdaptyPaywall` オブジェクトの `hasViewConfiguration` プロパティを使用して、ペイウォールにビュー設定があるかどうかを確認することもできます。 <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ペイウォールのビュー数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールのビュー数が予想の2倍になっている。 **原因**: コード内で `logShowPaywall` を呼び出している可能性があります。ペイウォールビルダーを使用している場合、この呼び出しによってビュー数が重複します。ペイウォールビルダーで作成したペイウォールでは、アナリティクスが自動的に記録されるため、このメソッドを使用する必要はありません。 **解決策**: ペイウォールビルダーを使用している場合は、コード内で `logShowPaywall` を呼び出していないことを確認してください。 --- # File: kmp-implement-paywalls-manually --- --- title: "Kotlin Multiplatform SDKでペイウォールを手動で実装する" description: "Adapty SDKを使用してKotlin MultiplatformアプリにペイウォールをKotlin Multiplatformで手動実装する方法を学びましょう。" --- ## 購入の受け付け \{#accept-purchases\} 自分で実装したペイウォールを使用している場合、`makePurchase` メソッドを使って購入処理を Adapty に委譲できます。これにより、すべてのユーザーシナリオが自動的に処理され、あなたは購入結果のハンドリングだけに集中できます。 :::important `makePurchase` は Adapty ダッシュボードで作成されたプロダクトと連携します。[クイックスタートガイド](quickstart)に従って、ダッシュボードでプロダクトの設定と取得方法を必ず構成してください。 ::: <CustomDocCardList ids={['kmp-quickstart-manual', 'fetch-paywalls-and-products-kmp', 'present-remote-config-paywalls-kmp', 'kmp-making-purchases', 'kmp-restore-purchase', 'kmp-troubleshoot-purchases']} /> ## オブザーバーモード \{#observer-mode\} 購入処理ロジックをゼロから独自に実装したいが、Adapty の高度な分析機能は引き続き活用したい場合は、オブザーバーモードを使用できます。 :::important オブザーバーモードの制限事項については[こちら](observer-vs-full-mode)をご確認ください。 ::: <CustomDocCardList ids={['implement-observer-mode-kmp', 'report-transactions-observer-mode-kmp', 'kmp-troubleshoot-purchases']} /> --- # File: kmp-quickstart-manual --- --- title: "Kotlin Multiplatform SDKのカスタムペイウォールで購入機能を有効にする" description: "Adapty SDKをKotlin Multiplatformのカスタムペイウォールでアプリ内課金を有効にする方法。" --- このガイドでは、カスタムペイウォールへのAdaptyの統合方法について説明します。ペイウォールの実装を完全に制御しながら、Adapty SDKがプロダクトの取得、新規購入の処理、および以前の購入の復元を行います。このガイドはAdapty Kotlin Multiplatform SDK v4(ベータ版)APIを使用しています。v3をお使いの場合は、対応するメソッド名については[移行ガイド](migration-to-kmp-sdk-v4)を参照してください。 :::important **このガイドは、カスタムペイウォールを実装する開発者向けです。** 購入機能を最も簡単に有効にしたい場合は、[Adapty Flow Builder](kmp-quickstart-paywalls)をご利用ください。Flow Builder を使えば、ノーコードのビジュアルエディターでフローを作成でき、購入ロジックはすべて Adapty が自動的に処理します。また、アプリを再公開することなく、さまざまなデザインをテストできます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトを設定する \{#set-up-products\} アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定。Adapty では、プロダクトを取得する唯一の方法がペイウォールです。この設計により、アプリのコードを変更することなく、プロダクト・価格・オファーを変更できます。SDK v4 では、プレースメントのペイウォールバリアントは **flow** オブジェクトによって管理されます。フローを取得してそのプロダクトを参照する形になります。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでプレースメントにペイウォールを設定し、コード内ではプレースメント ID を指定してリクエストします。これにより、A/B テストの実施や、ユーザーごとに異なるペイウォールの表示が簡単に行えます。 Make sure you understand these concepts even if you work with your custom paywall. Basically, they are just your way to manage the products you sell in your app. カスタムペイウォールを実装するには、**ペイウォール**を作成して**プレースメント**に追加する必要があります。この設定によってプロダクトを取得できるようになります。ダッシュボードで何をすればよいかを理解するには、クイックスタートガイド[こちら](quickstart)を参照してください。 ### ユーザーの管理 \{#manage-users\} バックエンド認証の有無にかかわらず、Adapty を利用できます。 ただし、Adapty SDK は匿名ユーザーと識別済みユーザーを異なる方法で処理します。詳細を理解し、ユーザーを適切に管理するために、[識別クイックスタートガイド](kmp-quickstart-identify)をご覧ください。 ## ステップ 1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、以下の手順を行います。 1. [プレースメント](placements) ID を `getFlow` メソッドに渡して `flow` オブジェクトを取得する。 2. `getPaywallProducts` メソッドを使用して、このフローのプロダクト配列を取得する。 ```kotlin showLineNumbers fun loadPaywall() { Adapty.getFlow(placementId = "YOUR_PLACEMENT_ID") .onSuccess { flow -> Adapty.getPaywallProducts(flow = flow) .onSuccess { products -> // Use products to build your custom paywall UI } .onError { error -> // Handle the error } } .onError { error -> // Handle the error } } ``` ## ステップ 2. 購入を受け付ける \{#step-2-accept-purchases\} ユーザーがカスタムペイウォール上のプロダクトをタップしたら、選択されたプロダクトを引数に `makePurchase` メソッドを呼び出してください。これにより購入フローが処理され、更新されたプロファイルが返されます。 ```kotlin showLineNumbers fun purchaseProduct(product: AdaptyPaywallProduct) { Adapty.makePurchase(product = product) .onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // Purchase successful, profile updated } is AdaptyPurchaseResult.UserCanceled -> { // User canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Purchase is pending (e.g., user will pay offline with cash) } } } .onError { error -> // Handle the error } } ``` ## ステップ 3. 購入の復元 \{#step-3-restore-purchases\} アプリストアでは、サブスクリプションを提供するすべてのアプリに対して、ユーザーが購入を復元できる手段を設けることを求めています。 ユーザーが復元ボタンをタップしたときに `restorePurchases` メソッドを呼び出してください。これにより、購入履歴が Adapty と同期され、更新されたプロファイルが返されます。 ```kotlin showLineNumbers fun restorePurchases() { Adapty.restorePurchases() .onSuccess { profile -> // Restore successful, profile updated } .onError { error -> // Handle the error } } ``` ## ステップ 4. サブスクリプションのステータスを確認する \{#step-4-check-the-subscription-status\} 購入またはリストア後は、ペイウォールを表示するか有料機能を解放するかを判断するために、ユーザーの[アクセスレベル](access-level)を確認します。`makePurchase` メソッドと `restorePurchases` メソッドはすでに更新済みのプロファイルを返しますが、アプリ内の他の場所で現在のステータスが必要な場合は `getProfile` メソッドを使用してください: ```kotlin showLineNumbers fun checkPremiumAccess() { Adapty.getProfile() .onSuccess { profile -> val hasPremiumAccess = profile.accessLevels["premium"]?.isActive == true // Grant access to paid features if hasPremiumAccess is true } .onError { error -> // Handle the error } } ``` サブスクリプションのステータスを確認・監視する方法(リアルタイム更新のリスニングを含む)については、[サブスクリプションのステータスを確認する](kmp-check-subscription-status)を参照してください。 ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備ができました。[App Store サンドボックス](test-purchases-in-sandbox)または[Google Play ストア](testing-on-android)でテスト購入を行い、ペイウォールからの購入が正常に完了することを確認してください。本番環境に近い実装例を確認するには、サンプルアプリの [AppViewModel.kt](https://github.com/adaptyteam/AdaptySDK-KMP/blob/main/example/composeMultiplatformApp/composeApp/src/commonMain/kotlin/com/adapty/exampleapp/AppViewModel.kt) をご覧ください。購入処理のエラーハンドリングや状態管理の実装方法が確認できます。 --- # File: fetch-paywalls-and-products-kmp --- --- title: "Kotlin Multiplatform SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "Adapty Kotlin Multiplatform SDKでペイウォールとプロダクトを取得して、ユーザーの収益化を強化しましょう。" --- <SDKv4> リモートコンフィグとカスタムペイウォールを表示する前に、それらに関する情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。**Flow Builder** または **Paywall Builder** でカスタマイズされたフローやペイウォールの取得方法については、[フローとペイウォールの取得](kmp-get-pb-paywalls)をご覧ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでフローとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[フローまたはペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに [Adapty SDK をインストールする](sdk-installation-kotlin-multiplatform)。 </details> ## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)は App Store と Google Play 両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームのプロダクトはフローやペイウォールに組み込まれており、モバイルアプリの特定のプレースメントでユーザーに表示できます。 プロダクトを表示するには、`getFlow` メソッドを使って[プレースメント](placements)のいずれかから `AdaptyFlow` を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードすべきIDはプレースメントIDのみです。フローはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。たとえば、フローが今日2つのプロダクトを返し、明日3つを返す場合でも、コードを変更せずにすべてを表示できるようにしてください。 ::: ```kotlin showLineNumbers Adapty.getFlow( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定だと考えられる場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` を使用してキャッシュデータが存在する場合はそれを返すことを検討してください。この場合、ユーザーが受け取るデータが最新でない可能性はありますが、インターネット接続の状態にかかわらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、ネットワークリクエストを避けるためにセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリーンアップした場合にのみ消去されます。</p><p></p><p>Adapty SDK はフローとペイウォールを 2 つの層に保存します。1 つ目は上述の定期更新キャッシュで、2 つ目は[フォールバックペイウォール](kmp-use-fallback-paywalls)です。また、フローとペイウォールをより速く取得するために CDN を使用し、CDN が利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が乏しい状況でも信頼性を確保しながら、常に最新バージョンのフローとペイウォールを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5 秒 | <p>このメソッドのタイムアウトを制限する値です。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。</p><p></p><p>内部では複数のリクエストで構成される場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅くタイムアウトすることがあります。</p> | プロダクトIDをハードコードしないでください!フローはリモートで設定されるため、利用可能なプロダクト、プロダクト数、特別オファー(無料トライアルなど)は随時変更される可能性があります。こうしたシナリオにコードが対応できるよう注意してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはその2つを表示する必要があります。その後3つのプロダクトを取得した場合、コードを変更することなく3つすべてを表示できる必要があります。ハードコードが必要なのはプレースメントIDのみです。 レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | `AdaptyFlow` オブジェクト。フロー識別子、ペイウォールのバリアント(`paywalls` — それぞれに独自のプロダクト識別子を持つ)、設定されたロケールごとに1エントリの `remoteConfigs` リスト、およびその他のプロパティが含まれます。フローのプロダクトを取得するには、`getPaywallProducts(flow)` を呼び出してください。 | :::note v4 では、`getFlow` に `locale` パラメーターはありません。`createFlowView` でフローをレンダリングする際、ローカライズは自動的に解決されます。カスタムペイウォールの場合、利用可能なすべてのロケールが `flow.remoteConfigs` にまとめて返されます。ユーザーのデバイスまたはアプリの設定に合ったロケールを選択してください。詳細については、[ローカライズとロケールコード](kmp-localizations-and-locale-codes)をご覧ください。 ::: ## プロダクトの取得 \{#fetch-products\} フローを取得したら、それに対応するプロダクト配列を照会できます: ```kotlin showLineNumbers Adapty.getPaywallProducts(flow).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティが含まれます。 | 独自のフロー設計を実装する場合、[`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) オブジェクトの以下のプロパティが必要になることがあります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **Price** | ローカライズされた価格を表示するには、`product.price.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づいています。`product.price.amount` を使用して価格を数値として取得することもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには、`product.price.currencySymbol` を使用します。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.subscriptionDetails?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づいています。サブスクリプション期間をプログラムで取得するには、`product.subscriptionDetails?.subscriptionPeriod` を使用します。そこから `unit` 列挙型にアクセスして長さ(DAY、WEEK、MONTH、YEAR、または UNKNOWN)を取得できます。`numberOfUnits` の値で期間の単位数を取得できます。たとえば、四半期ごとのサブスクリプションの場合、unit プロパティには `MONTH`、numberOfUnits プロパティには `3` が表示されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかどうかを示すバッジやその他のインジケーターを表示するには、`product.subscriptionDetails?.introductoryOfferPhases` プロパティを確認してください。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下の便利なプロパティが含まれています:<br/>• `paymentMode`:`FREE_TRIAL`、`PAY_AS_YOU_GO`、`PAY_UPFRONT`、`UNKNOWN` の値を持つ列挙型。無料トライアルは `FREE_TRIAL` タイプになります。<br/>• `price`:割引価格を数値で表したもの。無料トライアルの場合は `0` を確認してください。<br/>• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズして説明する文字列。たとえば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。<br/>• `subscriptionPeriod`:このプロパティを使用して、オファー期間の個別の詳細を取得することもできます。オファーに対しても前のセクションで説明したのと同様の方法で機能します。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## デフォルトオーディエンスのフローでフロー取得を高速化する \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ瞬時に取得されるため、この処理の高速化を気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が不安定な場合、フローの取得に予想以上の時間がかかることがあります。そのような状況では、何も表示しないよりもデフォルトのフローを表示することで、スムーズなユーザー体験を確保したい場合があるでしょう。 これに対処するには、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けフローを取得します。ただし、推奨されるアプローチは `getFlow` メソッドでフローを取得することである点を理解しておくことが重要です。詳細は上記の[フロー情報の取得](fetch-paywalls-and-products-kmp#fetch-flow-information)セクションをご覧ください。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるフローを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョン向けにフローを設計するか、現在の(レガシー)バージョンのユーザーがレンダリングされないフローで問題に遭遇することを許容するかを選択する必要があります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じフローを見ることになるため、パーソナライズされたターゲティング(国、マーケティングアトリビューション、独自のカスタム属性に基づくものを含む)が失われます。 デフォルトオーディエンス向けのフロー取得を高速化するメリットが上記のデメリットを上回ると判断した場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-kmp#fetch-flow-information)で説明した `getFlow` を引き続き使用してください。 ::: ```kotlin showLineNumbers Adapty.getFlowForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", fetchPolicy = AdaptyPaywallFetchPolicy.Default ).onSuccess { flow -> // the requested flow }.onError { error -> // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを受け取れるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュを返します。この場合、最新データが届かないことがありますが、接続状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時にのみ消去されます。</p> | </SDKv4> <SDKv3> リモートコンフィグとカスタムペイウォールを紹介する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズされたペイウォールの取得方法については、[ペイウォールビルダーのペイウォールと設定を取得する](kmp-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. [ペイウォールを作成し、プロダクトをペイウォールに組み込む](create-paywall)(Adapty ダッシュボード)。 3. [プレースメントを作成し、ペイウォールをプレースメントに組み込む](create-placement)(Adapty ダッシュボード)。 4. [Adapty SDK をインストールする](sdk-installation-kotlin-multiplatform)(モバイルアプリ)。 </details> ## ペイウォール情報の取得 \{#fetch-paywall-information\} Adapty では、[プロダクト](product)は App Store と Google Play 両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはペイウォールに統合され、モバイルアプリの特定のプレースメントで表示できるようになります。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)から[ペイウォール](paywalls)を取得する必要があります。 :::important **プロダクト ID をハードコードしないでください。** ハードコードすべき ID はプレースメント ID のみです。ペイウォールはリモートで設定されるため、プロダクト数や利用可能なオファーはいつでも変更される可能性があります。アプリはこれらの変更を動的に処理する必要があります。今日ペイウォールが 2 つのプロダクトを返し、明日 3 つを返す場合でも、コードを変更せずにすべてを表示できるようにしてください。 ::: ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` を使用してキャッシュデータが存在する場合にそれを返すことを検討してください。この場合、ユーザーが最新のデータを取得できないことがありますが、接続状況に関わらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中のネットワークリクエストを避けるために安全に使用できます。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動でのクリーンアップ時のみクリアされます。</p><p></p><p>Adapty SDK はペイウォールを2つの層に保存します。上記の定期的に更新されるキャッシュと[フォールバックペイウォール](kmp-use-fallback-paywalls)です。また、ペイウォールをより高速に取得するためにCDNを使用し、CDNに到達できない場合に備えたスタンドアロンのフォールバックサーバーも使用します。このシステムは、インターネット接続が不安定な場合でも信頼性を確保しつつ、常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルのフォールバックが返されます。</p><p></p><p>内部的に複数のリクエストで構成される場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトすることがあります。</p> | プロダクトIDをハードコードしないでください!ペイウォールはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特別オファー(無料トライアルなど)は随時変更される可能性があります。こうしたシナリオにコードで対応できるようにしてください。 例えば、最初に2つのプロダクトを取得した場合、アプリはその2つを表示する必要があります。後で3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できる必要があります。ハードコードする必要があるのはプレースメントIDだけです。 レスポンスパラメーター: | パラメータ | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォールの識別子、リモートコンフィグ、その他のプロパティを持つ [`AdaptyPaywall`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall/) オブジェクト。 | ## プロダクトの取得 \{#fetch-products\} ペイウォールを取得したら、それに対応するプロダクトの配列を取得できます: ```kotlin showLineNumbers Adapty.getPaywallProducts(paywall).onSuccess { products -> // the requested products }.onError { error -> // handle the error } ``` レスポンスパラメーター: | パラメーター | 説明 | | :-------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティを含む [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) オブジェクトのリスト。 | 独自のペイウォールデザインを実装する際、[`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) オブジェクトから以下のプロパティを参照することになるでしょう。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **Price** | ローカライズされた価格を表示するには、`product.price.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づきます。`product.price.amount` を使用すると、価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.price.currencySymbol` を使用します。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.subscriptionDetails?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づきます。プログラムでサブスクリプション期間を取得するには、`product.subscriptionDetails?.subscriptionPeriod` を使用します。`unit` 列挙型から期間の長さ(DAY、WEEK、MONTH、YEAR、または UNKNOWN)を取得できます。`numberOfUnits` の値は期間の単位数を返します。例えば、四半期サブスクリプションの場合、unit プロパティには `MONTH`、numberOfUnits プロパティには `3` が表示されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかどうかをバッジなどで表示するには、`product.subscriptionDetails?.introductoryOfferPhases` プロパティを確認します。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下のプロパティが含まれます:<br/>• `paymentMode`:`FREE_TRIAL`、`PAY_AS_YOU_GO`、`PAY_UPFRONT`、`UNKNOWN` の値を持つ列挙型。無料トライアルは `FREE_TRIAL` タイプになります。<br/>• `price`:数値としての割引価格。無料トライアルの場合は `0` になります。<br/>• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列。例えば、3日間のトライアルオファーの場合、このフィールドには `3 days` と表示されます。<br/>• `subscriptionPeriod`:オファー期間の詳細を個別に取得するには、このプロパティを使用します。前のセクションで説明したサブスクリプション期間と同様の動作をします。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## デフォルトオーディエンスのペイウォールでペイウォールの取得を高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ瞬時に取得されるため、このプロセスを高速化することを気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合、ペイウォールの取得に予想以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を提供したいと思うかもしれません。 これに対処するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、指定されたプレースメントの **All Users** オーディエンス向けペイウォールを取得します。ただし、推奨されるアプローチは `getPaywall` メソッドでペイウォールを取得することである点を理解しておくことが重要です。詳細は上記の[ペイウォール情報の取得](fetch-paywalls-and-products-kmp#fetch-paywall-information)セクションをご覧ください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したペイウォールを設計するか、現在の(レガシー)バージョンのユーザーがペイウォールの未レンダリングに関する問題に遭遇することを許容するか、どちらかを選ぶ必要があります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同じペイウォールを見ることになり、国、マーケティングのアトリビューション、独自のカスタム属性に基づくパーソナライズされたターゲティングが失われます。 デフォルトオーディエンス向けのペイウォール取得を高速化するメリットを優先したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-kmp#fetch-paywall-information)で説明した `getPaywall` を引き続き使用してください。 ::: ```kotlin showLineNumbers Adapty.getPaywallForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成した際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメータはマイナス(**-**)文字で区切られた1つ以上のサブタグで構成された言語コードである必要があります。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p> | | **fetchPolicy** | デフォルト: `AdaptyPaywallFetchPolicy.Default` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` を使用してキャッシュデータが存在する場合にそれを返すことを検討してください。この場合、ユーザーは最新のデータを取得できないことがありますが、インターネット接続の状態に関わらず、より速い読み込みを体験できます。キャッシュは定期的に更新されるため、ネットワークリクエストを減らすためにセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストールや手動でのクリーンアップによってのみ削除されます。</p> | </SDKv3> --- # File: present-remote-config-paywalls-kmp --- --- title: "Kotlin Multiplatform SDKでリモートコンフィグで設計されたペイウォールをレンダリングする" description: "Adapty Kotlin Multiplatform SDKでリモートコンフィグペイウォールを表示し、ユーザーエクスペリエンスをパーソナライズする方法をご確認ください。" --- <SDKv4> リモートコンフィグを使ってペイウォールをカスタマイズした場合は、ユーザーに表示するためのレンダリングをアプリのコードで実装する必要があります。リモートコンフィグはニーズに合わせた柔軟な設計が可能なため、ペイウォールに何を含めるか、どのような見た目にするかはすべて自由に決められます。Adapty はリモートコンフィグを取得するメソッドを提供しており、カスタムペイウォールの表示方法をご自身でコントロールできます。 ## フローのリモートコンフィグを取得して表示する \{#get-flow-remote-config-and-present-it\} v4 では、フローは `remoteConfigs` リストに設定済みロケールごとに 1 つの `AdaptyRemoteConfig` エントリを持ちます。ユーザーの言語設定に合ったロケールを選択し、必要な値を読み取ります。 ```kotlin showLineNumbers Adapty.getFlow("YOUR_PLACEMENT_ID") .onSuccess { flow -> val config = flow.remoteConfigs.firstOrNull { it.locale == "en" } ?: flow.remoteConfigs.firstOrNull() val headerText = config?.dataMap?.get("header_text") as? String // use the remote config values } .onError { error -> // handle the error } ``` ここまでで必要な値がすべて揃ったので、次はそれらをレンダリングして視覚的に魅力的なページに組み上げます。さまざまなスマートフォンの画面サイズや向きに対応したデザインを心がけ、デバイスを問わず快適に使えるユーザー体験を提供してください。 :::warning 以下の説明に従って[ペイウォール表示イベントを記録](present-remote-config-paywalls-kmp#track-paywall-view-events)してください。これにより、Adapty アナリティクスがファネルおよび A/B テスト用のデータを収集できるようになります。 ::: ペイウォールの表示が完了したら、次は購入フローの設定に進みます。ユーザーが購入を行う際は、フローのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実装](kmp-making-purchases)をご覧ください。 [フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](kmp-use-fallback-paywalls)をおすすめします。このバックアップは、インターネット接続やキャッシュが利用できない場合にユーザーへ表示され、そのような状況でもスムーズなエクスペリエンスを提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adapty はフローやペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、表示イベントの記録はお客様自身で行う必要があります。ユーザーがフローを見たタイミングを把握できるのはお客様だけだからです。 表示イベントを記録するには、`.logShowFlow(flow)` を呼び出すだけです。呼び出すと、ファネルや A/B テストの指標に反映されます。 :::important [フローBuilder](adapty-flow-builder) や [ペイウォールビルダー](adapty-paywall-builder) でレンダリングされたフローやペイウォールを表示する場合、`.logShowFlow(flow)` を呼び出す必要はありません。これらの場合、Adapty が自動的にビューを追跡します。 ::: ```kotlin showLineNumbers Adapty.logShowFlow(flow) .onSuccess { // flow view logged successfully } .onError { error -> // handle the error } ``` リクエストパラメーター: | パラメータ | 必須 | 説明 | | :-------- | :------- |:-----------------------------------------------------------------| | **flow** | 必須 | `Adapty.getFlow` で取得した `AdaptyFlow` オブジェクト。 | </SDKv4> <SDKv3> リモートコンフィグを使用してペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリング処理をアプリのコードに実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、ペイウォールに含める内容や表示方法はすべて自由に設定できます。リモートコンフィグを通じて設定したカスタムペイウォールを表示するために、リモートコンフィグを取得するメソッドを提供しています。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> val headerText = paywall.remoteConfig?.dataMap?.get("header_text") as? String // use the remote config values }.onError { error -> // handle the error } ``` 必要な値をすべて取得したら、それらをレンダリングして視覚的に魅力的なページに組み立てます。さまざまなモバイル端末の画面サイズや向きに対応したデザインにすることで、あらゆるデバイスでシームレスかつ使いやすい体験を提供できます。 :::warning 以下で説明する手順に従い、必ず[ペイウォール表示イベントを記録](present-remote-config-paywalls-kmp#track-paywall-view-events-1)してください。これにより、Adapty アナリティクスがファネルおよび A/B テスト用のデータを収集できるようになります。 ::: ペイウォールの表示が完了したら、購入フローの設定に進みましょう。ユーザーが購入を行う際は、ペイウォールのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入処理](kmp-making-purchases)をご覧ください。 [フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](kmp-use-fallback-paywalls)をおすすめします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーへ表示され、そのような状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見るタイミングを把握しているのがあなた自身であるため、手動での記録が必要です。 ペイウォールの表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。これにより、ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder) で作成したペイウォールを表示している場合は、`.logShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```kotlin showLineNumbers Adapty.logShowPaywall(paywall = paywall) .onSuccess { // paywall view logged successfully } .onError { error -> // handle the error } ``` リクエストパラメータ: | パラメーター | 必須/任意 | 説明 | | :---------- | :------- |:-------------------------------------------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/) オブジェクト。 | </SDKv3> --- # File: kmp-making-purchases --- --- title: "Kotlin Multiplatform 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)を使用していますか?** 購入は自動的に処理されるため、この手順はスキップできます。 **ステップごとのガイダンスをお探しですか?** エンドツーエンドの実装手順については、[クイックスタートガイド](kmp-implement-paywalls-manually)をご覧ください。 ::: ```kotlin showLineNumbers Adapty.makePurchase(product = product).onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // Grant access to the paid features } } is AdaptyPurchaseResult.UserCanceled -> { // Handle the case where the user canceled the purchase } is AdaptyPurchaseResult.Pending -> { // Handle deferred purchases (e.g., the user will pay offline with cash) } } }.onError { error -> // Handle the error } ``` リクエストパラメータ: | パラメータ | 必須 | 説明 | | :---------- | :------- |:----------------------------------------------------------------------------------------------------------------------------------------------| | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-paywall-product/) オブジェクト。 | レスポンスパラメータ: | パラメータ | 説明 | |---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>リクエストが成功した場合、レスポンスにはこのオブジェクトが含まれます。[AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) オブジェクトは、ユーザーのアクセスレベル、サブスクリプション、アプリ内の買い切り購入に関する包括的な情報を提供します。</p><p>アクセスレベルのステータスを確認して、ユーザーが必要なアクセス権を持っているかどうかを判断してください。</p> | :::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\} ユーザーが現在のサブスクリプションを更新する代わりに新しいサブスクリプションを選択した場合、その動作はアプリストアによって異なります。Google Play の場合、サブスクリプションは自動的に更新されません。以下の説明に従って、モバイルアプリのコードで切り替えを管理する必要があります。 Android でサブスクリプションを別のものに切り替えるには、追加パラメータを指定して `.makePurchase()` メソッドを呼び出してください: ```kotlin showLineNumbers val subscriptionUpdateParams = AdaptyAndroidSubscriptionUpdateParameters( oldSubVendorProductId = "old_subscription_product_id", replacementMode = AdaptyAndroidSubscriptionUpdateReplacementMode.CHARGE_FULL_PRICE ) val purchaseParams = AdaptyPurchaseParameters.Builder() .setSubscriptionUpdateParams(subscriptionUpdateParams) .build() Adapty.makePurchase( product = product, parameters = purchaseParams ).onSuccess { purchaseResult -> when (purchaseResult) { is AdaptyPurchaseResult.Success -> { val profile = purchaseResult.profile // successful cross-grade } is AdaptyPurchaseResult.UserCanceled -> { // user canceled the purchase flow } is AdaptyPurchaseResult.Pending -> { // the purchase has not been finished yet, e.g. user will pay offline by cash } } }.onError { error -> // Handle the error } ``` 追加リクエストパラメータ: | パラメータ | 必須 | 説明 | |:---------------|:---------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **parameters** | 任意 | [`AdaptyPurchaseParameters`](https://kmp.adapty.io/adapty/com.adapty.kmp.models/-adapty-purchase-parameters/) を通じて渡される [`AdaptyAndroidSubscriptionUpdateParameters`](https://kmp.adapty.io/////adapty/com.adapty.kmp.models/-adapty-android-subscription-update-parameters/) オブジェクト。 | サブスクリプションと切り替えモードについては、Google Developer ドキュメントで詳しく確認できます: - [切り替えモードについて](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\} <Details> <summary>オファーコードについて</summary> オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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アナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。 </Details> アプリ内でコード引き換えシートを表示するには: ```kotlin showLineNumbers Adapty.presentCodeRedemptionSheet() .onSuccess { // code redemption sheet presented successfully } .onError { error -> // 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)を有効にすることができます。 ```kotlin showLineNumbers Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withGoogleEnablePendingPrepaidPlans(true) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } ``` --- # File: kmp-restore-purchase --- --- title: "Kotlin Multiplatform SDKでのアプリ内購入の復元" description: "シームレスなユーザー体験を確保するためにAdaptyで購入を復元する方法を学びます。" --- 購入の復元は、サブスクリプションやアプリ内課金などの以前に購入したコンテンツへのアクセスを、再度料金を請求されることなく取り戻せる機能です。この機能は、アプリをアンインストール・再インストールしたユーザーや、新しいデバイスに切り替えたユーザーが、以前に購入したコンテンツに再度料金を支払わずにアクセスしたい場合に特に便利です。 :::note [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールでは、追加のコードなしに購入が自動的に復元されます。その場合は、このステップをスキップできます。 ::: ペイウォールのカスタマイズに[ペイウォールビルダー](adapty-paywall-builder)を使用していない場合に購入を復元するには、`.restorePurchases()`メソッドを呼び出します: ```kotlin showLineNumbers Adapty.restorePurchases().onSuccess { profile -> if (profile.accessLevels["YOUR_ACCESS_LEVEL"]?.isActive == true) { // successful access restore } }.onError { error -> // handle the error } ``` レスポンスパラメーター: | パラメーター | 説明 | |---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>[`AdaptyProfile`](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-profile/)オブジェクトです。このモデルにはアクセスレベル、サブスクリプション、および非サブスクリプション購入に関する情報が含まれています。</p><p>ユーザーがアプリにアクセスできるかどうかを判断するには、**アクセスレベルのステータス**を確認してください。</p> | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: implement-observer-mode-kmp --- --- title: "Kotlin Multiplatform SDKにオブザーバーモードを実装する" description: "Adaptyでオブザーバーモードを実装して、Kotlin Multiplatform SDKでユーザーのサブスクリプションイベントを追跡します。" --- すでに独自の購入インフラを持っており、Adapty への完全移行に踏み切れない場合は、[オブザーバーモード](observer-vs-full-mode)を検討してみてください。基本的な使い方では、オブザーバーモードにより高度なアナリティクスや、アトリビューション・アナリティクスシステムとのシームレスな統合が利用できます。 このニーズを満たす場合は、以下の2つの手順が必要です。 1. Adapty SDKの設定時に`observerMode`パラメーターを`true`に設定してオンにします。[Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)のセットアップ手順に従ってください。 2. 既存の購入インフラから[トランザクションを報告](report-transactions-observer-mode-kmp)します。 :::tip SDK v4では、ObserverモードでAdaptyレンダリングのフローやペイウォールを表示することもできます。ユーザーが購入または復元ボタンをタップすると、SDKがそのアクションをあなたのコードに渡し、購入や復元を自分で実行できます。[Observerモードでフローを表示する](kmp-present-flows-in-observer-mode)をご覧ください。 ::: ## オブザーバーモードの設定 \{#observer-mode-setup\} Adapty をサブスクリプションイベントの送信とアナリティクスにのみ使用し、購入やサブスクリプションのステータス管理は自分で行う場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作している場合、Adapty SDK はトランザクションをクローズしません。そのため、トランザクションの処理は必ずご自身で行ってください。 ::: ```kotlin showLineNumbers val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") .withObserverMode(true) // default false .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised in observer mode") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } ``` パラメーター: | パラメータ | 説明 | | --------------------------- | ------------------------------------------------------------ | | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御するブール値。デフォルト値は `false` です。 | ## オブザーバーモードで Adapty のペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adapty のペイウォールや A/B テスト機能も併用したい場合は可能ですが、オブザーバーモードでは追加の設定が必要です。上記の手順に加えて、以下を行ってください: 1. [リモートコンフィグペイウォール](present-remote-config-paywalls-kmp)の場合と同様に、通常通りペイウォールを表示します。 3. 購入トランザクションに[ペイウォールを紐付け](report-transactions-observer-mode-kmp)ます。 --- # File: report-transactions-observer-mode-kmp --- --- title: "Kotlin Multiplatform SDKのObserverモードでトランザクションを報告する" description: "Kotlin Multiplatform SDKのAdapty ObserverモードでユーザーインサイトとRevenue追跡のための購入トランザクションを報告します。" --- Observerモードでは、Adapty SDKは既存の購入システムを通じて行われた購入を自動的に追跡することができません。アプリストアからのトランザクションを手動で報告する必要があります。アナリティクスのエラーを防ぐために、アプリをリリースする**前**にこの設定を完了することが重要です。 `reportTransaction`を使用して、各トランザクションをAdaptyに明示的に報告してください。 :::warning **トランザクションの報告を省略しないでください!** `reportTransaction`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に`variationId`を含めてください。これにより、購入がトリガーしたペイウォールに関連付けられ、正確なペイウォールアナリティクスが確保されます。 ```kotlin showLineNumbers Adapty.reportTransaction( transactionId = "your_transaction_id", variationId = paywall.variationId ).onSuccess { profile -> // Transaction reported successfully // profile contains updated user data }.onError { error -> // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | --------------- | --------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | 必須 | アプリストアの購入から取得したトランザクションID。通常、ストアから返される購入トークンまたはトランザクション識別子です。 | | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://kmp.adapty.io//////adapty/com.adapty.kmp.models/-adapty-paywall/)オブジェクトの`variationId`プロパティを使用して取得できます。 | --- # File: kmp-troubleshoot-purchases --- --- title: "Kotlin Multiplatform SDKの購入に関するトラブルシューティング" description: "Kotlin Multiplatform SDKの購入に関するトラブルシューティング" --- このガイドでは、Kotlin Multiplatform SDKで手動購入を実装する際によく発生する問題の解決方法を説明します。 ## makePurchaseは正常に呼び出されるが、プロファイルが更新されない \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **問題**: `makePurchase`メソッドが正常に完了するにもかかわらず、ユーザーのプロファイルとサブスクリプションの状態がAdaptyに反映されない。 **原因**: 通常、これはGoogle Play Storeのセットアップが不完全か、設定に問題があることを示しています。 **解決策**: [Google Playのセットアップ手順](initial-android)がすべて完了しているか確認してください。 ## makePurchaseが2回呼び出される \{#makepurchase-is-invoked-twice\} **問題**: 同じ購入に対して`makePurchase`メソッドが複数回呼び出されている。 **原因**: UIの状態管理の問題や、ユーザーの素早い操作によって購入フローが複数回トリガーされる場合に発生します。 **解決策**: [Google Playのセットアップ手順](initial-android)がすべて完了しているか確認してください。 ## オブザーバーモードでのAdaptyError.cantMakePayments \{#adaptyerror-cantmakepayments-in-observer-mode\} **問題**: オブザーバーモードで`makePurchase`を使用すると`AdaptyError.cantMakePayments`が発生する。 **原因**: オブザーバーモードでは、Adaptyの`makePurchase`メソッドを使用せず、購入処理を自前で行う必要があります。 **解決策**: 購入に`makePurchase`を使用している場合は、オブザーバーモードを無効にしてください。`makePurchase`を使用するか、オブザーバーモードで自前の購入処理を行うか、どちらか一方を選択する必要があります。詳細は[オブザーバーモードの実装](implement-observer-mode-kmp)を参照してください。 ## 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 Storeから課金不可のエラーが返される。 **原因**: このエラーはAdatyとは無関係です。デバイスで課金が利用できないことを示すGoogle Play Billing Libraryのエラーです。 **解決策**: このエラーは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`が見つからないというエラーが発生する。 **原因**: 通常、これはサンドボックステストに関連する問題です。 **解決策**: 新しいサンドボックスユーザーを作成して再試行してください。これにより、サンドボックス環境での購入完了ハンドラーの問題が解決することが多いです。 --- # File: kmp-user --- --- title: "Kotlin Multiplatform SDKでのユーザーとアクセス" description: "Adapty SDKを使ってKotlin Multiplatformアプリでユーザーとアクセスレベルを操作する方法を学びましょう。" --- このページでは、Kotlin Multiplatformアプリでユーザーとアクセスレベルを操作するためのすべてのガイドをまとめています。必要なトピックを選んでください: - **[ユーザーを識別する](kmp-identifying-users)** - アプリでユーザーを識別する方法を学ぶ - **[ユーザーデータを更新する](kmp-setting-user-attributes)** - ユーザー属性とプロファイルデータを設定する - **[サブスクリプション状態の変化を監視する](kmp-listen-subscription-changes)** - サブスクリプションの変化をリアルタイムで監視する - **[キッズモード](kids-mode-kmp)** - アプリにキッズモードを実装する --- # File: kmp-identifying-users --- --- title: "Kotlin Multiplatform 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` パラメータとして渡すだけです: ```kotlin showLineNumbers Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId("YOUR_USER_ID") .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } } ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 設定後に Customer User ID を設定する \{#setting-customer-user-id-after-configuration\} SDK の設定時にユーザー ID がない場合は、後から `.identify()` メソッドを使っていつでも設定できます。このメソッドが最もよく使われるのは、登録後やログイン後に匿名ユーザーから認証済みユーザーへ切り替わるタイミングです。 ```kotlin showLineNumbers Adapty.identify("YOUR_USER_ID").onSuccess { // successful identify }.onError { error -> // handle the error } ``` リクエストパラメータ: - **Customer User ID**(必須): 文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信 ユーザーが再度アカウントにログインする場合など、Adapty のサーバーにすでにそのユーザーの情報が存在していることがあります。このような場合、Adapty SDK は自動的に新しいユーザーとして動作を切り替えます。カスタム属性やサードパーティネットワークからのアトリビューションなど、匿名ユーザーに対してデータを渡していた場合は、識別されたユーザーに対してそのデータを再送信する必要があります。 また、新しいユーザーのデータが異なる可能性があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得する必要があることにも注意してください。 ::: ### ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()` メソッドを呼び出すことで、いつでもユーザーをログアウトさせることができます: ```kotlin showLineNumbers Adapty.logout().onSuccess { // successful logout }.onError { error -> // handle the error } ``` その後、`.identify()` メソッドを使ってユーザーをログインさせることができます。 ## `appAccountToken` を割り当てる(iOS) \{#assign-appaccounttoken-ios\} [`iosAppAccountToken`](https://developer.apple.com/documentation/storekit/product/purchaseoption/appaccounttoken(_:)) は、App Store のトランザクションを内部ユーザー ID に紐付けるための **UUID** です。 StoreKit はすべてのトランザクションにこのトークンを関連付けるため、バックエンドで App Store のデータをユーザーと照合することができます。 ユーザーごとに安定した UUID を生成し、同じアカウントに対してデバイスをまたいで再利用してください。 これにより、購入や App Store の通知が正しく紐付けられたままになります。 トークンは、SDK のアクティベーション時またはユーザーの識別時の 2 つの方法で設定できます。 :::important `iosAppAccountToken` は必ず `customerUserId` と一緒に渡す必要があります。 トークンのみを渡した場合、トランザクションに含まれません。 ::: ```kotlin showLineNumbers // During configuration: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } // Or when identifying users Adapty.identify( customerUserId = "YOUR_USER_ID", iosAppAccountToken = "YOUR_IOS_APP_ACCOUNT_TOKEN" ).onSuccess { // successful identify }.onError { error -> // handle the error } ``` ## 難読化アカウント ID を設定する(Android) \{#set-obfuscated-account-ids-android\} Google Play では、ユーザーのプライバシーとセキュリティを強化するために、特定のユースケースで難読化アカウント ID が必要です。これらの ID は、ユーザー情報を匿名に保ちながら Google Play が購入を識別するのに役立ち、不正防止やアナリティクスにおいて特に重要です。 アプリが機密性の高いユーザーデータを扱っている場合や、特定のプライバシー規制への準拠が求められる場合に、これらの ID を設定する必要があるかもしれません。難読化 ID により、Google Play は実際のユーザー識別子を公開せずに購入を追跡できます。 :::important `androidObfuscatedAccountId` は必ず `customerUserId` と一緒に渡す必要があります。 難読化アカウント ID のみを渡した場合、トランザクションに含まれません。 ::: ```kotlin showLineNumbers // During configuration: Adapty.activate( AdaptyConfig.Builder("PUBLIC_SDK_KEY") .withCustomerUserId( id = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ) .build() ).onSuccess { // successful activation }.onError { error -> // handle the error } // Or when identifying users Adapty.identify( customerUserId = "YOUR_USER_ID", androidObfuscatedAccountId = "YOUR_OBFUSCATED_ACCOUNT_ID" ).onSuccess { // successful identify }.onError { error -> // handle the error } ``` ## デバイスをまたいでユーザーを検出する \{#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: kmp-setting-user-attributes --- --- title: "Kotlin Multiplatform SDKでユーザー属性を設定する" description: "Adaptyでユーザー属性を設定して、オーディエンスのセグメンテーションを改善する方法を学びます。" --- メールアドレスや電話番号など、アプリのユーザーにオプションの属性を設定できます。設定した属性は、ユーザー[セグメント](segments)の作成やCRMでの確認に活用できます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します。 ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() .withEmail("email@email.com") .withPhoneNumber("+18888888888") .withFirstName("John") .withLastName("Appleseed") .withGender(AdaptyProfile.Gender.FEMALE) .withBirthday(AdaptyProfile.Date(1970, 1, 3)) Adapty.updateProfile(builder.build()) .onSuccess { // profile updated successfully } .onError { error -> // handle the error } ``` `updateProfile` メソッドで以前に設定した属性はリセットされません。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 使用可能なキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters.Builder` で使用できるキー `<Key>` と値 `<Value>` は以下のとおりです。 | キー | 値 | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | Enum(使用可能な値: `AdaptyProfile.Gender.FEMALE`、`AdaptyProfile.Gender.MALE`、`AdaptyProfile.Gender.OTHER`) | | birthday | Date | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定できます。これらは通常、アプリの使用状況に関連するものです。たとえば、フィットネスアプリであれば週あたりのエクササイズ回数、語学学習アプリであればユーザーの習熟度レベルなどが考えられます。セグメントで使用してターゲットを絞ったペイウォールやオファーを作成したり、アナリティクスでどのプロダクト指標が収益に最も影響するかを分析したりするのに役立ちます。 ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withCustomAttribute("key1", "value1") ``` 既存のキーを削除するには、`.withRemovedCustomAttribute()` メソッドを使用します。 ```kotlin showLineNumbers val builder = AdaptyProfileParameters.Builder() builder.withRemovedCustomAttribute("key2") ``` 設定済みのカスタム属性を事前に確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning `customAttributes` の値は最新の状態でない場合があります。ユーザー属性は複数のデバイスからいつでも送信される可能性があるため、最後の同期以降にサーバー上の属性が変更されている場合があります。 ::: ### 制限事項 \{#limits\} - ユーザーあたり最大30件のカスタム属性 - キー名は最大30文字。キー名には英数字および以下の記号が使用できます: `_` `-` `.` - 値は文字列または小数で、50文字以内。 --- # File: kmp-listen-subscription-changes --- --- title: "Kotlin Multiplatform SDKでサブスクリプションのステータスを確認する" description: "Kotlin MultiplatorformアプリでAdaptyを使用してユーザーのサブスクリプションステータスを追跡・管理し、顧客維持率を向上させましょう。" --- Adaptyを使えば、サブスクリプションのステータス管理が簡単になります。プロダクトIDをコードに手動で埋め込む必要はありません。代わりに、[アクセスレベル](access-level)がアクティブかどうかを確認するだけで、ユーザーのサブスクリプションステータスをすぐに把握できます。 サブスクリプションステータスの確認を始める前に、[リアルタイム デベロッパー通知 (RTDN)](enable-real-time-developer-notifications-rtdn) を設定してください。 ## アクセスレベルとAdaptyProfileオブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは [AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) オブジェクトのプロパティです。アプリ起動時(例:[ユーザーを識別する](android-identifying-users#setting-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更があれば随時更新することを推奨します。こうすることで、都度リクエストを送らずにプロファイルオブジェクトを活用できます。 プロファイルの更新通知を受け取るには、以下の[サブスクリプションステータスを含むプロファイル更新の監視](android-listen-subscription-changes)セクションで説明しているプロファイル変更のリスナーを設定してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()` メソッドを使用してください: ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> // check the access }.onError { error -> // handle the error } ``` レスポンスパラメーター: | パラメーター | 説明 | | --------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile | <p>[AdaptyProfile](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-profile/) オブジェクトです。通常、ユーザーがアプリのプレミアム機能にアクセスできるかどうかを判断するには、プロファイルのアクセスレベルのステータスを確認するだけで十分です。</p><p></p><p>`.getProfile` メソッドは常にAPIへのクエリを試みるため、最新の結果を返します。ネットワーク接続がないなどの理由でAdapty SDKがサーバーから情報を取得できない場合は、キャッシュのデータが返されます。また、Adapty SDKは `AdaptyProfile` のキャッシュを定期的に更新し、情報をできるだけ最新の状態に保ちます。</p> | `.getProfile()` メソッドはユーザープロファイルを返し、そこからアクセスレベルのステータスを取得できます。アプリには複数のアクセスレベルを設定することも可能です。たとえばニュースアプリでトピックごとにサブスクリプションを販売する場合、「sports」や「science」といったアクセスレベルを作成できます。ただし、ほとんどのケースでは1つのアクセスレベルで十分です。その場合はデフォルトの「premium」アクセスレベルをそのままご利用ください。 デフォルトの「premium」アクセスレベルを確認する例: ```kotlin showLineNumbers Adapty.getProfile().onSuccess { profile -> if (profile.accessLevels["premium"]?.isActive == true) { // grant access to premium features } }.onError { error -> // handle the error } ``` ### サブスクリプションステータスの更新を監視する \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adaptyはイベントを発火します。 Adaptyからのメッセージを受け取るには、追加の設定が必要です: ```kotlin showLineNumbers Adapty.setOnProfileUpdatedListener { profile -> // handle any changes to subscription state } ``` Adaptyはアプリ起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDKに実装されたキャッシュには、プロファイルのサブスクリプションステータスが保存されます。つまり、サーバーが利用できない場合でも、キャッシュされたデータからプロファイルのサブスクリプション情報を取得できます。 ただし、キャッシュから直接データをリクエストすることはできません。SDKは1分ごとにサーバーへ定期的なクエリを行い、プロファイルに関する更新や変更を確認します。新しいトランザクションやその他の更新など、変更が検出された場合は、サーバーとの同期を保つためにキャッシュデータへ反映されます。 --- # File: kmp-deal-with-att --- --- title: "Kotlin Multiplatform SDKでATTを処理する" description: "Kotlin MultiplatformでAdaptyを使い始めて、サブスクリプションのセットアップと管理を効率化しましょう。" --- アプリがAppTrackingTransparencyフレームワークを使用してアプリトラッキングの認証リクエストをユーザーに表示する場合、[認証ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/)をAdaptyに送信する必要があります。 ```kotlin showLineNumbers val profileParameters = AdaptyProfileParameters.Builder() .withAttStatus(3) // 3 = ATTrackingManagerAuthorizationStatusAuthorized .build() Adapty.updateProfile(profileParameters) .onSuccess { // ATT status updated successfully } .onError { error -> // handle AdaptyError } ``` :::warning この値は変更されたらできるだけ早く送信することを強くお勧めします。そうすることで、設定済みのインテグレーションにタイムリーにデータが送信されます。 ::: --- # File: kids-mode-kmp --- --- title: "Kotlin Multiplatform SDKのキッズモード" description: "キッズモードを簡単に有効化してGoogleのポリシーに準拠。Kotlin Multiplatform SDKではGAIDや広告データを収集しません。" --- Kotlin Multiplatformアプリが子ども向けの場合、[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 Advertising 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の扱いにも注意が必要です。`<FirstName.LastName>`形式のユーザー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\} ポリシーに準拠するため、Adapty SDKの初期化時にAndroid Advertising ID(AAID/GAID)とIPアドレスの収集を無効にする必要があります: ```kotlin showLineNumbers override fun onCreate() { super.onCreate() val config = AdaptyConfig .Builder("PUBLIC_SDK_KEY") // highlight-start .withGoogleAdvertisingIdCollectionDisabled(true) // set to `true` .withIpAddressCollectionDisabled(true) // set to `true` // highlight-end .build() Adapty.activate(configuration = config) .onSuccess { Log.d("Adapty", "SDK initialised with privacy settings") } .onError { error -> Log.e("Adapty", "Adapty init error: ${error.message}") } } ``` --- # File: kmp-onboardings --- --- title: "Kotlin Multiplatform SDKにおけるオンボーディング" description: "Adapty SDKを使ってKotlin MultiplatformアプリでオンボーディングSDKを操作する方法を解説します。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や機能改善は行われません。代わりに[フロー](kmp-get-pb-paywalls)をご利用ください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、スムーズなアニメーション、一貫したネイティブな外観、高速な読み込み、WebViewへの依存がなくなります。詳しくは[フロー&ペイウォールの取得](kmp-get-pb-paywalls)と[フロー&ペイウォールの表示](kmp-present-paywalls)をご覧ください。 ::: <CustomDocCardList /> --- # File: kmp-get-onboardings --- --- title: "Kotlin Multiplatform SDKでオンボーディングを取得する" description: "Kotlin MultiplatformのAdaptyでオンボーディングを取得する方法を学びましょう。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](kmp-get-pb-paywalls)を使用してください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、そしてWebViewへの依存がなくなります。始めるには[フローとペイウォールの取得](kmp-get-pb-paywalls)および[フローとペイウォールの表示](kmp-present-paywalls)をご覧ください。 ::: [Adapty ダッシュボードのビルダーでオンボーディングのビジュアルデザインを完成させた](design-onboarding)後、Kotlin Multiplatform アプリでそれを表示できます。このプロセスの最初のステップは、以下で説明するように、プレースメントに関連付けられたオンボーディングとそのビュー設定を取得することです。 始める前に、以下を確認してください: 1. [Adapty Kotlin Multiplatform SDK](sdk-installation-kotlin-multiplatform) バージョン 3.15.0 以上がインストールされていること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## オンボーディングの取得 \{#fetch-onboarding\} ノーコードビルダーで[オンボーディング](onboardings)を作成すると、アプリが取得・表示するためのコンテナとして保存されます。このコンテナは、表示するコンテンツ、表示方法、ユーザーの操作(クイズの回答やフォーム入力など)の処理まで、すべてを管理します。また、アナリティクスイベントも自動的に追跡されるため、ビュートラッキングを別途実装する必要はありません。 パフォーマンスを最大限に高めるため、ユーザーに表示する前に画像が十分ダウンロードできるよう、早い段階でオンボーディングの設定を取得しておくことをおすすめします。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```kotlin showLineNumbers Adapty.getOnboarding( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, loadTimeout = 5.seconds ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | オンボーディングのローカライズ識別子。このパラメーターは、マイナス(**-**)で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目はリージョンを表します。<p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDKはサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境にいる可能性がある場合は、`.returnCacheDataElseLoad` を使用して、キャッシュが存在する場合にキャッシュデータを返すことを検討してください。この場合、最新のデータが取得できないこともありますが、通信状況に関わらず読み込み時間が短縮されます。キャッシュはセッション中も定期的に更新されるため、ネットワークリクエストを避けるために安全に使用できます。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2つの層で保存します。1つは上記の定期更新キャッシュ、もう1つはフォールバックオンボーディングです。また、CDN を使用してオンボーディングを高速に取得し、CDN が利用できない場合に備えてスタンドアロンのフォールバックサーバーも使用します。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト時間を制限します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>まれに、内部で複数のリクエストが行われる場合があるため、`loadTimeout` で指定した時間より若干遅れてタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | |:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | オンボーディングの識別子と設定、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyOnboarding`](https://kmp.adapty.io///adapty/com.adapty.kmp.models/-adapty-onboarding/) オブジェクト。 | ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ瞬時にフェッチされるため、このプロセスの高速化を気にする必要はありません。ただし、オーディエンスやオンボーディングの数が多く、ユーザーのインターネット接続が不安定な場合、オンボーディングのフェッチに想定以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないよりも、デフォルトのオンボーディングを表示してスムーズなユーザー体験を提供することを検討するとよいでしょう。 これに対処するには、`getOnboardingForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンス向けオンボーディングを取得します。ただし、推奨されるアプローチは `getOnboarding` メソッドでオンボーディングを取得することであり、詳細については上記の[オンボーディングの取得](#fetch-onboarding)セクションを参照してください。 :::warning `getOnboardingForDefaultAudience` の代わりに `getOnboarding` の使用を検討してください。前者には以下の重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のある設計が必要になるか、古いバージョンでの表示崩れを許容する必要があります。 - **パーソナライズなし**: 「全ユーザー」オーディエンス向けのコンテンツのみを表示するため、国、アトリビューション、カスタム属性によるターゲティングができません。 これらのデメリットよりも取得速度のメリットが大きい場合は、以下に示すように `getOnboardingForDefaultAudience` を使用してください。そうでない場合は、[上記](#fetch-onboarding)で説明している `getOnboarding` を使用してください。 ::: ```kotlin showLineNumbers Adapty.getOnboardingForDefaultAudience( placementId = "YOUR_PLACEMENT_ID", locale = "en", fetchPolicy = AdaptyPaywallFetchPolicy.Default, ).onSuccess { paywall -> // the requested paywall }.onError { error -> // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | オンボーディングのローカライズ識別子です。マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。<br/>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDKはサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。このオプションを推奨するのは、ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーがネットワークの不安定な環境を使用していると思われる場合は、`.returnCacheDataElseLoad` の使用を検討してください。キャッシュが存在する場合はキャッシュされたデータを返すため、ユーザーは最新データを取得できない場合がありますが、通信状況に関わらず高速に読み込めます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリをアンインストールするか手動でクリアした場合のみ削除されます。</p><p></p><p>Adapty SDKはオンボーディングをローカルに2層で保存します。1つは上記の定期更新キャッシュ、もう1つはフォールバックオンボーディングです。また、オンボーディングをより高速に取得するためにCDNを使用し、CDNに接続できない場合に備えて独立したフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも、常に最新バージョンのオンボーディングを確実に取得できるよう設計されています。</p> | --- # File: kmp-present-onboardings --- --- title: "Kotlin Multiplatform SDKでオンボーディングを表示する" description: "オンボーディングを効果的に表示してコンバージョンを高める方法を学びましょう。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](kmp-get-pb-paywalls)を使用してください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、アニメーションがよりスムーズで、ネイティブな外観と操作感が一貫しており、読み込み時間が短く、WebViewランタイムへの依存もありません。まずは[フローとペイウォールの取得](kmp-get-pb-paywalls)と[フローとペイウォールの表示](kmp-present-paywalls)をご覧ください。 ::: ビルダーを使ってオンボーディングをカスタマイズした場合、Kotlin Multiplatform アプリのコードでレンダリングを気にする必要はありません。このようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [Adapty Kotlin Multiplatform SDK](sdk-installation-kotlin-multiplatform) 3.16.1 以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 Adapty Kotlin Multiplatform SDKには、オンボーディングを表示する方法が2つあります: - **Compose Multiplatformを使用する場合** - **Compose Multiplatformを使用しない場合** ## Compose Multiplatformを使用する場合 \{#with-compose-multiplatform\} オンボーディングを表示するには、`createOnboardingView`メソッドで作成した`view`に対して`view.present()`メソッドを呼び出します。各`view`は一度しか使用できません。再度オンボーディングを表示する必要がある場合は、`createOnboardingView`をもう一度呼び出して新しい`view`インスタンスを作成してください。 :::warning 同じ`view`を再作成せずに再利用すると、エラーが発生する場合があります。 ::: ```kotlin showLineNumbers title="Kotlin Multiplatform" viewModelScope.launch { AdaptyUI.createOnboardingView(onboarding = onboarding).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ### iOS のプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのオンボーディングの表示スタイルを設定できます。このパラメータには `AdaptyUIIOSPresentationStyle.FULLSCREEN`(デフォルト)または `AdaptyUIIOSPresentationStyle.PAGESHEET` を指定できます。 ```kotlin showLineNumbers viewModelScope.launch { val view = AdaptyUI.createOnboardingView(onboarding = onboarding).getOrNull() view?.present(iosPresentationStyle = AdaptyUIIOSPresentationStyle.PAGESHEET) } ``` ### オンボーディング内のリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、アプリを切り替えることなくウェブページを表示できるシームレスなユーザー体験が提供されます。 外部ブラウザでリンクを開きたい場合は、`externalUrlsPresentation` パラメータを `AdaptyWebPresentation.EXTERNAL_BROWSER` に設定することでこの動作をカスタマイズできます: ```kotlin showLineNumbers viewModelScope.launch { AdaptyUI.createOnboardingView( onboarding = onboarding, externalUrlsPresentation = AdaptyWebPresentation.EXTERNAL_BROWSER // default – IN_APP_BROWSER ).onSuccess { view -> view.present() }.onError { error -> // handle the error } } ``` ## Compose Multiplatformを使わない場合 \{#without-compose-multiplatform\} :::note `createNativeOnboardingView` はコア モジュール `io.adapty:adapty-kmp` の一部です。Compose Multiplatform を使用していないプロジェクトでは、`io.adapty:adapty-kmp-ui` 依存関係は不要です。 ::: Compose Multiplatform を使わずにオンボーディングを埋め込むには、`createNativeOnboardingView` を呼び出します。レイアウトに追加できる `AdaptyNativeOnboardingView` が返されます: <Tabs> <TabItem value="android" label="Android"> ```kotlin showLineNumbers title="Kotlin Multiplatform (Android)" val nativeView = AdaptyUI.createNativeOnboardingView( context = context, viewModelStoreOwner = activity, onboarding = onboarding, observer = myOnboardingObserver, ) // Embed in your Compose layout: AndroidView( factory = { nativeView.view }, modifier = Modifier.fillMaxSize() ) ``` </TabItem> <TabItem value="ios" label="iOS"> KMP インターフェースのデフォルトメソッドは Swift では `@required` になるため、Swift から直接 `AdaptyUIOnboardingsEventsObserver` を実装することはできません。まず `iosMain` でオープン基底クラスを宣言してください: ```kotlin showLineNumbers title="iosMain (Kotlin)" open class BaseOnboardingObserver : AdaptyUIOnboardingsEventsObserver ``` 次に Swift でサブクラスを作成し、必要なメソッドのみをオーバーライドします。 ```swift showLineNumbers title="Swift" class MyOnboardingObserver: BaseOnboardingObserver { override func onboardingViewOnCloseAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { // remove nativeView from your view hierarchy } } let nativeView = AdaptyUI.shared.createNativeOnboardingView( onboarding: onboarding, observer: MyOnboardingObserver() ) // nativeView.viewController is a UIViewController. // Add it to your SwiftUI view or UIKit hierarchy. ``` </TabItem> </Tabs> ### ビューを破棄する \{#dispose-the-view\} レイアウトからビューを削除する際は`dispose()`を呼び出してください。これによりイベントリスナーの登録が解除され、内部リソースが解放されます。 ```kotlin showLineNumbers title="Kotlin Multiplatform" nativeView.dispose() ``` --- # File: kmp-handling-onboarding-events --- --- title: "Kotlin Multiplatform SDKでオンボーディングイベントを処理する" description: "AdaptyのKotlin Multiplatformでオンボーディング関連イベントを処理します。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や機能改善は行われません。代わりに[フロー](kmp-get-pb-paywalls)を使用してください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存がなくなります。まずは[フロー&ペイウォールの取得](kmp-get-pb-paywalls)と[フロー&ペイウォールの表示](kmp-present-paywalls)をご覧ください。 ::: 始める前に、以下を確認してください: 1. [Adapty Kotlin Multiplatform SDK](sdk-installation-kotlin-multiplatform) 3.15.0 以降がインストールされている。 2. [オンボーディングを作成](create-onboarding)している。 3. オンボーディングを[プレースメント](placements)に追加している。 ビルダーで設定したオンボーディングは、アプリが応答できるイベントを生成します。これらのイベントへの応答方法については、以下をご覧ください。 ## オンボーディングイベントオブザーバーの設定 \{#set-up-the-onboarding-event-observer\} オンボーディングイベントを処理するには、`AdaptyUIOnboardingsEventsObserver`インターフェースを実装し、`AdaptyUI.setOnboardingsEventsObserver()`でセットアップする必要があります。これはアプリのライフサイクルの早い段階、通常はメインアクティビティやアプリの初期化時に行ってください。 ```kotlin // In your app initialization AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` ## カスタムアクション \{#custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。このIDをコード内で使用し、カスタムアクションとして処理できます。 <img src={require('./img/ios-events-1.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 例えば、ユーザーが **Login** や **Allow notifications** などのカスタムボタンをタップすると、デリゲートメソッド `onCustomAction` がビルダーのアクション ID とともに呼び出されます。"allowNotifications" のように、独自の ID を作成できます。 ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnCustomAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { when (actionId) { "openPaywall" -> { // Display paywall from onboarding // You would typically fetch and present a new paywall here mainUiScope.launch { // Example: Get paywall by placement ID // val paywallResult = Adapty.getPaywall("your_placement_id") // paywallResult.onSuccess { paywall -> // val paywallViewResult = AdaptyUI.createPaywallView(paywall) // paywallViewResult.onSuccess { paywallView -> // paywallView.present() // } // } } } "allowNotifications" -> { // Handle notification permissions } else -> { // Handle other custom actions } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ## オンボーディングを閉じる \{#closing-onboarding\} オンボーディングは、ユーザーが**Close**アクションが割り当てられたボタンをタップしたときに閉じられたと見なされます。ユーザーがオンボーディングを閉じたときの動作を管理する必要があります。例えば: :::important ユーザーがオンボーディングを閉じたときの動作を管理する必要があります。たとえば、オンボーディング自体の表示を停止する必要があります。 ::: [`createNativeOnboardingView`](kmp-present-onboardings#without-compose-multiplatform) を使用している場合、`view.isStandaloneView` は `false` になります — デフォルトの実装では `view.dismiss()` は呼び出されません。代わりに、このコールバック内でレイアウトからビューを削除し、`dispose()` を呼び出してください。 ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnCloseAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { // Dismiss the onboarding screen mainUiScope.launch { view.dismiss() } // Additional cleanup or navigation logic can be added here // For example, navigate back or show main app content } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>イベント例(クリックして展開)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ## ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。ペイウォールが閉じられた後に開きたい場合は、[`onboardingViewOnCloseAction`](#closing-onboarding) を処理してペイウォールを開く方が、よりシンプルな方法です。この場合、イベントデータに依存する必要はありません。 ::: オンボーディングでペイウォールを扱う最もスムーズな方法は、アクション ID をペイウォールのプレースメント ID と同じにすることです。こうすることで、プレースメント ID を使ってすぐにペイウォールを取得・表示できます。 ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnPaywallAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, actionId: String ) { // Get the paywall using the placement ID from the action mainUiScope.launch { val paywallResult = Adapty.getPaywall(placementId = actionId) paywallResult.onSuccess { paywall -> val paywallViewResult = AdaptyUI.createPaywallView(paywall) paywallViewResult.onSuccess { paywallView -> paywallView.present() }.onError { error -> // handle the error } }.onError { error -> // handle the error } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>イベント例(クリックして展開)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ## オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、以下のメソッドが呼び出されます。 ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewDidFinishLoading( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta ) { // Handle loading completion // You can add any initialization logic here } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>イベント例(クリックして展開)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ## ナビゲーションイベント \{#navigation-events\} `onboardingViewOnAnalyticsEvent` メソッドは、オンボーディングフロー中にさまざまな分析イベントが発生したときに呼び出されます。 `event` オブジェクトは次のいずれかの型になります。 |型 | 説明 | |------------|-------------| | `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | オンボーディングが読み込まれたとき | | `AdaptyOnboardingsAnalyticsEventScreenPresented` | 任意の画面が表示されたとき | | `AdaptyOnboardingsAnalyticsEventScreenCompleted` | 画面が完了したとき。オプションの `elementId`(完了した要素の識別子)とオプションの `reply`(ユーザーからの応答)を含みます。ユーザーが画面を終了するための操作を行ったときにトリガーされます。 | | `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | 2番目の画面が表示されたとき | | `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | 入力フィールドを通じてユーザーのメールアドレスが収集されたときにトリガーされます | | `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | ユーザーが `final` IDを持つ画面に到達したときにトリガーされます。このイベントが必要な場合は、最後の画面に `final` IDを割り当ててください。 | | `AdaptyOnboardingsAnalyticsEventUnknown` | 認識できないイベント型に対して使用されます。`name`(不明なイベントの名前)と `meta`(追加のメタデータ)を含みます | 各イベントには以下のフィールドを含む `meta` 情報が付与されます: | フィールド | 説明 | |------------|-------------| | `onboardingId` | オンボーディングフローの一意識別子 | | `screenClientId` | 現在の画面の識別子 | | `screenIndex` | フロー内での現在の画面の位置 | | `screensTotal` | フロー内の画面の総数 | アナリティクスイベントをトラッキングに活用する例を以下に示します: ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnAnalyticsEvent( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, event: AdaptyOnboardingsAnalyticsEvent ) { when (event) { is AdaptyOnboardingsAnalyticsEventOnboardingStarted -> { // Track onboarding start trackEvent("onboarding_started", event.meta) } is AdaptyOnboardingsAnalyticsEventScreenPresented -> { // Track screen presentation trackEvent("screen_presented", event.meta) } is AdaptyOnboardingsAnalyticsEventScreenCompleted -> { // Track screen completion with user response trackEvent("screen_completed", event.meta, event.elementId, event.reply) } is AdaptyOnboardingsAnalyticsEventOnboardingCompleted -> { // Track successful onboarding completion trackEvent("onboarding_completed", event.meta) } is AdaptyOnboardingsAnalyticsEventUnknown -> { // Handle unknown events trackEvent(event.name, event.meta) } // Handle other cases as needed } } private fun trackEvent(eventName: String, meta: AdaptyUIOnboardingMeta, elementId: String? = null, reply: String? = null) { // Implement your analytics tracking here // For example, send to your analytics service } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript // OnboardingStarted { "meta": { "onboardingId": "onboarding_123", "screenClientId": "welcome_screen", "screenIndex": 0, "screensTotal": 4 } } // ScreenPresented { "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 4 } } // ScreenCompleted { "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 1, "screensTotal": 4 }, "elementId": "profile_form", "reply": "success" } // SecondScreenPresented { "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 1, "screensTotal": 4 } } // UserEmailCollected { "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 1, "screensTotal": 4 } } // OnboardingCompleted { "meta": { "onboardingId": "onboarding_123", "screenClientId": "final_screen", "screenIndex": 3, "screensTotal": 4 } } ``` </Details> --- # File: kmp-onboarding-input --- --- title: "Kotlin Multiplatform SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用して、Kotlin MultiplatformアプリでオンボーディングのデータをKotlin MultiplatformアプリのAdapty SDKで保存・活用しましょう。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](kmp-get-pb-paywalls)をご利用ください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存がなくなります。はじめるには[フロー&ペイウォールの取得](kmp-get-pb-paywalls)と[フロー&ペイウォールの表示](kmp-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`onboardingViewOnStateUpdatedAction` メソッドが呼び出されます。フィールドのタイプはコード内で保存または処理できます。 例: ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnStateUpdatedAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, elementId: String, params: AdaptyOnboardingsStateUpdatedParams ) { // Store user preferences or responses when (params) { is AdaptyOnboardingsSelectParams -> { // Handle single selection val id = params.id val value = params.value val label = params.label AppLogger.d("Selected option: $label (id: $id, value: $value)") } is AdaptyOnboardingsMultiSelectParams -> { // Handle multiple selections } is AdaptyOnboardingsInputParams -> { // Handle text input } is AdaptyOnboardingsDatePickerParams -> { // Handle date selection } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` <Details> <summary>保存データの例(実際の実装では形式が異なる場合があります)</summary> ```javascript // Example of a saved select action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "preferences_screen", "screen_index": 1, "total_screens": 3 }, "action": { "element_id": "preference_selector", "element_type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "interests_screen", "screen_index": 2, "total_screens": 3 }, "action": { "element_id": "interests_selector", "element_type": "multi_select", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 0, "total_screens": 3 }, "action": { "element_id": "name_input", "element_type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "id": "onboarding_on_state_updated_action", "view": { /* AdaptyUI.OnboardingView object */ }, "meta": { "onboarding_id": "onboarding_123", "screen_cid": "profile_screen", "screen_index": 0, "total_screens": 3 }, "action": { "element_id": "birthday_picker", "element_type": "date_picker", "value": { "day": 15, "month": 6, "year": 1990 } } } ``` </Details> ## ユースケース \{#use-cases\} ### ユーザープロファイルにデータを反映する \{#enrich-user-profiles-with-data\} 入力データをユーザープロファイルとすぐに紐づけ、同じ情報を二度聞かないようにするには、アクションの処理時に入力データで[ユーザープロファイルを更新](kmp-setting-user-attributes)する必要があります。 例えば、`name` IDのテキストフィールドにユーザーの名前を入力してもらい、その値をユーザーの名として設定したい場合や、`email` フィールドにメールアドレスを入力してもらいたい場合、アプリのコードは次のようになります。 ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnStateUpdatedAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, elementId: String, params: AdaptyOnboardingsStateUpdatedParams ) { // Store user preferences or responses when (params) { is AdaptyOnboardingsInputParams -> { // Handle text input val builder = AdaptyProfileParameters.Builder() // Map elementId to appropriate profile field when (elementId) { "name" -> { when (val input = params.input) { is AdaptyOnboardingsTextInput -> { builder.withFirstName(input.value) } } } "email" -> { when (val input = params.input) { is AdaptyOnboardingsEmailInput -> { builder.withEmail(input.value) } } } } // Update profile asynchronously mainUiScope.launch { val profileParams = builder.build() val result = Adapty.updateProfile(profileParams) result.onSuccess { profile -> // Profile updated successfully AppLogger.d("Profile updated: ${profile.email}") }.onError { error -> // Handle the error AppLogger.e("Failed to update profile: ${error.message}") } } } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` ### 回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングでクイズを使用することで、オンボーディング完了後にユーザーに表示するペイウォールをカスタマイズすることもできます。 たとえば、スポーツの経験についてユーザーに質問し、異なるユーザーグループに対して異なるCTAやプロダクトを表示することができます。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、その選択肢に意味のあるIDを割り当てます。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](kmp-setting-user-attributes)します。 ```kotlin class MyAdaptyUIOnboardingsEventsObserver : AdaptyUIOnboardingsEventsObserver { override fun onboardingViewOnStateUpdatedAction( view: AdaptyUIOnboardingView, meta: AdaptyUIOnboardingMeta, elementId: String, params: AdaptyOnboardingsStateUpdatedParams ) { // Handle quiz responses and set custom attributes when (params) { is AdaptyOnboardingsSelectParams -> { // Handle quiz selection val builder = AdaptyProfileParameters.Builder() // Map quiz responses to custom attributes when (elementId) { "experience" -> { // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.withCustomAttribute("experience", params.value) } } // Update profile asynchronously mainUiScope.launch { val profileParams = builder.build() val result = Adapty.updateProfile(profileParams) result.onSuccess { profile -> // Profile updated successfully AppLogger.d("Custom attribute 'experience' set to: ${params.value}") }.onError { error -> // Handle the error AppLogger.e("Failed to update profile: ${error.message}") } } } } } } // Set up the observer AdaptyUI.setOnboardingsEventsObserver(MyAdaptyUIOnboardingsEventsObserver()) ``` 3. [カスタム属性の値ごとにセグメントを作成する](segments)。 4. [プレースメント](placements)を作成し、作成した各セグメントに対して[オーディエンス](audience)を追加する。 5. アプリのコードにプレースメントの[ペイウォールを表示する](kmp-paywalls)。オンボーディングにペイウォールを開くボタンがある場合は、[このボタンのアクションへの応答](kmp-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装する。 --- # File: kmp-best-practices --- --- title: "Kotlin Multiplatform SDKのベストプラクティス" description: "Kotlin MultiplatformでAdapty SDKを統合するためのリファレンスパターン — 呼び出し順序、エラーハンドリング、その他の本番環境対応ルール。" --- <CustomDocCardList /> --- # File: kmp-sdk-call-order --- --- title: "Kotlin Multiplatform SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの消失、アトリビューションの欠落、断続的なアクティベーションエラーを防ぎます。" --- `Adapty.activate()` は、他のAdapty SDKメソッドを呼び出す前に完了している必要があります。完了するまで、SDKには状態がありません。`activate()` の前または並行して発行された呼び出しは、アクティベーションエラーで失敗します。詳細は[Kotlin Multiplatform SDKのエラー処理](kmp-handle-errors)を参照してください。 アプリがユーザー認証を行い、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `Adapty.identify()` を呼び出してください。`identify` が完了するまで、ユーザー操作に関連するメソッドは呼び出さないでください。`identify` と競合する呼び出しはエラーを返すか、アクティベーション時に作成された匿名プロファイルに紐付けられます。この状態になると、アトリビューション・`appsflyer_id` などのMMP ID・インストールの帰属先が、識別済みプロファイルに引き継がれないことがあります。アプリがユーザー認証を行わない場合は、`identify` を呼び出さず、匿名プロファイルのまま利用を続けてください。 MMP やアナリティクス SDK(AppsFlyer、Adjust、Branch、PostHog)も同様のルールに従います。`Adapty.activate` を呼び出す前に、これらを先に初期化し、UID コールバックを受け取るまで待ってください。そうしないと、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)、`AdaptyConfig.Builder` に渡してください。この方法では匿名プロファイルが作成されないため、手順4は不要です。 | ステップ | 呼び出し | タイミング | 備考 | |------|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------| | 1 | MMP または分析 SDK を初期化する(AppsFlyer、Adjust、PostHog、Branch) | アプリ起動時、最初に実行 | MMP の UID コールバック(例:`getAppsFlyerUID`)を待機する。 | | 2a | `Adapty.activate(configuration = AdaptyConfig.Builder("KEY").withCustomerUserId(...).build())` | アプリ起動時、ステップ 1 の後、customer user ID がある場合 | 推奨。匿名プロファイルは作成されない。 | | 2b | `Adapty.activate(configuration = AdaptyConfig.Builder("KEY").build())` (`withCustomerUserId` なし) | アプリ起動時、ステップ 1 の後、customer user ID がない場合(または収集しない場合) | Adapty が匿名プロファイルを作成する。 | | 3 | MMP ごとに `Adapty.setIntegrationIdentifier("appsflyer_id", uid)` を呼び出す | ステップ 2 の後、ユーザーアクション呼び出しの前 | MMP の ID を正しいプロファイルに紐付けるために必要。 | | 4 | `Adapty.identify("YOUR_USER_ID").onSuccess { ... }.onError { ... }` | ステップ 3 の後(MMP がない場合はステップ 2 の後)、ステップ 5 の前 — 認証を使うパス 2b のみ | ユーザーアクション呼び出しの前に `onSuccess` を待機すること。`identify` 実行中の並行呼び出しは匿名プロファイルに紐付く可能性がある。 | | 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()` によって新しい匿名プロファイルが作成されます。このプロファイルはウェブプロファイルとリンクされていません。認証フローやインストールリファラーからアプリ起動前にカスタマーユーザーIDを解決できる場合は、直接 `AdaptyConfig.Builder` に渡してください。そうしないと、`identify("YOUR_USER_ID")` を呼び出し、さらに `restorePurchases` を呼び出すまで、デバイスからウェブ購入が見えない状態になります。 各ウェブチェックアウトで送信するメタデータについては、以下を参照してください: - [Stripe](stripe) - [Paddle](paddle) --- # File: kmp-optimize-paywall-fetching --- --- title: "Kotlin Multiplatform SDKでのペイウォール取得の最適化" description: "Adapty ペイウォールを確実に取得する: Kotlin Multiplatform のタイミング、キャッシュ、フォールバックパターン。" --- Kotlin Multiplatform での信頼性の高いペイウォール取得には、3つの要件があります: 高速なレンダリング、オーディエンスターゲティングに基づくペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバックです。以下のルールでは、これを実現するためのタイミング、キャッシュ、フォールバックパターンについて説明します。 :::tip 以下のルールは、`Adapty.activate()` および `Adapty.identify()` がすでに解決済みであることを前提としています。詳細は [Kotlin Multiplatform SDK の呼び出し順序](kmp-sdk-call-order) を参照してください。 ::: 以下のアドバイスでは v3 のメソッド名を使用しています。SDK v4 では `getPaywall` が `getFlow` に名称変更されていますが([移行ガイド](migration-to-kmp-sdk-v4) を参照)、すべてのルールはそのまま適用されます。 ## ルールと注意点 \{#rules-and-pitfalls\} | こうする | こうしない | 理由 | |---|---|---| | 表示しようとしているプレースメントだけ取得する。 | 起動時にすべてのプレースメントを一括プリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、バースト中にブラックスクリーンが発生する。 | | アトリビューションが解決する時間を確保してから `getPaywall` を取得する(例:`activate` の 1〜2 秒後、または `setOnProfileUpdatedListener` が発火した後)。 | アプリ起動時に `getPaywall` を呼び出す。 | アトリビューションがまだ反映されていないため、ペイウォールはデフォルトのオーディエンスに対して解決され、セグメントや ASA のパーソナライズが暗黙的にスキップされる。 | | `loadTimeout` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無期限に待ち続ける。 | タイムアウトがないと、通信状況の悪いユーザーはネットワークが解決するまで白紙の画面を見続けるか、アプリを閉じてしまう。 | [ペイウォールとプロダクトの取得](fetch-paywalls-and-products-kmp)で`fetchPolicy`と`loadTimeout`パラメーターのリファレンスを確認し、[プレースメント](placements)で適切なプレースメントの選び方を参照してください。 ## 接続が不安定な環境向けの調整 \{#tune-for-poor-connectivity\} 接続が継続的に不安定な市場(農村地帯、交通機関、ルーティングの影響を受ける地域)向け: - 最初の取得を除くすべての取得で `fetchPolicy = AdaptyPaywallFetchPolicy.ReturnCacheDataElseLoad` を設定する。 - Adapty ダッシュボードのすべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeout` を3〜5秒に設定し、タイムアウトが発生した場合はフォールバックを受け入れる。 - ペイウォールの表示を `Adapty.getProfile()` に依存させない。`getPaywall` を独立して呼び出し、プロファイルの遅延がUIをブロックしないようにする。 --- # File: kmp-test --- --- title: "Kotlin Multiplatform SDKでテストとリリース" description: "AdaptyでKotlin MultiplatformアプリのサブスクリプションステータスをチェックするKotlin Multiplatformでのテスト方法を学びます。" --- Kotlin MultiplatformアプリにAdapty SDKを実装済みであれば、すべてが正しく設定されており、購入が期待通りに動作することを確認したいはずです。これには、SDK連携のテストと、サンドボックス環境での実際の購入フローのテストが含まれます。 ## アプリのテスト \{#test-your-app\} アプリ内課金の包括的なテストについては、プラットフォーム固有のテストガイドを参照してください:[iOSテストガイド](test-purchases-in-sandbox)および[Androidテストガイド](testing-on-android)。 ## リリースの準備 \{#prepare-for-release\} アプリをストアに申請する前に、[リリースチェックリスト](release-checklist)に従って以下を確認してください: - ストア接続とサーバー通知が設定されている - 購入が完了し、Adaptyに報告されている - アクセスが正しくアンロックおよびリストアされる - プライバシーとレビューの要件を満たしている --- # File: kmp-reference --- --- title: "Kotlin Multiplatform SDK リファレンス" description: "Adapty Kotlin Multiplatform SDK のリファレンスドキュメント。" --- このページには、Adapty Kotlin Multiplatform SDK のリファレンスドキュメントが掲載されています。必要なトピックを選択してください: - **[SDK モデル](https://kmp.adapty.io/adapty/)** - SDK が使用するデータモデルと構造 - **[エラーの処理](kmp-handle-errors)** - エラーハンドリングとトラブルシューティング --- # File: kmp-handle-errors --- --- title: "Kotlin Multiplatform SDKのエラー処理" description: "Adaptyを使ったKotlin MultiplatformアプリでのエラーハンドリングをLearnします。" --- このページでは、Adapty Kotlin Multiplatform SDKのエラー処理について説明します。 ## エラー処理の基本 \{#error-handling-basics\} Adapty SDKのすべてのメソッドは、成功またはエラーのいずれかの結果を返します。両方のケースを必ず処理してください。 <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers Adapty.getProfile { result -> when (result) { is AdaptyResult.Success -> { val profile = result.value // Handle success } is AdaptyResult.Error -> { val error = result.error // Handle error Log.e("Adapty", "Error: ${error.message}") } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers Adapty.getProfile(result -> { if (result instanceof AdaptyResult.Success) { AdaptyProfile profile = ((AdaptyResult.Success<AdaptyProfile>) result).getValue(); // Handle success } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); // Handle error Log.e("Adapty", "Error: " + error.getMessage()); } }); ``` </TabItem> </Tabs> ## よくあるエラーコード \{#common-error-codes\} | エラーコード | 説明 | 解決策 | |------------|-------------|----------| | 1000 | プロダクトIDが見つからない | ダッシュボードでプロダクトの設定を確認する | | 1001 | ネットワークエラー | インターネット接続を確認する | | 1002 | 無効なSDKキー | SDKキーを確認する | | 1003 | 支払いを処理できない | デバイスが支払いをサポートしていない | | 1004 | プロダクトが利用できない | ストアでプロダクトが設定されていない | ## 特定のエラーの処理 \{#handle-specific-errors\} ### ネットワークエラー \{#network-errors\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers Adapty.getPaywall("main") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // Use paywall } is AdaptyResult.Error -> { val error = result.error when (error.code) { 1001 -> { // Network error - show offline message showOfflineMessage() } else -> { // Other errors showErrorMessage(error.message) } } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers Adapty.getPaywall("main", result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue(); // Use paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); switch (error.getCode()) { case 1001: // Network error - show offline message showOfflineMessage(); break; default: // Other errors showErrorMessage(error.getMessage()); break; } } }); ``` </TabItem> </Tabs> ### 購入エラー \{#purchase-errors\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers product.makePurchase { result -> when (result) { is AdaptyResult.Success -> { val purchase = result.value // Purchase successful showSuccessMessage() } is AdaptyResult.Error -> { val error = result.error when (error.code) { 1003 -> { // Can't make payments showPaymentNotAvailableMessage() } 1004 -> { // Product not available showProductNotAvailableMessage() } else -> { // Other purchase errors showPurchaseErrorMessage(error.message) } } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers product.makePurchase(result -> { if (result instanceof AdaptyResult.Success) { AdaptyPurchase purchase = ((AdaptyResult.Success<AdaptyPurchase>) result).getValue(); // Purchase successful showSuccessMessage(); } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); switch (error.getCode()) { case 1003: // Can't make payments showPaymentNotAvailableMessage(); break; case 1004: // Product not available showProductNotAvailableMessage(); break; default: // Other purchase errors showPurchaseErrorMessage(error.getMessage()); break; } } }); ``` </TabItem> </Tabs> ## エラー回復の戦略 \{#error-recovery-strategies\} ### ネットワークエラー時の再試行 \{#retry-on-network-errors\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers fun getPaywallWithRetry(placementId: String, maxRetries: Int = 3) { var retryCount = 0 fun attemptGetPaywall() { Adapty.getPaywall(placementId) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value // Use paywall } is AdaptyResult.Error -> { val error = result.error if (error.code == 1001 && retryCount < maxRetries) { // Network error - retry retryCount++ Handler(Looper.getMainLooper()).postDelayed({ attemptGetPaywall() }, 1000 * retryCount) // Exponential backoff } else { // Max retries reached or other error showErrorMessage(error.message) } } } } } attemptGetPaywall() } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers public void getPaywallWithRetry(String placementId, int maxRetries) { AtomicInteger retryCount = new AtomicInteger(0); Runnable attemptGetPaywall = new Runnable() { @Override public void run() { Adapty.getPaywall(placementId, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue(); // Use paywall } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); if (error.getCode() == 1001 && retryCount.get() < maxRetries) { // Network error - retry retryCount.incrementAndGet(); new Handler(Looper.getMainLooper()).postDelayed(this, 1000 * retryCount.get()); } else { // Max retries reached or other error showErrorMessage(error.getMessage()); } } }); } }; attemptGetPaywall.run(); } ``` </TabItem> </Tabs> ### キャッシュデータへのフォールバック \{#fallback-to-cached-data\} <Tabs groupId="current-os" queryString> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers class PaywallManager { private var cachedPaywall: AdaptyPaywall? = null fun getPaywall(placementId: String) { Adapty.getPaywall(placementId) { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value cachedPaywall = paywall showPaywall(paywall) } is AdaptyResult.Error -> { val error = result.error if (error.code == 1001 && cachedPaywall != null) { // Network error - use cached paywall showPaywall(cachedPaywall!!) showOfflineIndicator() } else { // No cache available or other error showErrorMessage(error.message) } } } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers public class PaywallManager { private AdaptyPaywall cachedPaywall; public void getPaywall(String placementId) { Adapty.getPaywall(placementId, result -> { if (result instanceof AdaptyResult.Success) { AdaptyPaywall paywall = ((AdaptyResult.Success<AdaptyPaywall>) result).getValue(); cachedPaywall = paywall; showPaywall(paywall); } else if (result instanceof AdaptyResult.Error) { AdaptyError error = ((AdaptyResult.Error) result).getError(); if (error.getCode() == 1001 && cachedPaywall != null) { // Network error - use cached paywall showPaywall(cachedPaywall); showOfflineIndicator(); } else { // No cache available or other error showErrorMessage(error.getMessage()); } } }); } } ``` </TabItem> </Tabs> ## 次のステップ \{#next-steps\} - [Code-1000 noProductIDsFoundエラーの修正](InvalidProductIdentifiers-kmp) - [Code-1003 cantMakePaymentsエラーの修正](cantMakePayments-kmp) - [完全なAPIリファレンス](https://android.adapty.io) - SDKの全ドキュメント --- # File: InvalidProductIdentifiers-kmp --- --- title: "Kotlin Multiplatform 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** をコピーします。 <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 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) に移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テスト中のプロダクトが **Ready to Submit** になっていることを確認します。なっていない場合は、[App Store のプロダクト](app-store-products)ページの手順に従ってください。 <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. テーブルのプロダクト ID と、Adapty ダッシュボードの [**Products**](https://app.adapty.io/products) タブに表示されているプロダクト ID を比較します。ID が一致しない場合は、テーブルからプロダクト ID をコピーして、Adapty ダッシュボードでそのプロダクト ID を使って[プロダクトを作成](create-product)してください。 <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 3. プロダクトの提供状況を確認する \{#step-4-check-product-availability\} 1. **App Store Connect** に戻り、同じ **Subscriptions** セクションを開きます。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックしてプロダクト一覧を表示します。 3. テスト中のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Availability** セクションまでスクロールし、必要な国や地域がすべて一覧に含まれていることを確認します。 <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 4. プロダクトの価格を確認する \{#step-5-check-product-prices\} 1. 再度 **App Store Connect** の **Monetization** → **Subscriptions** セクションに移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックします。 3. テスト中のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Subscription Pricing** までスクロールし、**Current Pricing for New Subscribers** セクションを展開します。 <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 必要な価格がすべて一覧に含まれていることを確認します。 <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 5. アプリの有料ステータス、銀行口座、税務フォームがアクティブであることを確認する \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. [**App Store Connect**](https://appstoreconnect.apple.com/) のホームページで **Business** をクリックします。 <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 会社名を選択します。 <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. スクロールして、**Paid Apps Agreement**、**Bank Account**、**Tax forms** がすべて **Active** と表示されていることを確認します。 <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これらの手順を実施することで、`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-kmp --- --- title: "Kotlin Multiplatform SDKにおけるCode-1003 cantMakePaymentエラーの修正方法" description: "Adaptyでサブスクリプションを管理する際の支払い処理エラーを解決します。" --- 1003エラー(`cantMakePayments`)は、このデバイスでアプリ内課金ができないことを示しています。 `cantMakePayments`エラーが発生している場合、通常は以下のいずれかの原因が考えられます: - デバイスの制限:このエラーはAdaptyとは無関係です。以下の解決方法を参照してください。 - オブザーバーモードの設定:`makePurchase`メソッドとオブザーバーモードは同時に使用できません。以下のセクションを参照してください。 ## 問題:デバイスの制限 \{#issue-device-restrictions\} | 問題 | 解決方法 | |-----------------------------|---------------------------------------------------------| | スクリーンタイムの制限 | [スクリーンタイム](https://support.apple.com/en-us/102470)でアプリ内課金の制限を無効にする | | アカウントの停止 | Appleサポートに連絡してアカウントの問題を解決する | | 地域の制限 | 対応地域のApp Storeアカウントを使用する | ## 問題:オブザーバーモードとmakePurchaseの併用 \{#issue-using-both-observer-mode-and-makepurchase\} 購入処理に`makePurchase`を使用している場合、オブザーバーモードを使用する必要はありません。[オブザーバーモード](observer-vs-full-mode)が必要なのは、購入ロジックを自分で実装する場合のみです。 したがって、`makePurchase`を使用している場合は、SDK有効化コードからオブザーバーモードの有効化を安全に削除できます。 --- # File: kmp-sdk-migration-guides --- --- title: "Kotlin Multiplatform SDK 移行ガイド" description: "Adapty Kotlin Multiplatform SDK バージョンの移行ガイド。" --- このページには、Adapty Kotlin Multiplatform SDK のすべての移行ガイドが掲載されています。詳細な手順については、移行先のバージョンを選択してください: - **[v4.0(ベータ版)への移行](migration-to-kmp-sdk-v4)** - **[v3.15 への移行](migration-to-kmp-315)** --- # File: migration-to-kmp-sdk-v4 --- --- title: "Adapty Kotlin Multiplatform SDK を v. 4.0 へ移行する" description: "ペイウォール API をフロー API に置き換えることで Adapty Kotlin Multiplatform SDK v4.0 (beta) へ移行します。Flow Builder と Paywall Builder の両方に対応しています。" --- Adapty Kotlin Multiplatform SDK 4.0 (beta) ではフローが導入され、それに伴いペイウォール API の名称が変更されました。新しい API は新しい Flow Builder と既存の Paywall Builder の両方で動作するため、Adapty ダッシュボード側での設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `Adapty.getPaywall(placementId, locale)` | `Adapty.getFlow(placementId)` | | `Adapty.getPaywallForDefaultAudience(placementId, locale)` | `Adapty.getFlowForDefaultAudience(placementId)` | | `Adapty.getPaywallProducts(paywall)` | `Adapty.getPaywallProducts(flow)` | | `Adapty.logShowPaywall(paywall)` | `Adapty.logShowFlow(flow)` | | `AdaptyPaywall` | `AdaptyFlow` | | `AdaptyUI.createPaywallView(paywall, ...)` | `AdaptyUI.createFlowView(flow, ...)` | | `AdaptyUI.createNativePaywallView(...)` → `AdaptyNativePaywallView` | `AdaptyUI.createNativeFlowView(...)` → `AdaptyNativeFlowView` | | `AdaptyUIPaywallView` | `AdaptyUIFlowView` | | `AdaptyUI.presentPaywallView(view)` / `dismissPaywallView(view)` | `AdaptyUI.presentFlowView(view)` / `dismissFlowView(view)` | | `AdaptyUI.setPaywallsEventsObserver(observer)` | `AdaptyUI.setFlowsEventsObserver(observer)` | | `AdaptyUI.registerPaywallEventsListener` / `unregisterPaywallEventsListener` | `AdaptyUI.registerFlowEventsListener` / `unregisterFlowEventsListener` | | `AdaptyUIPaywallsEventsObserver` | `AdaptyUIFlowsEventsObserver` | | `AdaptyUIPaywallPlatformView(paywall, ...)` | `AdaptyUIFlowPlatformView(flow, ...)` | | `paywallViewDidPerformAction`、`paywallViewDidAppear`、その他の `paywallView...` コールバック | `flowViewDidPerformAction`、`flowViewDidAppear`、その他の `flowView...` コールバック | | `paywallViewDidFailRendering` | `flowViewDidReceiveError` | `AdaptyPaywallProduct` はその名前を保持します — プロダクトは引き続きフローに属しており、`getPaywallProducts` もその名前を保持し、`AdaptyFlow` を受け取るようになりました。`getFlow` および `getFlowForDefaultAudience` メソッドは、`locale` パラメーターを受け取らなくなりました。購入およびプロファイル API(`makePurchase`、`restorePurchases`、`getProfile`、`identify`、`updateProfile`)と `setFallback` によるフォールバックは変更されていません。オンボーディングメソッドは引き続き動作しますが、非推奨となっています — [オンボーディング API の非推奨](#onboarding-api-deprecation) を参照してください。一部のデフォルト動作が変更されました — [デフォルト動作の変更](#default-behavior-changes) を参照してください。 ## インストール \{#installation\} v4.0 はプレリリース版のため、正確なバージョンを固定してください。Gradle は動的レンジではプレリリースバージョンを選択しません: ```toml showLineNumbers title="libs.versions.toml" [versions] adapty-kmp = "4.0.0-beta.1" [libraries] adapty-kmp = { module = "io.adapty:adapty-kmp", version.ref = "adapty-kmp" } adapty-kmp-ui = { module = "io.adapty:adapty-kmp-ui", version.ref = "adapty-kmp" } ``` `adapty-kmp-ui` モジュールが必要なのは、Compose Multiplatform レイヤー(`view.present()`)でフローやペイウォールをレンダリングする場合のみです。完全なセットアップ手順については、[Adapty SDK のインストール](sdk-installation-kotlin-multiplatform)をご覧ください。 両プラットフォームのネイティブ Adapty SDK は 4.x リリースにバンプされており、自動的に解決されるため、ビルドの変更は不要です。iOS のデプロイメントターゲットは **15.0** のままで、このリリースによる変更はありません。 ## フローの取得 \{#fetching-flows\} ### getPaywall → getFlow 戻り値の型が `AdaptyPaywall` から `AdaptyFlow` に変わり、`locale` パラメータが削除されました。フローをレンダリングする際、ロケールは自動的に解決されます。カスタムペイウォールの場合、すべてのロケールは `flow.remoteConfigs` に含まれます。 ```diff showLineNumbers - Adapty.getPaywall("YOUR_PLACEMENT_ID", locale = "en") - .onSuccess { paywall -> - // use the paywall + Adapty.getFlow("YOUR_PLACEMENT_ID") + .onSuccess { flow -> + // use the flow } .onError { error -> // handle the error } ``` `getPaywallForDefaultAudience` も同様に名前が変更されています: ```diff showLineNumbers - Adapty.getPaywallForDefaultAudience("YOUR_PLACEMENT_ID", locale = "en") + Adapty.getFlowForDefaultAudience("YOUR_PLACEMENT_ID") ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` は名前はそのままですが、`AdaptyFlow` を受け取るようになりました: ```diff showLineNumbers - Adapty.getPaywallProducts(paywall) + Adapty.getPaywallProducts(flow) .onSuccess { products -> // use the products } ``` ## データモデル \{#data-model\} `getFlow` は `AdaptyPaywall` の代わりに `AdaptyFlow` を返し、オブジェクトの構造が変わりました。 | v3 `AdaptyPaywall` プロパティ | v4 `AdaptyFlow` プロパティ | 対応内容 | |---|---|---| | `remoteConfig: AdaptyRemoteConfig?` (単一) | `remoteConfigs: List<AdaptyRemoteConfig>` | フローは設定された言語ごとに1つのリモートコンフィグを持ちます。ユーザーに合ったものを取得するには: `flow.remoteConfigs.firstOrNull { it.locale == "en" }` | | _(新規)_ | `paywalls: List<AdaptyFlowPaywall>` | 各エントリはフロー内の1つのペイウォールバリエーションで、`name`、`variationId`、`productIdentifiers` を持ちます。WebペイウォールのメソッドはAdaptyFlowPaywallを引数に受け取ります — [Webペイウォールメソッド](#web-paywall-methods)を参照してください。 | | `productIdentifiers` | 移動 | プロダクト識別子は各バリエーションに移動しました: `flow.paywalls[i].productIdentifiers`。プロダクトの取得には引き続き `getPaywallProducts(flow)` を使用してください。 | | `hasViewConfiguration` | 削除 | コードから`hasViewConfiguration`のチェックをすべて削除してください — 代わりに`createFlowView`がエラーを返します([フローの表示](#displaying-flows)を参照)。 | `hasViewConfiguration` は `AdaptyOnboarding` に残ります — フローモデルのみが削除されます。 ## Webペイウォールメソッド \{#web-paywall-methods\} `openWebPaywall` と `createWebPaywallUrl` の名前はそのままですが、`paywall` パラメータが `AdaptyFlowPaywall` を受け取る `flowPaywall` パラメータに置き換わりました。`AdaptyFlowPaywall` は `flow.paywalls` のバリアントの1つです。引き続き `AdaptyPaywallProduct` を渡すこともできます: ```diff showLineNumbers - Adapty.openWebPaywall(paywall = paywall) + flow.paywalls.firstOrNull()?.let { flowPaywall -> + Adapty.openWebPaywall(flowPaywall = flowPaywall) + } ``` ## フローのビュー数を追跡する \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` は `logShowFlow` に名前が変更され、`AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリアントに対して記録されるため、既存のファネルや A/B テストの指標はダッシュボードを変更することなくそのまま機能します。 ```diff showLineNumbers - Adapty.logShowPaywall(paywall) + Adapty.logShowFlow(flow) ``` v3 と同様に、[フロービルダー](adapty-flow-builder)または[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示する際は、このメソッドを呼び出す必要はありません。Adapty がそれらのビューを自動的にトラッキングします。 ## フローの表示 \{#displaying-flows\} ### createPaywallView → createFlowView ファクトリーメソッドの名前を変更し、`AdaptyFlow` を渡します。返されるビューの型は `AdaptyUIPaywallView` から `AdaptyUIFlowView` に変更されますが、メソッド(`present`、`dismiss`)およびオプションパラメーター(`loadTimeout`、`preloadProducts`、`customTags`、`customTimers`、`customAssets`、`productPurchaseParams`)は変更ありません: ```diff showLineNumbers - AdaptyUI.createPaywallView(paywall) + AdaptyUI.createFlowView(flow) .onSuccess { view -> view.present() } .onError { error -> // handle the error } ``` Compose Multiplatformを使用しない場合、ネイティブのファクトリーメソッドも同様にリネームされます: ```diff showLineNumbers - AdaptyUI.createNativePaywallView(paywall) + AdaptyUI.createNativeFlowView(flow) ``` `createFlowView` は、フローにビューが設定されていない場合に `AdaptyResult.Error` を返します — これはv3の `hasViewConfiguration` チェックに置き換わります: ```diff showLineNumbers - if (paywall.hasViewConfiguration) { - AdaptyUI.createPaywallView(paywall) - .onSuccess { view -> view.present() } - } + AdaptyUI.createFlowView(flow) + .onSuccess { view -> view.present() } + .onError { error -> + // the flow has no view configured, or view creation failed + } ``` :::note フロービューは使い捨てです。`dismiss()` を呼び出すとビューが破棄されるため、フローを再表示するには `createFlowView` を再度呼び出してください。 ::: ## イベントの処理 \{#handling-events\} イベントオブザーバーは `AdaptyUIPaywallsEventsObserver` から `AdaptyUIFlowsEventsObserver` に名前が変わり、コールバックの `paywallView` プレフィックスが `flowView` に変わります。既存のハンドラー本体のコード変更は不要です。型名とオーバーライドを変更するだけです。 ```diff showLineNumbers - AdaptyUI.setPaywallsEventsObserver(object : AdaptyUIPaywallsEventsObserver { - override fun paywallViewDidFinishPurchase( - view: AdaptyUIPaywallView, + AdaptyUI.setFlowsEventsObserver(object : AdaptyUIFlowsEventsObserver { + override fun flowViewDidFinishPurchase( + view: AdaptyUIFlowView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult ) { // custom logic after purchase } }) ``` コールバックも1つ名前が変更されています。`paywallViewDidFailRendering` が `flowViewDidReceiveError` になりました。以前と同じレンダリングエラーに加え、購入以外のランタイムエラーでも発火します。 ```diff showLineNumbers - override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) {} + override fun flowViewDidReceiveError(view: AdaptyUIFlowView, error: AdaptyError) {} ``` コールバックの全一覧については、[フロー & ペイウォールイベントの処理](kmp-handling-events)を参照してください。 ### Compose プラットフォームビュー \{#compose-platform-view\} Compose Multiplatform のコンポーザブルを使用してビューを埋め込む場合、`AdaptyUIPaywallPlatformView(paywall, ...)` は `AdaptyUIFlowPlatformView(flow, ...)` に名称変更されます。イベントコールバックの `onDid...` という名前はそのまま維持されますが、`onDidFailRendering` のみ `onDidReceiveError` に変更されます。 ```diff showLineNumbers - AdaptyUIPaywallPlatformView( - paywall = paywall, + AdaptyUIFlowPlatformView( + flow = flow, onDidFinishPurchase = { view, product, result -> /* ... */ }, ) ``` v3と同様に、ここで渡すコールバック(および`registerFlowEventsListener`で登録したオブザーバー)は、グローバルオブザーバーの**代わりに**ではなく、**追加として**実行されます。つまり、コールバックはイベントを監視するのみであり、グローバルのデフォルト動作を置き換えるものではありません。[変更されたデフォルト動作](#default-behavior-changes)に注意してください。たとえば、グローバルのデフォルトでは購入後にビューが閉じられなくなっています。 ### 新しいAPI \{#new-apis\} - `AdaptyUI.setObserverModeResolver(...)` に `AdaptyUIObserverModeResolver` を指定することで、SDKが[オブザーバーモード](implement-observer-mode-kmp)で動作している際にフローから開始された購入と復元を処理できます。以前はネイティブのiOSおよびAndroid SDKのみで利用可能でした。詳細は[オブザーバーモードでフローを表示する](kmp-present-flows-in-observer-mode)を参照してください。 - `AdaptyUI.setSystemRequestsHandler(...)` に `AdaptyUISystemRequestsHandler` を指定することで、フローからのシステムリクエスト(OSの権限プロンプトやアプリレビューリクエスト)を処理するために予約されています。フローはまだこれらのリクエストをトリガーしないため、ハンドラーを登録する必要はありません。 - 新しいオプションの `flowViewDidReceiveAnalyticEvent` コールバックは、フローからのカスタム分析イベント用に予約されています。フローはまだこれらをコードに送出しないため、実装する必要はありません。 - `AdaptyUI.openWebUrl(url, openIn)` および `AdaptyUI.requestAppReview()` — これらはデフォルトの `OpenUrlAction` 処理とデフォルトの `handleAppReviewRequest` を支援するため、URLおよびアプリレビューのプロンプトはそのままネイティブで処理されます。これらのデフォルトをオーバーライドする場合にのみ直接呼び出してください。 - `AdaptyConfig.ServerCluster.CN` — `DEFAULT` および `EU` と並ぶ新しいサーバークラスターオプションで、アプリを[AdaptyのChinaサーバー](china-cluster)に接続するために使用します。 ## デフォルト動作の変更 \{#default-behavior-changes\} これらの変更はコンパイルエラーを引き起こさないため、ランタイムでテストしてください。 - **購入完了時の挙動**: v3 では、デフォルトの `paywallViewDidFinishPurchase` が `AdaptyPurchaseResult.UserCanceled` 以外の購入結果に対してビューを閉じていました。v4 では、デフォルトの `flowViewDidFinishPurchase` は何もしないため、**購入が完了してもフローは明示的に閉じるまで開いたままになります** — iOS の挙動に合わせた変更です。自動的に閉じる動作に依存していた場合は、購入完了後に自分で `view.dismiss()` を呼び出してください。 - **Android のシステムバック**: v3 では、デフォルトの `paywallViewDidPerformAction` が `CloseAction` と `AndroidSystemBackAction` の両方でビューを閉じていました。v4 では、デフォルトは `CloseAction` のみを処理します — **システムバックボタンでは単独でフローが閉じなくなりました**。これは、システムジェスチャーでフローを閉じられない iOS の挙動に合わせたものです。ユーザーが明示的に閉じられるよう(**Close** ボタンや `on_device_back` アクションなど)対応するか、`flowViewDidPerformAction` 内で自分でビューを閉じてください。 - **ビューのエラー**: v3 では、デフォルトの `paywallViewDidFailRendering` は何もしませんでした。v4 では、デフォルトの `flowViewDidReceiveError` が**ビューを閉じます** — ビューを開いたままにしたい場合やエラーを独自に処理したい場合はオーバーライドしてください。 - **ビューは使い捨て**: `dismiss()` を呼び出すとビューは破棄されます。フローを再度表示するには、`createFlowView` をもう一度呼び出してください。 ## オンボーディング API の廃止 \{#onboarding-api-deprecation\} レガシーのオンボーディング API は、[フロービルダー](adapty-flow-builder)への移行に伴い v4.0 で非推奨となりました。現時点では引き続き動作しますが、将来のリリースで削除される予定です。オンボーディングをフロービルダーへ移行する計画を立ててください。 非推奨のシンボル: `getOnboarding`、`getOnboardingForDefaultAudience`、`AdaptyUI.createOnboardingView`、`AdaptyUI.createNativeOnboardingView`、`AdaptyUIOnboardingsEventsObserver`。 --- # File: migration-to-kmp-315 --- --- title: "Adapty Kotlin Multiplatform SDK 3.15.0 移行ガイド" description: "Adapty Kotlin Multiplatform SDK 3.15.0 の移行手順" --- Adapty Kotlin Multiplatform SDK 3.15.0 はメジャーリリースであり、新機能と改善が含まれています。ただし、一部の移行作業が必要になる場合があります。 1. オブザーバークラスとメソッド名を更新する。 2. フォールバックペイウォールのメソッド名を更新する。 3. イベントハンドリングメソッドのビュークラス名を更新する。 ## オブザーバークラスとメソッド名を更新する \{#update-observer-class-and-method-names\} オブザーバークラスとその登録メソッドの名前が変更されました: ```diff - import com.adapty.kmp.AdaptyUIObserver + import com.adapty.kmp.AdaptyUIPaywallsEventsObserver - import com.adapty.kmp.models.AdaptyUIView + import com.adapty.kmp.models.AdaptyUIPaywallView - class MyAdaptyUIObserver : AdaptyUIObserver { - override fun paywallViewDidPerformAction(view: AdaptyUIView, action: AdaptyUIAction) { + class MyAdaptyUIPaywallsEventsObserver : AdaptyUIPaywallsEventsObserver { + override fun paywallViewDidPerformAction(view: AdaptyUIPaywallView, action: AdaptyUIAction) { // handle actions } } // Set up the observer - AdaptyUI.setObserver(MyAdaptyUIObserver()) + AdaptyUI.setPaywallsEventsObserver(MyAdaptyUIPaywallsEventsObserver()) ``` ## フォールバックペイウォールのメソッド名を更新する \{#update-fallback-paywalls-method-name\} フォールバックペイウォールを設定するメソッド名が変更されました: ```diff showLineNumbers - Adapty.setFallbackPaywalls(assetId = "fallback.json") + Adapty.setFallback(assetId = "fallback.json") .onSuccess { // Fallback paywalls loaded successfully } .onError { error -> // Handle the error } ``` ## イベントハンドリングメソッドのビュークラス名を更新する \{#update-view-class-name-in-event-handling-methods\} すべてのイベントハンドリングメソッドで、`AdaptyUIView` の代わりに新しい `AdaptyUIPaywallView` クラスを使用するようになりました: ```diff - override fun paywallViewDidAppear(view: AdaptyUIView) { + override fun paywallViewDidAppear(view: AdaptyUIPaywallView) { // Handle paywall appearance } - override fun paywallViewDidDisappear(view: AdaptyUIView) { + override fun paywallViewDidDisappear(view: AdaptyUIPaywallView) { // Handle paywall disappearance } - override fun paywallViewDidSelectProduct(view: AdaptyUIPaywallView, productId: String) { + override fun paywallViewDidSelectProduct(view: AdaptyUIView, productId: String) { // Handle product selection } - override fun paywallViewDidStartPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct) { + override fun paywallViewDidStartPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct) { // Handle purchase start } - override fun paywallViewDidFinishPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { + override fun paywallViewDidFinishPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, purchaseResult: AdaptyPurchaseResult) { // Handle purchase result } - override fun paywallViewDidFailPurchase(view: AdaptyUIView, product: AdaptyPaywallProduct, error: AdaptyError) { + override fun paywallViewDidFailPurchase(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct, error: AdaptyError) { // Add your purchase failure handling logic here } - override fun paywallViewDidFinishRestore(view: AdaptyUIView, profile: AdaptyProfile) { + override fun paywallViewDidFinishRestore(view: AdaptyUIPaywallView, profile: AdaptyProfile) { // Add your successful restore handling logic here } - override fun paywallViewDidFailRestore(view: AdaptyUIView, error: AdaptyError) { + override fun paywallViewDidFailRestore(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your restore failure handling logic here } - override fun paywallViewDidFinishWebPaymentNavigation(view: AdaptyUIView, product: AdaptyPaywallProduct?, error: AdaptyError?) { + override fun paywallViewDidFinishWebPaymentNavigation(view: AdaptyUIPaywallView, product: AdaptyPaywallProduct?, error: AdaptyError?) { // Handle web payment navigation result } - override fun paywallViewDidFailLoadingProducts(view: AdaptyUIView, error: AdaptyError) { + override fun paywallViewDidFailLoadingProducts(view: AdaptyUIPaywallView, error: AdaptyError) { // Add your product loading failure handling logic here } - override fun paywallViewDidFailRendering(view: AdaptyUIView, error: AdaptyError) { + override fun paywallViewDidFailRendering(view: AdaptyUIPaywallView, error: AdaptyError) { // Handle rendering error } ``` --- # End of Documentation _Generated on: 2026-07-24T13:00:57.705Z_ _Successfully processed: 48/48 files_ # REACT-NATIVE - 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.707Z Total files: 45 --- # File: sdk-installation-react-native-expo --- --- title: "Install & configure Adapty React Native SDK in an Expo project" description: "Step-by-step guide on installing Adapty React Native SDK in an Expo project for subscription-based apps." --- :::important このガイドでは、**Expo プロジェクト**への Adapty React Native SDK のインストールと設定について説明します。 **Pure React Native(Expo なし)**を使用している場合は、代わりに [React Native インストールガイド](sdk-installation-react-native-pure) をご覧ください。 ::: Adapty SDK には、React Native アプリにシームレスに統合するための 2 つの主要モジュールが含まれています: - **Core Adapty**: このモジュールは、アプリで Adapty が正常に動作するために必要です。 - **AdaptyUI**: このモジュールは、クロスプラットフォームのペイウォールを簡単に作成できるノーコードツール「[Adapty ペイウォールビルダー](adapty-paywall-builder)」を使用する場合に必要です。AdaptyUI はコアモジュールと同時に自動的に有効化されます。 React Native アプリへのアプリ内課金の実装方法について詳しく知りたい場合は、[こちらのチュートリアル](https://adapty.io/blog/react-native-in-app-purchases-tutorial/)をご覧ください。 :::tip Adapty SDKをExpoアプリに統合する実際の例を見てみたいですか?サンプルアプリをご確認ください: - [Expo devビルドサンプル](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo):実際の購入やペイウォールビルダーを含む全機能対応 - [Expo Go & Webサンプル](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock):モックモードでのテスト用 ::: 完全な実装のウォークスルーは、以下の動画でもご覧いただけます: <div style={{ textAlign: 'center' }}> <iframe width="560" height="315" src="https://www.youtube.com/embed/TtCJswpt2ms?si=FlFJGvpj-U33yoNK" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe> </div> ## 要件 \{#requirements\} Adapty React Native SDK は iOS 15.0+ が必要です。 iOS 向けにビルドするには **Swift 6.0** 以降が必要です。[キッズモード](kids-mode-react-native)には **Swift 6.1** 以降が必要です。 :::info SDK v3.17 以降、Adapty SDK はデフォルトで Google Play Billing Library v8.0.0 を使用します。 ::: :::info SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ::: ## Adapty SDK のインストール \{#install-adapty-sdk\} :::important v4 以降、Adapty React Native SDK はネイティブ依存関係の CocoaPods インストールをサポートしなくなりました。v4 以降([フロービルダー](adapty-flow-builder)向け)が必要な場合は、代わりに以下の [Adapty SDK 4.0: Swift Package Manager を有効にする](#adapty-sdk-40-enable-swift-package-manager) を参照してください。 ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) :::important [Expo Dev Client](https://docs.expo.dev/versions/latest/sdk/dev-client/)(カスタム開発ビルド)は、ExpoプロジェクトでAdaptyを使用するために必要です。 Expo Goはカスタムネイティブモジュールをサポートしていないため、UI/ロジック開発用の[**モックモード**](#set-up-mock-mode-for-expo-go--expo-web)でのみ使用できます(実際の購入やAdaptyUI/ペイウォールビルダーのレンダリングはありません)。 ::: 1. Adapty SDKをインストールします(`@adapty/core`も自動的にインストールされます): ```sh npx expo install react-native-adapty npx expo prebuild ``` 2. EASまたはローカルビルドを使用して、開発用アプリをビルドします: <Tabs> <TabItem value="eas" label="EAS build" default> ```sh # For iOS eas build --profile development --platform ios # For Android eas build --profile development --platform android ``` </TabItem> <TabItem value="local" label="Local build"> ```sh # For iOS npx expo run:ios # For Android npx expo run:android ``` </TabItem> </Tabs> 3. 開発サーバーを起動します: ```sh npx expo start --dev-client ``` ### Adapty SDK 4.0: Swift Package Manager を有効にする \{#adapty-sdk-40-enable-swift-package-manager\} React Native SDK 4.0 — [フローBuilder](adapty-flow-builder) サポートを追加 — は **React Native 0.75 以降** が必要です。SDK をインストールします: ```sh npx expo install react-native-adapty@^4.0.0 ``` v4はCocoaPodsのサブ依存関係の代わりに、Swift Package Manager経由でネイティブiOS SDK(`Adapty`、`AdaptyUI`、`AdaptyPlugin`)を取得します([CocoaPodsのspecリポジトリは2026年12月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/))。SPMはダイナミックフレームワークを必要とするため、Expoでは[`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/)プラグインで有効にします。`app.json`(または`app.config.js`)に追加してください: ```json showLineNumbers title="app.json" { "expo": { "plugins": [ [ "expo-build-properties", { "ios": { "useFrameworks": "dynamic" } } ] ] } } ``` 次に、プラグインをインストールしてネイティブプロジェクトを再生成します: ```sh npx expo install expo-build-properties npx expo prebuild --clean ``` 詳細な移行手順については、[Adapty React Native SDK を v4 へ移行する](migration-to-react-native-sdk-v4) を参照してください。 ## Adapty SDK の Adapty モジュールを有効化する \{#activate-adapty-module-of-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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 `App.tsx` に以下のコードをコピーして Adapty を有効化します: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` :::important `activate` が解決するまで、他の Adapty SDK メソッドを呼び出さないでください。完全な順序については [React Native SDK の呼び出し順序](react-native-sdk-call-order) を参照してください。 ::: 次に、アプリ内でペイウォールを設定します: - [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、[ペイウォールビルダーのクイックスタート](react-native-quickstart-paywalls)を参照してください。 - 独自のペイウォール UI を構築する場合は、[カスタムペイウォールのクイックスタート](react-native-quickstart-manual)を参照してください。 :::tip 開発環境でのアクティベーションエラーを回避するには、[こちらのヒント](#development-environment-tips)を参照してください。 ::: ## AdaptyUI モジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、AdaptyUI モジュールが必要です。コアモジュールを有効化すると自動的に有効化されるため、追加の操作は不要です。 ## オプション設定 \{#optional-setup\} ### ログ \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty はエラーやその他の重要な情報をログに記録し、状況を把握しやすくします。以下のログレベルが利用可能です。 | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | エラーのみがログに記録されます | | `warn` | エラーおよび重大なエラーは引き起こさないものの注意すべきSDKからのメッセージがログに記録されます | | `info` | エラー、警告、および各種情報メッセージがログに記録されます | | `verbose` | 関数呼び出し、APIクエリなど、デバッグ時に役立つ可能性のある追加情報がすべてログに記録されます | ログレベルは、Adapty の設定前または設定中にアプリ内で指定できます。 ```typescript showLineNumbers title="App.tsx" // Set log level before activation // 'verbose' is recommended for development and the first production release adapty.setLogLevel('verbose'); // Or set it during configuration adapty.activate('YOUR_PUBLIC_SDK_KEY', { logLevel: 'verbose', }); ``` ### データポリシー \{#data-policies\} Adaptyはユーザーの個人データを明示的に送信しない限り保存しませんが、ストアや国のガイドラインに準拠するために追加のデータセキュリティポリシーを実装することができます。 #### IPアドレスの収集と共有を無効にする \{#disable-ip-address-collection-and-sharing\} Adaptyモジュールをアクティベートする際に、`ipAddressCollectionDisabled`を`true`に設定すると、ユーザーのIPアドレスの収集と共有を無効にできます。デフォルト値は`false`です。 このパラメータを使用して、ユーザーのプライバシーを強化し、地域のデータ保護規制(GDPRやCCPAなど)に準拠し、IPベースの機能がアプリに不要な場合に不必要なデータ収集を削減できます。 ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ipAddressCollectionDisabled: true, }); ``` #### 広告IDの収集と共有を無効にする \{#disable-advertising-id-collection-and-sharing\} Adapty モジュールを有効化する際、広告識別子の収集を無効にするには、iOS の場合は `ios.idfaCollectionDisabled`、Android の場合は `android.adIdCollectionDisabled` を `true` に設定してください。デフォルト値は `false` です。 App Store / Play Store のポリシーへの準拠、App Tracking Transparency プロンプトの表示回避、または広告 ID に基づくアトリビューションや分析がアプリで不要な場合に、このパラメータを使用してください。 ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, }); ``` #### AdaptyUI のメディアキャッシュ設定 \{#set-up-media-cache-configuration-for-adaptyui\} デフォルトでは、AdaptyUI はパフォーマンス向上とネットワーク使用量の削減のために、画像や動画などのメディアをキャッシュします。カスタム設定を指定することで、キャッシュの動作を変更できます。 `mediaCache` を使用して、デフォルトのキャッシュ設定を上書きしてください: ```typescript adapty.activate('YOUR_PUBLIC_SDK_KEY', { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, }); ``` | パラメーター | 必須 | 説明 | |-----------|----------|-------------| | memoryStorageTotalCostLimit | 任意 | メモリ上のキャッシュサイズ(バイト単位)。デフォルト値はプラットフォームによって異なります。 | | memoryStorageCountLimit | 任意 | メモリストレージのアイテム数制限。デフォルト値はプラットフォームによって異なります。 | | diskStorageSizeLimit | 任意 | ディスク上のファイルサイズ制限(バイト単位)。デフォルト値はプラットフォームによって異なります。 | ### ローカルアクセスレベルを有効にする(Android) \{#enable-local-access-levels-android\} デフォルトでは、[ローカルアクセスレベル](local-access-levels)は iOS で有効、Android で無効になっています。Android でも有効にするには、`localAccessLevelAllowed` を `true` に設定してください: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { android: { localAccessLevelAllowed: true, }, }); ``` ### バックアップ復元時のデータクリア \{#clear-data-on-backup-restore\} `clearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検出し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールなど、ローカルに保存されたすべてのSDKデータを削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { clearDataOnBackup: true }, }); ``` ## 開発環境に関するヒント \{#development-environment-tips\} #### Expo Go / Expo Web 向けモックモードの設定 \{#set-up-mock-mode-for-expo-go--expo-web\} Expo Go および Expo Web 環境では、Adapty のネイティブモジュールにアクセスできません。ランタイムエラーを避けながら、アプリの UI やペイウォールのロジックをビルド・テストできるよう、Adapty は**モックモード**を提供しています。 ::::important モックモードは、実際の購入をテストするためのツールでは**ありません**: - App Store / Google Play の購入フローを**開きません**。また、実際のトランザクションを**作成しません**。 - **Adapty ペイウォールビルダー(AdaptyUI)**で作成したペイウォール/オンボーディングを**レンダリングしません**。 - Adaptyのネイティブモジュールは**完全にバイパスされます**。Xcode/Androidビルドにネイティブ SDK ファイルが存在しない場合や、無効な API キーを使用した場合でもエラーは発生しません。 実際の購入やペイウォールビルダーのペイウォールをテストするには、モックモードが自動的に無効になる Expo Dev Client / プロダクションビルドを使用してください。 :::: **デフォルトでは**、SDKはExpo GoおよびWeb環境を自動的に検出し、モックモードを有効にします。モックデータをカスタマイズしたい場合を除き、設定は不要です。 モックモードが有効な場合: - すべてのAdaptyメソッドは、Adaptyのサーバーへのネットワークリクエストを行わずにモックデータを返します。 - デフォルトでは、初期モックプロファイルにアクティブなサブスクリプションはありません。 - デフォルトでは、`makePurchase(...)` は購入成功をシミュレートし、プレミアムアクセスを付与します。 アクティベーション時に `mockConfig` を使ってモックデータをカスタマイズできます。設定フォーマットとサポートされているパラメータは[こちら](https://react-native.adapty.io/interfaces/adaptymockconfig)をご覧ください。 ```typescript showLineNumbers title="App.tsx" try { await adapty.activate('YOUR_PUBLIC_SDK_KEY', { mockConfig: { // Customize the initial mock profile (optional) }, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` SDKのメソッドを有効化前に呼び出す必要がある場合(`isActivated()`や`setLogLevel()`など)、`activate()`の前に`enableMock()`を使用してください。ブリッジがすでに初期化されている場合、このメソッドは何もしません。 ```typescript showLineNumbers title="App.tsx" adapty.enableMock(); // オプション: mockConfigを渡してモックデータをカスタマイズできます // これで有効化前にメソッドを呼び出せます await adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` #### 開発目的でSDKの有効化を遅らせる \{#delay-sdk-activation-for-development-purposes\} Adapty は SDK のアクティベーション時に必要なユーザーデータをすべて事前取得するため、最新データへのアクセスが高速になります。 ただし、iOS シミュレーターでは開発中に認証を頻繁に求められるため、問題が生じることがあります。Adapty は StoreKit の認証フローを制御できませんが、SDK が最新のユーザーデータを取得するリクエストを遅延させることができます。 `__debugDeferActivation` プロパティを有効にすると、次に Adapty SDK を呼び出すまで `activate` の実行が保留されます。これにより、必要でない場合に認証データを求めるプロンプトが不必要に表示されるのを防げます。 この機能は**開発用途のみを想定したもの**であり、すべてのユーザーシナリオに対応しているわけではない点にご注意ください。本番環境では、実際のデバイスは認証データを記憶しており、何度も認証を求めることはないため、アクティベーションを遅らせるべきではありません。 推奨する使用方法は以下のとおりです。 ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __debugDeferActivation: isSimulator(), // 'isSimulator' from any 3rd party library }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### React NativeのFast RefreshにおけるSDKアクティベーションエラーのトラブルシューティング \{#troubleshoot-sdk-activation-errors-on-react-natives-fast-refresh\} React NativeでAdapty SDKを使って開発していると、次のエラーが発生することがあります:`Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` これは、React Native のファスト リフレッシュ機能が開発中に複数のアクティベーション呼び出しをトリガーするために発生します。これを防ぐには、`__ignoreActivationOnFastRefresh` オプションを `__DEV__`(React Native の開発モードフラグ)に設定してください。 ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __ignoreActivationOnFastRefresh: __DEV__, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` ## トラブルシューティング \{#troubleshooting\} #### iOSの最小バージョンエラー \{#minimum-ios-version-error\} iOSビルド時に、**最小iOSバージョン**またはデプロイメントターゲットに関するエラーが表示されることがあります。AdaptyはiOS 15.0以降を必要とします。 ExpoはiOSプロジェクト(`Podfile`を含む)を`expo prebuild`の実行時に生成するため、**`Podfile`を直接編集しないでください**。代わりに、`expo-build-properties`設定プラグインを使用してデプロイメントターゲットを設定してください。 1. プラグインをインストールします: ```sh npx expo install expo-build-properties ``` 2. ExpoのConfig(`app.json`または`app.config.js`)を更新して、iOSのデプロイメントターゲットを設定します: ``` { "expo": { // ...other Expo config... "plugins": [ [ "expo-build-properties", { "ios": { // Adapty requires iOS 15.0+. "deploymentTarget": "15.0" } } ], ] } } ``` 3. ネイティブ iOS プロジェクトを再生成してリビルドします: ``` npx expo prebuild --clean npx expo run:ios # or `eas build -p ios` on your CI ``` #### Android Auto Backup マニフェストの競合 \{#android-auto-backup-manifest-conflict\} Expo で複数の SDK(Adapty、AppsFlyer、expo-secure-store など)を使用していて、それぞれが Android Auto Backup を設定している場合、マニフェストのマージ競合が発生することがあります。 典型的なエラーは次のようになります: `Manifest merger failed : Attribute application@fullBackupContent value=(@xml/secure_store_backup_rules) from AndroidManifest.xml:24:248-306 is also present at [io.adapty:android-sdk:3.12.0] AndroidManifest.xml:9:18-70 value=(@xml/adapty_backup_rules).` この競合を解決するには、Adapty プラグインに Android バックアップ設定を管理させる必要があります。 プロジェクトで `expo-secure-store` も使用している場合は、重複を避けるためにそのバックアップ設定を無効にしてください。 `app.json` の設定方法は以下のとおりです。 ```json title="app.json" { "expo": { "plugins": [ ["react-native-adapty", { "replaceAndroidBackupConfig": true }], ["expo-secure-store", { "configureAndroidBackup": false }] ] } } ``` `replaceAndroidBackupConfig` オプションはデフォルトで `false` です。有効にすると、Adapty プラグインが Android のバックアップルールを管理できるようになります。 `expo-secure-store` を使用している場合は、警告を防ぐために `"configureAndroidBackup": false` を含めてください。SecureStore のバックアップ設定は Adapty によって処理されます。 :::important このセットアップは、Adapty、AppsFlyer、および expo-secure-store のバックアップ要件にのみ対応しています。 プロジェクト内の他のライブラリがカスタムバックアップルールを定義している場合は、手動で設定する必要があります。 ::: --- # File: sdk-installation-react-native-pure --- --- title: "Install & configure Adapty SDK in a pure React Native project" description: "Step-by-step guide on installing Adapty SDK on React Native for subscription-based apps." --- :::important このガイドは**純粋な React Native(非 Expo)プロジェクト**にのみ適用されます。 **Expo** を使用している場合は、代わりに [Expo インストールガイド](sdk-installation-react-native-expo)を参照してください。 ::: Adapty SDK には、React Native アプリへシームレスに統合するための 2 つの主要モジュールが含まれています: - **Core Adapty**: このモジュールは、アプリでAdaptyを正しく動作させるために必要です。 - **AdaptyUI**: このモジュールは、クロスプラットフォームのペイウォールをノーコードで簡単に作成できる[Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合に必要です。AdaptyUIはコアモジュールと一緒に自動的に有効になります。 :::tip Adapty SDKをモバイルアプリに実際に統合した例を見たいですか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを示す[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples)をご覧ください。 ::: ## 要件 \{#requirements\} Adapty React Native SDK は iOS 15.0 以上が必要です。 iOS 向けビルドには **Swift 6.0** 以降が必要です。[キッズモード](kids-mode-react-native) は **Swift 6.1** 以降が必要です。 :::info SDK v3.17 以降、Adapty SDK はデフォルトで Google Play Billing Library v8.0.0 を使用します。 ::: :::info SDKのインストールは、Adaptyセットアップのステップ5です。アプリ内で課金が機能するようにするには、アプリをストアに接続し、Adapty ダッシュボードでプロダクト、ペイウォール、プレースメントを作成する必要があります。[クイックスタートガイド](quickstart)では、必要なすべての手順を説明しています。 ::: ## Adapty SDKのインストール \{#install-adapty-sdk\} :::important v4以降、Adapty React Native SDKはネイティブ依存関係のCocoaPodsインストールをサポートしなくなりました。v4以降([フロービルダー](adapty-flow-builder)用)が必要な場合は、以下の[Adapty SDK 4.0: Swift Package Managerを有効にする](#adapty-sdk-40-enable-swift-package-manager)の手順に従ってください。 ::: [![Release](https://img.shields.io/github/v/release/adaptyteam/AdaptySDK-React-Native.svg?style=flat&logo=react)](https://github.com/adaptyteam/AdaptySDK-React-Native/releases) 1. Adapty SDK をインストールします(`@adapty/core` も自動的にインストールされます): ```sh showLineNumbers title="Shell" # using npm npm install react-native-adapty # or using yarn yarn add react-native-adapty ``` 2. iOS の場合、pods をインストールします: ```sh showLineNumbers title="Shell" cd ios && pod install ``` <details> <summary>Android で React Native のバージョンが 0.73.0 より古い場合(クリックして展開)</summary> `/android/build.gradle` ファイルを更新してください。`kotlin-gradle-plugin:1.8.0` 以降の依存関係が含まれていることを確認してください: ```groovy showLineNumbers title="/android/build.gradle" ... buildscript { ... dependencies { ... classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0" } } ... ``` </details> ### Adapty SDK 4.0: Swift Package Managerを有効にする \{#adapty-sdk-40-enable-swift-package-manager\} React Native SDK 4.0 — [フロービルダー](adapty-flow-builder)のサポートを追加 — は **React Native 0.75以降**が必要です。SDKをインストールします: ```sh showLineNumbers title="Shell" npm install react-native-adapty@^4.0.0 # or using yarn yarn add react-native-adapty@^4.0.0 ``` v4 では、ネイティブ iOS SDK(`Adapty`、`AdaptyUI`、`AdaptyPlugin`)を CocoaPods のサブ依存関係ではなく、Swift Package Manager 経由で取得するようになりました([CocoaPods のスペックリポジトリは 2026 年 12 月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/))。SPM にはダイナミックフレームワークが必要です。`ios/Podfile` のターゲットに以下を追加し、pod を再インストールしてください: ```ruby showLineNumbers title="ios/Podfile" use_frameworks! :linkage => :dynamic ``` ```sh showLineNumbers title="Shell" cd ios && pod install --repo-update ``` 以前に `Adapty`、`AdaptyUI`、または `AdaptyPlugin` を CocoaPods のサブ依存関係として追加していた場合は、まず `Podfile` から `pod 'Adapty'`、`pod 'AdaptyUI'`、`pod 'AdaptyPlugin'` の行を削除してください。 :::warning デフォルトのスタティックリンクからダイナミックフレームワークへ切り替えると、モジュラーヘッダーに対応していないライブラリと競合する場合があり、Flipper とも互換性がありません。詳細は [Migrate Adapty React Native SDK to v4](migration-to-react-native-sdk-v4) をご確認ください。 ::: ## Adapty SDK の Adapty モジュールを有効化する \{#activate-adapty-module-of-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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 以下のコードを `App.tsx` にコピーして Adapty を有効化してください: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` :::important 他の Adapty SDK メソッドを呼び出す前に、`activate` の解決を待ってください。完全な順序については [React Native SDK の呼び出し順序](react-native-sdk-call-order) を参照してください。 ::: 次に、アプリ内でペイウォールを設定します: - [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、[ペイウォールビルダーのクイックスタート](react-native-quickstart-paywalls)をご覧ください。 - 独自のペイウォール UI を構築する場合は、[カスタムペイウォールのクイックスタート](react-native-quickstart-manual)をご覧ください。 :::tip 開発環境でのアクティベーションエラーを避けるには、[こちらのヒント](#development-environment-tips)をご参照ください。 ::: ## AdaptyUI モジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、AdaptyUI モジュールが必要です。コアモジュールを有効化すると自動的に有効になるため、追加の操作は不要です。 ## オプション設定 \{#optional-setup\} ### ロギング \{#logging\} #### ロギングシステムのセットアップ \{#set-up-the-logging-system\} Adapty はエラーやその他の重要な情報をログに記録し、状況を把握するのに役立てます。以下のログレベルが利用可能です。 | Level | Description | | ---------- | ------------------------------------------------------------ | | `error` | エラーのみがログに記録されます | | `warn` | エラーおよび重大なエラーは発生しないものの注意が必要なSDKからのメッセージがログに記録されます | | `info` | エラー、警告、およびさまざまな情報メッセージがログに記録されます | | `verbose` | 関数呼び出しやAPIクエリなど、デバッグ時に役立つ可能性のある追加情報がすべてログに記録されます | AdaptyConfigurationの前後どちらでもログレベルを設定できます: ```typescript showLineNumbers title="App.tsx" // Set log level before activation // 'verbose' is recommended for development and the first production release adapty.setLogLevel('verbose'); // Or set it during configuration adapty.activate('YOUR_PUBLIC_SDK_KEY', { logLevel: 'verbose', }); ``` ### データポリシー \{#data-policies\} Adapty はユーザーの個人データを保存しませんが(明示的に送信した場合を除く)、ストアや国のガイドラインに準拠するために、追加のデータセキュリティポリシーを実装することができます。 #### IPアドレスの収集と共有を無効にする \{#disable-ip-address-collection-and-sharing\} Adapty モジュールを有効化する際に、`ipAddressCollectionDisabled` を `true` に設定すると、ユーザーのIPアドレスの収集と共有を無効にできます。デフォルト値は `false` です。 このパラメーターを使用すると、ユーザーのプライバシー保護、地域のデータ保護規制(GDPRやCCPAなど)への準拠、またはIPベースの機能がアプリに不要な場合の不必要なデータ収集の削減に役立ちます。 ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ipAddressCollectionDisabled: true, }); ``` #### 広告IDの収集と共有を無効にする \{#disable-advertising-id-collection-and-sharing\} Adapty モジュールをアクティベートする際、広告識別子の収集を無効にするには、iOS の場合は `ios.idfaCollectionDisabled`、Android の場合は `android.adIdCollectionDisabled` を `true` に設定してください。デフォルト値は `false` です。 このパラメーターは、App Store / Play Store のポリシーへの準拠、App Tracking Transparency プロンプトの表示回避、または広告 ID を使用したアトリビューションや分析が不要な場合に活用できます。 ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { idfaCollectionDisabled: true, }, android: { adIdCollectionDisabled: true, }, }); ``` #### AdaptyUI のメディアキャッシュ設定を行う \{#set-up-media-cache-configuration-for-adaptyui\} デフォルトでは、AdaptyUI はパフォーマンス向上とネットワーク使用量削減のためにメディア(画像や動画など)をキャッシュします。カスタム設定を指定することで、キャッシュの動作をカスタマイズできます。 デフォルトのキャッシュ設定を上書きするには `mediaCache` を使用してください: ```typescript adapty.activate('YOUR_PUBLIC_SDK_KEY', { mediaCache: { memoryStorageTotalCostLimit: 200 * 1024 * 1024, // Optional: memory cache size in bytes memoryStorageCountLimit: 2147483647, // Optional: max number of items in memory diskStorageSizeLimit: 200 * 1024 * 1024, // Optional: disk cache size in bytes }, }); ``` | パラメータ | 必須 | 説明 | |-----------|------|------| | memoryStorageTotalCostLimit | 任意 | メモリ上のキャッシュサイズ(バイト単位)。デフォルト値はプラットフォームによって異なります。 | | memoryStorageCountLimit | 任意 | メモリストレージのアイテム数の上限。デフォルト値はプラットフォームによって異なります。 | | diskStorageSizeLimit | 任意 | ディスク上のファイルサイズの上限(バイト単位)。デフォルト値はプラットフォームによって異なります。 | ### Androidでローカルアクセスレベルを有効にする \{#enable-local-access-levels-android\} デフォルトでは、[ローカルアクセスレベル](local-access-levels)はiOSで有効、Androidで無効になっています。Androidでも有効にするには、`localAccessLevelAllowed`を`true`に設定します: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { android: { localAccessLevelAllowed: true, }, }); ``` ### バックアップ復元時のデータクリア \{#clear-data-on-backup-restore\} `clearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検出し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールを含むローカルに保存されたSDKデータをすべて削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { ios: { clearDataOnBackup: true }, }); ``` ## 開発環境に関するヒント \{#development-environment-tips\} #### 開発目的でのSDKアクティベーションの遅延 \{#delay-sdk-activation-for-development-purposes\} AdaptyはSDKのアクティベーション時に必要なユーザーデータをすべてプリフェッチし、最新データへの高速アクセスを実現します。 ただし、iOSシミュレーターでは開発中に認証を頻繁に求められるため、これが問題になる場合があります。AdaptyはStoreKitの認証フローを制御できませんが、最新ユーザーデータを取得するSDKのリクエストを遅延させることは可能です。 `__debugDeferActivation` プロパティを有効にすると、次の Adapty SDK 呼び出しが行われるまで activate の呼び出しが保留されます。これにより、認証データが不要な場合に不必要なプロンプトが表示されるのを防ぎます。 **この機能は開発用途限定**であることに注意してください。すべてのユーザーシナリオをカバーするわけではありません。本番環境では、実際のデバイスは通常認証データを記憶しており、繰り返し認証情報を求めることがないため、アクティベーションを遅らせるべきではありません。 推奨される使用方法は次のとおりです。 ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __debugDeferActivation: isSimulator(), // 'isSimulator' from any 3rd party library }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### React Native の Fast Refresh で SDK のアクティベーションエラーが発生した場合のトラブルシューティング \{#troubleshoot-sdk-activation-errors-on-react-natives-fast-refresh\} React Native で Adapty SDK を使って開発していると、`Adapty can only be activated once. Ensure that the SDK activation call is not made more than once.` というエラーが発生することがあります。 これは React Native のファスト リフレッシュ機能が開発中に複数回のアクティベーション呼び出しをトリガーするために発生します。これを防ぐには、`__ignoreActivationOnFastRefresh` オプションに `__DEV__`(React Native の開発モードフラグ)を設定してください。 ```typescript showLineNumbers title="Typescript" try { adapty.activate('PUBLIC_SDK_KEY', { __ignoreActivationOnFastRefresh: __DEV__, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); // Handle the error appropriately for your app } ``` #### ローカルテスト用のモックモードを設定する \{#set-up-mock-mode-for-local-testing\} ローカル開発やテスト時には、サンドボックスの App Store/Google Play アカウントを用意しなくても済むよう、またイテレーションを高速化するために、モックモードを有効にすることができます。モックモードは Adapty のネイティブモジュールを完全にバイパスし、シミュレートされたデータを返します。 :::important モックモードは実際の購入をテストするためのツールでは**ありません**: - App Store / Google Play の購入フローを**開きません**。また、実際のトランザクションを**作成しません**。 - **Adapty ペイウォールビルダー(AdaptyUI)**で作成されたペイウォール/オンボーディングを**レンダリングしません**。 - Adapty のネイティブモジュールは**完全にバイパスされます**。Xcode/Android ビルドにネイティブ SDK ファイルが存在しない場合や、無効な API キーを使用している場合でもエラーは発生しません。 - Adapty のサーバーにはデータが送信されません。 実際の購入とペイウォールビルダーのペイウォールをテストするには、モックモードを無効にしてサンドボックスアカウントを使用してください。 ::: モックモードを有効にするには、`enableMock` を `true` に設定します: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { enableMock: true, }); ``` モックモードが有効な場合: - すべての Adapty メソッドは、Adapty のサーバーにネットワークリクエストを送ることなくモックデータを返します。 - デフォルトでは、初期モックプロファイルにはアクティブなサブスクリプションがありません。 - デフォルトでは、`makePurchase(...)` は購入成功をシミュレートし、プレミアムアクセスを付与します。 `mockConfig` を使って、アクティベーション時にモックデータをカスタマイズできます。設定フォーマットとサポートされているパラメータは[こちら](https://react-native.adapty.io/interfaces/adaptymockconfig)を参照してください。 ```typescript showLineNumbers title="App.tsx" try { await adapty.activate('YOUR_PUBLIC_SDK_KEY', { mockConfig: { // Customize the initial mock profile (optional) }, }); } catch (error) { console.error('Failed to activate Adapty SDK:', error); } ``` アクティベーション前にSDKのメソッド(`isActivated()` や `setLogLevel()` など)を呼び出す必要がある場合は、`activate()` の前に `enableMock()` を使用してください。ブリッジがすでに初期化されている場合、このメソッドは何も行いません。 ```typescript showLineNumbers title="App.tsx" adapty.enableMock(); // Optional: pass mockConfig to customize mock data // Now you can call methods before activation await adapty.activate('YOUR_PUBLIC_SDK_KEY'); ``` ## トラブルシューティング \{#troubleshooting\} #### iOS最小バージョンエラー \{#minimum-ios-version-error\} iOS最小バージョンエラーが発生した場合は、Podfileを更新してください: ```diff -platform :ios, min_ios_version_supported +platform :ios, '15.0' ``` #### AndroidのAuto Backupマニフェスト競合 \{#android-auto-backup-manifest-conflict\} 一部の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` ファイルのルートの `<manifest>` タグに tools が含まれていることを確認してください: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. `<application>` でバックアップ属性を上書きする \{#2-override-backup-attributes-in-application\} 同じ `AndroidManifest.xml` ファイルで、`<application>` タグを更新して、アプリが最終的な値を提供し、マニフェストマージャーにライブラリの値を置き換えるよう指示します: ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` いずれかの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" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Android 11以前**(従来のフルバックアップコンテンツ形式を使用): ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> #### Androidで別のアプリから戻ったあとに購入が失敗する \{#purchases-fail-after-returning-from-another-app-in-android\} 購入フローを開始するActivityに非デフォルトの`launchMode`が設定されている場合、ユーザーがGoogle Play、銀行アプリ、またはブラウザから戻ったときにAndroidがActivityを誤って再生成または再利用することがあります。その結果、購入結果が失われたり、キャンセルとして処理されたりすることがあります。 購入フローを正しく機能させるには、購入フローを開始するActivityのlaunchModeに`standard`または`singleTop`のみを使用し、その他のモードは避けてください。 `AndroidManifest.xml`で、購入フローを開始するActivityが`standard`または`singleTop`に設定されていることを確認してください。 ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### Swift 6のビルドエラー(PodfileのSWIFT_VERSIONオーバーライドが原因) \{#swift-6-build-errors-caused-by-podfile-swift_version-override\} React Native アプリを iOS 向けにビルドする際、Adapty の pod ターゲットで Swift 6 のコンパイルエラーが発生することがあります。よくある症状としては、`AdaptyUIBuilderLogic` での `@Sendable` の不一致、Adapty 型の `Sendable` 準拠の欠如、アクター分離エラーなどが挙げられます。 Adapty の pods は `s.swift_version = '6.0'` を宣言しており、ビルドには Swift 6 が必要です。アプリ本体のコードは Swift 5 のままで問題ありません。Swift 6 でのビルドが必要なのは、Adapty の pod ターゲット(`Adapty`、`AdaptyUI`、`AdaptyUIBuilder`、`AdaptyLogger`、`AdaptyPlugin`)のみです。 最も一般的な原因は、`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` ポッドターゲット → **Build Settings** → **Swift Language Version** を選択します。**Swift 6** になっていれば正常です。 --- # File: react-native-quickstart-paywalls --- --- title: "React Native SDKでFlow Builderを使ってアプリ内課金を有効にする" description: "Adapty Flow Builderでアプリ内課金を有効にするクイックスタートガイド。" --- アプリ内課金を有効にするには、3つの主要な概念を理解する必要があります: - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**フロー**](adapty-flow-builder) – ノーコードのフロービルダーで作成した、プロダクトをユーザーに提示するための画面シーケンス。SDK は `getFlow` で取得します。自分のコードで UI を構築したい場合は、ペイウォールを使ってください — 詳細は[ペイウォールを手動で実装する](react-native-quickstart-manual)を参照してください。 - [**プレースメント**](placements) – アプリ内でフローを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでフローをプレースメントに紐付けておき、コード内でプレースメント ID を指定してリクエストします。これにより、A/B テストの実施や、ユーザーごとに異なるフローの表示が簡単に行えます。 Adapty では、アプリ内で購入を有効にする方法を3つ提供しています。アプリの要件に応じていずれかを選択してください。 | 実装方法 | 複雑さ | 使用する場合 | |---|---|---| | Adapty フロービルダー | ✅ 簡単 | [ノーコードビルダーで購入対応済みの完全なフローを作成](quickstart-paywalls)します。Adapty が自動的にレンダリングし、複雑な購入フロー、レシート検証、サブスクリプション管理をすべて裏側で処理します。 | | 手動で作成したペイウォール | 🟡 中程度 | アプリのコードでペイウォール UI を実装しますが、プロダクトの柔軟性を保つために Adapty からフローオブジェクトを取得します。[ガイド](react-native-quickstart-manual)をご覧ください。 | | オブザーバーモード | 🔴 難しい | すでに独自の購入処理インフラを持っており、それを引き続き使用したい場合に選択します。オブザーバーモードには Adapty における制限があることに注意してください。[こちらの記事](observer-vs-full-mode)をご覧ください。 | :::important **以下の手順では、Adapty フロービルダーで作成したフローの実装方法を説明します。** ペイウォール UI を自分で実装したい場合は、[ペイウォールを手動で実装する](react-native-quickstart-manual)をご覧ください。 ::: Adapty フロービルダーで作成したフローを表示するには、アプリのコードで以下を行うだけです。 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-reactnative)します。 :::tip これらの手順を最速で完了するには、[クイックスタートガイド](quickstart)に従うか、[Developer CLI](developer-cli-quickstart)を使ってペイウォールとプレースメントを作成してください。 ::: ## 1. フローを取得する \{#1-get-the-flow\} フローはダッシュボードで設定したプレースメントに紐づいています。プレースメントを使うと、オーディエンスごとに異なるフローを表示したり、[A/B テスト](ab-tests)を実施したりできます。 Adapty フロービルダーで作成したフローを取得するには、`getFlow` メソッドを使って[プレースメント](placements) ID から `flow` オブジェクトを取得します。フローには表示に必要な UI 要素とスタイリング情報が含まれています。 ```typescript showLineNumbers title="React Native" try { const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); // the requested flow } catch (error) { // handle the error } ``` ## 2. フローを表示する \{#display-the-flow\} フローを取得したら、あとは数行追加するだけで表示できます。 <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React コンポーネント" default> 既存のコンポーネントツリー内にフローを埋め込むには、React Native コンポーネント階層に `AdaptyFlowView` コンポーネントを直接使用します。 ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>( (result, product) => result.type !== 'user_cancelled', [], ); return ( <AdaptyFlowView flow={flow} style={{ flex: 1 }} onPurchaseCompleted={onPurchaseCompleted} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> フローをスタンドアロン画面として表示するには、`createFlowView` メソッドで `view` を作成し、イベントハンドラーを設定してから `view.present()` を呼び出します。各 `view` は一度しか使用できません。フローを再度表示する必要がある場合は、`createFlowView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 ```typescript showLineNumbers title="React Native" try { const view = await createFlowView(flow); view.setEventHandlers({ onPurchaseCompleted(result, product) { return result.type !== 'user_cancelled'; }, }); await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> :::tip フローの表示方法の詳細については、[ガイド](react-native-present-paywalls)をご覧ください。 ::: ## 3. ボタンアクションの処理 \{#handle-button-actions\} フロー内でユーザーがボタンをクリックすると、React Native SDKは購入、復元、フローのクローズ、URLのオープンを自動的に処理します。 ただし、カスタムまたは事前定義されたIDを持つボタンについては、コード内でアクションを処理する必要があります。また、デフォルトの動作をオーバーライドしたい場合もあります。 たとえば、以下はクローズボタンのデフォルトの動作です。コードに追加する必要はありませんが、必要な場合にどのように実装するかを確認できます。 <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> React コンポーネントでは、`AdaptyFlowView` コンポーネント内で直接アクションを処理します: ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>( () => true, // allow the flow to close [], ); const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>( (actionId) => false, [], ); return ( <AdaptyFlowView flow={flow} style={{ flex: 1 }} onCloseButtonPress={onCloseButtonPress} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> モーダル表示の場合、`setEventHandlers` を使用してイベントハンドラーを実装します: ```typescript showLineNumbers title="React Native" const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; // allow the flow to close }, }); ``` </TabItem> </Tabs> :::tip ボタンの[アクション](react-native-handle-paywall-actions)と[イベント](react-native-handling-events-1)の処理方法については、ガイドをご覧ください。 ::: ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: これでアプリにペイウォールを表示する準備が整いました。[App Store サンドボックス](test-purchases-in-sandbox)または[Google Play Store](testing-on-android)でテスト購入を行い、ペイウォールからテスト購入を完了できることを確認してください。 次に、適切なユーザーにペイウォールを表示したり有料機能へのアクセスを付与したりするために、[ユーザーのアクセスレベルを確認](react-native-check-subscription-status)する必要があります。 ## 完全な例 \{#full-example\} このガイドのすべてのステップをアプリにまとめて統合する方法を紹介します。 <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```javascript showLineNumbers title="React Native (TSX)" export default function FlowScreen() { const [flow, setFlow] = useState(null); const loadFlow = async () => { try { const flowData = await adapty.getFlow('YOUR_PLACEMENT_ID'); setFlow(flowData); } catch (error) { console.warn('Error loading flow:', error); } }; const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>( () => true, [], ); const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>( (result, product) => result.type !== 'user_cancelled', [], ); useEffect(() => { loadFlow(); }, []); return ( <View style={{ flex: 1 }}> {flow ? ( <AdaptyFlowView flow={flow} style={{ flex: 1 }} onCloseButtonPress={onCloseButtonPress} onPurchaseCompleted={onPurchaseCompleted} /> ) : ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Button title="Load Flow" onPress={loadFlow} /> </View> )} </View> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> ```javascript showLineNumbers title="React Native" export default function FlowScreen() { const showFlow = async () => { try { const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); const view = await createFlowView(flow); view.setEventHandlers({ onCloseButtonPress() { return true; }, onPurchaseCompleted(result, product) { return result.type !== 'user_cancelled'; }, }); await view.present(); } catch (error) { // handle any error that may occur during the process console.warn('Error showing flow:', error); } }; // you can add a button to manually trigger the flow for testing purposes return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Button title="Show Flow" onPress={showFlow} /> </View> ); } ``` </TabItem> </Tabs> --- # File: react-native-check-subscription-status --- --- title: "React Native SDKでサブスクリプションステータスを確認する" description: "AdaptyでReact Nativeアプリのサブスクリプションステータスを確認する方法を学びましょう。" --- ユーザーが有料コンテンツにアクセスできるか、またはペイウォールを表示すべきかを判断するには、プロファイルの[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態にアクセスして、ユーザーにペイウォールを表示するか有料機能へのアクセスを許可するかを判断する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ペイウォールを表示するか有料コンテンツを表示するかを決める際は、プロファイル内のユーザーの[アクセスレベル](access-level)を確認します。2つの方法があります: - 最新のプロファイルデータがすぐに必要な場合(アプリ起動時など)や強制的に更新したい場合は、`getProfile` を呼び出す。 - **自動プロファイル更新**を設定して、サブスクリプションステータスが変わるたびに自動で更新されるローカルコピーを保持する。 ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得する最も簡単な方法は、`getProfile` メソッドでプロファイルにアクセスすることです: ```typescript showLineNumbers try { const profile = await adapty.getProfile(); } catch (error) { // handle the error } ``` ### サブスクリプション更新を購読する \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取るには: 1. `adapty.addEventListener('onLatestProfileLoad')` を使ってプロファイルの変更を監視します。ユーザーのサブスクリプションステータスが変わるたびに、Adaptyが自動的にこのメソッドを呼び出します。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存しておくと、追加のネットワークリクエストなしにアプリ全体で利用できます。 ```javascript class SubscriptionManager { private currentProfile: any = null; constructor() { // Listen for profile updates adapty.addEventListener('onLatestProfileLoad', (profile) => { this.currentProfile = profile; // Update UI, unlock content, etc. }); } // Use stored profile instead of calling getProfile() hasAccess(): boolean { return this.currentProfile?.accessLevels?.['premium']?.isActive ?? false; } } ``` :::note Adaptyはアプリ起動時に `onLatestProfileLoad` イベントリスナーを自動的に呼び出し、デバイスがオフラインの場合でもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールのロジックを連携させる \{#connect-profile-with-paywall-logic\} ペイウォールの表示や有料機能へのアクセス許可をすぐに判断する必要がある場合は、ユーザーのプロファイルを直接確認できます。この方法は、アプリ起動時、プレミアムセクションへの移動時、特定コンテンツの表示前などのシナリオで役立ちます。 ```javascript const checkAccessLevel = async () => { try { const profile = await adapty.getProfile(); return profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive === true; } catch (error) { console.warn('Error checking access level:', error); return false; // Show paywall if access check fails } }; const initializePaywall = async () => { try { await loadPaywall(); const hasAccess = await checkAccessLevel(); if (!hasAccess) { // Show paywall if no access } } catch (error) { console.warn('Error initializing paywall:', error); } }; ``` ## 次のステップ \{#next-steps\} サブスクリプションステータスの追跡方法がわかったら、ユーザーが支払済みのコンテンツにアクセスできるよう[ユーザープロファイルの操作](react-native-quickstart-identify)について学びましょう。 --- # File: react-native-quickstart-identify --- --- title: "React Native SDKでユーザーを識別する" description: "React NativeでAdaptyを使ったアプリ内サブスクリプション管理のクイックスタートガイド。" --- :::important このガイドは、独自の認証システムを持っている方向けです。ここでは、Adaptyでユーザープロファイルを管理し、既存の認証システムと連携させる方法を説明します。 ::: ユーザーの購入をどのように管理するかは、アプリの認証モデルによって異なります。 - アプリがバックエンド認証を使用せず、ユーザーデータを保存しない場合は、[匿名ユーザーのセクション](#anonymous-users)を参照してください。 - アプリにバックエンド認証がある(または導入予定の)場合は、[識別済みユーザーのセクション](#identified-users)を参照してください。 **主要な概念**: - **プロファイル**はSDKが動作するために必要なエンティティで、Adaptyが自動的に作成します。 - プロファイルは匿名**(カスタマーユーザーIDなし)**または識別済み**(カスタマーユーザーIDあり)**のいずれかです。 - **カスタマーユーザーID**を提供することで、AdaptyのプロファイルとあなたのシステムのIDを紐付けられます。 匿名ユーザーと識別済みユーザーの違いは以下の通りです: | | 匿名ユーザー | 識別済みユーザー | |-------------------------|---------------------------------------------------|-------------------------------------------------------------------------| | **購入管理** | ストアレベルの購入復元 | カスタマーユーザーIDを通じてデバイスをまたいで購入履歴を維持 | | **プロファイル管理** | 再インストールのたびに新しいプロファイルが作成される | セッションやデバイスをまたいで同じプロファイルを使用 | | **データの永続性** | 匿名ユーザーのデータはアプリのインストールに紐付く | 識別済みユーザーのデータはアプリのインストールをまたいで保持される | ## 匿名ユーザー \{#anonymous-users\} バックエンド認証がない場合、**アプリのコードで認証処理を行う必要はありません**: 1. アプリの初回起動時にSDKが有効化されると、AdaptyはそのユーザーのためにNew プロファイルを**作成**します。 2. ユーザーがアプリ内で何か購入すると、その購入は**Adaptyプロファイルとストアアカウントに紐付けられます**。 3. ユーザーがアプリを**再インストール**したり、**新しいデバイス**にインストールしたりすると、Adaptyは有効化時に**新しい匿名プロファイルを作成**します。 4. ユーザーがそれ以前にアプリで購入していた場合、デフォルトではSDK有効化時にApp Storeから購入履歴が自動的に同期されます。 匿名ユーザーの場合、インストールのたびに新しいプロファイルが作成されますが、Adaptyアナリティクスでは[新規インストールとみなす基準を設定](general#4-installs-definition-for-analytics)できるため、問題にはなりません。 :::note バックアップからの復元は、再インストールとは異なる動作をします。デフォルトでは、ユーザーがバックアップから復元する際、SDKはキャッシュされたデータを保持し、新しいプロファイルを作成しません。この動作は`clearDataOnBackup`設定で変更できます。[詳細を確認する](sdk-installation-react-native-pure#clear-data-on-backup-restore)。 ::: 匿名ユーザーの場合、**デバイスID**に基づいてインストール数をカウントします。この場合、再インストールを含め、デバイス上のアプリインストールがそれぞれ1回のインストールとしてカウントされます。 ## 識別済みユーザー \{#identified-users\} ユーザーを識別する方法は2つあります: - [**ログイン/サインアップ時:**](#during-loginsignup) アプリ起動後にユーザーがサインインする場合、認証時に`identify()`をカスタマーユーザーIDと共に呼び出します。 - [**SDKの有効化時:**](#during-the-sdk-activation) アプリ起動時にカスタマーユーザーIDがすでに保存されている場合、`activate()`呼び出し時にそれを渡します。 :::important デフォルトでは、あるカスタマーユーザーIDから購入が発生した際、そのIDが別のカスタマーユーザーIDに紐付いていても、アクセスレベルは共有されます。つまり、両方のプロファイルが有料アクセスを持ちます。この設定を変更して、一方のプロファイルから他方へアクセスを移譲したり、共有を無効にしたりすることもできます。詳細は[こちらの記事](general#6-sharing-paid-access-between-user-accounts)を参照してください。 ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(例:ログインやサインアップ後)、`identify`メソッドを使ってカスタマーユーザーIDを設定します。 - **このカスタマーユーザーIDを初めて使う場合**、Adaptyは自動的に現在のプロファイルに紐付けます。 - **以前にこのカスタマーユーザーIDでユーザーを識別したことがある場合**、Adaptyはそのカスタマーユーザーに紐付いたプロファイルへ切り替えます。 :::important カスタマーユーザーIDはユーザーごとに一意である必要があります。パラメータの値をハードコードすると、すべてのユーザーが同一人物とみなされます。 ::: 他のSDKメソッドを呼び出す前に、必ず`identify`を`await`してください。並列呼び出しを行うと`#3006 profileWasChanged`が発生したり、匿名プロファイルに対して操作が行われる場合があります。詳しくは[React Native SDKの呼び出し順序](react-native-sdk-call-order)を参照してください。 ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // Unique for each user // successfully identified } catch (error) { // handle the error } ``` ### SDKの有効化時 \{#during-the-sdk-activation\} SDKを有効化する時点でカスタマーユーザーIDが既にわかっている場合、`identify`を別途呼び出さずに`activate`メソッドに渡すことができます。 カスタマーユーザーIDがわかっているにもかかわらず、有効化後にのみ設定した場合、有効化時にAdaptyは新しい匿名プロファイルを作成し、`identify`を呼び出した後にのみ既存のプロファイルに切り替わります。 既存のカスタマーユーザーID(以前に使用したもの)または新しいものを渡すことができます。新しいものを渡した場合、有効化時に作成される新しいプロファイルが自動的にそのカスタマーユーザーIDに紐付けられます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスダッシュボードに影響しません。インストールはデバイスIDに基づいてカウントされるためです。 デバイスIDはストアからデバイスへのアプリの1回のインストールを表し、アプリの再インストール後にのみ再生成されます。 初回インストールか再インストールかや、既存のカスタマーユーザーIDを使用するかどうかには依存しません。 プロファイルの作成(SDK有効化時またはログアウト時)、ログイン、または再インストールなしのアプリアップグレードでは、追加のインストールイベントは発生しません。 インストールをデバイスではなく一意のユーザーに基づいてカウントしたい場合は、**App settings**で[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```typescript showLineNumbers adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID" // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. }); ``` ### ユーザーをログアウトさせる \{#log-users-out\} ユーザーのログアウトボタンがある場合は、`logout`メソッドを使用します。 :::important ユーザーのログアウト時に、新しい匿名プロファイルが作成されます。 ::: ```typescript showLineNumbers try { await adapty.logout(); // successful logout } catch (error) { // handle the error } ``` :::info ユーザーをアプリに再度ログインさせるには、`identify`メソッドを使用してください。 ::: ### ログインなしで購入を許可する \{#allow-purchases-without-login\} ユーザーがログイン前後の両方で購入できる場合、ログイン後もアクセスが維持されるよう対応が必要です: 1. ログアウト状態のユーザーが購入を行うと、AdaptyはそれをそのユーザーのプロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyは識別済みプロファイルに切り替えます。 - 新しいカスタマーユーザーID(例:登録前に購入が行われた場合)の場合、Adaptyはそのカスタマーユーザーを現在のプロファイルに割り当て、購入履歴が引き継がれます。 - 既存のカスタマーユーザーID(すでにプロファイルに紐付いている)の場合、プロファイル切り替え後に実際のアクセスレベルを取得する必要があります。識別後すぐに[`getProfile`](react-native-check-subscription-status)を呼び出すか、[プロファイルの更新をリッスン](react-native-check-subscription-status)してデータを自動的に同期させてください。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内課金のロジックを実装できました。アプリの収益化を成功させてください! Adaptyをさらに活用するために、以下のトピックもご確認ください: - [**テスト**](troubleshooting-test-purchases):すべてが期待通りに動作することを確認する - [**オンボーディング**](react-native-onboardings):オンボーディングでユーザーを引き付けてリテンションを向上させる - [**インテグレーション**](configuration):マーケティングアトリビューションや分析サービスをわずか1行のコードで連携する - [**カスタムプロファイル属性の設定**](react-native-setting-user-attributes):ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/Bテストを実施したり、ユーザーごとに異なるペイウォールを表示したりする --- # File: adapty-sdk-integration-skill-react-native --- --- title: "SDKインテグレーションスキルを使ってAdaptyをReact Nativeアプリに統合する" description: "adapty-sdk-integrationスキルを使用して、AIコーディングツールでAdapty SDKをReact Nativeアプリにエンドツーエンドで統合します。" --- :::important このスキルはベータ版です。処理が止まったり予期しない動作が発生した場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor-react-native)を参照してください。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-react-native --- --- title: "AIアシスタントを使ってAdaptyをReact Nativeアプリに統合する" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使って、AdaptyをReact Nativeアプリに統合するためのステップバイステップガイド。" --- このガイドでは、AIコーディングツールを使いながら、AdaptyをReact Nativeアプリに順を追って統合していきます。必要なAdaptyのドキュメントを正しい順番でAIに渡してください。 For a fully automated integration, use the [adapty-sdk-integration skill](https://github.com/adaptyteam/adapty-sdk-integration-skill): it runs the whole integration from your AI coding tool in one command. ## 始める前に:ダッシュボードの設定 \{#before-you-start-dashboard-setup\} AdaptyでSDKのコードを書く前に、ダッシュボードでいくつかの設定が必要です。インタラクティブなLLMスキルを使うか、ダッシュボードから手動で行うかを選べます。 ### スキルを使う方法(推奨)\{#skill-approach-recommended\} Adapty CLIスキルを使うと、LLMがダッシュボードを開かずに、アプリ・プロダクト・アクセスレベル・ペイウォール・プレースメントを直接設定できます。必要なのは、ダッシュボードで[ストアを連携する](integrate-payments)ことだけです。 ``` npx skills add adaptyteam/adapty-cli --skill adapty-cli ``` スキルを追加したら、エージェントで `/adapty-cli` を実行してください。ストアの連携でダッシュボードを開くタイミングも含め、各ステップをガイドしてくれます。 ### ダッシュボードを使う方法 \{#dashboard-approach\} 手動で設定したい場合は、コードを書く前に以下の準備が必要です。LLMはダッシュボードの値を自動で取得できないため、自分で用意する必要があります。 1. **ストアを連携する**:Adapty ダッシュボードで **App settings → General** を開き、両プラットフォームを対象とする場合はApp StoreとGoogle Playの両方を連携してください。課金を機能させるために必須です。 [ストアを連携する](integrate-payments) 2. **Public SDKキーをコピーする**:Adapty ダッシュボードで **App settings → General** を開き、**API keys** セクションを確認します。コード内では、`adapty.activate("YOUR_PUBLIC_SDK_KEY")` に渡す文字列です。 3. **プロダクトを1つ以上作成する**:Adapty ダッシュボードで **Products** ページを開いてください。コード内でプロダクトを直接参照することはありません — Adaptはペイウォールを通じてプロダクトを提供します。 [プロダクトを追加する](quickstart-products) 4. **ペイウォールとプレースメントを作成する**:Adapty ダッシュボードで **Paywalls** ページにペイウォールを作成し、**Placements** ページでプレースメントに割り当ててください。コード内では、`adapty.getPaywall("YOUR_PLACEMENT_ID")` に渡すプレースメントIDを使います。 [ペイウォールを作成する](quickstart-paywalls) 5. **アクセスレベルを設定する**:Adapty ダッシュボードで **Products** ページの各プロダクトに設定します。コード内では `profile.accessLevels['premium']?.isActive` で確認する文字列です。デフォルトの `premium` アクセスレベルはほとんどのアプリで問題ありません。プロダクトによって異なる機能(例:`basic` プランと `pro` プラン)をユーザーに提供する場合は、コーディングを始める前に[追加のアクセスレベルを作成](assigning-access-level-to-a-product)してください。 :::tip 5つの準備が整ったら、コードを書き始められます。「Public SDKキーはXで、プレースメントIDはY」とLLMに伝えると、正しい初期化コードとペイウォール取得コードを生成してもらえます。 ::: ### 準備ができたら設定するもの \{#set-up-when-ready\} コーディングを始める前に必須ではありませんが、統合が進むにつれて必要になります: - **A/B テスト**:**Placements** ページで設定します。コードの変更は不要です。 [A/B テスト](ab-tests) - **追加のペイウォールとプレースメント**:異なるプレースメントIDで `getPaywall` の呼び出しを追加します。 - **アナリティクス連携**:**Integrations** ページで設定します。設定方法は連携先によって異なります。[アナリティクス連携](analytics-integration)と[アトリビューション連携](attribution-integration)を参照してください。 ## LLMにAdaptyのドキュメントを渡す \{#feed-adapty-docs-to-your-llm\} ### Context7を使う方法(推奨)\{#use-context7-recommended\} [Context7](https://context7.com)は、LLMが最新のAdaptyドキュメントに直接アクセスできるMCPサーバーです。質問内容に応じて適切なドキュメントを自動で取得するため、URLを手動で貼り付ける必要がありません。 Context7は**Cursor**、**Claude Code**、**Windsurf**、その他のMCP対応ツールで動作します。セットアップするには以下を実行してください: ``` npx ctx7 setup ``` エディタを自動検出してContext7サーバーを設定します。手動セットアップの方法は[Context7のGitHubリポジトリ](https://github.com/upstash/context7)を参照してください。 設定が完了したら、プロンプト内でAdaptyライブラリを参照します: ``` Use the adaptyteam/adapty-docs library to look up how to install the React Native SDK ``` :::warning Context7を使えばドキュメントのURLを手動で貼り付ける必要はなくなりますが、実装の順序は重要です。すべてが正しく動作するよう、以下の[実装ウォークスルー](#implementation-walkthrough)をステップごとに進めてください。 ::: ### プレーンテキストのドキュメントを使う方法 \{#use-plain-text-docs\} AdaptyのドキュメントはプレーンテキストのMarkdownとして取得できます。URLの末尾に `.md` を追加するか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例:[adapty-cursor-react-native.md](https://adapty.io/docs/ja/adapty-cursor-react-native.md) 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステップには、貼り付け用の `.md` リンクが入った「LLMに送るプロンプト」ブロックが含まれています。 より多くのドキュメントを一度に渡したい場合は、以下の[インデックスファイルとプラットフォーム別サブセット](#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が自動でレンダリングします。 - [**手動で作成したペイウォール**](react-native-making-purchases):コードで独自のペイウォールUIを構築しつつ、プロダクトの取得と購入処理にAdaptyを使います。 - [**オブザーバーモード**](observer-vs-full-mode):既存の購入インフラをそのまま使い、Adaptyはアナリティクスと連携にのみ使用します。 どれを選ぶか迷ったら、[クイックスタートの比較表](react-native-quickstart-paywalls)を参照してください。 ### SDKのインストールと設定 \{#install-and-configure-the-sdk\} npm(またはyarn)でAdapty SDKの依存関係を追加し、Public SDKキーで有効化します。これが基盤となるため、ここが機能しないと他のすべてが動作しません。 ExpoとベアのReact Nativeプロジェクトでは別々のインストールガイドがあります — 自分のセットアップに合ったものを選んでください。 **ガイド:** - [Expoでインストールする](sdk-installation-react-native-expo) - [ベアReact Nativeでインストールする](sdk-installation-react-native-pure) LLMに送るプロンプト(セットアップに合ったものを選ぶか、両方送ってください): ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-react-native-expo.md - https://adapty.io/docs/ja/sdk-installation-react-native-pure.md ``` :::tip[チェックポイント] - **確認事項:** アプリがiOSとAndroidの両方でビルドおよび実行できること。Metroバンドラーのログにアクティベーションログが表示されること。 - **注意点:** 「Public API key is missing」が表示される場合 → プレースホルダーをApp settingsの実際のキーに置き換えたか確認してください。 ::: ### ペイウォールの表示と購入処理 \{#show-paywalls-and-handle-purchases\} プレースメントIDでペイウォールを取得し、表示して、購入イベントを処理します。必要なガイドは購入の処理方法によって異なります。 進めながらサンドボックスで各購入をテストしてください — 最後まで待たずに行うことをお勧めします。設定方法は[サンドボックスで購入をテストする](test-purchases-in-sandbox)を参照してください。 <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **ガイド:** - [ペイウォールを使って購入を有効にする(クイックスタート)](react-native-quickstart-paywalls) - [ペイウォールビルダーのペイウォールと設定を取得する](react-native-get-pb-paywalls) - [ペイウォールを表示する](react-native-present-paywalls) - [ペイウォールのイベントを処理する](react-native-handling-events-1) - [ボタンアクションに応答する](react-native-handle-paywall-actions) LLMに送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/react-native-quickstart-paywalls.md - https://adapty.io/docs/ja/react-native-get-pb-paywalls.md - https://adapty.io/docs/ja/react-native-present-paywalls.md - https://adapty.io/docs/ja/react-native-handling-events-1.md - https://adapty.io/docs/ja/react-native-handle-paywall-actions.md ``` :::tip[チェックポイント] - **確認事項:** 設定したプロダクトとともにペイウォールが表示されること。プロダクトをタップするとサンドボックス購入ダイアログが表示されること。 - **注意点:** ペイウォールが空、または `getPaywall` エラーが出る場合 → プレースメントIDがダッシュボードと完全に一致しているか、プレースメントにオーディエンスが割り当てられているかを確認してください。 ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](react-native-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products-react-native) - [リモートコンフィグで設計したペイウォールをレンダリングする](present-remote-config-paywalls-react-native) - [購入を処理する](react-native-making-purchases) - [購入を復元する](react-native-restore-purchase) LLMに送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/react-native-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products-react-native.md - https://adapty.io/docs/ja/present-remote-config-paywalls-react-native.md - https://adapty.io/docs/ja/react-native-making-purchases.md - https://adapty.io/docs/ja/react-native-restore-purchase.md ``` :::tip[チェックポイント] - **確認事項:** カスタムペイウォールにAdaptyから取得したプロダクトが表示されること。プロダクトをタップするとサンドボックス購入ダイアログが表示されること。 - **注意点:** プロダクト配列が空の場合 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、プレースメントにオーディエンスが設定されているかを確認してください。 ::: </TabItem> <TabItem value="observer" label="Observer mode"> **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードを実装する](implement-observer-mode-react-native) - [オブザーバーモードでトランザクションを報告する](report-transactions-observer-mode-react-native) 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-react-native.md - https://adapty.io/docs/ja/report-transactions-observer-mode-react-native.md ``` :::tip[チェックポイント] - **確認事項:** 既存の購入フローでサンドボックス購入を行った後、Adapty ダッシュボードの **Event Feed** にトランザクションが表示されること。 - **注意点:** イベントが表示されない場合 → Adaptyにトランザクションを報告しているか、両方のストアでサーバー通知が設定されているかを確認してください。 ::: </TabItem> </Tabs> ### サブスクリプション状態を確認する \{#check-subscription-status\} 購入後、ユーザープロファイルのアクセスレベルがアクティブかどうかを確認してプレミアムコンテンツの表示を制限します。 **ガイド:** [サブスクリプション状態を確認する](react-native-check-subscription-status) LLMに送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/react-native-check-subscription-status.md ``` :::tip[チェックポイント] - **確認事項:** サンドボックス購入後、`profile.accessLevels['premium']?.isActive` が `true` を返すこと。 - **注意点:** 購入後に `accessLevels` が空の場合 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているかを確認してください。 ::: ### ユーザーを識別する \{#identify-users\} アプリのユーザーアカウントをAdaptyのプロファイルに紐づけて、複数のデバイスをまたいで購入を継続させます。 :::important アプリに認証機能がない場合は、このステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](react-native-quickstart-identify) LLMに送るプロンプト: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/react-native-quickstart-identify.md ``` :::tip[チェックポイント] - **確認事項:** `adapty.identify("your-user-id")` を呼び出した後、ダッシュボードの **Profiles** セクションにカスタムユーザーIDが表示されること。 - **注意点:** 匿名プロファイルのアトリビューションを避けるため、アクティベーション後、ペイウォールの取得前に `identify` を呼び出してください。 ::: ### リリース準備をする \{#prepare-for-release\} サンドボックスでの統合が正常に動作したら、リリースチェックリストを確認して本番環境の準備が整っているか確認してください。 **ガイド:** [リリースチェックリスト](release-checklist) LLMに送るプロンプト: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ja/release-checklist.md ``` :::tip[チェックポイント] - **確認事項:** チェックリストの全項目が確認済みであること:ストアの連携、サーバー通知、購入フロー、アクセスレベルの確認、プライバシー要件。 - **注意点:** サーバー通知が設定されていない場合 → **App settings → iOS SDK** でApp Store サーバー通知を設定し、**App settings → Android SDK** でGoogle Play リアルタイム デベロッパー通知を設定してください。 ::: ## プレーンテキストのドキュメントインデックスファイル \{#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つのファイルにまとめたもの。非常に大きいファイルのため、全体像が必要な場合にのみ使用してください。 - React Native専用の [`react-native-llms.txt`](https://adapty.io/docs/ja/react-native-llms.txt) と [`react-native-llms-full.txt`](https://adapty.io/docs/ja/react-native-llms-full.txt):サイト全体と比べてトークン数を節約できるプラットフォーム別のサブセットです。 --- # File: react-native-get-pb-paywalls --- --- title: "フローとペイウォールの取得 - React Native" description: "React Native アプリで Adapty からフローとペイウォールを取得します。" --- <SDKv4> <MethodPromo method="getFlow" /> [フローまたはペイウォールビルダーでペイウォールをデザイン](adapty-paywall-builder)したら、モバイルアプリにそれを表示できます。まず、以下で説明するように、プレースメントに関連付けられたフローまたはペイウォールとそのビュー設定を取得します。 このトピックはフローとペイウォールビルダーでカスタマイズしたペイウォールに関するものです。ペイウォールを手動で実装する場合は、[リモートコンフィグペイウォールのペイウォールとプロダクトの取得](fetch-paywalls-and-products-react-native)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでフローとペイウォールを表示する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[フロー/ペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フロー/ペイウォールを組み込む](create-placement)。 4. モバイルアプリに [Adapty SDK](sdk-installation-reactnative) をインストールする。 </details> ## フローまたはペイウォールの取得 \{#fetch-flowpaywall\} Flow Builder またはペイウォールビルダーを使ってフローまたはペイウォールを作成した場合、モバイルアプリのコード上でそれをユーザーに表示するためのレンダリング処理を自分で実装する必要はありません。そのようなフローやペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてIDを取得し、ビュー設定を取得した上で、モバイルアプリ内に表示する必要があります。 フローまたはペイウォールをできるだけ早い段階で取得し、その[ビューを作成](react-native-get-pb-paywalls#fetch-the-view-configuration)しておきましょう — 理想的には表示するよりもかなり前に行います。`createFlowView` メソッドはビューの設定を読み込み、画像のダウンロードとキャッシュをバックグラウンドで開始します。早めに呼び出すほど、ダウンロードが完了するまでの時間を確保できます。フローまたはペイウォールを表示する頃には、設定と画像がすでにキャッシュされた状態になっています。 フローまたはペイウォールを取得するには、`getFlow` メソッドを使用します: ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlow(placementId); // the requested flow/paywall } catch (error) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |-------------------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方式はユーザーが常に最新のデータを取得できるため、推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用することを検討してください。キャッシュが存在する場合はキャッシュデータを返します。この場合、ユーザーが最新のデータを取得できないことがありますが、接続状態にかかわらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、ネットワークリクエストを避けるためにセッション中に使用しても安全です。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリーンアップした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存します。1つは上記の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。また、CDN を使用してペイウォールをより速く取得し、CDN に接続できない場合に備えてスタンドアローンのフォールバックサーバーも利用しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeoutMs** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>内部で複数のリクエストが実行される場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p><p>Android の場合: 拡張関数(例: `5.seconds`、`.seconds` は `import com.adapty.utils.seconds` から)を使用するか、`TimeInterval.seconds(5)` で `TimeInterval` を作成できます。制限なしにするには `TimeInterval.INFINITE` を使用してください。</p> | ## レスポンスパラメータ \{#response-parameters\} | パラメータ | 説明 | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Flow | フローの識別子(`id`、`variationId`)、名前、プレースメント、ペイウォールのバリアント(`paywalls`)、リモートコンフィグ(`remoteConfigs`)を含む `AdaptyFlow` オブジェクト。 | ## ビュー設定の取得 \{#fetch-the-view-configuration\} :::important ビルダーの **Show on device** トグルを必ず有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: プレースメントが **Flow Builder** または **ペイウォールビルダー** でデザインされている場合、Adapty が UI をレンダリングします。`createFlowView` でビューを作成し、[フローまたはペイウォールを表示](react-native-present-paywalls)してください。プレースメントがビルダー UI を持たないカスタムペイウォールの場合は、代わりに[リモートコンフィグペイウォールとして処理](present-remote-config-paywalls-react-native)してください。 React Native SDK では、ビューの設定を事前に取得する必要はなく、`createFlowView` を直接呼び出せます。 :::warning `createFlowView` メソッドの戻り値は一度しか使用できません。再度使用する必要がある場合は、`createFlowView` メソッドを新たに呼び出してください。再作成せずに二度呼び出すと、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```typescript showLineNumbers try { const view = await createFlowView(flow); } catch (error) { // handle the error } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :------------------- | :------- | :----------------------------------------------------------- | | **flow** | 必須 | 目的のフロー/ペイウォールのコントローラーを取得するための `AdaptyFlow` オブジェクト。 | | **customTags** | 任意 | カスタムタグとその解決済みの値の辞書を定義します。カスタムタグはコンテンツ内のプレースホルダーとして機能し、フロー/ペイウォール内でパーソナライズされたコンテンツを提供するために特定の文字列に動的に置き換えられます。詳細については、ペイウォールビルダーのカスタムタグに関するトピックを参照してください。 | | **prefetchProducts** | 任意 | 画面上のプロダクト表示タイミングを最適化するために有効にします。`true` にすると、AdaptyUI が必要なプロダクトを自動的にフェッチします。デフォルト: `false`。 | | **android.enableSafeArea** | 任意 | Android のみ(iOS では無視されます)。ネストされたオブジェクトとして渡してください: `android: { enableSafeArea: true }`。`true` にすると、フロービューにセーフエリアのパディングが適用されます。モーダル表示(`createFlowView` + `present()`)の場合はデフォルトで `true`、埋め込みの `AdaptyFlowView` コンポーネントの場合はデフォルトで `false` です。ほとんどのケースではデフォルト設定が適しています。 | :::note 複数の言語を使用している場合は、[フローのローカライズを追加する方法](add-paywall-locale-in-adapty-paywall-builder)と、ロケールコードを正しく使用する方法を[こちら](react-native-localizations-and-locale-codes)でご確認ください。 ::: ビューを取得したら、[フロー/ペイウォールを表示](react-native-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` を使用してください。 ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlowForDefaultAudience(id); // the requested flow/paywall } catch (error) { // handle the error } ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` の使用を検討してください。この設定では、キャッシュが存在する場合にキャッシュデータを返します。最新データが得られないケースはありますが、接続状況に関わらず読み込みが速くなります。キャッシュはセッション中も定期的に更新されるため、ネットワークリクエストを減らす目的で安心して利用できます。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリアした場合のみ削除されます。</p> | ## アセットのカスタマイズ \{#customize-assets\} フロー/ペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には、あらかじめ `hero_image` および `hero_video` という定義済みIDが割り当てられています。カスタムアセットバンドルでは、これらのIDを使って各要素を指定し、動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 たとえば、次のようなことができます。 - 特定のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中にローカルのプレビュー画像を表示する。 - 動画の再生前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty React Native SDK をバージョン 3.8.0 以上に更新してください。 ::: シンプルなディクショナリを使ってカスタムアセットを提供する例を以下に示します: ```javascript const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; view = await createFlowView(flow, { customAssets }) ``` :::note アセットが見つからない場合、フロー/ペイウォールはデフォルトの外観にフォールバックします。 ::: </SDKv4> <SDKv3> [Adapty ダッシュボードの新しいペイウォールビルダーでペイウォールのビジュアルデザインを作成](adapty-paywall-builder)した後、それをモバイルアプリに表示できます。最初のステップは、プレースメントに関連付けられたペイウォールとそのビュー設定を取得することです。詳細は以下をご覧ください。 :::warning 新しいペイウォールビルダーは、React Native SDK バージョン 3.0 以降で動作します。 ::: ペイウォールビルダーでカスタマイズしたペイウォールについての説明です。ペイウォールを手動で実装している場合は、[モバイルアプリでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する](fetch-paywalls-and-products-react-native)トピックを参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールの表示を開始する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加](create-paywall)します。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加](create-placement)します。 4. モバイルアプリに [Adapty SDK](sdk-installation-reactnative) をインストールします。 </details> ## ペイウォールビルダーで作成したペイウォールを取得する \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーを使ってペイウォールをデザインした場合](adapty-paywall-builder)、ユーザーに表示するためのレンダリングコードをアプリ内に書く必要はありません。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。ただし、プレースメントを通じてペイウォールのIDを取得し、ビュー設定を取得した上で、アプリ内に表示する必要があります。 最適なパフォーマンスを確保するには、ユーザーに表示する前に画像のダウンロードが完了するよう十分な時間を確保するために、ペイウォールとその[ビュー設定](react-native-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)をできるだけ早く取得することが重要です。 ペイウォールを取得するには、`getPaywall` メソッドを使用します。 ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywall(placementId, locale); // the requested paywall } catch (error) { // handle the error } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |-------------------|--------|-----------| | **placementId** | 必須 | 取得したい[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-paywall-locale-in-adapty-paywall-builder)の識別子。ハイフン(**-**)で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目はリージョンを表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードおよび推奨する使用方法については、[ローカライゼーションとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。常に最新のデータをユーザーに届けられるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定だと考えられる場合は、`.returnCacheDataElseLoad` を使用して、キャッシュが存在する場合はキャッシュデータを返すようにすることを検討してください。この場合、最新データが届かないことがありますが、接続が不安定な状況でも読み込みが速くなります。キャッシュはこまめに更新されるため、ネットワークリクエストを減らす目的でセッション中に使用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存します。1つは上述の定期更新キャッシュ、もう1つは[フォールバックペイウォール](fallback-paywalls)です。また、ペイウォールの取得を高速化するために CDN を使用し、CDN に接続できない場合に備えたスタンドアロンのフォールバックサーバーも備えています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeoutMs** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルのフォールバックが返されます。</p><p>内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p><p>Android の場合:`TimeInterval` は拡張関数(例:`5.seconds`(`.seconds` は `import com.adapty.utils.seconds` から)など)または `TimeInterval.seconds(5)` で作成できます。制限なしに設定するには `TimeInterval.INFINITE` を使用してください。</p> | ## レスポンスパラメータ \{#response-parameters\} | パラメーター | 説明 | | :-------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Paywall | プロダクト ID のリスト、ペイウォール識別子、リモートコンフィグ、およびその他のいくつかのプロパティを含む [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) オブジェクト。 | ## ペイウォールビルダーで作成したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーの **Show on device** トグルを有効にしてください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、`ViewConfiguration` が含まれているかどうかを確認してください。これが含まれている場合、そのペイウォールはペイウォールビルダーで作成されたことを示します。この情報をもとに、ペイウォールの表示方法を決定してください。`ViewConfiguration` が存在する場合はペイウォールビルダーのペイウォールとして扱い、存在しない場合は[リモートコンフィグのペイウォールとして処理してください](present-remote-config-paywalls-react-native)。 React Native SDK では、ビュー設定を手動で取得せずに、直接 `createPaywallView` メソッドを呼び出してください。 :::warning `createPaywallView` メソッドの結果は一度しか使用できません。再度使用する必要がある場合は、`createPaywallView` メソッドを新たに呼び出してください。再作成せずに2回呼び出すと、`AdaptyUIError.viewAlreadyPresented` エラーが発生する可能性があります。 ::: ```typescript showLineNumbers // for the Adapty SDK < 3.14 – import {createPaywallView} from 'react-native-adapty/dist/ui'; if (paywall.hasViewConfiguration) { try { const view = await createPaywallView(paywall); } catch (error) { // handle the error } } else { //use your custom logic } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :------------------- | :------- | :----------------------------------------------------------- | | **paywall** | 必須 | 目的のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **customTags** | 任意 | カスタムタグとその解決済みの値のディクショナリを定義します。カスタムタグはペイウォールコンテンツ内のプレースホルダーとして機能し、特定の文字列に動的に置き換えることでペイウォール内のコンテンツをパーソナライズします。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | | **prefetchProducts** | 任意 | 画面上のプロダクト表示タイミングを最適化するために有効にします。`true` の場合、AdaptyUI は必要なプロダクトを自動的に取得します。デフォルト: `false`。 | :::note 複数の言語を使用している場合は、[ペイウォールビルダーのローカライゼーションを追加する方法](add-paywall-locale-in-adapty-paywall-builder)と、ロケールコードの正しい使い方については[こちら](react-native-localizations-and-locale-codes)をご覧ください。 ::: ビューを取得したら、[ペイウォールを表示](react-native-present-paywalls)してください。 ## デフォルトオーディエンス向けペイウォールを取得して表示を高速化する \{#get-a-paywall-for-a-default-audience-to-fetch-it-faster\} 通常、ペイウォールはほぼ即座に取得されるため、速度を気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合、ペイウォールの取得に予想以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したい場合があるでしょう。 これに対処するには、`getPaywallForDefaultAudience` メソッドを使用できます。このメソッドは、**All Users** オーディエンス向けに指定されたプレースメントのペイウォールを取得します。ただし、推奨アプローチは `getPaywall` メソッドでペイウォールを取得することであり、詳細は上記の[ペイウォール情報の取得](#fetch-paywall-designed-with-paywall-builder)セクションを参照してください。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現行バージョンと将来のバージョン)で異なるペイウォールを表示する必要がある場合、課題が生じることがあります。現行(レガシー)バージョンに対応したペイウォールを設計するか、現行(レガシー)バージョンのユーザーがペイウォールを表示できない問題を許容するか、いずれかの対応が必要になります。 - **ターゲティングの喪失**: すべてのユーザーに **All Users** オーディエンス向けに設計された同一のペイウォールが表示されます。これにより、国、マーケティングのアトリビューション、独自のカスタム属性などに基づくパーソナライズされたターゲティングができなくなります。 これらのデメリットを許容してペイウォールの取得を高速化したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](#fetch-paywall-designed-with-paywall-builder)で説明した `getPaywall` を使用してください。 ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywallForDefaultAudience(id, locale); // the requested paywall } catch (error) { // handle the error } ``` :::note `getPaywallForDefaultAudience` メソッドは、React Native SDK バージョン 2.11.2 以降で利用できます。 ::: | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-remote-config-locale)の識別子です。このパラメータは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードである必要があります。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードの詳細および推奨される使用方法については、[ローカライゼーションとロケールコード](react-native-localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法はユーザーが常に最新のデータを受け取れるため、推奨しています。</p><p></p><p>ただし、ユーザーがインターネット接続の不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在すればそれを返す方法も検討してください。この場合、最新データが届かないことがありますが、接続状態に関わらず読み込み時間が短縮されます。キャッシュはセッション中に定期的に更新されるため、ネットワークリクエストを減らす目的で安全に使用できます。</p><p></p><p>なお、キャッシュはアプリを再起動しても保持され、アプリの再インストールまたは手動クリアを行った場合にのみ削除されます。</p> | ## アセットのカスタマイズ \{#customize-assets\} ペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像とヒーロー動画には、`hero_image` と `hero_video` というあらかじめ定義された ID があります。カスタムアセットバンドルでは、これらの ID を指定して要素の動作をカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタム ID を設定する](custom-media)必要があります。 たとえば、次のようなことができます。 - 一部のユーザーに別の画像や動画を表示する。 - リモートのメイン画像の読み込み中にローカルのプレビュー画像を表示する。 - 動画の再生前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty React Native SDK をバージョン 3.8.0 以上に更新してください。 ::: シンプルなディクショナリを使ってカスタムアセットを提供する例を示します: ```javascript const customAssets: Record<string, AdaptyCustomAsset> = { 'custom_image': { type: 'image', relativeAssetPath: 'custom_image.png' }, 'hero_video': { type: 'video', fileLocation: { ios: { fileName: 'custom_video.mp4' }, android: { relativeAssetPath: 'videos/custom_video.mp4' } } } }; view = await createPaywallView(paywall, { customAssets }) ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの外観にフォールバックします。 ::: </SDKv3> --- # File: react-native-present-paywalls --- --- title: "フローとペイウォールの表示 - React Native" description: "Adapty を使って React Native アプリでフローとペイウォールをユーザーに表示します。" --- <SDKv4> <MethodPromo method="getFlow" label="Display flows and paywalls" /> フローまたはペイウォールをフローービルダーで作成した場合、ユーザーに表示するためのレンダリング処理をモバイルアプリのコードに実装する必要はありません。そのようなフローには、表示するコンテンツと表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [フローまたはペイウォールを作成](create-paywall)していること。 2. [プレースメント](placements)に追加していること。 3. [フローを取得してビューを準備](react-native-get-pb-paywalls)していること。 :::warning このガイドは**フローおよびペイウォールビルダーで作成されたペイウォール**専用です。SDK v4.0以降が必要です。フローの表示方法はリモートコンフィグペイウォールとは異なります。 - **リモートコンフィグペイウォール**の表示については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。 ::: Adapty React Native SDK では、フローとペイウォールを表示する方法が2つあります: - **Reactコンポーネント**: アプリのアーキテクチャやナビゲーションシステムに組み込めるコンポーネントです。 - **モーダル表示** ## Reactコンポーネント \{#react-component\} フローを既存のコンポーネントツリーに埋め込むには、React Nativeのコンポーネント階層に`AdaptyFlowView`コンポーネントを直接使用します。埋め込みコンポーネントを使うことで、アプリのアーキテクチャやナビゲーションシステムに統合できます。 :::tip `AdaptyFlowView` コンポーネントは、レンダリング時(設定と画像の読み込み時)にビューを作成します。事前に読み込むには、アプリの早い段階で同じフローに対して [`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) を呼び出してください。コンポーネントはキャッシュされたデータを再利用し、ダウンロードを待たずにレンダリングします。 ::: ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const flowParams = useMemo(() => ({ loadTimeoutMs: 3000, }), []); const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<FlowEventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<FlowEventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<FlowEventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<FlowEventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<FlowEventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<FlowEventHandlers['onRestoreFailed']>((error) => {}, []); const onAppeared = useCallback<FlowEventHandlers['onAppeared']>(() => {}, []); const onError = useCallback<FlowEventHandlers['onError']>((error) => {}, []); const onLoadingProductsFailed = useCallback<FlowEventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => {}, []); const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<FlowEventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyFlowView flow={flow} params={flowParams} style={styles.flow} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onAppeared={onAppeared} onError={onError} onLoadingProductsFailed={onLoadingProductsFailed} onCustomAction={onCustomAction} onUrlPress={onUrlPress} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` ## モーダル表示 \{#modal-presentation\} フローをスタンドアロン画面として表示するには、[`createFlowView`](react-native-get-pb-paywalls#fetch-the-view-configuration) メソッドで作成した `view` に対して `view.present()` メソッドを使用します。各 `view` は一度しか使用できません。再度フローを表示する必要がある場合は、`createFlowView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用することは禁止されています。`AdaptyUIError.viewAlreadyPresented` エラーが発生します。 ::: ```typescript showLineNumbers title="React Native (TSX)" const view = await createFlowView(flow); // Optional: handle flow events (close, purchase, restore, etc) // view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` :::important `setEventHandlers` を複数回呼び出すと、以前に設定したハンドラーが上書きされ、デフォルトおよび指定したイベントの既存ハンドラーがすべて置き換えられます。 ::: ### iOSのプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメータを渡すことで、iOS でのフローの表示方法を設定できます。このパラメータには `'full_screen'`(デフォルト)または `'page_sheet'` を指定できます。 ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## 開発者定義タイマーを使用する \{#use-developer-defined-timer\} モバイルアプリで開発者定義タイマーを使用するには、`timerId`(この例では `CUSTOM_TIMER_NY`)を使います。これは Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。これにより、アプリはタイマーを正しい値(例:元日までの残り時間を現在時刻から引いた `13d 09h 03m 34s` のような形式)で動的に更新できます。 <Tabs> <TabItem value="component" label="React component"> ```typescript showLineNumbers title="React Native (TSX)" const flowParams = { customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } }; <AdaptyFlowView flow={flow} params={flowParams} // ... your event handlers /> ``` </TabItem> <TabItem value="modal" label="Modal presentation"> ```typescript showLineNumbers title="React Native (TSX)" const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createFlowView(flow, { customTimers }); ``` </TabItem> </Tabs> この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリはタイマーに正しい値(例:タイマーの終了時刻(元旦など)から現在時刻を引いた `13d 09h 03m 34s`)を動的に反映できます。 ## ダイアログを表示する \{#show-dialog\} Android でフロービューが表示されている場合は、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常の RN アラートがフロービューの背面に表示されるため、ユーザーには見えません。このメソッドを使用すると、すべてのプラットフォームでフローの前面に正しくダイアログが表示されます。 ```typescript showLineNumbers title="React Native (TSX)" try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the flow await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## サブスクリプションを別のものに切り替える \{#replace-one-subscription-with-another\} Androidで、ユーザーが既存のサブスクリプションをアクティブな状態で新しいサブスクリプションを購入しようとした場合、フロービューの作成時にサブスクリプション更新パラメーターを渡すことで、新しい購入の処理方法を制御できます。現在のサブスクリプションを新しいものに切り替えるには、`createFlowView`の`productPurchaseParams`に`oldSubVendorProductId`と`prorationMode`パラメーターを指定してください。 ```typescript showLineNumbers title="React Native (TSX)" const productPurchaseParams = flow.paywalls .flatMap((variation) => variation.productIdentifiers) .map((productId) => { let params = {}; if (Platform.OS === 'android') { params.android = { subscriptionUpdateParams: { oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION', prorationMode: 'with_time_proration', }, }; } return { productId, params }; }); const view = await createFlowView(flow, { productPurchaseParams }); ``` </SDKv4> <SDKv3> ペイウォールビルダーを使用してペイウォールをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングする必要はありません。このようなペイウォールには、ペイウォール内に表示する内容とその表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [ペイウォールを作成](create-paywall)している。 2. ペイウォールを[プレースメント](placements)に追加している。 3. [ペイウォールをフェッチしてビューを準備](react-native-get-pb-paywalls)している。 :::warning このガイドは、SDK v3.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。ペイウォールの表示方法は、ペイウォールビルダーのバージョンやリモートコンフィグのペイウォールによって異なります。 - **リモートコンフィグのペイウォール**を表示する方法については、[リモートコンフィグで設計されたペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。 ::: Adapty React Native SDK には、ペイウォールを表示する方法が 2 つあります: - **React コンポーネント**: アプリのアーキテクチャやナビゲーションシステムに組み込めるコンポーネントです。 - **モーダル表示** ## Reactコンポーネント \{#react-component\} :::note **Reactコンポーネント**アプローチを使用するには、SDK 3.14.0以降が必要です。 ::: 既存のコンポーネントツリー内にペイウォールを埋め込むには、React Nativeのコンポーネント階層の中で`AdaptyPaywallView`コンポーネントを直接使用します。埋め込みコンポーネントを使うことで、アプリのアーキテクチャやナビゲーションシステムに組み込むことができます。 :::note Androidでは、ペイウォールがステータスバーの背後まで拡張されていない場合、ペイウォールの上部にビジュアルオーバーレイが表示されることがあります。ペイウォールではこれをオフにすることをお勧めします。[ペイウォール上部のビジュアルオーバーレイ(Android)](#visual-overlay-at-the-top-of-the-paywall-android)をご覧ください。 ::: ```typescript showLineNumbers title="React Native (TSX)" function MyPaywall({ paywall }) { const paywallParams = useMemo(() => ({ loadTimeoutMs: 3000, }), []); const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<EventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<EventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<EventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<EventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<EventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<EventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<EventHandlers['onRestoreFailed']>((error) => {}, []); const onPaywallShown = useCallback<EventHandlers['onPaywallShown']>(() => {}, []); const onRenderingFailed = useCallback<EventHandlers['onRenderingFailed']>((error) => {}, []); const onLoadingProductsFailed = useCallback<EventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => {}, []); const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<EventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyPaywallView paywall={paywall} params={paywallParams} style={styles.paywall} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onPaywallShown={onPaywallShown} onRenderingFailed={onRenderingFailed} onLoadingProductsFailed={onLoadingProductsFailed} onCustomAction={onCustomAction} onUrlPress={onUrlPress} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` ## モーダル表示 \{#modal-presentation\} ペイウォールをスタンドアロン画面として表示するには、[`createPaywallView`](react-native-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) メソッドで作成した `view` に対して `view.present()` メソッドを呼び出します。各 `view` は一度しか使用できません。ペイウォールを再度表示する必要がある場合は、`createPaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用することは禁止されています。`AdaptyUIError.viewAlreadyPresented` エラーが発生します。 ::: ```typescript showLineNumbers title="React Native (TSX)" const view = await createPaywallView(paywall); // Optional: handle paywall events (close, purchase, restore, etc) // view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` :::important `setEventHandlers` を複数回呼び出すと、指定したハンドラーで既存のハンドラーが上書きされます。デフォルトのハンドラーと以前に設定したハンドラーの両方が、対象のイベントについて置き換えられます。 ::: ### iOS のプレゼンテーションスタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOS でのペイウォールの表示方法を設定できます。このパラメーターには `'full_screen'`(デフォルト)または `'page_sheet'` を指定できます。 ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## 開発者定義タイマーを使用する \{#use-developer-defined-timer\} モバイルアプリで開発者定義タイマーを使用するには、`timerId`(この例では `CUSTOM_TIMER_NY`)を使います。これは Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。これにより、アプリはタイマーを正しい値(例:`13d 09h 03m 34s`、タイマーの終了時刻(元日など)から現在時刻を引いた値)で動的に更新できます。 <Tabs> <TabItem value="component" label="React component"> ```typescript showLineNumbers title="React Native (TSX)" const paywallParams = { customTimers: { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } }; <AdaptyPaywallView paywall={paywall} params={paywallParams} // ... your event handlers /> ``` </TabItem> <TabItem value="modal" label="Modal presentation"> ```typescript showLineNumbers title="React Native (TSX)" const customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) }; const view = await createPaywallView(paywall, { customTimers }); ``` </TabItem> </Tabs> この例では、`CUSTOM_TIMER_NY` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。`timerResolver` により、アプリはタイマーの終了時刻(元旦など)から現在時刻を引いた値として `13d 09h 03m 34s` のような正確な値でタイマーを動的に更新します。 ## ダイアログを表示する \{#show-dialog\} Android でペイウォールビューが表示されている場合、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常の RN アラートがペイウォールビューの背後に表示されるため、ユーザーには見えません。このメソッドを使用することで、すべてのプラットフォームでペイウォールの前面にダイアログが正しく表示されます。 ```typescript showLineNumbers title="React Native (TSX)" try { const action = await view.showDialog({ title: 'Close paywall?', content: 'You will lose access to exclusive offers.', primaryActionTitle: 'Stay', secondaryActionTitle: 'Close', }); if (action === 'secondary') { // User confirmed - close the paywall await view.dismiss(); } // If primary - do nothing, user stays } catch (error) { // handle error } ``` ## 別のサブスクリプションへの切り替え \{#replace-one-subscription-with-another\} Androidで、ユーザーが既存のサブスクリプションを有効な状態で新しいサブスクリプションを購入しようとする場合、ペイウォールビューの作成時にサブスクリプション更新パラメータを渡すことで、新しい購入の処理方法を制御できます。現在のサブスクリプションを新しいサブスクリプションに切り替えるには、`createPaywallView` の `productPurchaseParams` に `oldSubVendorProductId` と `prorationMode` パラメータを指定してください。 ```typescript showLineNumbers title="React Native (TSX)" const productPurchaseParams = paywall.productIdentifiers.map((productId) => { let params = {}; if (Platform.OS === 'android') { params.android = { subscriptionUpdateParams: { oldSubVendorProductId: 'PRODUCT_ID_OF_THE_CURRENT_ACTIVE_SUBSCRIPTION', prorationMode: 'with_time_proration', }, }; } return { productId, params }; }); const view = await createPaywallView(paywall, { productPurchaseParams }); ``` ## トラブルシューティング \{#troubleshooting\} ### ペイウォール上部のビジュアルオーバーレイ(Android) \{#visual-overlay-at-the-top-of-the-paywall-android\} :::note この設定は React Native SDK 3.15.5 以降でサポートされており、ベア React Native プロジェクトでのみ利用できます。 Expo managed workflow を使用している場合、この Android リソースを直接追加することはできません。この設定を適用するには、対応する Android リソースを追加するカスタム Expo config プラグインを作成し、app.config.js に登録する必要があります。これは Expo がネイティブ Android プロジェクトを管理しているため必須です。 ::: `AdaptyPaywallView` がステータスバーの後ろまで拡張されていない場合でも、その上部にビジュアルオーバーレイが表示されることがあります。これを削除するには、アプリに次のブールリソースを追加してください: 1. `android/app/src/main/res/values` に移動します。`bools.xml` ファイルがない場合は作成してください。 2. 次のリソースを追加します: ```xml <resources> <bool name="adapty_paywall_enable_safe_area_paddings">false</bool> </resources> ``` この変更はアプリ内のすべてのペイウォールにグローバルに適用されることに注意してください。 </SDKv3> --- # File: react-native-handle-paywall-actions --- --- title: "フローアクションへの対応 - React Native" description: "Adapty を使用して React Native のフローとペイウォールのボタンアクションを処理し、アプリのマネタイズを向上させます。" --- <SDKv4> Adapty のフロービルダーやペイウォールビルダーを使ってフローやペイウォールを構築する場合、ボタンを適切に設定することが重要です。 1. [フロー/ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクション ID を作成します。 2. 割り当てたアクションごとに処理するコードをアプリに記述します。 このガイドでは、カスタムアクションおよび既存アクションをコードで処理する方法を説明します。 :::warning **購入、復元、フロー/ペイウォールのクローズ、URL オープンは自動的に処理されます。** デフォルトの動作を設定したり、カスタムアクションへの応答を実装したりすることができます。 ::: :::note SDKは、プッシュ通知やカメラアクセスなどのシステム権限リクエスト用に `onRequestPermission` フローハンドラーを公開しています。現時点ではフローがこれらのリクエストをトリガーしないため、今すぐ実装する必要はありません。 ::: ## フローとペイウォールを閉じる \{#close-flows-and-paywalls\} フローまたはペイウォールを閉じるボタンを追加するには: 1. ビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、フローまたはペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info React Native SDK では、`close` アクションはデフォルトでフローまたはペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。たとえば、あるフローを閉じると別のフローが開くようにすることも可能です。 ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> For React component, handle the close action through individual event handler props: ```javascript function MyPaywall({ flow }) { const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => { // Handle close button press - navigate away or hide component navigation.goBack(); }, [navigation]); return ( <AdaptyFlowView flow={flow} style={styles.container} onCloseButtonPress={onCloseButtonPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> モーダル表示の場合は、クローズハンドラーを実装します: ```javascript const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; // allow flow or paywall closing } }); ``` </TabItem> </Tabs> ## フローやペイウォールからURLを開く \{#open-urls-from-flows-and-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ビルダーで **Link** 要素を追加し、**Open URL** アクションが設定されたボタンと同じ方法で処理してください。 ::: フローやペイウォールにリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info React Native SDKでは、`openUrl`アクションはデフォルトでURLを開く動作をトリガーします。ただし、必要に応じてコード内でこの動作を上書きできます。 ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Reactコンポーネントの場合は、イベントハンドラープロップを通じてURLの開き方を制御します: ```javascript function MyPaywall({ flow }) { const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url) => { Linking.openURL(url); }, []); return ( <AdaptyFlowView flow={flow} style={styles.container} onUrlPress={onUrlPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> For modal presentation, implement the URL handler: ```javascript const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onUrlPress(url) { Linking.openURL(url); return false; // Keep flow or paywall open }, }); ``` </TabItem> </Tabs> ## カスタムアクションの処理 \{#handle-custom-actions\} ほかのアクションを処理するボタンを追加するには、次の手順に従います。 1. ビルダーでボタンを追加し、**Custom** アクションを割り当てて、IDを設定します。 2. アプリのコードで、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のフローやペイウォールを表示するボタンを追加できます。 <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Reactコンポーネントの場合は、イベントハンドラープロップを通じてカスタムアクションを処理します。 ```javascript function MyPaywall({ flow }) { const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => { if (actionId === 'openNewPaywall') { // Display another flow or paywall } }, []); return ( <AdaptyFlowView flow={flow} style={styles.container} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> モーダル表示の場合は、カスタムアクションハンドラーを実装します: ```javascript const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another flow or paywall } }, }); ``` </TabItem> </Tabs> </SDKv4> <SDKv3> Adapty ペイウォールビルダーを使用してペイウォールを構築する場合は、ボタンを適切に設定することが重要です: 1. [ペイウォールビルダーにボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクションIDを作成します。 2. 割り当てた各アクションを処理するコードをアプリに記述します。 このガイドでは、カスタムおよび既存のアクションをコードで処理する方法を説明します。 :::warning **購入・復元・ペイウォールの閉鎖・URL開封は自動で処理されます。** それ以外のボタンアクションはすべて、アプリのコードで適切に対応を実装する必要があります。 ::: ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードで、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 :::info React Native SDK では、`close` アクションはデフォルトでペイウォールを閉じる動作をトリガーします。ただし、必要に応じてコードでこの動作をオーバーライドできます。たとえば、あるペイウォールを閉じると別のペイウォールが開くようにすることも可能です。 ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> For React component, handle the close action through individual event handler props: ```javascript function MyPaywall({ paywall }) { const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => { // Handle close button press - navigate away or hide component navigation.goBack(); }, [navigation]); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCloseButtonPress={onCloseButtonPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> モーダル表示の場合は、クローズハンドラーを実装してください: ```javascript const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; // allow paywall closing } }); ``` </TabItem> </Tabs> ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションを持つボタンと同じ方法で処理してください。 ::: ペイウォールからリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには: 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 2. アプリのコードで、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 :::info React Native SDK では、`openUrl` アクションはデフォルトでURLを開く動作をします。ただし、必要に応じてコード内でこの動作をオーバーライドできます。 ::: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> Reactコンポーネントの場合、イベントハンドラーのプロパティを通じてURLを開く処理を行います: ```javascript function MyPaywall({ paywall }) { const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => { Linking.openURL(url); }, []); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onUrlPress={onUrlPress} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> For modal presentation, implement the URL handler: ```javascript const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onUrlPress(url) { Linking.openURL(url); return false; // Keep paywall open }, }); ``` </TabItem> </Tabs> ## アプリにログインする \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Login** アクションを割り当てます。 2. アプリのコードで、ユーザーを識別する `login` アクションのハンドラーを実装します。 <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> React component の場合、イベントハンドラーのプロパティを通じてログインを処理します: ```javascript function MyPaywall({ paywall }) { const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => { if (actionId === 'login') { navigation.navigate('Login'); } }, [navigation]); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> モーダル表示の場合は、ログインハンドラーを実装してください: ```javascript const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'login') { navigation.navigate('Login'); } } }); ``` </TabItem> </Tabs> ## カスタムアクションの処理 \{#handle-custom-actions\} ほかのアクションを処理するボタンを追加するには: 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当てて、IDを付与します。 2. アプリのコードで、作成したアクションIDに対応するハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のペイウォールを表示するボタンを追加できます: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> React componentの場合は、イベントハンドラーのプロップでカスタムアクションを処理します: ```javascript function MyPaywall({ paywall }) { const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => { if (actionId === 'openNewPaywall') { // Display another paywall } }, []); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCustomAction={onCustomAction} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> モーダル表示の場合は、カスタムアクションハンドラーを実装します: ```javascript const unsubscribe = view.setEventHandlers({ onCustomAction(actionId) { if (actionId === 'openNewPaywall') { // Display another paywall } }, }); ``` </TabItem> </Tabs> </SDKv3> --- # File: react-native-handling-events-1 --- --- title: "フローとペイウォールのイベントを処理する - React Native" description: "Adapty の SDK を使って React Native アプリでフローとペイウォールのイベントを処理します。" --- <SDKv4> :::important このガイドでは、購入・復元・プロダクト選択・フローのレンダリングに関するイベント処理について説明します。ボタンの処理(フローを閉じる、リンクを開く、カスタムアクションなど)も設定できます。詳細は[ボタンアクションの処理に関するガイド](react-native-handle-paywall-actions)をご覧ください。 ::: フローおよびフローに含まれるペイウォールビルダーで作成されたペイウォールでは、購入や復元のために追加のコードは必要ありません。ただし、アプリが応答できるいくつかのイベントが生成されます。これらのイベントには、ボタンの押下(閉じるボタン、URL、プロダクトの選択など)や、フロー上で行われた購入関連のアクションに関する通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。 モバイルアプリ内のフロー画面で発生するプロセスを制御または監視するには、イベントハンドラーを実装してください: <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> React コンポーネントでは、`AdaptyFlowView` コンポーネントの個別のイベントハンドラープロップを通じてイベントを処理します。 ```typescript showLineNumbers title="React Native (TSX)" function MyFlow({ flow }) { const onCloseButtonPress = useCallback<FlowEventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<FlowEventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<FlowEventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<FlowEventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<FlowEventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<FlowEventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<FlowEventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<FlowEventHandlers['onRestoreFailed']>((error) => {}, []); const onAppeared = useCallback<FlowEventHandlers['onAppeared']>(() => {}, []); const onError = useCallback<FlowEventHandlers['onError']>((error) => {}, []); const onLoadingProductsFailed = useCallback<FlowEventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<FlowEventHandlers['onUrlPress']>((url, openIn) => { adapty.openWebUrl(url, openIn); return false; }, []); const onCustomAction = useCallback<FlowEventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<FlowEventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyFlowView flow={flow} style={styles.container} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onAppeared={onAppeared} onError={onError} onLoadingProductsFailed={onLoadingProductsFailed} onUrlPress={onUrlPress} onCustomAction={onCustomAction} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> モーダル表示の場合は、イベントハンドラーメソッドを実装してください。 :::important `setEventHandlers` を複数回呼び出すと、以前に設定したハンドラーが上書きされます。デフォルトのハンドラーと、該当イベントに対して以前に設定したハンドラーの両方が置き換えられます。 ::: ```javascript showLineNumbers title="React Native (TSX)" const view = await createFlowView(flow); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; }, onAndroidSystemBack() { return true; }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type !== 'user_cancelled'; }, onPurchaseStarted(product) { /***/}, onPurchaseFailed(error, product) { /***/ }, onRestoreCompleted(profile) { /***/ }, onRestoreFailed(error) { /***/ }, onProductSelected(productId) { /***/}, onError(error) { /***/ }, onLoadingProductsFailed(error) { /***/ }, onUrlPress(url, openIn) { adapty.openWebUrl(url, openIn); return false; // Keep flow open }, onAppeared() { /***/ }, onDisappeared() { /***/ }, onWebPaymentNavigationFinished() { /***/ }, }); ``` </TabItem> </Tabs> <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // onCloseButtonPress { //イベントを記録する } // onAndroidSystemBack { //イベントを記録する } // onUrlPress { "url": "https://example.com/terms" } // onCustomAction { "actionId": "login" } // onProductSelected { "productId": "premium_monthly" } // onPurchaseStarted { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onPurchaseCompleted - Success { "purchaseResult": { "type": "success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onPurchaseCompleted - Cancelled { "purchaseResult": { "type": "user_cancelled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onPurchaseFailed { "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onRestoreCompleted { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } // onRestoreFailed { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } // onError { "error": { "code": "rendering_failed", "message": "Failed to render flow interface", "details": { "underlyingError": "Invalid flow configuration" } } } // onLoadingProductsFailed { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } // onAppeared { //イベントを記録する } // onDisappeared { //イベントを記録する } // onWebPaymentNavigationFinished { //イベントを記録する } ``` </Details> 必要なイベントハンドラーだけ登録すれば、不要なものは省略できます。未使用のイベントリスナーは作成されません。必須のイベントハンドラーはありません。 イベントハンドラーはブール値を返します。`true` が返された場合、表示プロセスが完了したとみなされ、フロー画面が閉じてそのビューのイベントリスナーが削除されます。 一部のイベントハンドラーには、必要に応じて上書きできるデフォルトの動作があります。 - `onCloseButtonPress`: 閉じるボタンが押されたときにフローを閉じます。 - `onUrlPress`: タップされた URL を開き、フローを開いたままにします。 - `onAndroidSystemBack`(モーダル表示のみ): **Back** ボタンが押されたときにフローを開いたままにします。`true` を返すと閉じます。 - `onRestoreCompleted`: リストアが成功した後もフローを開いたままにします。`true` を返すと閉じます。 - `onPurchaseCompleted`: 購入完了後もフローを開いたままにします。`true` を返すと閉じます。 - `onError`: フローのレンダリングに失敗した場合、フローを閉じます。 ### イベントハンドラー \{#event-handlers\} | イベントハンドラー | 説明 | |:-----------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | ユーザーがカスタムアクション(例:[カスタムボタン](paywall-buttons)のクリック)を実行したときに呼び出されます。 | | **onUrlPress** | ユーザーがフロー内のURLをクリックしたときに呼び出されます。 | | **onAndroidSystemBack** | モーダル表示のみ:ユーザーがAndroidシステムの **Back** ボタンをタップしたときに呼び出されます。 | | **onCloseButtonPress** | 閉じるボタンが表示されているときにユーザーがタップすると呼び出されます。このハンドラーでフロー画面を閉じることを推奨します。 | | **onPurchaseCompleted** | 購入が完了したとき(成功・ユーザーによるキャンセル・承認待ちを問わず)に呼び出されます。購入が成功した場合は、更新された `AdaptyProfile` が提供されます。ユーザーによるキャンセルや保留中の支払い(例:保護者の承認が必要な場合)は、`onPurchaseFailed` ではなくこのイベントをトリガーします。 | | **onPurchaseStarted** | ユーザーが「購入」アクションボタンをタップして購入プロセスを開始したときに呼び出されます。 | | **onPurchaseFailed** | エラー(例:支払い制限、無効なプロダクト、ネットワーク障害、トランザクション検証エラー)により購入が失敗したときに呼び出されます。ユーザーによるキャンセルや保留中の支払いには呼び出されず、それらは代わりに `onPurchaseCompleted` をトリガーします。 | | **onRestoreStarted** | ユーザーが購入の復元プロセスを開始したときに呼び出されます。 | | **onRestoreCompleted** | 購入の復元が成功したときに呼び出され、更新された `AdaptyProfile` が提供されます。ユーザーが必要な `accessLevel` を持っている場合は画面を閉じることを推奨します。確認方法については[サブスクリプションステータス](react-native-listen-subscription-changes)のトピックを参照してください。 | | **onRestoreFailed** | 復元プロセスが失敗したときに呼び出され、`AdaptyError` が提供されます。 | | **onProductSelected** | フロービュー内のプロダクトが選択されたときに呼び出されます。購入前にユーザーが何を選択したかを監視できます。 | | **onError** | ビューのレンダリング中にエラーが発生したときに呼び出され、`AdaptyError` が提供されます。このエラーは本来発生しないものですので、もし発生した場合はご連絡ください。 | | **onLoadingProductsFailed** | プロダクトの読み込みが失敗したときに呼び出され、`AdaptyError` が提供されます。ビュー作成時に `prefetchProducts: true` を設定していない場合、AdaptyUI が必要なオブジェクトをサーバーから自動的に取得します。 | | **onAppeared** | フローがユーザーに表示されたときに呼び出されます。iOS では、ユーザーがフロー内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップしてインアプリブラウザでウェブペイウォールが開いたときにも呼び出されます。 | | **onDisappeared** | モーダル表示のみ:ユーザーによってフローが閉じられたときに呼び出されます。iOS では、フローからインアプリブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えたときにも呼び出されます。 | | **onWebPaymentNavigationFinished** | [ウェブペイウォール](web-paywall)を購入のために開こうとした後(成功・失敗を問わず)に呼び出されます。 | | **onAnalytics** | フローからのカスタム分析イベント用に予約されています。フローはまだこれらをコードに送信しないため、実装する必要はありません。 | | **onRequestAppReview** | フローからのアプリレビューリクエスト用に予約されています。フローはまだアプリレビューリクエストをトリガーしないため、実装する必要はありません。 | | **onRequestPermission** | フローからのシステム権限リクエスト(プッシュ通知やカメラアクセスなど)用に予約されています。フローはまだ権限リクエストをトリガーしないため、実装する必要はありません。 | | **onObserverPurchaseInitiated** | オブザーバーモードのみ:ユーザーがフロー内の購入ボタンをタップしたときに呼び出されます。Adapty は購入を実行しません。独自の購入コードで購入を行い、その後トランザクションを Adapty に報告してください。詳しくは下記の[オブザーバーモードでの購入処理](#handle-purchases-in-observer-mode)を参照してください。 | | **onObserverRestoreInitiated** | オブザーバーモードのみ:ユーザーがフロー内の復元ボタンをタップしたときに呼び出されます。Adapty は復元を実行しません。自分で復元を行い、復元されたトランザクションを報告してください。詳しくは下記の[オブザーバーモードでの購入処理](#handle-purchases-in-observer-mode)を参照してください。 | ### オブザーバーモードでの購入処理 \{#handle-purchases-in-observer-mode\} SDKを[オブザーバーモード](implement-observer-mode-react-native)(`observerMode: true`)で有効化し、Adaptyがレンダリングするフローを表示している場合、SDKは代わりに購入処理を行いません。ユーザーが購入ボタンまたは復元ボタンをタップすると、SDKは`onObserverPurchaseInitiated`または`onObserverRestoreInitiated`を呼び出します。独自のコードで購入または復元を実行し、提供されたコールバックでフローのローディングインジケーターを制御した後、Adaptyに[トランザクションを報告](report-transactions-observer-mode-react-native)してください。 ```typescript showLineNumbers const unsubscribe = view.setEventHandlers({ onObserverPurchaseInitiated(product, onStartPurchase, onFinishPurchase) { onStartPurchase(); // show the flow's loading indicator myPurchaseApi(product.vendorProductId) .then((transactionId) => adapty.reportTransaction(transactionId)) .finally(() => onFinishPurchase()); // hide the loading indicator return false; // keep the flow open; dismiss it yourself after success }, onObserverRestoreInitiated(onStartRestore, onFinishRestore) { onStartRestore(); myRestoreApi() .finally(() => onFinishRestore()); return false; }, }); ``` </SDKv4> <SDKv3> :::important このガイドは、購入・復元・プロダクト選択・ペイウォール表示に関するイベント処理について説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の処理も実装する必要があります。詳細は[ボタン操作の処理に関するガイド](react-native-handle-paywall-actions)をご覧ください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定されたペイウォールは、購入や復元のために追加のコードを書く必要はありません。ただし、アプリが応答できるイベントが生成されます。これらのイベントには、ボタン押下(閉じるボタン、URL、プロダクト選択など)や、ペイウォールでの購入関連アクションの通知が含まれます。これらのイベントへの対応方法については、以下をご覧ください。 :::warning このガイドは、Adapty SDK v3.0以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。 ::: ペイウォール画面上で発生するプロセスを制御・監視するには、イベントハンドラーを実装します。 <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> React component では、`AdaptyPaywallView` コンポーネントの各イベントハンドラープロップを通じてイベントを処理します。 ```typescript showLineNumbers title="React Native (TSX)" function MyPaywall({ paywall }) { const onCloseButtonPress = useCallback<EventHandlers['onCloseButtonPress']>(() => {}, []); const onProductSelected = useCallback<EventHandlers['onProductSelected']>((productId) => {}, []); const onPurchaseStarted = useCallback<EventHandlers['onPurchaseStarted']>((product) => {}, []); const onPurchaseCompleted = useCallback<EventHandlers['onPurchaseCompleted']>((purchaseResult, product) => {}, []); const onPurchaseFailed = useCallback<EventHandlers['onPurchaseFailed']>((error, product) => {}, []); const onRestoreStarted = useCallback<EventHandlers['onRestoreStarted']>(() => {}, []); const onRestoreCompleted = useCallback<EventHandlers['onRestoreCompleted']>((profile) => {}, []); const onRestoreFailed = useCallback<EventHandlers['onRestoreFailed']>((error) => {}, []); const onPaywallShown = useCallback<EventHandlers['onPaywallShown']>(() => {}, []); const onRenderingFailed = useCallback<EventHandlers['onRenderingFailed']>((error) => {}, []); const onLoadingProductsFailed = useCallback<EventHandlers['onLoadingProductsFailed']>((error) => {}, []); const onUrlPress = useCallback<EventHandlers['onUrlPress']>((url) => { Linking.openURL(url); }, []); const onCustomAction = useCallback<EventHandlers['onCustomAction']>((actionId) => {}, []); const onWebPaymentNavigationFinished = useCallback<EventHandlers['onWebPaymentNavigationFinished']>(() => {}, []); return ( <AdaptyPaywallView paywall={paywall} style={styles.container} onCloseButtonPress={onCloseButtonPress} onProductSelected={onProductSelected} onPurchaseStarted={onPurchaseStarted} onPurchaseCompleted={onPurchaseCompleted} onPurchaseFailed={onPurchaseFailed} onRestoreStarted={onRestoreStarted} onRestoreCompleted={onRestoreCompleted} onRestoreFailed={onRestoreFailed} onPaywallShown={onPaywallShown} onRenderingFailed={onRenderingFailed} onLoadingProductsFailed={onLoadingProductsFailed} onUrlPress={onUrlPress} onCustomAction={onCustomAction} onWebPaymentNavigationFinished={onWebPaymentNavigationFinished} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> モーダル表示の場合は、イベントハンドラーメソッドを実装してください。 :::important `setEventHandlers` を複数回呼び出すと、提供したハンドラーが上書きされ、該当イベントのデフォルトハンドラーと以前に設定したハンドラーの両方が置き換えられます。 ::: ```javascript showLineNumbers title="React Native (TSX)" const view = await createPaywallView(paywall); const unsubscribe = view.setEventHandlers({ onCloseButtonPress() { return true; }, onAndroidSystemBack() { return true; }, onPurchaseCompleted(purchaseResult, product) { return purchaseResult.type !== 'user_cancelled'; }, onPurchaseStarted(product) { /***/}, onPurchaseFailed(error) { /***/ }, onRestoreCompleted(profile) { /***/ }, onRestoreFailed(error) { /***/ }, onProductSelected(productId) { /***/}, onRenderingFailed(error) { /***/ }, onLoadingProductsFailed(error) { /***/ }, onUrlPress(url) { Linking.openURL(url); return false; // Keep paywall open }, onPaywallShown() { /***/ }, onPaywallClosed() { /***/ }, onWebPaymentNavigationFinished() { /***/ }, }); ``` </TabItem> </Tabs> <Details> <summary>イベントの例(クリックして展開)</summary> ```javascript // onCloseButtonPress { //イベントを記録する } // onAndroidSystemBack { //イベントを記録する } // onUrlPress { "url": "https://example.com/terms" } // onCustomAction { "actionId": "login" } // onProductSelected { "productId": "premium_monthly" } // onPurchaseStarted { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onPurchaseCompleted - Success { "purchaseResult": { "type": "success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onPurchaseCompleted - Cancelled { "purchaseResult": { "type": "user_cancelled" }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onPurchaseFailed { "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } }, "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "price": { "amount": 9.99, "currencyCode": "USD", "currencySymbol": "$", "localizedString": "$9.99" } } } // onRestoreCompleted { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } // onRestoreFailed { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } // onRenderingFailed { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } // onLoadingProductsFailed { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } // onPaywallShown { //イベントを記録する } // onPaywallClosed { //イベントを記録する } // onWebPaymentNavigationFinished { //イベントを記録する } ``` </Details> 必要なイベントハンドラのみを登録し、不要なものは省略できます。未使用のイベントリスナーは作成されません。必須のイベントハンドラはありません。 イベントハンドラはブール値を返します。`true` が返された場合、表示プロセスが完了したとみなされ、ペイウォール画面が閉じられ、このビューのイベントリスナーが削除されます。 一部のイベントハンドラーにはデフォルトの動作があり、必要に応じて上書きできます: - `onCloseButtonPress`: 閉じるボタンが押されたときにペイウォールを閉じます。 - `onUrlPress`: タップされたURLを開き、ペイウォールは表示したままにします。 - `onAndroidSystemBack`(モーダル表示のみ): **Back** ボタンが押されたときにペイウォールを閉じます。 - `onRestoreCompleted`: リストアが成功した後にペイウォールを閉じます。 - `onPurchaseCompleted`: ユーザーがキャンセルしない限り、ペイウォールを閉じます。 - `onRenderingFailed`: レンダリングに失敗した場合にペイウォールを閉じます。 ### イベントハンドラー \{#event-handlers\} | イベントハンドラー | 説明 | |:-----------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **onCustomAction** | ユーザーがカスタムアクションを実行したとき(例:[カスタムボタン](paywall-buttons)をクリックしたとき)に呼び出されます。 | | **onUrlPress** | ユーザーがペイウォール内のURLをクリックしたときに呼び出されます。 | | **onAndroidSystemBack** | モーダル表示のみ:ユーザーがAndroidのシステム **Back** ボタンをタップしたときに呼び出されます。 | | **onCloseButtonPress** | 閉じるボタンが表示されており、ユーザーがそれをタップしたときに呼び出されます。このハンドラー内でペイウォール画面を閉じることを推奨します。 | | **onPurchaseCompleted** | 購入が完了したとき(成功・ユーザーによるキャンセル・承認待ちのいずれの場合も)に呼び出されます。購入が成功した場合は更新された `AdaptyProfile` が提供されます。ユーザーによるキャンセルや保護者の承認待ちなどの保留中の支払いはこのイベントをトリガーし、`onPurchaseFailed` はトリガーされません。 | | **onPurchaseStarted** | ユーザーが「購入」アクションボタンをタップして購入プロセスを開始したときに呼び出されます。 | | **onPurchaseFailed** | エラー(支払い制限、無効なプロダクト、ネットワーク障害、トランザクション検証の失敗など)により購入が失敗したときに呼び出されます。ユーザーによるキャンセルや保留中の支払いでは呼び出されず、その場合は `onPurchaseCompleted` がトリガーされます。 | | **onRestoreStarted** | ユーザーが購入の復元プロセスを開始したときに呼び出されます。 | | **onRestoreCompleted** | 購入の復元が成功し、更新された `AdaptyProfile` が提供されたときに呼び出されます。ユーザーが必要な `accessLevel` を持っている場合はこの画面を閉じることを推奨します。確認方法については[サブスクリプションのステータス](react-native-listen-subscription-changes)をご参照ください。 | | **onRestoreFailed** | 復元プロセスが失敗し、`AdaptyError` が提供されたときに呼び出されます。 | | **onProductSelected** | ペイウォールビュー内のプロダクトが選択されたときに呼び出されます。購入前にユーザーが何を選択しているかを確認できます。 | | **onRenderingFailed** | ビューのレンダリング中にエラーが発生し、`AdaptyError` が提供されたときに呼び出されます。このようなエラーは本来発生しないため、もし発生した場合はお知らせください。 | | **onLoadingProductsFailed** | プロダクトの読み込みに失敗し、`AdaptyError` が提供されたときに呼び出されます。ビューの作成時に `prefetchProducts: true` を設定していない場合、AdaptyUI が必要なオブジェクトをサーバーから自動的に取得します。 | | **onPaywallShown** | ペイウォールがユーザーに表示されたときに呼び出されます。iOS では、ユーザーがペイウォール内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップしてアプリ内ブラウザでウェブペイウォールが開いたときにも呼び出されます。 | | **onPaywallClosed** | モーダル表示のみ:ユーザーによってペイウォールが閉じられたときに呼び出されます。iOS では、ペイウォールからアプリ内ブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えたときにも呼び出されます。 | | **onWebPaymentNavigationFinished** | 購入のために[ウェブペイウォール](web-paywall)を開こうとした後、成功・失敗に関わらず呼び出されます。 | </SDKv3> --- # File: react-native-use-fallback-paywalls-expo --- --- title: "ExpoプロジェクトでフォールバックペイウォールをExpoプロジェクトで使用する" description: "react-native-adapty configプラグインを使用して、Expo React NativeプロジェクトでフォールバックペイウォールExpoプロジェクトを設定します。" --- :::important このガイドは **Expo プロジェクト**に適用されます。 **純粋な React Native(Expo を使用しない場合)**を使用している場合は、[純粋な React Native のフォールバックペイウォールガイド](react-native-use-fallback-paywalls-pure)をご覧ください。 ::: スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: Adapty SDK はフォールバックファイルを**ネイティブ**バンドルから読み込みます。iOS の場合は `.app` パッケージ内のリソース、Android の場合は `android/app/src/main/assets/` 配下のエントリです。Expo プロジェクトでは、`npx expo prebuild --clean` を実行するたびにこれらのディレクトリが再生成されるため、ファイルを手動で配置することはできません。`react-native-adapty` の設定プラグインが、ファイルをネイティブバンドルに自動的に組み込んでくれます。 :::tip [`FocusJournalExpo` サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo)で、完全な動作環境のセットアップを確認できます。 ::: ## 設定 \{#configuration\} 1. フォールバック JSON ファイルをプロジェクト内の任意の場所に配置します。通常は他のアセットと同じ場所に置きます: ``` <your-project>/ └── assets/ ├── ios_fallback.json └── android_fallback.json ``` 2. `app.json`(または `app.config.js`)の `react-native-adapty` エントリに `fallbackFile` オプションを追加します。各プラットフォームキーは任意です。必要なプラットフォームのみ設定してください: ```json title="app.json" { "expo": { "plugins": [ [ "react-native-adapty", { "fallbackFile": { "ios": "./assets/ios_fallback.json", "android": "./assets/android_fallback.json" } } ] ] } } ``` :::note Adapty はプラットフォームごとに異なるフォールバック JSON をエクスポートします — iOS では Apple のプロダクト ID、Android では Google Play のプロダクト ID が使用されます。各プラットフォームに対応するファイルを指定してください。 ::: 3. ネイティブプロジェクトを再生成します: ```sh title="Shell" npx expo prebuild ``` プラグインは iOS ファイルを Xcode プロジェクトのバンドルリソースに追加し、Android ファイルを `android/app/src/main/assets/` にコピーします。prebuild の出力には次のような行が含まれます: ``` [react-native-adapty] Registered ios_fallback.json as iOS bundle resource [react-native-adapty] Copied android_fallback.json to android assets/ ``` 4. 実行時に SDK へファイルを登録します: ```typescript showLineNumbers title="App.tsx" await adapty.activate('PUBLIC_SDK_KEY'); await adapty.setFallback({ ios: { fileName: 'ios_fallback.json' }, android: { relativeAssetPath: 'android_fallback.json' }, }); ``` `setFallback` に渡すファイル名は、`fallbackFile` で設定したファイルのベース名と一致している必要があります。 :::important `setFallback` は、SDK が対象のフロー、ペイウォール、またはオンボーディングを取得する前に実行する必要があります。 ::: ## 確認 \{#verification\} `npx expo prebuild` 実行後、両方のプラットフォームを確認してください: - **Android**: `android/app/src/main/assets/` の内容を一覧表示します。`fallbackFile.android` で設定したファイルが存在し、iOS 専用のファイル名が含まれていないことを確認してください。 - **iOS**: `ios/<ProjectName>.xcodeproj/project.pbxproj` で iOS のファイル名を検索します。`PBXFileReference`、`Resources` グループ、`PBXResourcesBuildPhase` に表示されているはずです。Android 専用のファイル名が `project.pbxproj` に含まれていないことを確認してください。 --- # File: react-native-use-fallback-paywalls-pure --- --- title: "純粋なReact Nativeプロジェクトでフォールバックペイウォールを使用する" description: "純粋なReact Native(非Expo)プロジェクトでフォールバックペイウォールを設定する方法。" --- :::important このガイドは**純粋な React Native(非 Expo)プロジェクト**に適用されます。 **Expo** を使用している場合は、代わりに [Expo フォールバックガイド](react-native-use-fallback-paywalls-expo) をご覧ください。 ::: スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} ### Android 1. フォールバック設定ファイルをアプリケーションに追加します。以下のディレクトリから1つ選択してください: * **android/app/src/main/assets/** * **android/app/src/main/res/raw/** 注意:`res/raw` フォルダには特別なファイル命名規則があります(アルファベットで始まること、大文字不可、アンダースコア以外の特殊文字不可、スペース不可)。 2. `FileLocation` 定数の `android` プロパティを更新します: * ファイルが `assets` ディレクトリにある場合は、そのディレクトリからの相対パスを渡します。 * ファイルが `res/raw` ディレクトリにある場合は、拡張子なしのファイル名を渡します。 ### iOS \{#ios\} 1. フォールバック JSON ファイルをプロジェクトバンドルに追加します:XCode で **File** メニューを開き、**Add Files to "YourProjectName"** オプションを選択します。 2. 設定ファイルの名前を `FileLocation` 定数の `ios` プロパティに渡します。 ## 例 \{#example\} <Tabs groupId="current-os" queryString> <TabItem value="current" label="Current (v3.8+)" default> ```typescript showLineNumbers //after v3.8 const fileLocation = { ios: { fileName: 'ios_fallback.json' }, android: { //if the file is located in 'android/app/src/main/assets/' relativeAssetPath: 'android_fallback.json' } } await adapty.setFallback(fileLocation); ``` </TabItem> <TabItem value="old" label="Legacy (before v3.8)"> ```typescript showLineNumbers //Legacy (before v3.8) const paywallsLocation = { ios: { fileName: 'ios_fallback.json' }, android: { //if the file is located in 'android/app/src/main/assets/' relativeAssetPath: 'android_fallback.json' } } await adapty.setFallbackPaywalls(paywallsLocation); ``` </TabItem> </Tabs> | パラメーター | 説明 | | :------------------- | :------------------------------------------------------- | | **fileLocation** | フォールバック設定ファイルの場所を表すオブジェクト。 | --- # File: react-native-localizations-and-locale-codes --- --- title: "React Native SDKでローカライズとロケールコードを使用する" description: "Adapty SDKを使用してReact Nativeアプリのペイウォールをローカライズするためのガイドです。" --- <SDKv4> ## これが重要な理由 \{#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. Adapty はロケールコードが完全に一致するローカライズを検索します 3. 一致するものが見つからない場合、Adapty は最初のハイフンより前の部分文字列(`pt-br` の場合は `pt`)を取得し、一致するローカライズを検索します 4. それでも一致するものが見つからない場合、Adapty はデフォルトの `en` ローカライズを返します このようにして、`'pt_BR'`、`pt-BR`、`pt-br` はすべて同じローカライズに解決されます。 ## ローカライズの実装 \{#implementing-localizations\} SDK v4 では、フローを取得する際にロケールコードを渡す必要はありません。 - **フロービルダーとペイウォールビルダーのペイウォール**: Adapty はデバイスの設定とビルダーで設定したローカライズをもとに、自動的にローカライズを解決します。`createFlowView` でフローをレンダリングするだけで、ロケールコードは不要です。 - **カスタム(リモートコンフィグ)ペイウォール**: `getFlow` は設定済みのすべてのローカライズを `flow.remoteConfigs` に返します。各エントリには `lang` コードと `data` オブジェクトが含まれます。独自のフォールバック処理を加えつつ、ユーザーに合ったエントリを選択してください。 ```typescript showLineNumbers const flow = await adapty.getFlow('placement_id'); const config = flow.remoteConfigs?.find((c) => c.lang === 'en') ?? flow.remoteConfigs?.[0]; // read your values from config?.data ``` 上記のロケールコードマッチングルールは、各リモートコンフィグに保存された `lang` コードを Adapty がどのように正規化するかを説明しています。 </SDKv4> <SDKv3> ## これが重要な理由 \{#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 を呼び出す際に、そのキーの値を取り出して使います。例を示します: ```javascript showLineNumbers // 1. Modify your localization files (e.g., using react-i18next) /* en.json */ { "adapty_paywalls_locale": "en" } /* es.json */ { "adapty_paywalls_locale": "es" } /* pt-BR.json */ { "adapty_paywalls_locale": "pt-br" } // 2. Extract and use the locale code const MyComponent = () => { const { t } = useTranslation(); const fetchPaywall = async () => { const locale = t('adapty_paywalls_locale'); // pass locale code to adapty.getPaywall or adapty.getPaywallForDefaultAudience method const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; }; ``` そうすることで、アプリのすべてのユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。 ## ローカライゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} すべてのローカライゼーションにロケールコードを明示的に定義しなくても、同様の(ただし完全に同一ではない)結果を得ることができます。その方法は、たとえば [`react-native-localize`](https://github.com/zoontek/react-native-localize) を使って、デバイスからロケールコードを取得するというものです。 ```javascript showLineNumbers const fetchPaywall = async () => { // getLocales() はユーザーの優先ロケールをBCP-47形式(例: 'en-US', 'pt-BR')で返します const locale = RNLocalize.getLocales()[0].languageTag; // ロケールコードを adapty.getPaywall または adapty.getPaywallForDefaultAudience メソッドに渡します const paywall = await adapty.getPaywallForDefaultAudience('placement_id', locale); }; ``` このアプローチはいくつかの理由からお勧めしません。 1. iOSでは、優先言語と現在の地域ロケールは必ずしも一致しません。ローカライゼーションが正しく選択されるようにするには、推奨されているローカライズされた文字列ファイルを使用するアプローチで動作するAppleの解決ロジックに任せるか、自分でその仕組みを再現する必要があります。 2. デバイスのロケールが、Adaptyで設定したどのローカライゼーションとも一致しない場合があります。その場合、SDKは最初のサブタグでマッチングを試み、それでも見つからない場合は最終的に`en`にフォールバックします — これは、そのユーザーに対してデフォルトにしたい言語ではない可能性があります。 万が一このアプローチを採用する場合は、関連するすべてのユースケースに対応していることを確認してください。 </SDKv3> --- # File: react-native-web-paywall --- --- title: "ウェブペイウォールの実装" description: "Adapty SDK を使用して React Native アプリにウェブペイウォールを実装する方法を説明します。" --- :::important 始める前に、[ダッシュボードでウェブペイウォールを設定](web-paywall)し、Adapty SDK バージョン 3.6.1 以降をインストールしていることを確認してください。 ::: ## ウェブペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールを使用する場合は、SDK メソッドを使ってウェブペイウォールを処理する必要があります。`.openWebPaywall` メソッドは以下を行います: 1. 特定のユーザーに表示されたペイウォールと、そのユーザーがリダイレクトされるウェブページを Adapty が紐付けるための、一意の URL を生成します。 2. ユーザーがアプリに戻ってきたことを検知し、短い間隔で `.getProfile` をリクエストして、プロファイルのアクセス権が更新されたかどうかを確認します。 これにより、支払いが成功してアクセス権が更新された場合、サブスクリプションはほぼ即座にアプリ内で有効化されます。 ```typescript showLineNumbers title="React Native (TSX)" try { await adapty.openWebPaywall(product); } catch (error) { console.warn('Failed to open web paywall:', error); } ``` :::note `openWebPaywall` メソッドには 2 つのバージョンがあります: 1. `openWebPaywall(product)` — ペイウォールに基づいて URL を生成し、プロダクトデータも URL に追加します。 2. `openWebPaywall(paywall)` — ペイウォールに基づいて URL を生成しますが、プロダクトデータは URL に追加しません。Adapty ペイウォール内のプロダクトとウェブペイウォール内のプロダクトが異なる場合に使用してください。 ::: #### エラーのハンドリング \{#handle-errors\} | エラー | 説明 | 推奨される対処法 | |-----------------------------------------|--------------------------------------------------------|---------------------------------------------------------------------------| | AdaptyError.paywallWithoutPurchaseUrl | ペイウォールにウェブ購入 URL が設定されていない | Adapty ダッシュボードでペイウォールが正しく設定されているか確認してください | | AdaptyError.productWithoutPurchaseUrl | プロダクトにウェブ購入 URL が設定されていない | Adapty ダッシュボードでプロダクトの設定を確認してください | | AdaptyError.failedOpeningWebPaywallUrl | ブラウザで URL を開くことができなかった | デバイスの設定を確認するか、別の購入方法を提供してください | | AdaptyError.failedDecodingWebPaywallUrl | URL のパラメータのエンコードに失敗した | URL パラメータが有効で正しい形式であることを確認してください | ## アプリ内ブラウザでウェブペイウォールを開く \{#open-web-paywalls-in-an-in-app-browser\} :::important アプリ内ブラウザでのウェブペイウォールの表示は、Adapty SDK v3.15 以降でサポートされています。 ::: デフォルトでは、ウェブペイウォールは外部ブラウザで開きます。 シームレスなユーザー体験を提供するために、アプリ内ブラウザでウェブペイウォールを開くことができます。これにより、ウェブ購入ページがアプリ内に表示され、ユーザーはアプリを切り替えることなく取引を完了できます。 これを有効にするには、`openWebPaywall` の第 2 引数に `WebPresentation.BrowserInApp` を渡してください: ```typescript showLineNumbers title="React Native (TSX)" try { await adapty.openWebPaywall( product, WebPresentation.BrowserInApp, // default – WebPresentation.BrowserOutApp ); } catch (error) { console.warn('Failed to open web paywall:', error); } ``` --- # File: react-native-troubleshoot-paywall-builder --- --- title: "React Native SDKでのペイウォールビルダーのトラブルシューティング" description: "React Native SDKでのペイウォールビルダーのトラブルシューティング" --- このガイドでは、React Native SDKでAdapty ペイウォールビルダーを使用して設計したペイウォールに関する一般的な問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: フローまたはペイウォールのビュー設定の取得に失敗する。 **原因**: ペイウォールビルダーでデバイス表示が有効になっていない。 **解決策**: ペイウォールビルダーの **Show on device** トグルを有効にしてください。 <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ペイウォールのビュー数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールのビュー数が予想の2倍になっている。 **原因**: コード内で `logShowFlow`(React Native SDK v4以降)/ `logShowPaywall` を呼び出している可能性があります。ペイウォールビルダーまたはフロービルダーを使用している場合、この呼び出しによってビュー数が重複します。これらのツールで作成したフローやペイウォールでは、アナリティクスが自動的に追跡されるため、このメソッドを使用する必要はありません。 **解決策**: ペイウォールビルダーまたはフロービルダーを使用している場合は、コード内で `logShowFlow`(React Native SDK v4以降)/ `logShowPaywall` を呼び出していないことを確認してください。 ## その他の問題 \{#other-issues\} **問題**: 上記で説明されていないペイウォールビルダー関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](react-native-sdk-migration-guides)を参照してSDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: react-native-quickstart-manual --- --- title: "React Native SDKのカスタムペイウォールで購入を有効にする" description: "Adapty SDKをReact Nativeのカスタムペイウォールに統合して、アプリ内課金を有効にする方法を解説します。" --- このガイドでは、Adaptyをカスタムペイウォールに統合する方法を説明します。ペイウォールの実装を完全にコントロールしながら、Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を行います。 :::important **このガイドは、カスタムペイウォールを実装する開発者向けです。** 購入機能を最も簡単に導入したい場合は、[Adapty フローBuilder](react-native-quickstart-paywalls) をご利用ください。フローBuilderを使えば、ノーコードのビジュアルエディターでフローを作成でき、購入ロジックはすべてAdaptyが自動的に処理します。また、アプリを再公開することなく、さまざまなデザインをテストできます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトの設定 \{#set-up-products\} アプリ内課金を有効にするには、3つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定。Adapty では、プロダクトを取得する唯一の方法がペイウォールです。この設計により、アプリのコードを変更することなく、プロダクト・価格・オファーを修正できます。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでプレースメントにペイウォールを設定し、コード内ではプレースメント ID を指定してリクエストします。これにより、A/B テストの実施や、ユーザーごとに異なるペイウォールの表示が簡単に行えます。 これらのコンセプトは、カスタムペイウォールを使う場合でも必ず把握しておいてください。要するに、アプリで販売するプロダクトを管理するための仕組みです。 カスタムペイウォールを実装するには、**ペイウォール**を作成し、**プレースメント**に追加する必要があります。この設定により、プロダクトを取得できるようになります。ダッシュボードで何をすべきかを確認するには、[こちら](quickstart)のクイックスタートガイドを参照してください。 ### ユーザーの管理 \{#manage-users\} バックエンド認証の有無にかかわらず使用できます。 ただし、Adapty SDKは匿名ユーザーと識別済みユーザーを異なる方法で処理します。詳細を把握し、ユーザーを適切に扱うために、[識別クイックスタートガイド](react-native-quickstart-identify)をお読みください。 ## ステップ 1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、次の手順に従います。 1. [プレースメント](placements) ID を `getFlow` メソッドに渡して `flow` オブジェクトを取得します。 2. `getPaywallProducts` メソッドを使用して、このフローのプロダクト配列を取得します。 ```typescript showLineNumbers async function loadPaywall() { try { const flow: AdaptyFlow = await adapty.getFlow('YOUR_PLACEMENT_ID'); const products: AdaptyPaywallProduct[] = await adapty.getPaywallProducts(flow); // Use products to build your custom paywall UI } catch (error) { // Handle the error } } ``` ## ステップ2:購入を受け付ける \{#step-2-accept-purchases\} ユーザーがカスタムペイウォール上でプロダクトをタップしたら、選択されたプロダクトを引数として `makePurchase` メソッドを呼び出します。これにより購入フローが処理され、更新されたプロファイルが返されます。 ```typescript showLineNumbers async function purchaseProduct(product: AdaptyPaywallProduct) { try { const purchaseResult: AdaptyPurchaseResult = await adapty.makePurchase(product); switch (purchaseResult.type) { case 'success': // Purchase successful, profile updated break; case 'user_cancelled': // User canceled the purchase break; case 'pending': // Purchase is pending (e.g., user will pay offline with cash) break; } } catch (error) { // Handle the error } } ``` ## ステップ 3. 購入を復元する \{#step-3-restore-purchases\} アプリストアでは、サブスクリプションを提供するすべてのアプリに対して、ユーザーが購入を復元できる手段を提供することを義務付けています。 ユーザーが復元ボタンをタップしたときに `restorePurchases` メソッドを呼び出してください。これにより、ユーザーの購入履歴が Adapty と同期され、更新されたプロファイルが返されます。 ```typescript showLineNumbers async function restorePurchases() { try { const profile: AdaptyProfile = await adapty.restorePurchases(); // Restore successful, profile updated } catch (error) { // Handle the error } } ``` ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備が整いました。[App Store サンドボックス](test-purchases-in-sandbox)または[Google Play Store](testing-on-android)でテスト購入を行い、ペイウォールからテスト購入が完了できることを確認してください。本番環境に対応した実装でどのように動作するかを確認するには、サンプルアプリの[CustomPurchaseScreen.tsx](https://github.com/adaptyteam/AdaptySDK-React-Native/blob/master/examples/ExpoGoWebMock/src/CustomPurchaseScreen.tsx)を参照してください。エラー処理、ローディング状態、UI状態管理を含む購入処理の実装例が確認できます。 次に、[購入が完了しているかどうかを確認](react-native-check-subscription-status)して、ペイウォールを表示するか有料機能へのアクセスを許可するかを判断します。 --- # File: fetch-paywalls-and-products-react-native --- --- title: "React Native SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "Adapty React Native SDKでペイウォールとプロダクトを取得し、ユーザーのマネタイズを強化しましょう。" --- <SDKv4> リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。**Flow Builder** や **Paywall Builder** でカスタマイズされたフローやペイウォールの取得方法については、[Flow Builder のフローと Paywall Builder のペイウォールおよびその設定を取得する](react-native-get-pb-paywalls) を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでフローとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)する。 2. Adapty ダッシュボードで[フローまたはペイウォールを作成し、プロダクトを組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、フローまたはペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに[Adapty SDK をインストール](sdk-installation-reactnative)する。 </details> ## フローの情報を取得する \{#fetch-flow-information\} Adapty では、[プロダクト](product)は App Store と Google Play の両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームのプロダクトはフローやペイウォールに組み込まれており、モバイルアプリの特定のプレースメント内で表示できます。 プロダクトを表示するには、`getFlow` メソッドを使って[プレースメント](placements)のいずれかから `AdaptyFlow` を取得する必要があります。 :::important **プロダクト ID をハードコードしないでください。** ハードコードしてよい ID はプレースメント ID のみです。フローはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。たとえば、今日のフローがプロダクトを 2 つ返し、明日 3 つ返しても、コードを変更せずにすべて表示できるようにしてください。 ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlow(id); // the requested flow } catch (error) { // handle the error } ``` | パラメーター | 必須/任意 | 説明 | |-------------------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるよう、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合はそれを返すことを検討してください。この場合、最新データが反映されないことがありますが、接続状態に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを省くために使っても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はフローとペイウォールを2層で保存します。上記の定期更新キャッシュと[フォールバックペイウォール](react-native-use-fallback-paywalls)です。また、フローとペイウォールの取得を高速化するために CDN を使用し、CDN に接続できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムにより、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのフローを取得できます。</p> | | **loadTimeoutMs** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p></p><p>内部的に複数のリクエストで構成される場合があるため、まれに `loadTimeout` で指定した時間より若干遅くタイムアウトすることがあります。</p> | :::note v4 では、`getFlow` は `locale` パラメータを受け取らなくなりました。カスタムペイウォールの場合、利用可能なすべてのロケールはフローのリモートコンフィグ(`flow.remoteConfigs`)で返されます。ユーザーのデバイスまたはアプリ設定に合ったものを選択してください。 ::: プロダクトIDをハードコードしないでください!フローはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特別オファー(無料トライアルなど)は随時変更される可能性があります。これらのシナリオに対応できるようコードを設計してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはその2つを表示します。しかし後で3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できる必要があります。ハードコードが必要なのはプレースメントIDだけです。 レスポンスのパラメーター: | パラメーター | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Flow | プレースメント、識別子(`id`、`variationId`)、名前、ペイウォールのバリアント(`paywalls`)、設定済みロケールごとのエントリーを含む `remoteConfigs` 配列を持つ `AdaptyFlow` オブジェクト。フローのプロダクトを取得するには、`getPaywallProducts(flow)` を呼び出してください。 | ## プロダクトの取得 \{#fetch-products\} フローを取得したら、そのフローに対応するプロダクトの配列を取得できます。 ```typescript showLineNumbers try { // ...flow const products = await adapty.getPaywallProducts(flow); // the requested products list } catch (error) { // handle the error } ``` レスポンスパラメーター: | パラメーター | 説明 | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他いくつかのプロパティが含まれます。 | 独自のペイウォールデザインを実装する際には、[`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。以下によく使われるプロパティを示しますが、利用可能なすべてのプロパティの詳細はリンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づいて行われます。 | | **Price** | ローカライズされた価格を表示するには、`product.price?.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づいています。`product.price?.amount` を使用して価格を数値として取得することもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには、`product.price?.currencySymbol` を使用します。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.subscription?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づいています。プログラムでサブスクリプション期間を取得するには、`product.subscription?.subscriptionPeriod` を使用します。そこから `unit` プロパティにアクセスして期間の長さ(`'day'`、`'week'`、`'month'`、`'year'`、または `'unknown'`)を取得できます。`numberOfUnits` の値で期間の単位数を取得できます。たとえば、四半期ごとのサブスクリプションの場合、`unit` プロパティには `'month'`、`numberOfUnits` プロパティには `3` が表示されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかどうかを示すバッジやその他のインジケーターを表示するには、`product.subscription?.offer?.phases` プロパティを確認します。このリストには、無料トライアルフェーズと初回価格フェーズの最大2つの割引フェーズを含めることができます。各フェーズオブジェクトには次の便利なプロパティがあります:<br/>• `paymentMode`:`'free_trial'`、`'pay_as_you_go'`、`'pay_up_front'`、`'unknown'` の値を持つ文字列。無料トライアルは `'free_trial'` タイプになります。<br/>• `price`:割引価格(数値)。無料トライアルの場合は `0` を確認します。<br/>• `localizedNumberOfPeriods`:オファーの期間をデバイスのロケールでローカライズした文字列。たとえば、3日間のトライアルオファーの場合、このフィールドには `'3 days'` と表示されます。<br/>• `subscriptionPeriod`:オファー期間の個別の詳細はこのプロパティで取得することもできます。前のセクションで説明したのと同様の方法でオファーにも使用できます。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた割引のサブスクリプション期間。 | ## デフォルトオーディエンスフローでフローの取得を高速化する \{#speed-up-flow-fetching-with-default-audience-flow\} 通常、フローはほぼ瞬時に取得されるため、この処理を高速化することを気にする必要はありません。ただし、オーディエンスやプレースメントが多数あり、ユーザーのインターネット接続が遅い場合は、フローの取得に予想以上の時間がかかることがあります。このような状況では、何も表示しないよりも、デフォルトのフローを表示してスムーズなユーザー体験を提供したい場合があるでしょう。 これに対処するために、`getFlowForDefaultAudience` メソッドを使用できます。このメソッドは、指定したプレースメントの **All Users** オーディエンスのフローを取得します。ただし、推奨される方法は、上記の[フロー情報の取得](fetch-paywalls-and-products-react-native#fetch-flow-information)セクションで説明されている `getFlow` メソッドを使用してフローを取得することである点を理解しておくことが重要です。 :::warning `getFlow` を推奨する理由 `getFlowForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 異なるアプリバージョン(現在のバージョンと将来のバージョン)で異なるフローを表示する必要がある場合、課題が生じる可能性があります。現在の(レガシー)バージョンに対応したフローを設計するか、現在の(レガシー)バージョンのユーザーがフローが正常に表示されない問題に直面することを受け入れるかのどちらかを選ぶことになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同一のフローを見ることになり、国、マーケティングのアトリビューション、独自のカスタム属性に基づくパーソナライズされたターゲティングができなくなります。 これらのデメリットを受け入れてでも高速なフロー取得のメリットを活かしたい場合は、以下のように `getFlowForDefaultAudience` メソッドを使用してください。そうでない場合は、[上記](fetch-paywalls-and-products-react-native#fetch-flow-information)で説明した `getFlow` を引き続き使用してください。 ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const flow = await adapty.getFlowForDefaultAudience(id); // the requested flow } catch (error) { // handle the error } ``` | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを受け取れることが保証されるためです。</p><p></p><p>ただし、ユーザーがネットワーク接続の不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` を使用して、キャッシュが存在すればそちらを返すことを検討してください。この場合、最新データが届かないことがありますが、接続状況にかかわらず読み込み時間が短縮されます。キャッシュはセッション中に定期的に更新されるため、不要なネットワークリクエストを避ける目的で使用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持されます。クリアされるのは、アプリのアンインストール時または手動でのクリーンアップ時のみです。</p> | </SDKv4> <SDKv3> リモートコンフィグとカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグとカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズしたペイウォールの取得方法については、[ペイウォールビルダーのペイウォールとその設定を取得する](react-native-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. [ペイウォールを作成し、プロダクトをペイウォールに追加する](create-paywall)(Adapty ダッシュボード) 3. [プレースメントを作成し、ペイウォールをプレースメントに追加する](create-placement)(Adapty ダッシュボード) 4. [Adapty SDK をインストールする](sdk-installation-reactnative)(モバイルアプリ) </details> ## ペイウォール情報を取得する \{#fetch-paywall-information\} Adapty では、[プロダクト](product)は App Store と Google Play の両方からのプロダクトを組み合わせたものです。これらのクロスプラットフォームのプロダクトはペイウォールに統合されており、モバイルアプリの特定のプレースメント内に表示することができます。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)のいずれかから[ペイウォール](paywalls)を取得する必要があります。 :::important **プロダクト ID をハードコードしないでください。** ハードコードすべき ID はプレースメント ID だけです。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。今日ペイウォールが 2 つのプロダクトを返し、明日 3 つを返すようになっても、コードを変更せずにすべてを表示できるようにしてください。 ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywall(id, locale); // the requested paywall } catch (error) { // handle the error } ``` | パラメーター | 有無 | 説明 | |-------------------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-remote-config-locale)の識別子。マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよび推奨する使用方法については、[ローカライゼーションとロケールコード](react-native-localizations-and-locale-codes)をご覧ください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境を利用していると想定される場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合にキャッシュデータを返すことを検討してください。この場合、最新データが取得できないことがありますが、接続状況に関わらず高速な読み込みが実現できます。キャッシュは定期的に更新されるため、セッション中のネットワークリクエストを避ける用途では安全に使用できます。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はペイウォールを2つの層で保存します。上記の定期更新キャッシュと[フォールバックペイウォール](react-native-use-fallback-paywalls)です。また、ペイウォールの高速取得のために CDN を使用し、CDN に到達できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも、常に最新バージョンのペイウォールを確実に取得できるよう設計されています。</p> | | **loadTimeoutMs** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p></p><p>内部では複数のリクエストで構成される処理のため、まれに `loadTimeout` で指定した時間よりもわずかに遅れてタイムアウトが発生する場合があります。</p> | プロダクトIDをハードコードしないでください!ペイウォールはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特典(無料トライアルなど)は随時変更される場合があります。こうしたシナリオに対応できるコードを記述してください。 たとえば、最初に2つのプロダクトを取得した場合、アプリはそれら2つを表示する必要があります。後で3つのプロダクトを取得した場合は、コードを変更することなく3つすべてを表示できなければなりません。ハードコードする必要があるのはプレースメントIDのみです。 レスポンスのパラメーター: | パラメータ | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォールの識別子、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) オブジェクト。 | ## プロダクトの取得 \{#fetch-products\} ペイウォールを取得したら、それに対応するプロダクトの配列を取得できます。 ```typescript showLineNumbers try { // ...paywall const products = await adapty.getPaywallProducts(paywall); // the requested products list } catch (error) { // handle the error } ``` レスポンスパラメーター: | パラメータ | 説明 | | :-------- |:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Products | [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) オブジェクトのリスト。プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他のプロパティが含まれます。 | 独自のペイウォールデザインを実装する場合、[`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) オブジェクトから以下のプロパティにアクセスする必要があります。よく使われるプロパティを以下に示しますが、利用可能なすべてのプロパティの詳細については、リンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには、`product.localizedTitle` を使用します。ローカライズはデバイスのロケールではなく、ユーザーが選択したストアの国に基づきます。 | | **Price** | ローカライズされた価格を表示するには、`product.price?.localizedString` を使用します。このローカライズはデバイスのロケール情報に基づきます。`product.price?.amount` を使用すると、価格を数値として取得することもできます。値はローカル通貨で提供されます。対応する通貨記号を取得するには、`product.price?.currencySymbol` を使用します。 | | **Subscription Period** | 期間(週、月、年など)を表示するには、`product.subscription?.localizedSubscriptionPeriod` を使用します。このローカライズはデバイスのロケールに基づきます。プログラムでサブスクリプション期間を取得するには、`product.subscription?.subscriptionPeriod` を使用します。そこから `unit` プロパティにアクセスして、長さ(`'day'`、`'week'`、`'month'`、`'year'`、または `'unknown'`)を取得できます。`numberOfUnits` の値で期間の単位数を取得できます。たとえば、四半期ごとのサブスクリプションの場合、`unit` プロパティには `'month'`、`numberOfUnits` には `3` が設定されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれていることを示すバッジやインジケーターを表示するには、`product.subscription?.offer?.phases` プロパティを確認してください。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むリストです。各フェーズオブジェクトには以下の便利なプロパティがあります:<br/>• `paymentMode`:`'free_trial'`、`'pay_as_you_go'`、`'pay_up_front'`、`'unknown'` の値を持つ文字列。無料トライアルは `'free_trial'` タイプになります。<br/>• `price`:割引価格(数値)。無料トライアルの場合は `0` を確認してください。<br/>• `localizedNumberOfPeriods`:デバイスのロケールを使用してローカライズされた、オファーの長さを説明する文字列。たとえば、3日間のトライアルオファーの場合、このフィールドには `'3 days'` が表示されます。<br/>• `subscriptionPeriod`:このプロパティを使用して、オファー期間の個別の詳細を取得することもできます。オファーに対しても、前のセクションで説明したものと同じ方法で機能します。<br/>• `localizedSubscriptionPeriod`:ユーザーのロケールに合わせてフォーマットされた、割引のサブスクリプション期間。 | ## デフォルトオーディエンスのペイウォールでペイウォール取得を高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ瞬時に取得されるため、この処理を高速化することを気にする必要はありません。ただし、オーディエンスやペイウォールの数が多く、ユーザーのインターネット接続が不安定な場合、ペイウォールの取得に想定以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を提供したいと思うでしょう。 これを解決するには、`getPaywallForDefaultAudience` メソッドを使用します。このメソッドは、**All Users** オーディエンスに対して指定されたプレースメントのペイウォールを取得します。ただし、推奨されるアプローチは、上記の [ペイウォール情報の取得](fetch-paywalls-and-products-react-native#fetch-paywall-information) セクションで説明されている `getPaywall` メソッドでペイウォールを取得することです。 :::warning `getPaywall` を推奨する理由 `getPaywallForDefaultAudience` メソッドにはいくつかの重大な欠点があります: - **後方互換性の問題**: 現在のバージョンと将来のバージョンで異なるペイウォールを表示する必要がある場合、問題が生じる可能性があります。現在(レガシー)バージョンに対応したペイウォールを設計するか、現在(レガシー)バージョンのユーザーがペイウォールを表示できない問題を許容するかのどちらかになります。 - **ターゲティングの喪失**: すべてのユーザーが **All Users** オーディエンス向けに設計された同一のペイウォールを見ることになり、国、マーケティングのアトリビューション、独自のカスタム属性などに基づいたパーソナライズされたターゲティングができなくなります。 これらのデメリットを受け入れてでもペイウォールの高速取得を利用したい場合は、以下のように `getPaywallForDefaultAudience` メソッドを使用してください。そうでなければ、[上記](fetch-paywalls-and-products-react-native#fetch-paywall-information)で説明した `getPaywall` を使い続けることをおすすめします。 ::: ```typescript showLineNumbers try { const id = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const paywall = await adapty.getPaywallForDefaultAudience(id, locale); // the requested paywall } catch (error) { // handle the error } ``` :::note `getPaywallForDefaultAudience` メソッドは、React Native SDK バージョン 2.11.2 以降で利用できます。 ::: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-remote-config-locale)の識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードおよび推奨される使用方法については、[ローカライズとロケールコード](react-native-localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。この方法を推奨します。ユーザーが常に最新のデータを取得できるためです。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュが存在する場合にキャッシュデータを返すことを検討してください。この場合、最新のデータが取得できないことがありますが、接続状況にかかわらず読み込みが速くなります。キャッシュはセッション中も定期的に更新されるため、ネットワークリクエストを減らすために安全に活用できます。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリのアンインストール時または手動でクリアした場合にのみ削除されます。</p> | </SDKv3> --- # File: present-remote-config-paywalls-react-native --- --- title: "React Native SDKでリモートコンフィグで設計されたペイウォールをレンダリングする" description: "Adapty React Native SDKでリモートコンフィグのペイウォールを表示し、ユーザー体験をパーソナライズする方法を紹介します。" --- <SDKv4> リモートコンフィグを使ってフローをカスタマイズした場合、ユーザーに表示するためのレンダリングをアプリのコードに実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、フロービューをどのように表示するかはすべて自由に決められます。リモート設定を取得するためのメソッドを提供しており、リモートコンフィグで設定したカスタムフローを自由に表示できます。 ## フローのリモートコンフィグを取得して表示する \{#get-flow-remote-config-and-present-it\} v4 では、フローは設定された言語ごとに1つの `AdaptyRemoteConfig` エントリを `remoteConfigs` 配列に持ちます。ユーザーの言語設定に合ったものを選び、その `data` から必要な値を読み取ってください。 ```typescript showLineNumbers try { const flow = await adapty.getFlow("YOUR_PLACEMENT_ID"); const config = flow.remoteConfigs?.find((c) => c.lang === "en") ?? flow.remoteConfigs?.[0]; const headerText = config?.data?.["header_text"]; } catch (error) { // handle the error } ``` ここまでで必要な値がすべて揃ったので、次はそれらを視覚的に魅力的なページへレンダリングして組み立てましょう。さまざまなモバイル端末の画面サイズや向きに対応したデザインにして、どのデバイスでもスムーズで使いやすい体験を提供してください。 :::warning 以下で説明するように、[ペイウォールの表示イベントを記録](present-remote-config-paywalls-react-native#track-paywall-view-events)してください。これにより、Adapty アナリティクスがファネルや A/B テスト用の情報を収集できるようになります。 ::: フローの表示が完了したら、購入フローの設定に進みます。ユーザーが購入を行う際は、フローから取得したプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実行](react-native-making-purchases)をご覧ください。 インターネット接続がない場合やキャッシュが利用できない場合にユーザーにフォールバックペイウォールを表示するため、[フォールバックペイウォールと呼ばれるバックアップペイウォールを作成する](react-native-use-fallback-paywalls)ことをおすすめします。これにより、そのような状況でもスムーズなユーザー体験を確保できます。 ## フローの表示イベントをトラッキングする \{#track-paywall-view-events\} Adapty はフローのパフォーマンス計測をサポートしています。購入データは自動的に収集されますが、フローの表示ログは手動で記録する必要があります。ユーザーがフローを見たタイミングを把握できるのはあなただけだからです。 フローの表示イベントをログに記録するには、`.logShowFlow(flow)` を呼び出すだけです。これにより、ファネルや A/B テストのペイウォール指標に反映されます。 :::important [フローブルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示している場合、`.logShowFlow(flow)`を呼び出す必要はありません。Adapty がそれらのケースでは自動的にビューを追跡します。 ::: ```typescript showLineNumbers await adapty.logShowFlow(flow); ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :-------- | :------- |:-------------------------------------------------------------------------------------| | **flow** | 必須 | `adapty.getFlow(placementId)` で取得した `AdaptyFlow` オブジェクト。 | </SDKv4> <SDKv3> リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためのレンダリングをアプリのコードに実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、ペイウォールビューをどのように表示するかはあなた次第です。リモートコンフィグを取得するメソッドを用意しているので、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: "YOUR_PLACEMENT_ID" }); const headerText = paywall.remoteConfig?.data?.["header_text"]; } catch (error) { // handle the error } ``` これで必要な値をすべて取得できました。次は、それらを視覚的に魅力的なページにレンダリングして組み立てましょう。さまざまなスマートフォンの画面サイズや向きに対応したデザインを心がけ、デバイスを問わずシームレスで使いやすい体験を提供してください。 :::warning 以下で説明するように、必ず[ペイウォール表示イベントを記録](present-remote-config-paywalls-react-native#track-paywall-view-events)してください。これにより、Adapty アナリティクスがファネルや A/B テスト用の情報を収集できます。 ::: ペイウォールの表示が完了したら、購入フローの設定に進みます。ユーザーが購入を行う際は、ペイウォールのプロダクトを使って `.makePurchase()` を呼び出すだけです。`.makePurchase()` メソッドの詳細については、[購入の実行](react-native-making-purchases)をご覧ください。 [フォールバックペイウォールと呼ばれるバックアップペイウォールの作成](react-native-use-fallback-paywalls)をお勧めします。このバックアップは、インターネット接続がない場合やキャッシュが利用できない場合にユーザーに表示され、そのような状況でもスムーズな体験を提供します。 ## ペイウォールの表示イベントを記録する \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見るタイミングを把握しているのがあなただけなので、手動で記録する必要があります。 ペイウォールの表示イベントを記録するには、`.logShowPaywall(paywall)` を呼び出すだけです。これにより、ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder) で作成したペイウォールを表示している場合、`.logShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```typescript showLineNumbers await adapty.logShowPaywall(paywall); ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- |:--------------------------------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://react-native.adapty.io/interfaces/adaptypaywall) オブジェクト。 | </SDKv3> --- # File: react-native-making-purchases --- --- title: "React Native 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)を使用していますか?** 購入は自動的に処理されます。このステップはスキップできます。 **ステップバイステップのガイドをお探しですか?** フルコンテキストのエンドツーエンド実装手順については、[クイックスタートガイド](react-native-implement-paywalls-manually)をご覧ください。 ::: ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- |:-------------------------------------------------------------------------------------------------------------------------------| | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://react-native.adapty.io/interfaces/adaptypaywallproduct) オブジェクト。 | レスポンスパラメーター: | パラメーター | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>リクエストが成功した場合、このオブジェクトがレスポンスに含まれます。[AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile) オブジェクトは、アプリ内のユーザーのアクセスレベル、サブスクリプション、および買い切り購入に関する包括的な情報を提供します。</p><p>アクセスレベルのステータスを確認して、ユーザーがアプリへの必要なアクセス権を持っているかどうかを判断してください。</p> | :::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()` メソッドを呼び出します。 ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product, params); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` 追加のリクエストパラメーター: | パラメーター | 必須 | 説明 | | :--------- | :------- | :----------------------------------------------------------- | | **params** | 必須 | [`MakePurchaseParamsInput`](https://react-native.adapty.io/types/makepurchaseparamsinput) 型のオブジェクト。 | :::info **バージョン 3.8.2 以降**: `MakePurchaseParamsInput` の構造が更新されました。`oldSubVendorProductId` と `prorationMode` は `subscriptionUpdateParams` 配下にネストされ、`isOfferPersonalized` は上位レベルに移動しました。 例: ```javascript makePurchase(product, { android: { subscriptionUpdateParams: { oldSubVendorProductId: 'old_product_id', prorationMode: 'charge_prorated_price' }, isOfferPersonalized: true } }); ``` ::: サブスクリプションと置き換えモードの詳細については、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\} <Details> <summary>オファーコードについて</summary> オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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アナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。 </Details> アプリ内にコード利用シートを表示するには: ```typescript showLineNumbers adapty.presentCodeRedemptionSheet(); ``` :::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)を有効にすることができます。 ```typescript showLineNumbers adapty.activate("PUBLIC_SDK_KEY", { android: { pendingPrepaidPlansEnabled: true } }); ``` --- # File: react-native-restore-purchase --- --- title: "React Native SDKでのアプリ内購入の復元" description: "Adaptyで購入を復元してシームレスなユーザー体験を実現する方法を学びます。" --- iOSとAndroid両方での購入の復元は、ユーザーが再度課金されることなく、サブスクリプションやアプリ内課金などの以前に購入したコンテンツへのアクセスを取り戻せる機能です。この機能は、アプリをアンインストールして再インストールしたユーザーや、新しいデバイスに切り替えたユーザーが、再度支払いをせずに以前購入したコンテンツにアクセスしたい場合に特に役立ちます。 :::note [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールでは、追加のコードなしに購入が自動的に復元されます。その場合は、このステップをスキップできます。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使用してペイウォールをカスタマイズしていない場合に購入を復元するには、`.restorePurchases()` メソッドを呼び出します: ```typescript showLineNumbers try { const profile = await adapty.restorePurchases(); const isSubscribed = profile.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // restore access } } catch (error) { // handle the error } ``` レスポンスパラメーター: | パラメーター | 説明 | |---------|-----------| | **Profile** | <p>[`AdaptyProfile`](https://react-native.adapty.io/interfaces/adaptyprofile) オブジェクト。このモデルにはアクセスレベル、サブスクリプション、および非サブスクリプション購入に関する情報が含まれています。</p><p>ユーザーがアプリへのアクセス権を持っているかどうかを判断するには、**アクセスレベルのステータス**を確認してください。</p> | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: implement-observer-mode-react-native --- --- title: "React Native SDKでオブザーバーモードを実装する" description: "AdaptyのオブザーバーモードをReact Native SDKに実装して、ユーザーのサブスクリプションイベントを追跡する方法を説明します。" --- 独自の購入インフラをすでにお持ちで、Adaptyへの完全な移行の準備ができていない場合は、[オブザーバーモード](observer-vs-full-mode)を試すことができます。基本的な形式では、オブザーバーモードは高度な分析と、アトリビューションおよびアナリティクスシステムとのシームレスな連携を提供します。 これがニーズに合っている場合、必要な作業は次の2つだけです: 1. `observerMode` パラメータを `true` に設定して、Adapty SDKの設定時にオブザーバーモードを有効にする。セットアップ手順は[React Native](sdk-installation-reactnative)を参照してください。 2. 既存の購入インフラからAdaptyへ[トランザクションを報告する](report-transactions-observer-mode-react-native)。 ### オブザーバーモードのセットアップ \{#observer-mode-setup\} 購入とサブスクリプションのステータスを自分で管理し、サブスクリプションイベントの送信と分析にのみAdaptyを使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作している場合、Adapty SDKはトランザクションをクローズしないため、必ず自分でトランザクションを処理してください。 ::: ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { observerMode: true, // Enable observer mode }); ``` パラメータ: | パラメータ | 説明 | | --------------------------- | ------------------------------------------------------------ | | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御するboolean値。デフォルト値は `false` です。 | ## オブザーバーモードでAdaptyのペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adaptyのペイウォールとそのアクセスレベル機能も使いたい場合は利用できますが、オブザーバーモードでは追加のセットアップが必要です。上記の手順に加えて、次の作業が必要です: 1. [リモートコンフィグペイウォール](present-remote-config-paywalls-react-native)と同様にペイウォールを表示する。 3. 購入トランザクションに[ペイウォールを関連付ける](report-transactions-observer-mode-react-native)。 --- # File: report-transactions-observer-mode-react-native --- --- title: "React Native SDKのオブザーバーモードでトランザクションを報告する" description: "React Native SDKのAdapty Observer Modeで購入トランザクションを報告し、ユーザーインサイトと収益トラッキングを実現します。" --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+ (current)" default> オブザーバーモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡することができません。アプリストアからトランザクションを手動で報告する必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を完了させることが重要です。 各トランザクションをAdaptyに明示的に報告するには`reportTransaction`を使用します。 :::warning **トランザクションの報告を省略しないでください!** `reportTransaction`を呼び出さない場合、Adaptyはトランザクションを認識せず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に`variationId`を含めてください。これにより、購入が起動元のペイウォールに紐付けられ、正確なペイウォールアナリティクスが確保されます。 ```typescript showLineNumbers const variationId = paywall.variationId; try { await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | <ul><li> iOS の場合: トランザクションの識別子。</li><li> Android の場合: 購入のString識別子(`purchase.getOrderId`)。purchaseは課金ライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。</li></ul> | | variationId | 任意 | バリアントのString識別子。[AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall)オブジェクトの`variationId`プロパティを使用して取得できます。 | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x (legacy)" default> オブザーバーモードでは、Adapty SDKは既存の購入システムで行われた購入を自動的に追跡することができません。アプリストアからトランザクションを手動で報告するか、復元する必要があります。アナリティクスのエラーを防ぐため、アプリをリリースする**前に**この設定を完了させることが重要です。 両プラットフォームで`reportTransaction`を使用して各トランザクションを明示的に報告し、Androidでは追加ステップとして`restorePurchases`を使用してAdaptyがトランザクションを認識できるようにしてください。 :::warning **トランザクションの報告を省略しないでください!** これらのメソッドを呼び出さない場合、Adaptyはトランザクションを認識せず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に`variationId`を含めてください。これにより、購入が起動元のペイウォールに紐付けられ、正確なペイウォールアナリティクスが確保されます。 ```typescript showLineNumbers if (Platform.OS === 'android') { try { await adapty.restorePurchases(); } catch (error) { // handle the error } } ... const variationId = paywall.variationId; try { await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | <ul><li> iOS、StoreKit 1 の場合: [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction)オブジェクト。</li><li> iOS、StoreKit 2 の場合: [Transaction](https://developer.apple.com/documentation/storekit/transaction)オブジェクト。</li><li> Android の場合: 購入のString識別子(`purchase.getOrderId`)。purchaseは課金ライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。</li></ul> | | variationId | 任意 | バリアントのString識別子。[AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall)オブジェクトの`variationId`プロパティを使用して取得できます。 | </TabItem> <TabItem value="old2" label="Adapty SDK up to 3.2.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> **トランザクションの報告** - バージョン3.1.x以前は、App Storeのトランザクションを自動的に監視するため、手動での報告は不要です。 - バージョン3.2はオブザーバーモードをサポートしていません。 </TabItem> <TabItem value="kotlin" label="Android and Android-based cross-platforms" default> **トランザクションの報告** オブザーバーモードでAdaptyにトランザクションを報告するには`restorePurchases`を使用してください。詳細は[モバイルコードでの購入の復元](react-native-restore-purchase)ページをご覧ください。 :::warning **トランザクションの報告を省略しないでください!** `restorePurchases`を呼び出さない場合、Adaptyはトランザクションを認識せず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: </TabItem> </Tabs> **ペイウォールとトランザクションの関連付け** Adapty SDKは購入の発生元を判断できません。購入処理はお客様自身が行うためです。そのため、オブザーバーモードでペイウォールやA/B テストを使用する場合は、アプリストアから受け取ったトランザクションをモバイルアプリのコードで対応するペイウォールに関連付ける必要があります。アプリをリリースする前にこれを正しく設定することが重要です。設定しないと、アナリティクスにエラーが生じます。 ```typescript const variationId = paywall.variationId; try { await adapty.setVariationId('transactionId', variationId); } catch (error) { // handle the `AdaptyError` } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | --------- | ------------------------------------------------------------ | | transactionId | 必須 | <p>iOS、StoreKit 1 の場合: [SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction)オブジェクト。</p><p>iOS、StoreKit 2 の場合: [Transaction](https://developer.apple.com/documentation/storekit/transaction)オブジェクト。</p><p>Android の場合: 購入のString識別子(purchase.getOrderId)。purchaseは課金ライブラリの[Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase)クラスのインスタンスです。</p> | | variationId | 必須 | バリアントのString識別子。[AdaptyPaywall](https://react-native.adapty.io/interfaces/adaptypaywall)オブジェクトの`variationId`プロパティを使用して取得できます。 | </TabItem> </Tabs> --- # File: react-native-troubleshoot-purchases --- --- title: "React Native SDKでの購入に関するトラブルシューティング" description: "React Native SDKでの購入に関するトラブルシューティング" --- このガイドでは、React Native SDKで手動購入を実装する際によく発生する問題の解決方法を説明します。 ## makePurchaseは正常に呼び出されるが、プロファイルが更新されない \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **問題**: `makePurchase`メソッドは正常に完了するが、ユーザーのプロファイルとサブスクリプションのステータスがAdaptyで更新されない。 **原因**: 通常、Google Play Storeのセットアップが不完全か、設定に問題があることを示しています。 **解決策**: [Google Playのセットアップ手順](initial-android)がすべて完了していることを確認してください。 ## makePurchaseが2回呼び出される \{#makepurchase-is-invoked-twice\} **問題**: 同じ購入に対して`makePurchase`メソッドが複数回呼び出されている。 **原因**: UIの状態管理の問題や、ユーザーの素早い操作によって購入フローが複数回トリガーされる場合によく発生します。 **解決策**: [Google Playのセットアップ手順](initial-android)がすべて完了していることを確認してください。 ## オブザーバーモードでのAdaptyError.cantMakePayments \{#adaptyelrorcantmakepayments-in-observer-mode\} **問題**: オブザーバーモードで`makePurchase`を使用すると`AdaptyError.cantMakePayments`が発生する。 **原因**: オブザーバーモードでは、購入はご自身の側で処理する必要があり、Adaptyの`makePurchase`メソッドは使用できません。 **解決策**: 購入に`makePurchase`を使用する場合は、オブザーバーモードをオフにしてください。`makePurchase`を使用するか、オブザーバーモードで購入を自分で処理するか、どちらか一方を選択する必要があります。詳細は[オブザーバーモードの実装](implement-observer-mode-react-native)をご覧ください。 ## Adapty error: (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 Storeから請求不可エラーが返される。 **原因**: このエラーは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\} **問題**: 上記に該当しない購入関連の問題が発生している。 **解決策**: 必要に応じて[移行ガイド](react-native-sdk-migration-guides)を使用してSDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: react-native-identifying-users --- --- title: "React Native SDKでユーザーを識別する" description: "Adapty SDKを使用してReact Nativeアプリでユーザーを識別する方法を学びましょう。" --- Adaptyはすべてのユーザーに対して内部プロファイルIDを作成します。ただし、独自の認証システムがある場合は、Customer User IDを設定してください。[Profiles](profiles-crm)セクションでCustomer User IDからユーザーを検索したり、[サーバーサイドAPI](getting-started-with-server-side-api)で使用したりできます。このIDはすべての連携先にも送信されます。 ### 設定時にCustomer User IDを設定する \{#setting-customer-user-id-on-configuration\} 設定時にユーザーIDが取得できる場合は、`.activate()`メソッドの`customerUserId`パラメーターとして渡すだけです。 ```typescript showLineNumbers adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID" }); ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 設定後にCustomer User IDを設定する \{#setting-customer-user-id-after-configuration\} SDKの設定時にユーザーIDが取得できない場合は、後から`.identify()`メソッドを使っていつでも設定できます。最も一般的なユースケースは、ユーザーが匿名ユーザーから認証済みユーザーに切り替わる、登録後や認証後です。 ```typescript showLineNumbers try { await adapty.identify("YOUR_USER_ID"); // successfully identified } catch (error) { // handle the error } ``` リクエストパラメーター: - **Customer User ID**(必須): 文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信 ユーザーがアカウントに再度ログインした場合など、Adaptyのサーバーがそのユーザーの情報をすでに保持しているケースがあります。そのような場合、Adapty SDKは自動的に新しいユーザーとして動作を切り替えます。カスタム属性やサードパーティネットワークからのアトリビューションなど、匿名ユーザーに対して設定していたデータがあれば、識別済みユーザーに対して再度送信する必要があります。 また、新しいユーザーのデータが異なる可能性があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得することも重要です。 ::: ### ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()`メソッドを呼び出すことで、いつでもユーザーをログアウトできます。 ```typescript showLineNumbers try { await adapty.logout(); // successful logout } catch (error) { // handle the 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`と一緒に渡す必要があります。 トークンのみを渡した場合、トランザクションに含まれません。 ::: ```typescript showLineNumbers // During configuration: adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID", ios: { appAccountToken: "YOUR_APP_ACCOUNT_TOKEN" }, }); // Or when identifying users try { await adapty.identify("YOUR_USER_ID", { ios: {appAccountToken: 'YOUR_APP_ACCOUNT_TOKEN'} }); // successfully identified } catch (error) { // handle the error } ``` ### 難読化アカウントIDを設定する(Android) \{#set-obfuscated-account-ids-android\} Google Playでは、ユーザーのプライバシーとセキュリティを強化するために、特定のユースケースで難読化アカウントIDが必要です。これらのIDは、ユーザー情報を匿名のまま購入をGoogle Playが識別するのに役立ちます。不正防止や分析において特に重要です。 アプリが機密性の高いユーザーデータを扱う場合や、特定のプライバシー規制への準拠が求められる場合に、これらのIDを設定する必要があります。難読化されたIDを使うことで、実際のユーザー識別子を公開せずにGoogle Playが購入を追跡できます。 ```typescript showLineNumbers // During configuration: adapty.activate("PUBLIC_SDK_KEY", { customerUserId: "YOUR_USER_ID", android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' } }); // Or when identifying users try { await adapty.identify("YOUR_USER_ID", { android: { obfuscatedAccountId: 'YOUR_OBFUSCATED_ACCOUNT_ID' } }); // successfully identified } catch (error) { // handle the error } ``` ## 複数デバイス間でユーザーを検出する \{#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: react-native-setting-user-attributes --- --- title: "React Native SDKでユーザー属性を設定する" description: "Adapty SDKを使ってReact Nativeアプリのユーザーデータとプロファイルデータを更新する方法を学びましょう。" --- メールアドレス、電話番号などの任意の属性をアプリのユーザーに設定できます。設定した属性を使ってユーザー[セグメント](segments)を作成したり、CRMで確認したりすることができます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()` メソッドを呼び出します: ```typescript showLineNumbers // Only for TypeScript validation const params: AdaptyProfileParameters = { email: 'email@email.com', phoneNumber: '+18888888888', firstName: 'John', lastName: 'Appleseed', gender: 'other', birthday: new Date().toISOString(), }; try { await adapty.updateProfile(params); } catch (error) { // handle `AdaptyError` } ``` なお、`updateProfile` メソッドで以前に設定した属性はリセットされません。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 利用可能なキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters.Builder` の利用可能なキー `<Key>` と値 `<Value>` は以下の通りです: | キー | 値 | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | 文字列 | | gender | 列挙型。使用できる値は `female`、`male`、`other` | | birthday | 日付 | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定することもできます。これらは通常、アプリの使用状況に関連しています。たとえば、フィットネスアプリであれば1週間あたりの運動回数、語学学習アプリであればユーザーの習熟度などが考えられます。セグメントで使用してターゲットを絞ったペイウォールやオファーを作成したり、アナリティクスで収益に最も影響するプロダクト指標を特定したりするのに活用できます。 ```typescript showLineNumbers try { await adapty.updateProfile({ codableCustomAttributes: { key_1: 'value_1', key_2: 2, }, }); } catch (error) { // handle `AdaptyError` } ``` 既存のキーを削除するには、`.withRemoved(customAttributeForKey:)` メソッドを使用します: ```typescript showLineNumbers try { // to remove a key, pass null as its value await adapty.updateProfile({ codableCustomAttributes: { key_1: null, key_2: null, }, }); } catch (error) { // handle `AdaptyError` } ``` 事前にどのカスタム属性が設定済みかを確認したい場合は、`AdaptyProfile` オブジェクトの `customAttributes` フィールドを使用してください。 :::warning ユーザー属性は複数のデバイスからいつでも送信される可能性があるため、`customAttributes` の値が最新でない場合があります。最後の同期以降にサーバー上の属性が変更されている可能性があります。 ::: ### 制限 \{#limits\} - ユーザーごとに最大30件のカスタム属性 - キー名は最大30文字。キー名には英数字および以下の文字を使用できます:`_` `-` `.` - 値は文字列または浮動小数点数で、最大50文字。 --- # File: react-native-listen-subscription-changes --- --- title: "React Native SDKでサブスクリプションステータスを確認する" description: "React NativeアプリでのAdaptyのユーザーサブスクリプションステータスの追跡と管理でカスタマーリテンションを向上させましょう。" --- Adaptyを使えば、サブスクリプションステータスの管理が簡単になります。プロダクトIDをコードに手動で記述する必要はありません。アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプションステータスを手軽に把握できます。 <details> <summary>サブスクリプションステータスの確認を始める前に(クリックして展開)</summary> - iOSの場合、[App Store Server Notifications](enable-app-store-server-notifications)を設定してください - Androidの場合、[リアルタイムデベロッパー通知(RTDN)](enable-real-time-developer-notifications-rtdn)を設定してください </details> ## アクセスレベルとAdaptyProfileオブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは[AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile)オブジェクトのプロパティです。アプリ起動時(例:[ユーザーを識別する](react-native-identifying-users#setting-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更があるたびに更新することをおすすめします。こうすることで、都度リクエストを送ることなくプロファイルオブジェクトを利用できます。 プロファイルの更新通知を受け取るには、以下の[プロファイル更新(アクセスレベルを含む)のリッスン](react-native-listen-subscription-changes)セクションで説明する方法でプロファイルの変更を監視してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.getProfile()`メソッドを使用します。 ```typescript showLineNumbers try { const profile = await adapty.getProfile(); } catch (error) { // handle the error } ``` レスポンスパラメーター: | パラメーター | 説明 | | --------- | ------------------------------------------------------------ | | Profile | <p>[AdaptyProfile](https://react-native.adapty.io/interfaces/adaptyprofile)オブジェクトです。通常、ユーザーがアプリのプレミアム機能にアクセスできるかどうかを判断するには、プロファイルのアクセスレベルステータスのみを確認すれば十分です。</p><p></p><p>`.getProfile`メソッドは常にAPIへのクエリを試みるため、最新の結果を提供します。何らかの理由(例:インターネット接続なし)でAdapty SDKがサーバーから情報を取得できない場合は、キャッシュのデータが返されます。また、Adapty SDKは`AdaptyProfile`キャッシュを定期的に更新し、情報をできる限り最新の状態に保ちます。</p> | `.getProfile()`メソッドはユーザープロファイルを返し、そこからアクセスレベルステータスを取得できます。1つのアプリに複数のアクセスレベルを設定することも可能です。例えば、ニュースアプリでトピックごとに独立したサブスクリプションを販売する場合、「sports」や「science」といったアクセスレベルを作成できます。ただし、ほとんどの場合はアクセスレベルは1つで十分なので、デフォルトの「premium」アクセスレベルをそのまま使用できます。 デフォルトの「premium」アクセスレベルを確認する例: ```typescript showLineNumbers try { const profile = await adapty.getProfile(); const isActive = profile.accessLevels?.["premium"]?.isActive; if (isActive) { // grant access to premium features } } catch (error) { // handle the error } ``` ### サブスクリプションステータスの更新をリッスンする \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションに変更があると、Adaptyはイベントを発火します。 Adaptyからメッセージを受け取るには、追加の設定が必要です。 ```typescript showLineNumbers // Create an "onLatestProfileLoad" event listener adapty.addEventListener('onLatestProfileLoad', profile => { // handle any changes to subscription state }); ``` アプリ起動時にもAdaptyはイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDKに実装されたキャッシュは、プロファイルのサブスクリプションステータスを保存します。そのため、サーバーが利用できない場合でも、キャッシュされたデータからプロファイルのサブスクリプションステータスを取得できます。 ただし、キャッシュからの直接データ取得はできません。SDKは1分ごとにサーバーへ定期的にクエリを送信し、プロファイルに関する更新や変更を確認します。新しいトランザクションやその他の更新といった変更があった場合、サーバーとの同期を保つためにキャッシュへ反映されます。 --- # File: react-native-deal-with-att --- --- title: "Deal with ATT in React Native SDK" description: "Get started with Adapty on React Native to streamline subscription setup and management." --- アプリが AppTrackingTransparency フレームワークを使用しており、ユーザーにアプリトラッキング認証リクエストを表示する場合は、[認証ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/) を Adapty に送信する必要があります。 ```typescript showLineNumbers try { await adapty.updateProfile({ // you can also pass a string value (validated via tsc) if you prefer appTrackingTransparencyStatus: AppTrackingTransparencyStatus.Authorized, }); } catch (error) { // handle `AdaptyError` } ``` :::warning この値は変更されたらできるだけ早く送信することを強くお勧めします。そうすることで、設定済みのインテグレーションにタイムリーにデータが送信されます。 ::: --- # File: kids-mode-react-native --- --- title: "React Native SDKのキッズモード" description: "キッズモードを簡単に有効化してAppleとGoogleのポリシーに準拠。React Native SDKではIDFA、GAID、広告データは収集されません。" --- React Nativeアプリが子ども向けの場合、[Apple](https://developer.apple.com/kids/)および[Google](https://support.google.com/googleplay/android-developer/answer/9893335)のポリシーに従う必要があります。Adapty SDKを使用している場合、いくつかの簡単な手順でポリシーに準拠した設定を行い、アプリストアの審査を通過できます。 :::important iOS では、Kids Mode は `KidsMode` Swift パッケージトレイトを通じて有効化されます。これにより、IDFA、AdSupport、AppTrackingTransparency に関するすべてのコードがコンパイル時に除外されます。v4 SDK(Swift Package Manager 経由でネイティブ iOS SDK をインストール)と **Xcode 26** 以降が必要です。詳細は以下の [iOS Podfile の更新内容](#updates-in-your-ios-podfile) を参照してください。 ::: ## 何が必要ですか? \{#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 の取り扱いにも注意が必要です。`<FirstName.LastName>` のような形式のユーザー 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\} ポリシーに準拠するため、Adapty SDK を有効化する際に、ユーザーの IDFA(iOS)、GAID/AAID(Android)、および IP アドレスの収集を無効にしてください。 ```typescript showLineNumbers title="App.tsx" adapty.activate('YOUR_PUBLIC_SDK_KEY', { // Disable IP address collection ipAddressCollectionDisabled: true, // Disable IDFA collection on iOS ios: { idfaCollectionDisabled: true, }, // Disable Google Advertising ID collection on Android android: { adIdCollectionDisabled: true, }, }); ``` ### iOSのPodfileの更新 \{#updates-in-your-ios-podfile\} App Store キッズカテゴリー(またはCOPPA準拠)に対応するには、ネイティブiOS SDKを`KidsMode` Swiftパッケージトレイトを使ってビルドする必要があります。これにより、IDFA、AdSupport、AppTrackingTransparencyに関するコードがすべてコンパイルから除外されます。React NativeはSwift Package Manager経由でネイティブSDKをインストールしますが、Swift Package Managerはパッケージトレイトを転送できないため、SDKにはトレイトを自動的に適用するPodfileヘルパーが用意されています。この手順には**Xcode 26**以降が必要です。 `ios/Podfile`でヘルパーをrequireし、`react_native_post_install`の**後に**呼び出してください: ```ruby showLineNumbers title="ios/Podfile" require Pod::Executable.execute_command('node', ['-p', 'require.resolve( "react-native-adapty/ios/adapty_kids_mode.rb", {paths: [process.argv[1]]}, )', __dir__]).strip # ... post_install do |installer| react_native_post_install( installer, config[:reactNativePath], :mac_catalyst_enabled => false ) adapty_enable_kids_mode(installer) end ``` 次に `pod install` を実行します: ```sh showLineNumbers title="Shell" cd ios && pod install ``` キッズモードが有効になっているか確認するには、`adapty.activate(...)` のログ行に `kids_mode_enabled: true` と表示されているかチェックしてください。`post_install` 内のヘルパー呼び出しは常に残しておいてください。React Native は `pod install` のたびに Swift パッケージの参照を再作成するため、ヘルパーはそのたびにトレイトを再適用する必要があります。 ### Android マニフェストの更新 \{#updates-in-your-android-manifest\} :::note アプリが**子ども専用**であり、Android 13(API 33)以上を対象としている場合、Google Play では `AD_ID` 権限のリクエストが禁止されています。アプリ内の別の SDK(アナリティクス、アトリビューション、広告など)がマニフェストのマージによってこの権限を追加する場合があります。`adIdCollectionDisabled` を設定すると、Adapty による ID の収集は停止されますが、別の SDK が宣言した権限が削除されるわけではありません。 ::: この権限を削除するには、`android/app/src/main/AndroidManifest.xml` の `<manifest>` 要素内に以下を追加してください。`<manifest>` 要素には `xmlns:tools="http://schemas.android.com/tools"` の宣言が必要です。 ```xml showLineNumbers title="AndroidManifest.xml" <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" /> ``` --- # File: react-native-get-onboardings --- --- title: "React Native SDKでオンボーディングを取得する" description: "AdaptyのReact Nativeでオンボーディングを取得する方法を学びましょう。" --- :::warning **オンボーディングは SDK v4 で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](react-native-get-pb-paywalls)を使用してください。オンボーディングは WebView 内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み時間、WebView ランタイムへの依存がなくなります。まずは[フローとペイウォールの取得](react-native-get-pb-paywalls)と[フローとペイウォールの表示](react-native-present-paywalls)をご覧ください。 ::: [Adapty ダッシュボードのビルダーでオンボーディングのビジュアル部分をデザイン](design-onboarding)したら、React Native アプリで表示できます。まず、プレースメントに関連付けられたオンボーディングとそのビュー設定を以下の手順で取得します。 始める前に、以下を確認してください: 1. [Adapty React Native SDK](sdk-installation-reactnative) バージョン 3.8.0 以上をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## オンボーディングを取得する \{#fetch-onboarding\} ノーコードビルダーで[オンボーディング](onboardings)を作成すると、アプリが取得・表示するためのコンテナとして設定が保存されます。このコンテナはエクスペリエンス全体を管理します。表示されるコンテンツ、その見せ方、そしてユーザーの操作(クイズの回答やフォームへの入力など)の処理がすべて含まれます。また、コンテナはアナリティクスイベントを自動的に追跡するため、ビューのトラッキングを別途実装する必要はありません。 パフォーマンスを最大限に発揮するために、ユーザーに表示する前に画像のダウンロードが完了するよう、早めにオンボーディングの設定を取得しておいてください。 オンボーディングを取得するには、`getOnboarding` メソッドを使用します: ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const onboarding = await adapty.getOnboarding(placementId, locale); // 取得したオンボーディング } catch (error) { // エラーを処理する } ``` 次に、`createOnboardingView` メソッドを呼び出してビューインスタンスを作成します。 :::warning `createOnboardingView` メソッドの戻り値は一度しか使用できません。再度使用する必要がある場合は、`createOnboardingView` メソッドを新たに呼び出してください。再作成せずに二度呼び出すと、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```typescript showLineNumbers // for the Adapty SDK < 3.14 – import {createOnboardingView} from 'react-native-adapty/dist/ui'; if (onboarding.hasViewConfiguration) { try { const view = await createOnboardingView(onboarding); } catch (error) { // handle the error } } else { //use your custom logic } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |-------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値を使用します。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライゼーション識別子です。マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定してください。最初のサブタグは言語、2番目のサブタグは地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードとその推奨の使い方については、[ローカライゼーションとロケールコード](localizations-and-locale-codes)をご覧ください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。この設定を推奨します。ユーザーが常に最新のデータを受け取れるためです。</p><p></p><p>ただし、ユーザーがインターネット接続の不安定な環境にいると考えられる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在すればそれを返すようにすることをご検討ください。この場合、ユーザーが最新データを受け取れないことがありますが、接続状況にかかわらず読み込み時間が短くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で使用しても問題ありません。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストール時または手動でクリアした場合にのみ削除されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層で保存します。1つは上記の定期更新されるキャッシュ、もう1つはフォールバックオンボーディングです。また、オンボーディングをより高速に取得するためにCDNを使用し、CDNに到達できない場合のためにスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | | **loadTimeoutMs** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。</p><p>内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間よりもわずかに遅くタイムアウトすることがあります。</p> | レスポンスパラメータ: | パラメータ | 説明 | |:----------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | [`AdaptyOnboarding`](https://react-native.adapty.io/interfaces/adaptyonboarding) オブジェクト。オンボーディングの識別子と設定、リモートコンフィグ、およびその他のプロパティを含みます。 | ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ即座にフェッチされるため、このプロセスを高速化することを心配する必要はありません。ただし、オーディエンスやオンボーディングが多数あり、ユーザーのインターネット接続が不安定な場合、オンボーディングのフェッチに予想以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないよりも、デフォルトのオンボーディングを表示してスムーズなユーザー体験を確保したいと思うかもしれません。 `getOnboardingForDefaultAudience` メソッドを使用することで、指定したプレースメントの **All Users** オーディエンス向けオンボーディングを取得できます。ただし、推奨されるアプローチは `getOnboarding` メソッドを使用してオンボーディングを取得することであり、詳細は上記の [オンボーディングの取得](#fetch-onboarding) セクションをご覧ください。 :::warning `getOnboardingForDefaultAudience` の代わりに `getOnboarding` の使用を検討してください。前者には重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のある設計が必要になるか、古いバージョンで表示が崩れることを許容する必要があります。 - **パーソナライズなし**: 「全ユーザー」オーディエンス向けのコンテンツのみ表示され、国・アトリビューション・カスタム属性に基づくターゲティングは利用できません。 取得速度の向上がこれらのデメリットを上回る場合は、以下に示す `getOnboardingForDefaultAudience` を使用してください。そうでない場合は、[上記](#fetch-onboarding)で説明した `getOnboarding` を使用してください。 ::: ```typescript showLineNumbers try { const placementId = 'YOUR_PLACEMENT_ID'; const locale = 'en'; const onboarding = await adapty.getOnboardingForDefaultAudience(placementId, locale); // リクエストされたオンボーディング } catch (error) { // エラーを処理する } ``` パラメーター: | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子です。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライズ識別子です。このパラメータは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードである必要があります。最初のサブタグは言語を、2つ目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードとその推奨される使い方については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを取得しようとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを受け取れるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーがネットワーク接続の不安定な環境にいると想定される場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在すればそれを返すことを検討してください。この場合、ユーザーが受け取るデータが最新でない可能性はありますが、接続状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避ける目的で利用しても問題ありません。</p><p></p><p>キャッシュはアプリを再起動しても保持され、アプリのアンインストール時または手動でクリーンアップした場合にのみ削除されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2つの層で保存します。1つは上記の定期更新キャッシュ、もう1つはフォールバックオンボーディングです。また、オンボーディングをより高速に取得するために CDN を使用し、CDN が利用できない場合に備えてスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な状況でも信頼性を確保しながら、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | --- # File: react-native-present-onboardings --- --- title: "React Native SDKでオンボーディングを表示する" description: "React Nativeでオンボーディングを表示してコンバージョンと収益を向上させる方法を解説します。" --- :::warning **オンボーディングは SDK v4 で非推奨となり、将来のリリースで削除される予定です。** バグ修正や改善は行われません。代わりに[フロー](react-native-get-pb-paywalls)を使用してください。オンボーディングは WebView 内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebView ランタイムへの依存がありません。詳しくは[フローとペイウォールの取得](react-native-get-pb-paywalls)および[フローとペイウォールの表示](react-native-present-paywalls)をご覧ください。 ::: ペイウォールビルダーを使ってオンボーディングをカスタマイズした場合、モバイルアプリのコード上でレンダリング処理を実装しなくても、ユーザーに表示できます。このようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 始める前に、以下を確認してください: 1. [Adapty React Native SDK](sdk-installation-reactnative) 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 Adapty React Native SDK では、オンボーディングを表示する方法が2つあります: - **Reactコンポーネント**: 埋め込み型コンポーネントとして、アプリのアーキテクチャやナビゲーションシステムに統合できます。 - **モーダル表示** ## React コンポーネント \{#react-component\} `AdaptyOnboardingView` コンポーネントを React Native のコンポーネント階層に直接組み込むことで、既存のコンポーネントツリーにオンボーディングを埋め込めます。埋め込み型コンポーネントを使うと、アプリのアーキテクチャやナビゲーションシステムとシームレスに統合できます。 :::note Android では、視覚的なレンダリングアーティファクトを避けるために、`AdaptyOnboardingView` の追加設定を推奨します。詳しくは [Android でシステム UI がオンボーディングコンテンツと重なる場合](#system-ui-overlaps-onboarding-content-on-android) を参照してください。 ::: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK バージョン 3.14 以降" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onAnalytics={onAnalytics} onClose={onClose} onCustom={onCustom} onPaywall={onPaywall} onStateUpdated={onStateUpdated} onFinishedLoading={onFinishedLoading} onError={onError} /> ); } ``` </TabItem> <TabItem value="old" label="SDK バージョン < 3.14" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { return ( <AdaptyOnboardingView onboarding={onboarding} style={{ flex: 1 }} eventHandlers={{ onAnalytics(event, meta) { // Handle analytics events }, onClose(actionId, meta) { // Handle close actions }, onCustom(actionId, meta) { // Handle custom actions }, onPaywall(actionId, meta) { // Handle paywall actions }, onStateUpdated(action, meta) { // Handle state updates }, onFinishedLoading(meta) { // Handle when onboarding finishes loading }, onError(error) { // Handle errors }, }} /> ); } ``` </TabItem> </Tabs> ## モーダル表示 \{#modal-presentation\} オンボーディングをユーザーが閉じられるスタンドアロン画面として表示するには、`createOnboardingView` メソッドで作成した `view` に対して `view.present()` メソッドを使用します。各 `view` は一度しか使用できません。オンボーディングを再度表示する必要がある場合は、`createOnboardingView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning 同じ `view` を再作成せずに再利用することは禁止されています。これを行うと `AdaptyUIError.viewAlreadyPresented` エラーが発生します。 ::: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> ```typescript showLineNumbers title="React Native (TSX)" const view = await createOnboardingView(onboarding); // Optional: handle onboarding events (close, custom actions, etc) // view.setEventHandlers({ ... }); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> <TabItem value="old" label="SDK version < 3.14" default> ```typescript showLineNumbers title="React Native (TSX)" const view = await createOnboardingView(onboarding); view.setEventHandlers(); // handle close press, etc try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> ### iOSの表示スタイルを設定する \{#configure-ios-presentation-style\} `present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOSでのペイウォールの表示方法を設定できます。パラメーターには `'full_screen'`(デフォルト)または `'page_sheet'` を指定できます。 ```typescript showLineNumbers try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` ## オンボーディング中のローダー \{#loader-during-onboarding\} React Native でオンボーディングを表示する際、オンボーディングが表示される前に短い白いフラッシュやローディング画面が表示されることがあります。これは、基盤となるネイティブビューが初期化される間に発生します。ニーズやワークフローに応じて、さまざまな方法で対処できます。 #### onFinishedLoading を使ったスプラッシュ画面の制御 \{#control-splash-screen-using-onfinishedloading\} :::note このアプローチは React コンポーネントを使用する場合にのみ利用可能です。モーダル表示には対応していません。 ::: React Nativeで推奨されるアプローチは、オンボーディングが完全に読み込まれるまでスプラッシュスクリーンまたはカスタムオーバーレイを表示し続け、その後手動で非表示にすることです。 Reactコンポーネント(`AdaptyOnboardingView`)を使用する場合は、スプラッシュスクリーンやオーバーレイを非表示にする前に`onFinishedLoading`イベントを待ちます: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK バージョン 3.14 以降" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const [isLoading, setIsLoading] = useState(true); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => { // Hide your splash screen or custom overlay here setIsLoading(false); }, []); return ( <> <AdaptyOnboardingView onboarding={onboarding} onFinishedLoading={onFinishedLoading} // ... other callbacks /> {isLoading && <YourCustomLoadingOverlay />} </> ); } ``` </TabItem> <TabItem value="old" label="SDK バージョン < 3.14"> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const [isLoading, setIsLoading] = useState(true); return ( <> <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onFinishedLoading(meta) { // Hide your splash screen or custom overlay here setIsLoading(false); }, // ... other handlers }} /> {isLoading && <YourCustomLoadingOverlay />} </> ); } ``` </TabItem> </Tabs> #### ネイティブローダーのカスタマイズ \{#customize-native-loader\} :::important Expo マネージドワークフローでは、カスタムネイティブレイアウト(Android の `res/layout` など)を配置することはサポートされていません。Expo アプリの場合、スプラッシュスクリーンを制御するか、React Native オーバーレイを使用するのが唯一の選択肢です。 ::: Android と iOS それぞれのプラットフォーム固有のレイアウトを使って、ネイティブローダーを差し替えることができます。モーダル表示を使用している場合は、この方法が唯一の選択肢になります。 ただし、React Native アプリではこのアプローチは通常あまり便利ではありません。 - Android と iOS で別々の実装が必要 - Expo マネージドワークフローとは互換性がない 各プラットフォーム向けにプレースホルダーを定義します: - **iOS**: `AdaptyOnboardingPlaceholderView.xib` を Xcode プロジェクトに追加します。[詳細はこちら](ios-present-onboardings#add-smooth-transitions-between-the-splash-screen-and-onboarding)。 - **Android**: `res/layout` に `adapty_onboarding_placeholder_view.xml` を作成し、プレースホルダーを定義します。[詳細はこちら](android-present-onboardings#add-smooth-transitions-between-the-splash-screen-and-onboarding)。 ## オンボーディングでのリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディングでのリンクの開き方のカスタマイズは、Adapty SDK v3.15.1 以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開きます。これにより、ユーザーはアプリを切り替えることなくウェブページを閲覧でき、シームレスなユーザー体験が提供されます。 外部ブラウザでリンクを開くように変更したい場合は、`externalUrlsPresentation` パラメータを `WebPresentation.BrowserOutApp` に設定してこの動作をカスタマイズできます。 <Tabs groupId="rn-onboarding-views" queryString> <TabItem value="component" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} externalUrlsPresentation={WebPresentation.BrowserOutApp} // default – BrowserInApp onAnalytics={onAnalytics} onClose={onClose} onCustom={onCustom} onPaywall={onPaywall} onStateUpdated={onStateUpdated} onFinishedLoading={onFinishedLoading} onError={onError} /> ); } ``` </TabItem> <TabItem value="modal" label="Modal presentation"> ```typescript showLineNumbers title="React Native (TSX)" const view = await createOnboardingView( onboarding, { externalUrlsPresentation: WebPresentation.BrowserOutApp } // default – BrowserInApp ); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## トラブルシューティング \{#troubleshooting\} ### システムUIがAndroidのオンボーディングコンテンツと重なる \{#system-ui-overlaps-onboarding-content-on-android\} :::note この設定はベアReact Nativeプロジェクトでのみサポートされています。 Expoマネージドワークフローを使用している場合、このAndroidリソースを直接追加することはできません。この設定を適用するには、対応するAndroidリソースを追加するカスタムExpo設定プラグインを作成し、app.config.jsに登録する必要があります。ExpoがネイティブAndroidプロジェクトを管理しているため、この手順が必要です。 ::: Androidで`AdaptyOnboardingView`を使用すると、ステータスバーやナビゲーションバーなどのシステムUI要素がペイウォールコンテンツの上に表示される場合があります。これを防ぐには、次のboolean リソースをアプリに追加してください: 1. `android/app/src/main/res/values` に移動します。`bools.xml` ファイルがない場合は作成してください。 2. 次のリソースを追加します: ```xml <resources> <bool name="adapty_onboarding_enable_safe_area_paddings">false</bool> </resources> ``` この変更はアプリ内のすべてのオンボーディングにグローバルに適用されます。 ## 次のステップ \{#next-steps\} オンボーディングを表示したら、[ユーザーのインタラクションとイベントの処理](react-native-handling-onboarding-events)について確認しましょう。オンボーディングイベントを処理して、ユーザーのアクションに応答したりアナリティクスを追跡したりする方法を学べます。 --- # File: react-native-handling-onboarding-events --- --- title: "React Native SDKでオンボーディングイベントを処理する" description: "AdaptyのReact Nativeを使用したオンボーディング関連イベントの処理方法。" --- :::warning **オンボーディングは SDK v4 で非推奨となり、将来のリリースで削除される予定です。** バグ修正や機能改善は行われません。代わりに [フロー](react-native-get-pb-paywalls) をご利用ください。オンボーディングは WebView 上で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebView ランタイムへの依存がなくなります。まずは [フローとペイウォールの取得](react-native-get-pb-paywalls) および [フローとペイウォールの表示](react-native-present-paywalls) をご覧ください。 ::: オンボーディングをビルダーで設定すると、アプリが応答できるイベントが生成されます。これらのイベントの処理方法は、使用しているプレゼンテーション方式によって異なります。 - **モーダルプレゼンテーション**: すべてのオンボーディングビューのイベントを処理するイベントハンドラーの設定が必要です - **Reactコンポーネント**: ウィジェット内のインラインコールバックパラメーターで直接イベントを処理します 始める前に、以下を確認してください: 1. [Adapty React Native SDK](sdk-installation-reactnative) バージョン 3.8.0 以降をインストール済みであること。 2. [オンボーディングを作成](create-onboarding)済みであること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 モバイルアプリのオンボーディング画面で発生するプロセスを制御・監視するには、イベントハンドラーを実装してください: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> React コンポーネントの場合、`AdaptyOnboardingView` コンポーネントの個別のイベントハンドラープロップを通じてイベントを処理します。 ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onAnalytics={onAnalytics} onClose={onClose} onCustom={onCustom} onPaywall={onPaywall} onStateUpdated={onStateUpdated} onFinishedLoading={onFinishedLoading} onError={onError} /> ); } ``` </TabItem> <TabItem value="standalone" label="モーダル表示"> モーダル表示の場合は、イベントハンドラーメソッドを実装してください。 :::important `setEventHandlers` を複数回呼び出すと、指定したハンドラーが上書きされ、そのイベントに対するデフォルトおよび以前に設定したハンドラーが両方とも置き換えられます。 ::: ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onAnalytics(event, meta) { // Track analytics events }, onClose(actionId, meta) { // Handle close action view.dismiss(); return true; }, onCustom(actionId, meta) { // Handle custom actions }, onPaywall(actionId, meta) { // Handle paywall actions }, onStateUpdated(action, meta) { // Handle user input updates }, onFinishedLoading(meta) { // Onboarding finished loading }, onError(error) { // Handle loading errors }, }); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK バージョン < 3.14"> SDK バージョン 3.14 未満では、モーダル表示のみサポートされています: ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onAnalytics(event, meta) { // Track analytics events }, onClose(actionId, meta) { // Handle close action view.dismiss(); return true; }, onCustom(actionId, meta) { // Handle custom actions }, onPaywall(actionId, meta) { // Handle paywall actions }, onStateUpdated(action, meta) { // Handle user input updates }, onFinishedLoading(meta) { // Onboarding finished loading }, onError(error) { // Handle loading errors }, }); try { await view.present(); } catch (error) { // handle the error } ``` </TabItem> </Tabs> ## イベントの種類 \{#event-types\} 以下のセクションでは、使用するプレゼンテーション方式に関わらず処理できる各種イベントについて説明します。 ### カスタムアクションの処理 \{#handle-custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。 <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このIDをコード内で使用し、カスタムアクションとして処理できます。たとえば、ユーザーが **Login** や **Allow notifications** のようなカスタムボタンをタップすると、ビルダーの **Action ID** と一致する `actionId` パラメーターでイベントハンドラーが呼び出されます。"allowNotifications" のような独自のIDを作成することも可能です。 <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => { switch (actionId) { case 'login': login(); break; case 'allow_notifications': allowNotifications(); break; } }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onCustom={onCustom} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onCustom(actionId, meta) { switch (actionId) { case 'login': login(); break; case 'allow_notifications': allowNotifications(); break; } }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onCustom(actionId, meta) { switch (actionId) { case 'login': login(); break; case 'allow_notifications': allowNotifications(); break; } }, }); ``` </TabItem> </Tabs> <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "actionId": "allow_notifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ### オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了すると、次のイベントが発生します。 <Tabs groupId="version" queryString> <TabItem value="new" label="SDK バージョン 3.14 以降" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React コンポーネント" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => { console.log('Onboarding loaded:', meta.onboardingId); }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onFinishedLoading={onFinishedLoading} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onFinishedLoading(meta) { console.log('Onboarding loaded:', meta.onboardingId); }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onFinishedLoading(meta) { console.log('Onboarding loaded:', meta.onboardingId); }, }); ``` </TabItem> </Tabs> <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ### オンボーディングを閉じる \{#closing-onboarding\} ユーザーが**Close**アクションが割り当てられたボタンをタップすると、オンボーディングは閉じられたとみなされます。 <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important ユーザーがオンボーディングを閉じたときの処理は、ご自身で実装する必要があります。たとえば、オンボーディング自体の表示を停止する処理が必要です。 ::: <Tabs groupId="version" queryString> <TabItem value="new" label="SDK バージョン 3.14 以降" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React コンポーネント" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding, navigation }) { const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => { navigation.goBack(); }, [navigation]); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onClose={onClose} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onClose(actionId, meta) { await view.dismiss(); return true; }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onClose(actionId, meta) { await view.dismiss(); return true; }, }); ``` </TabItem> </Tabs> <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ### ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。ペイウォールを閉じた後に開きたい場合は、より簡単な方法があります。クローズアクションを処理し、イベントデータに依存せずにペイウォールを開いてください。 ::: オンボーディングでペイウォールをシームレスに扱う最善の方法は、アクション ID をペイウォールのプレースメント ID と同じにすることです。 <Tabs groupId="version" queryString> <TabItem value="new" label="SDK バージョン 3.14 以降" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => { openPaywall(actionId); }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onPaywall={onPaywall} /> ); } const openPaywall = async (placementId) => { // Implement your paywall opening logic here }; ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> iOSでは、ペイウォールまたはオンボーディングのうち、画面に表示できるビューは一度に1つだけです。オンボーディングの上にペイウォールを表示した場合、バックグラウンドにあるオンボーディングをプログラムから操作することはできません。オンボーディングを閉じようとすると、代わりにペイウォールが閉じられ、オンボーディングがそのまま表示され続けます。これを避けるため、ペイウォールを表示する前に必ずオンボーディングのビューを閉じてください。 ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onPaywall(actionId, meta) { view.dismiss().then(() => { openPaywall(actionId); }); }, }); const openPaywall = async (placementId) => { // Implement your paywall opening logic here }; ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK バージョン < 3.14"> :::note iOSでは、ペイウォールまたはオンボーディングのビューは同時に1つしか画面に表示できません。オンボーディングの上にペイウォールを表示した場合、バックグラウンドのオンボーディングをプログラムで制御することはできません。オンボーディングを閉じようとすると、代わりにペイウォールが閉じられ、オンボーディングが表示されたままになります。これを避けるために、ペイウォールを表示する前に必ずオンボーディングのビューを閉じてください。 ::: ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onPaywall(actionId, meta) { view.dismiss().then(() => { openPaywall(actionId); }); }, }); const openPaywall = async (placementId) => { // ここにペイウォールを開くロジックを実装してください }; ``` </TabItem> </Tabs> <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ### ナビゲーションのトラッキング \{#tracking-navigation\} オンボーディングフロー中にさまざまなナビゲーション関連イベントが発生すると、アナリティクスイベントを受け取ります。 <Tabs groupId="version" queryString> <TabItem value="new" label="SDK version 3.14 or later" default> <Tabs groupId="presentation-method" queryString> <TabItem value="platform" label="React component" default> ```typescript showLineNumbers title="React Native (TSX)" function MyOnboarding({ onboarding }) { const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => { trackEvent(event.name, meta.onboardingId); }, []); return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} onAnalytics={onAnalytics} /> ); } ``` </TabItem> <TabItem value="standalone" label="Modal presentation"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.setEventHandlers({ onAnalytics(event, meta) { trackEvent(event.name, meta.onboardingId); }, }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="old" label="SDK version < 3.14"> ```javascript showLineNumbers title="React Native" const view = await createOnboardingView(onboarding); const unsubscribe = view.registerEventHandlers({ onAnalytics(event, meta) { trackEvent(event.name, meta.onboardingId); }, }); ``` </TabItem> </Tabs> `event` オブジェクトは以下のいずれかの型になります: | タイプ | 説明 | |------------|-------------| | `onboardingStarted` | オンボーディングが読み込まれたとき | | `screenPresented` | いずれかの画面が表示されたとき | | `screenCompleted` | 画面が完了したとき。オプションの `elementId`(完了した要素の識別子)とオプションの `reply`(ユーザーからの回答)を含む。ユーザーが画面を離れる操作を行ったときにトリガーされる。 | | `secondScreenPresented` | 2番目の画面が表示されたとき | | `userEmailCollected` | 入力フィールドからユーザーのメールアドレスが収集されたときにトリガーされる | | `onboardingCompleted` | ユーザーが `final` IDを持つ画面に到達したときにトリガーされる。このイベントが必要な場合は、[最後の画面に `final` IDを割り当ててください](design-onboarding)。 | | `unknown` | 認識できないイベントタイプの場合。`name`(不明なイベントの名前)と `meta`(追加のメタデータ)を含む | 各イベントには以下のフィールドを含む `meta` 情報が含まれています: | フィールド | 説明 | |------------|-------------| | `onboardingId` | オンボーディングフローの一意の識別子 | | `screenClientId` | 現在の画面の識別子 | | `screenIndex` | フロー内における現在の画面の位置 | | `screensTotal` | フロー内の画面の総数 | <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } } ``` </Details> --- # File: react-native-onboarding-input --- --- title: "React Native SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使用してReact NativeアプリでオンボーディングからのデータをSaveして活用する方法。" --- :::warning **オンボーディングはSDK v4で非推奨となり、将来のリリースで削除される予定です。** バグ修正や機能改善は行われません。代わりに[フロー](react-native-get-pb-paywalls)をご利用ください。オンボーディングはWebView内で動作しますが、フローはデバイス上でネイティブにレンダリングされるため、よりスムーズなアニメーション、一貫したネイティブの外観、高速な読み込み、WebViewランタイムへの依存なしで利用できます。詳細は[フローとペイウォールの取得](react-native-get-pb-paywalls)および[フローとペイウォールの表示](react-native-present-paywalls)をご覧ください。 ::: ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`onStateUpdatedAction` メソッドが呼び出されます。フィールドタイプをコード内で保存または処理できます。 例: ```javascript // Full-screen presentation const unsubscribe = view.setEventHandlers({ onStateUpdated(action, meta) { // Process data }, }); // Embedded widget <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onStateUpdated(action, meta) { // Process data }, }} /> ``` アクションの形式は[こちら](https://react-native.adapty.io/types/onboardingstateupdatedaction)をご覧ください。 <Details> <summary>保存されたデータの例(実装によって形式が異なる場合があります)</summary> ```javascript // Example of a saved select action { "elementId": "preference_selector", "elementType": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" }, "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "totalScreens": 3 } } // Example of a saved multi-select action { "elementId": "interests_selector", "elementType": "multi_select", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ], "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "totalScreens": 3 } } // Example of a saved input action { "elementId": "name_input", "elementType": "input", "value": { "type": "text", "value": "John Doe" }, "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "totalScreens": 3 } } // Example of a saved date picker action { "elementId": "birthday_picker", "elementType": "date_picker", "value": { "day": 15, "month": 6, "year": 1990 }, "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "totalScreens": 3 } } ``` </Details> ## ユースケース \{#use-cases\} ### ユーザープロファイルにデータを付加する \{#enrich-user-profiles-with-data\} 入力データをユーザープロファイルとすぐに紐付けて、同じ情報を二度尋ねないようにするには、アクションを処理する際に入力データで[ユーザープロファイルを更新](react-native-setting-user-attributes)する必要があります。 たとえば、`name` というIDのテキストフィールドでユーザーに名前を入力してもらい、その値をユーザーのファーストネームとして設定したいとします。また、`email` フィールドでメールアドレスも入力してもらうとします。アプリのコードでは、次のようになります。 ```javascript showLineNumbers // Full-screen presentation const unsubscribe = view.setEventHandlers({ onStateUpdated(action, meta) { // Store user preferences or responses if (action.elementType === 'input') { const profileParams = {}; // Map elementId to appropriate profile field switch (action.elementId) { case 'name': if (action.value.type === 'text') { profileParams.firstName = action.value.value; } break; case 'email': if (action.value.type === 'email') { profileParams.email = action.value.value; } break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // handle the error }); } } }, }); // Embedded widget <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onStateUpdated(action, meta) { // Store user preferences or responses if (action.elementType === 'input') { const profileParams = {}; // Map elementId to appropriate profile field switch (action.elementId) { case 'name': if (action.value.type === 'text') { profileParams.firstName = action.value.value; } break; case 'email': if (action.value.type === 'email') { profileParams.email = action.value.value; } break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // handle the error }); } } }, }} /> ``` ### アンケートの回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングでクイズを使用することで、オンボーディング完了後にユーザーに表示するペイウォールをカスタマイズすることもできます。 たとえば、スポーツの経験についてユーザーに質問し、ユーザーグループごとに異なるCTAやプロダクトを表示することができます。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、各選択肢に意味のあるIDを割り当てます。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](react-native-setting-user-attributes)します。 ```javascript showLineNumbers // Full-screen presentation const unsubscribe = view.setEventHandlers({ onStateUpdated(action, meta) { // Handle quiz responses and set custom attributes if (action.elementType === 'select') { const profileParams = {}; // Map quiz responses to custom attributes switch (action.elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) profileParams.codableCustomAttributes = { experience: action.value.value }; break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // handle the error }); } } }, }); // Embedded widget <AdaptyOnboardingView onboarding={onboarding} eventHandlers={{ onStateUpdated(action, meta) { // Handle quiz responses and set custom attributes if (action.elementType === 'select') { const profileParams = {}; // Map quiz responses to custom attributes switch (action.elementId) { case 'experience': // Set custom attribute 'experience' with the selected value (beginner, amateur, pro) profileParams.codableCustomAttributes = { experience: action.value.value }; break; } // Update profile if we have data to update if (Object.keys(profileParams).length > 0) { adapty.updateProfile(profileParams).catch(error => { // handle the error }); } } }, }} /> ``` 3. カスタム属性の値ごとに[セグメントを作成](segments)します。 4. [プレースメント](placements)を作成し、作成した各セグメントに対して[オーディエンス](audience)を追加します。 5. アプリのコードで、そのプレースメントに対する[ペイウォールを表示](react-native-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[このボタンのアクションへの応答](react-native-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: react-native-sdk-call-order --- --- title: "React Native SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的な#2002エラーを防ぎます。" --- `adapty.activate()` が完了してから、他のAdapty SDKメソッドを呼び出す必要があります。解決されるまで、SDKは状態を持ちません。`activate()` の前または並行して発行された呼び出しは、[`#2002 notActivated`](react-native-handle-errors#custom-network-codes) で失敗します。 アプリがユーザーを認証し、起動後にカスタマーユーザーIDを取得する場合は、その時点で `adapty.identify()` を呼び出してください。`identify` が解決されるまで、ユーザーアクションメソッドを呼び出さないでください。並行して実行される呼び出しは [`#3006 profileWasChanged`](react-native-handle-errors#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点によって決まります。 - **ステップ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('YOUR_PUBLIC_SDK_KEY', { customerUserId: 'YOUR_USER_ID' })` | アプリ起動時、ステップ1の後、カスタマーユーザーIDがある場合 | 推奨。匿名プロファイルは一切作成されません。 | | 2b | `adapty.activate('YOUR_PUBLIC_SDK_KEY')` (`customerUserId` なし) | アプリ起動時、ステップ1の後、カスタマーユーザーIDがない場合(または収集しない場合) | Adaptyが匿名プロファイルを作成します。 | | 3 | 各MMPに対して `adapty.updateAttribution(data, source, networkUserId)` | ステップ2の後、ユーザーアクション呼び出しの前 | MMP IDを正しいプロファイルに紐付けるために必要です。 | | 4 | `await adapty.identify('YOUR_USER_ID')` | ステップ3の後(MMPなしの場合はステップ2の後)、ステップ5の前 — 認証ありのパス2bのみ | 必ず `await` を使用してください。`identify` 中の並行呼び出しは `#3006 profileWasChanged` を発生させます。 | | 5 | `getPaywall`、`getPaywallProducts`、`restorePurchases`、`makePurchase`、`updateAttribution`、`updateProfile` | `identify` を呼び出す場合はステップ4の後、それ以外はステップ3の後(MMPなしの場合はステップ2の後) | これらの呼び出しには安定したプロファイルが必要です。 | :::important これらのステップをスキップすると、リピートユーザーのプレミアムアクセス喪失、プロファイルへの `appsflyer_id` の欠落、誤ったオーディエンスに対してペイウォールが返されるといった問題が発生します。 ::: ## Web2appおよびウェブファネルからのインストール \{#web2app-and-web-funnel-installs\} ユーザーがウェブチェックアウト(Stripe、Paddle)で購入し、その後ネイティブアプリをインストールした場合、デバイス最初の `activate()` が新しい匿名プロファイルを作成します。このプロファイルはウェブプロファイルとリンクされません。アプリ起動前にカスタマーユーザーIDを解決できる場合(認証フローやインストールリファラーから)、`activate()` に直接渡してください。そうでない場合、`identify('YOUR_USER_ID')` を呼び出してから `restorePurchases` を呼び出すまで、ウェブ購入はデバイス上で表示されません。 各ウェブチェックアウトで送信するメタデータについては、以下を参照してください: - [Stripe](stripe) - [Paddle](paddle) --- # File: react-native-optimize-paywall-fetching --- --- title: "React Native SDKでのペイウォール取得を最適化する" description: "Adaptyのペイウォールを確実に取得する:React Nativeのタイミング、キャッシュ、フォールバックのパターン。" --- React Nativeでペイウォールを確実に取得するには、高速なレンダリング、オーディエンスターゲティングが適用されたペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバックという3つの要件を満たす必要があります。以下のルールでは、それを実現するためのタイミング、キャッシュ、フォールバックのパターンを説明します。 :::tip これらのルールは、`adapty.activate()` と `adapty.identify()` がすでに解決済みであることを前提としています。詳しくは[React Native SDKのコール順序](react-native-sdk-call-order)をご覧ください。 ::: ## ルールと注意点 \{#rules-and-pitfalls\} | 推奨する方法 | 避けるべき方法 | 理由 | |---|---|---| | 表示しようとしているプレースメントのみを取得する。 | 起動時にすべてのプレースメントを並列で事前取得する。 | 一括事前取得はJSスレッドをブロックし、バーストの間にブラックスクリーンが発生する。 | | アトリビューションが解決される機会があった後に `getPaywall` を取得する — たとえば、`activate` の1〜2秒後、または `onProfileUpdate` が発火した後。 | ルートコンポーネントのマウント時に `getPaywall` を呼び出す。 | アトリビューションがまだ適用されていない。ペイウォールがデフォルトのオーディエンスに対して解決され、セグメントやASAのパーソナライゼーションが無効になる。 | | `loadTimeoutMs` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `getPaywall` を無期限に待機する。 | タイムアウトなしでは、接続状況が悪いユーザーはネットワークが解決されるまで空白の画面を見続けるか、アプリを閉じてしまう。 | `fetchPolicy` と `loadTimeoutMs` パラメーターのリファレンスは[ペイウォールとプロダクトの取得](fetch-paywalls-and-products-react-native)を、適切なプレースメントの選択は[プレースメント](placements)をご覧ください。 ## 接続状況が悪い場合のチューニング \{#tune-for-poor-connectivity\} 接続状況が継続的に悪い市場(農村部、乗り物での移動中、ルーティングの影響を受ける地域)向けには: - 最初の取得を除くすべての取得に `fetchPolicy: .returnCacheDataElseLoad` を設定する。 - Adaptyダッシュボードですべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeoutMs` を3〜5秒に設定し、タイムアウトが発火したときはフォールバックを受け入れる。 - `getProfile()` の完了をペイウォール表示の条件にしない。`getPaywall` を独立して呼び出すことで、プロファイルの遅延がUIをブロックしないようにする。 --- # File: react-native-show-aa-targeted-paywall --- --- title: "React Native SDKで初回起動時にAA対象のペイウォールを表示する" description: "React NativeでApple Ads向けのペイウォールをすぐに表示し、AdaptyProfile.appliedAttributionSourcesを使用してアトリビューションが適用されたときにApple Ads ユーザー向けにアップグレードする方法を解説します。" --- Apple Ads(AA)のアトリビューションは、`adapty.activate()` の後に非同期で届きます。初回起動時はまだ届いていないことが多いため、`getPaywall` はデフォルトのオーディエンスに対して解決され、Apple Ads ユーザーが AA セグメント対象のペイウォールを見逃してしまいます。アトリビューションが届くまでペイウォールの表示を遅らせるのではなく、まずすぐにペイウォールを表示し、AA アトリビューションが適用されたらリフレッシュするようにしましょう。これにより、Apple Ads ユーザーはターゲット向けのバリアントを受け取り、それ以外のユーザーは待たずにペイウォールを見ることができます。`AdaptyProfile.appliedAttributionSources` で AA アトリビューションが適用されたタイミングを確認できます。 ## 始める前に \{#before-you-start\} 以下が必要です: - Adapty React Native SDK **3.17.1** 以降。 - Adapty でアプリの Apple Ads が設定済みであること。[Apple Ads](apple-search-ads) を参照してください。 ## 仕組み \{#how-it-works\} `adapty.activate()` の後、SDK はバックグラウンドで Apple から Apple Ads のアトリビューションをリクエストし、その結果を Adapty のバックエンドに転送します。AA がプロファイルのアクティブなアトリビューションソースになると、SDK は `onLatestProfileLoad` リスナーに更新された `AdaptyProfile` を届けます。この時点で `appliedAttributionSources` 配列に `'apple_search_ads'` が含まれています。 これにより、ペイウォールの読み込みを2段階で行うことができます: 1. すぐに `getPaywall` を呼び出します。アトリビューションがまだ適用されていないため、Adapty はデフォルトのオーディエンスに対してリクエストを解決し、ユーザーはすぐにペイウォールを見ることができます。 2. `'apple_search_ads'` が現れたら、再度 `getPaywall` を呼び出します。Adapty は今度は Apple Ads のオーディエンスに対してリクエストを解決し、ターゲット向けのペイウォールを返します。これが最初のペイウォールと置き換わります。 `appliedAttributionSources` は空または存在しない場合があります。これは次のどちらかを意味します: - このプロファイルに対して Apple Ads のアトリビューションがまだ処理されていない、または - アトリビューションが全く届いていない。 いずれの場合でも、ステップ1は安全です。Adapty は現在のプロファイル状態に合致するオーディエンス(通常はデフォルトオーディエンス)に対してリクエストを解決します。ステップ2は `'apple_search_ads'` が現れたときだけ実行されます。 :::important その後の起動では、キャッシュされたプロファイルにすでに `appliedAttributionSources` に `'apple_search_ads'` が含まれているため、最初の `getPaywall` からすでに Apple Ads セグメント対象のペイウォールが返されます。2回目のフェッチや見た目の変化は発生しません。この2段階のフローが重要になるのは、アトリビューションがまだ処理中の初回起動時のみです。 ::: ## 実装 \{#implementation\} すぐにペイウォールを表示し、`'apple_search_ads'` を監視して届いたらペイウォールをリフレッシュします。 1. **SDKを有効化します。** [React Native SDKのインストールと設定](sdk-installation-reactnative)を参照してください。 2. **通常どおり `getPaywall` でペイウォールを読み込んで表示します。** アトリビューションを待たずに進めてください。 3. **`adapty.addEventListener('onLatestProfileLoad', …)` でプロファイルの更新を購読し**、`'apple_search_ads'` を監視します。現れたらペイウォールを再度フェッチし、更新されたものを表示します。リスナーをまだ設定していない場合は、[サブスクリプション更新のリッスン](react-native-check-subscription-status#listen-to-subscription-updates)を参照してください: ```typescript const subscription = adapty.addEventListener('onLatestProfileLoad', async profile => { if (!profile.appliedAttributionSources?.includes('apple_search_ads')) return; const targeted = await adapty.getPaywall(placementId); // present the targeted paywall in place of the first one }); // Call subscription.remove() after the upgrade, or after a timeout (see below). ``` 4. **タイムアウト後にリッスンを停止します。** ほとんどのユーザーは Apple Ads のアトリビューションを受け取らないため、セッション全体でリスナーを開き続けるのではなく、しばらくしたらリスナーを削除してください。リクエストが失敗した場合でもユーザーに常に何かが表示されるよう、そのプレースメントに[フォールバックペイウォール](react-native-use-fallback-paywalls)を設定してください。 ## 完全な実装例 \{#complete-example\} `onAppleAdsAttribution` は Apple Ads のアトリビューションが適用されると解決し、`timeoutMs` 以内に届かなければ拒否されます。以下の使用例では、すぐにペイウォールを読み込み、アトリビューションが届いたら再フェッチします。Apple Ads ユーザーはターゲット向けのペイウォールを受け取り、アトリビューションが届かなかった場合は最初のペイウォールがそのまま表示されます: ```typescript const APPLE_ADS_SOURCE = 'apple_search_ads'; const placementId = 'YOUR_PLACEMENT_ID'; function hasAppleAdsAttribution(profile: AdaptyProfile): boolean { return profile.appliedAttributionSources?.includes(APPLE_ADS_SOURCE) ?? false; } /** * Resolves once Apple Ads attribution is applied to the profile. * Rejects with a timeout error if attribution never arrives within `timeoutMs`. * Call after `adapty.activate()`. */ export function onAppleAdsAttribution(timeoutMs: number): Promise<void> { return new Promise((resolve, reject) => { let timer: ReturnType<typeof setTimeout> | undefined; let subscription: { remove: () => void } | undefined; const stop = () => { clearTimeout(timer); subscription?.remove(); }; subscription = adapty.addEventListener('onLatestProfileLoad', profile => { if (!hasAppleAdsAttribution(profile)) return; stop(); resolve(); }); timer = setTimeout(() => { stop(); reject(new Error(`Apple Ads attribution timed out after ${timeoutMs}ms`)); }, timeoutMs); }); } let paywall = await adapty.getPaywall(placementId); onAppleAdsAttribution(30_000) .then(() => adapty.getPaywall(placementId)) .then(updated => { paywall = updated; }) .catch(() => { console.log('Apple Ads attribution or loading failed'); }); ``` 初回起動時、Apple Ads ユーザーはデフォルトのペイウォールが置き換わる前に一瞬表示されることがあります。ペイウォールビルダーでペイウォールを表示している場合は、再表示が許容できるかどうかを検討するか、ペイウォールが表示される前にアップグレードを適用してください。`timeoutMs` は、どのくらいの間リッスンし続けるかに合わせて調整してください。届く場合のアトリビューションは通常、起動から数秒以内に届きます。 アプリがすでに別の目的(たとえば[サブスクリプションステータスの確認](react-native-check-subscription-status#listen-to-subscription-updates)など)で `onLatestProfileLoad` をリッスンしている場合は、変更の必要はありません。`adapty.addEventListener` は複数の独立したリスナーをサポートしているため、既存のリスナーに影響を与えることなく、このリスナーを追加できます。 --- # File: react-native-test --- --- title: "React Native SDK でのテストとリリース" description: "Adapty SDK を使って React Native アプリをテスト・リリースする方法を説明します。" --- Adapty SDK を React Native アプリに実装済みの場合、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-react-native --- --- title: "React Native 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** をコピーします。 <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 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) に移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テスト中のプロダクトが **Ready to Submit** になっていることを確認します。 <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 表示されているプロダクト ID と、Adapty ダッシュボードの [**Products**](https://app.adapty.io/products) タブにある ID を照合します。ID が一致しない場合は、表からプロダクト ID をコピーして、Adapty ダッシュボードでその ID を使って[プロダクトを作成](create-product)してください。 <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 3. プロダクトの提供状況を確認する \{#step-4-check-product-availability\} 1. **App Store Connect** に戻り、同じ **Subscriptions** セクションを開きます。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックしてプロダクト一覧を表示します。 3. テスト中のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Availability** セクションまでスクロールし、必要な国・地域がすべて表示されていることを確認します。 <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 4. プロダクトの価格を確認する \{#step-5-check-product-prices\} 1. 再度 **App Store Connect** の **Monetization** → **Subscriptions** セクションに移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックします。 3. テスト中のプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Subscription Pricing** までスクロールし、**Current Pricing for New Subscribers** セクションを展開します。 <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 必要な価格がすべて表示されていることを確認します。 <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 5. アプリの有料ステータス・銀行口座・税務書類がアクティブか確認する \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. [**App Store Connect**](https://appstoreconnect.apple.com/) のホームページで **Business** をクリックします。 <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 会社名を選択します。 <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 下にスクロールして、**Paid Apps Agreement**、**Bank Account**、**Tax forms** がすべて **Active** になっていることを確認します。 <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これらの手順を実行することで、`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-react-native --- --- title: "React Native SDKにおけるCode-1003 cantMakePaymentエラーの修正" description: "AdaptyでサブスクリプションManagerする際の決済エラーを解決する方法。" --- 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-react-native-sdk-v4 --- --- title: "Adapty React Native SDK を v. 4.0 に移行する" description: "ペイウォール API をフロー API に置き換えることで、Adapty React Native SDK v4.0(ベータ版)に移行します。フロービルダーとペイウォールビルダーの両方に対応しています。" --- Adapty React Native SDK 4.0(ベータ版)ではフローが導入され、ペイウォール API の名称が変更されました。新しい API はフロービルダーと既存のペイウォールビルダーの両方に対応しており、Adapty ダッシュボード側での設定変更は不要です。 ## クイックリファレンス \{#quick-reference\} | v3 | v4 | |---|---| | `adapty.getPaywall(placementId, locale?, params?)` | `adapty.getFlow(placementId, params?)` | | `adapty.getPaywallForDefaultAudience(placementId, locale?, params?)` | `adapty.getFlowForDefaultAudience(placementId, params?)` | | `adapty.getPaywallProducts(paywall)` | `adapty.getPaywallProducts(flow)` | | `adapty.logShowPaywall(paywall)` | `adapty.logShowFlow(flow)` | | `AdaptyPaywall`(型) | `AdaptyFlow` | | `createPaywallView(paywall)` | `createFlowView(flow)` | | `AdaptyPaywallView`(コンポーネント) | `AdaptyFlowView` | | `EventHandlers`(型) | `FlowEventHandlers` | | `onPaywallShown` | `onAppeared` | | `onPaywallClosed` | `onDisappeared` | | `onRenderingFailed` | `onError` | `AdaptyPaywallProduct` はその名前を維持しています — プロダクトは引き続きフローに属しており、`getPaywallProducts` は `AdaptyFlow` を引数として受け取るようになりました。`getFlow` および `getFlowForDefaultAudience` メソッドは `locale` パラメータを受け取らなくなりました。ビューメソッドの `present`、`dismiss`、`setEventHandlers`、`showDialog`、およびイベントハンドラの `onCloseButtonPress`、`onUrlPress`、`onCustomAction`、`onProductSelected`、`onPurchaseStarted`、`onPurchaseCompleted`、`onPurchaseFailed`、`onRestoreStarted`、`onRestoreCompleted`、`onRestoreFailed`、`onLoadingProductsFailed`、`onWebPaymentNavigationFinished`、`onAndroidSystemBack` はいずれも v3 と同じ名前を維持しています。デフォルトの動作に一部変更があります — 詳細は[デフォルト動作の変更](#default-behavior-changes)を参照してください。 ## 最低 iOS バージョン \{#minimum-ios-version\} Adapty React Native SDK 4.0 では、iOS の最低デプロイメントターゲットが iOS 13.0 から **iOS 15.0** に引き上げられました。アップグレードの前に、iOS デプロイメントターゲットを 15.0 以降に設定してください。 ## インストール \{#installation\} ### パッケージのアップデート \{#update-the-package\} v4.0 はプレリリース版のため、正確なバージョンを指定してインストールしてください。npm はキャレット/チルダの範囲指定ではプレリリース版を選択しません。 ```bash showLineNumbers npm install react-native-adapty@4.0.0 # or yarn add react-native-adapty@4.0.0 ``` ### iOS:ネイティブ SDK が Swift Package Manager 経由で提供されるようになりました \{#ios-native-sdks-now-come-through-swift-package-manager\} [CocoaPods の spec リポジトリは 2026年12月に読み取り専用になります](https://blog.cocoapods.org/CocoaPods-Specs-Repo/)。そのため、v4 以降、ネイティブの `Adapty`、`AdaptyUI`、`AdaptyPlugin` SDK は **CocoaPods のサブ依存として取得されなくなります** — podspec は **Swift Package Manager** 経由(`spm_dependency` ヘルパーを使用)でこれらを取得します。これにより、以下の 2 点が必要になります: - **React Native 0.75 以降** — `spm_dependency` podspec ヘルパーに必要です。古いバージョンでは `pod install` が明示的なエラーで失敗します。先に React Native をアップグレードするか、`react-native-adapty` 3.x を使用してください。 - **ダイナミックフレームワーク** — SPM の依存関係にはダイナミックリンクが必要です。有効にする方法は Expo とベアの React Native で異なります。 #### Expo [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/) 設定プラグインを追加し、`app.json`(または `app.config.js`)で iOS フレームワークをダイナミックに設定します: ```json showLineNumbers title="app.json" { "expo": { "plugins": [ [ "expo-build-properties", { "ios": { "useFrameworks": "dynamic" } } ] ] } } ``` 次に、プラグインをインストールしてネイティブプロジェクトを再生成します: ```bash showLineNumbers npx expo install expo-build-properties npx expo prebuild --clean ``` #### Bare React Native \{#bare-react-native\} iOS ターゲットにダイナミックフレームワークを追加し、pod を再インストールします: ```ruby showLineNumbers title="ios/Podfile" use_frameworks! :linkage => :dynamic ``` ```bash showLineNumbers cd ios && pod install --repo-update ``` 以前に `Adapty`、`AdaptyUI`、または `AdaptyPlugin` を CocoaPods のサブ依存関係として追加していた場合は、まず `Podfile` から `pod 'Adapty'`、`pod 'AdaptyUI'`、`pod 'AdaptyPlugin'` の行を削除してください。 :::warning デフォルトの静的リンクからダイナミックフレームワークへの切り替えは、モジュラーヘッダーをまだサポートしていないライブラリと競合する可能性があり、Flipper とは互換性がありません。ビルドの問題が発生した場合は、[Swift Package Manager と React Native ライブラリの統合に関する記事](https://www.callstack.com/blog/integrating-swift-package-manager-with-react-native-libraries)を参照してください。 ::: 完全なセットアップ手順については、[Adapty SDK のインストール](sdk-installation-reactnative)を参照してください。 ## フローの取得 \{#fetching-flows\} ### getPaywall → getFlow 返り値の型が `AdaptyPaywall` から `AdaptyFlow` に変更され、`locale` パラメータが削除されました。フローをレンダリングする際、ロケールは自動的に解決されます。カスタムペイウォールの場合、すべてのロケールは `flow.remoteConfigs` で返されます。 ```diff showLineNumbers - const paywall = await adapty.getPaywall('YOUR_PLACEMENT_ID', 'en'); + const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); ``` `getPaywallForDefaultAudience` も同様にリネームされます。 ```diff showLineNumbers - const paywall = await adapty.getPaywallForDefaultAudience('YOUR_PLACEMENT_ID', 'en'); + const flow = await adapty.getFlowForDefaultAudience('YOUR_PLACEMENT_ID'); ``` ### getPaywallProducts(paywall) → getPaywallProducts(flow) `getPaywallProducts` は名前はそのままですが、`AdaptyFlow` を受け取るようになりました: ```diff showLineNumbers - const products = await adapty.getPaywallProducts(paywall); + const products = await adapty.getPaywallProducts(flow); ``` ## データモデル \{#data-model\} `getFlow` は `AdaptyPaywall` の代わりに `AdaptyFlow` を返し、オブジェクトの構造が変わりました: | v3 `AdaptyPaywall` フィールド | v4 `AdaptyFlow` フィールド | 対応方法 | |---|---|---| | `remoteConfig?`(単一) | `remoteConfigs?: AdaptyRemoteConfig[]`(配列) | フローは設定された言語ごとにリモートコンフィグを1つ持ちます。ユーザーに合ったものを取得するには `flow.remoteConfigs?.find((c) => c.lang === 'en')` を使用してください。 | | `products` | `flow.paywalls[i].productIdentifiers` | プロダクト識別子はフロー全体ではなく、各フローバリエーションに移動しました。 | | `webPurchaseUrl?` | `flow.paywalls[i].webPurchaseUrl` | フローからペイウォールの各バリエーションに移動しました。 | | `version?: number` | `flowVersionId?: string` | 名前が変更され、型も `number` から `string` になりました。 | | `hasViewConfiguration` | 削除 | コードから `hasViewConfiguration` のチェックをすべて削除してください。 | | `requestLocale` | 削除 | ロケールはモデルに含まれなくなりました。 | | _(新規)_ | `paywalls: AdaptyFlowPaywall[]` | 各エントリはフロー内のペイウォールバリエーション1つに対応します。 | | _(新規)_ | `responseCreatedAt: number` | サーバーレスポンスのタイムスタンプ(ミリ秒単位)。 | プロダクト識別子がフローから各バリアントに移動しました: ```diff showLineNumbers - const ids = paywall.products; + const ids = flow.paywalls[0].productIdentifiers; ``` ## Webペイウォールのメソッド \{#web-paywall-methods\} `openWebPaywall` と `createWebPaywallUrl` はメソッド名を変更しませんが、第1引数が `AdaptyPaywall` の代わりに `AdaptyFlowPaywall`(フローのバリアント)になりました。引き続き `AdaptyPaywallProduct` も渡せます。 ```diff showLineNumbers const flow = await adapty.getFlow('YOUR_PLACEMENT_ID'); - await adapty.openWebPaywall(paywall); + await adapty.openWebPaywall(flow.paywalls[0]); ``` ## フローのビュー数を計測する \{#tracking-flow-views\} ### logShowPaywall → logShowFlow `logShowPaywall` は `logShowFlow` に名称変更され、`AdaptyFlow` を受け取るようになりました。イベントは引き続き同じバリエーションに対してログが記録されるため、既存のファネルや A/B テストの指標はダッシュボードの変更なしに引き続き機能します。 ```diff showLineNumbers - await adapty.logShowPaywall(paywall); + await adapty.logShowFlow(flow); ``` v3 と同様に、[フロービルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)でレンダリングされたフローやペイウォールを表示する際は、このメソッドを呼び出す必要はありません。Adapty がそれらのビューを自動的に追跡します。 ## フローの表示 \{#displaying-flows\} ### createPaywallView → createFlowView ファクトリー関数の名前を変更し、`AdaptyFlow` を渡します。返されるコントローラーのメソッド(`present`、`dismiss`、`setEventHandlers`、`showDialog`)は変わりません: ```diff showLineNumbers - import { createPaywallView } from 'react-native-adapty'; + import { createFlowView } from 'react-native-adapty'; - const view = await createPaywallView(paywall); + const view = await createFlowView(flow); await view.present(); ``` ### AdaptyPaywallView → AdaptyFlowView Reactコンポーネントでレンダリングする場合は、名前を変更して `flow` プロップを渡してください: ```diff showLineNumbers - import { AdaptyPaywallView } from 'react-native-adapty'; + import { AdaptyFlowView } from 'react-native-adapty'; - <AdaptyPaywallView paywall={paywall} /* … */ /> + <AdaptyFlowView flow={flow} /* … */ /> ``` :::note `createFlowView` で作成したフロービューは使い捨てです。`dismiss()` を呼び出すとビューが破棄されるため、フローを再度表示するには `createFlowView` を再度呼び出してください。埋め込み型の `AdaptyFlowView` はアンマウントすることで閉じられます。ハンドラーから `true` を返しても埋め込みビューは閉じないため、`onCloseButtonPress` などで自分自身の状態を変更してください。 ::: ## イベントの処理 \{#handling-events\} イベントハンドラーのインターフェース名が `EventHandlers` から `FlowEventHandlers` に変更され、3つのコールバックも名前が変わりました。既存のハンドラーの中身はそのままで、名前だけ変更してください。 ```diff showLineNumbers - onPaywallShown: () => { /* … */ }, + onAppeared: () => { /* … */ }, - onPaywallClosed: () => { /* … */ }, + onDisappeared: () => { /* … */ }, - onRenderingFailed: (error) => { /* … */ }, + onError: (error) => { /* … */ }, ``` 他のすべてのイベントハンドラーは名前が変わりません。また、2つのハンドラーは第2引数が追加されました:`onPurchaseCompleted` は `(purchaseResult, product)`、`onPurchaseFailed` は `(error, product)` となり、`product` は対象の `AdaptyPaywallProduct` です。完全な一覧は[フロー・ペイウォールイベントの処理](react-native-handling-events-1)を参照してください。 :::note `onDisappeared` は、`createFlowView().present()` でモーダル表示されたフローにのみ発火します。`AdaptyFlowView` コンポーネントはこれをプロップとして公開していないため、組み込みビューを閉じるにはアンマウントしてください。 ::: v4ではさらに、オプトインで使用できる機能がいくつか追加されています: - `adapty.openWebUrl(url, openIn?)` および `adapty.requestAppReview()` メソッド — これらはデフォルトの `onUrlPress` および `onRequestAppReview` ハンドラーを支えており、URLおよびアプリレビューのプロンプトはそのままネイティブで処理されます。これらのハンドラーをオーバーライドする場合にのみ、直接呼び出してください。 - フロー内のオブザーバーモードによる購入処理は、新しい `onObserverPurchaseInitiated` / `onObserverRestoreInitiated` ハンドラーを使用します。詳しくは[オブザーバーモードでの購入処理](react-native-handling-events-1#handle-purchases-in-observer-mode)をご覧ください。 ## 削除・非推奨のAPI \{#removed-and-deprecated-apis\} ### setFallbackPaywalls → setFallback `setFallbackPaywalls` は削除されました。代わりに同じ引数を受け取る `setFallback` を使用してください: ```diff showLineNumbers - await adapty.setFallbackPaywalls(fileLocation); + await adapty.setFallback(fileLocation); ``` ### 削除されたエクスポート \{#removed-exports\} 以下のシンボルは `react-native-adapty` からエクスポートされなくなりました。これらのインポートは削除してください: - **`AdaptyPaywall`**: 代わりに `AdaptyFlow` を使用してください。 - **`ProductReference`**: 代わりに `AdaptyProductIdentifier` を使用し、`flow.paywalls[i].productIdentifiers` から読み取ってください。 - **`AdaptyPaywallBuilder`**: 削除されました。フローとペイウォールはネイティブでレンダリングされます。 - **`AdaptyAndroidSubscriptionUpdateParameters`**: ネストされた `subscriptionUpdateParams` の形式を使用してください(下記参照)。 ### activate: lockMethodsUntilReady `lockMethodsUntilReady` は削除され、この動作は常に有効になりました。`activate` の呼び出しから削除してください。残しているとコンパイルエラーになります: ```diff showLineNumbers - await adapty.activate('PUBLIC_SDK_KEY', { lockMethodsUntilReady: true }); + await adapty.activate('PUBLIC_SDK_KEY'); ``` ### makePurchase: Android サブスクリプションの更新 \{#makepurchase-android-subscription-update\} フラットな Android サブスクリプション更新の形式は廃止されました。`oldSubVendorProductId` と `prorationMode` をネストされた `subscriptionUpdateParams` オブジェクトに移動し、`isOfferPersonalized` はトップレベルに残してください。完全な例については[購入の実装](react-native-making-purchases)を参照してください。 ### Android: セーフエリアのパディング \{#android-safe-area-paddings\} Android のブール型リソース `<bool name="adapty_paywall_enable_safe_area_paddings">…</bool>` は削除されました。`res/values/bools.xml` からこのリソースを削除し、フロービューを作成する際に `enableSafeArea` パラメータを使ってセーフエリアのパディングをランタイムで制御してください。デフォルト値は、モーダル表示の場合は `true`、埋め込みコンポーネントの場合は `false` です。 ### モックモード \{#mock-mode\} モックモード(Expo Go またはウェブプレビュー)で SDK を実行する場合は、モックコンフィグのキー `paywalls` を `flows` に変更してください。 ## デフォルト動作の変更点 \{#default-behavior-changes\} これらの変更はコンパイルエラーを引き起こしませんが、実行時にテストしてください: - **`onAndroidSystemBack`**: デフォルトの動作が、ビューを閉じる動作からビューを開いたまま維持する動作に変更されました。以前の動作を復元するには、ハンドラーから `true` を返してください。 - **`onPurchaseCompleted`**: デフォルトの動作が、ビューを閉じる動作(ユーザーが購入をキャンセルした場合を除く)から、常にビューを開いたまま維持する動作に変更されました。以前の動作を復元するには、ハンドラーから `purchaseResult.type !== 'user_cancelled'` を返してください。 - **`onRestoreCompleted`**: デフォルトの動作が、復元成功後にビューを閉じる動作からビューを開いたまま維持する動作に変更されました。以前の動作を復元するには、ハンドラーから `true` を返してください。 - **`onUrlPress`**: デフォルトの動作が変更され、ダッシュボードのアプリ内ブラウザまたは外部ブラウザの設定に従い、ネイティブレイヤーを通じてURLを開くようになりました。URLを独自に開くには、ハンドラーをオーバーライドしてください。 ## オンボーディング API の非推奨化 \{#onboarding-api-deprecation\} レガシーオンボーディング API は、[Flow Builder](adapty-flow-builder) への移行に伴い v4.0 で非推奨となりました。引き続き動作はしますが、IDE は `@deprecated` アノテーションを通じて非推奨のシンボルを警告します(実行時の警告はありません)。これらのシンボルは将来のリリースで削除される予定ですので、オンボーディングの Flow Builder への移行を計画してください。 非推奨のシンボル: `getOnboarding`、`getOnboardingForDefaultAudience`、`createOnboardingView`、`AdaptyOnboardingView`。 --- # File: migration-react-native-314 --- --- title: "Adapty React Native SDK を v3.14 に移行する" description: "Adapty React Native SDK v3.14 に移行して、パフォーマンスの向上と新しいマネタイズ機能を活用しましょう。" --- Adapty React Native SDK 3.14.0 はメジャーリリースであり、以下の対応が必要な変更が含まれています: - `registerEventHandlers` メソッドが `setEventHandlers` メソッドに置き換えられました。 - `AdaptyOnboardingView` では、イベントハンドラーが `eventHandlers` オブジェクトではなく個別の props として渡されるようになりました。 - UI コンポーネント向けの新しいシンプルなインポート方法が導入されました。 - `logShowOnboarding` メソッドが削除されました。 - React Native の最低バージョンが 0.73.0 に更新されました。 - ペイウォールとオンボーディングの iOS デフォルト表示スタイルがページシートからフルスクリーンに変更されました。 ## `registerEventHandlers` を `setEventHandlers` に置き換える \{#replace-registereventhandlers-with-seteventhandlers\} Adapty ペイウォールビルダーおよびオンボーディングビルダーで使用されていた `registerEventHandlers` メソッドが `setEventHandlers` メソッドに置き換えられました。 Adapty ペイウォールビルダーやオンボーディングビルダーを使用している場合は、アプリのコード内で `registerEventHandlers` を見つけて `setEventHandlers` に置き換えてください。 この変更はメソッドの動作をより明確にするために行われました。ハンドラーは `true`/`false` を返すため、1 つずつ処理されます。1 つのイベントに複数のハンドラーを設定すると、結果の動作が不明確になっていたためです。 `AdaptyOnboardingView` や `AdaptyPaywallView` などの React コンポーネントを使用する場合、自分自身の状態管理でコンポーネントの表示を制御するため、イベントハンドラーから `true`/`false` を返す必要はありません。戻り値が必要なのは、SDK がビューのライフサイクルを管理するモーダル画面表示の場合のみです。 :::important `setEventHandlers` を複数回呼び出すと、指定したハンドラーが上書きされ、デフォルトおよびそれ以前に設定したハンドラーが置き換えられます。 ::: ```diff showLineNumbers - const unsubscribe = view.registerEventHandlers({ - // your event handlers - }) const unsubscribe = view.setEventHandlers({ // your event handlers }) ``` ## UI コンポーネントのインポートパスを更新する \{#update-import-paths-for-ui-components\} Adapty SDK 3.14.0 では、UI コンポーネント向けのシンプルなインポート方法が導入されました。`react-native-adapty/dist/ui` からインポートする代わりに、`react-native-adapty` から直接インポートできるようになりました。 新しいインポート方法は標準的な React Native の慣行に沿っており、インポート文がよりシンプルになります。`AdaptyPaywallView` や `AdaptyOnboardingView` などの UI コンポーネントを使用している場合は、以下のようにインポートを更新してください: ```diff showLineNumbers - import { AdaptyPaywallView } from 'react-native-adapty/dist/ui'; + import { AdaptyPaywallView } from 'react-native-adapty'; - import { AdaptyOnboardingView } from 'react-native-adapty/dist/ui'; + import { AdaptyOnboardingView } from 'react-native-adapty'; - import { createPaywallView } from 'react-native-adapty/dist/ui'; + import { createPaywallView } from 'react-native-adapty'; - import { createOnboardingView } from 'react-native-adapty/dist/ui'; + import { createOnboardingView } from 'react-native-adapty'; ``` :::note 後方互換性のため、旧インポート方法(`react-native-adapty/dist/ui`)は引き続きサポートされています。ただし、一貫性と明確さのために新しいインポート方法の使用を推奨します。 ::: ## React コンポーネントのオンボーディングイベントハンドラーを更新する \{#update-onboarding-event-handlers-in-the-react-component\} オンボーディングのイベントハンドラーが、`AdaptyOnboardingView` の `eventHandlers` オブジェクトの外に移動されました。`AdaptyOnboardingView` を使用してオンボーディングを表示している場合は、イベント処理の構造を更新してください。 :::important イベントハンドラーの実装方法に注意してください。レンダリングのたびにオブジェクトが再生成されないようにするため、イベントを処理する関数には `useCallback` を使用してください。 ::: ```diff showLineNumbers import React, { useCallback } from 'react'; - import { AdaptyOnboardingView } from 'react-native-adapty/dist/ui'; + import { AdaptyOnboardingView } from 'react-native-adapty'; + import type { OnboardingEventHandlers } from 'react-native-adapty'; + + function MyOnboarding({ onboarding }) { + const onAnalytics = useCallback<OnboardingEventHandlers['onAnalytics']>((event, meta) => {}, []); + const onClose = useCallback<OnboardingEventHandlers['onClose']>((actionId, meta) => {}, []); + const onCustom = useCallback<OnboardingEventHandlers['onCustom']>((actionId, meta) => {}, []); + const onPaywall = useCallback<OnboardingEventHandlers['onPaywall']>((actionId, meta) => {}, []); + const onStateUpdated = useCallback<OnboardingEventHandlers['onStateUpdated']>((action, meta) => {}, []); + const onFinishedLoading = useCallback<OnboardingEventHandlers['onFinishedLoading']>((meta) => {}, []); + const onError = useCallback<OnboardingEventHandlers['onError']>((error) => {}, []); + return ( <AdaptyOnboardingView onboarding={onboarding} style={styles.container} - eventHandlers={{ - onAnalytics(event, meta) { /* ... */ }, - onClose(actionId, meta) { /* ... */ }, - onCustom(actionId, meta) { /* ... */ }, - onPaywall(actionId, meta) { /* ... */ }, - onStateUpdated(action, meta) { /* ... */ }, - onFinishedLoading(meta) { /* ... */ }, - onError(error) { /* ... */ }, - }} + onAnalytics={onAnalytics} + onClose={onClose} + onCustom={onCustom} + onPaywall={onPaywall} + onStateUpdated={onStateUpdated} + onFinishedLoading={onFinishedLoading} + onError={onError} /> ); + } ``` :::note 後方互換性のため、`eventHandlers` プロパティは引き続きサポートされていますが、非推奨となっています。上記のように個別のイベントハンドラープロパティへの移行を推奨します。 ::: ## `logShowOnboarding` を削除する \{#delete-logshowonboarding\} Adapty SDK 3.14.0 では、`logShowOnboarding` メソッドが SDK から削除されました。 このメソッドを使用していた場合、SDK をバージョン 3.14 以降にアップグレードすると利用できなくなります。 代わりに、[Adapty のノーコードオンボーディングビルダーでオンボーディングを作成](onboardings)できます。これらのオンボーディングのアナリティクスは自動的に追跡され、多くのカスタマイズオプションも利用できます。 ## React Native を更新する \{#update-react-native\} Adapty SDK 3.14.0 以降、React Native の最低サポートバージョンは 0.73.0 となります。それ以前のバージョンを使用している場合は、React Native を 0.73.0 以降に更新して、Adapty SDK を安定して利用できるようにしてください。 ## モーダルペイウォールとオンボーディングの iOS 表示スタイルを更新する \{#update-ios-presentation-style-for-modal-paywalls-and-onboardings\} Adapty SDK 3.14.0 では、`view.present()` メソッドを使用して表示するペイウォールとオンボーディングの iOS デフォルト表示スタイルがページシートからフルスクリーンに変更されました。 以前のページシート表示スタイルを維持したい場合は、`present()` メソッドに `iosPresentationStyle` パラメーターを渡してください: ```typescript showLineNumbers title="React Native (TSX)" try { await view.present({ iosPresentationStyle: 'page_sheet' }); } catch (error) { // handle the error } ``` --- # File: react-native-migration-guide-380 --- --- title: "Adapty React Native SDK を v3.8 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty React Native SDK v3.8 に移行する。" --- Adapty SDK 3.8.0 はメジャーリリースであり、いくつかの改善が含まれていますが、移行手順が必要になる場合があります。 ## プレースメント取得パラメータの入力型を更新する \{#update-input-type-for-getting-placement-params\} `GetPaywallParamsInput` は `GetPlacementParamsInput` に名称変更されました: ```diff showLineNumbers - type GetPaywallParamsInput = { + type GetPlacementParamsInput = { placementId: string; locale?: string; fetchPolicy?: AdaptyPlacementFetchPolicy; loadTimeoutMs?: number; } ``` ## フォールバックメソッドを更新する \{#update-fallback-method\} フォールバックを設定するメソッドが更新され、フォールバックの場所を指定する型の名前が変更されました: ```diff showLineNumbers - adapty.setFallbackPaywalls(paywallsLocation: Input.FallbackPaywallsLocation); + adapty.setFallback(fileLocation: Input.FileLocation); ``` ## ペイウォールプロパティへのアクセスを更新する \{#update-paywall-property-access\} 以下のプロパティが `AdaptyPaywall` から `AdaptyPlacement` に移動されました: ```diff showLineNumbers - paywall.abTestName - paywall.audienceName - paywall.revision - paywall.placementId + paywall.placement.abTestName + paywall.placement.audienceName + paywall.placement.revision + paywall.placement.id ``` --- # File: migration-to-react-native-sdk-34 --- --- title: "Adapty React Native SDK を v3.4 に移行する" description: "Adapty React Native SDK v3.4 に移行して、パフォーマンスの向上と新しいマネタイズ機能を活用しましょう。" --- Adapty SDK 3.4.0 はメジャーリリースであり、移行作業が必要な改善が含まれています。 ## フォールバックペイウォールファイルの更新 \{#update-fallback-paywall-files\} 新しい SDK バージョンとの互換性を確保するために、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新されたフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換え](react-native-use-fallback-paywalls)ます。 ## Observer Mode の実装を更新する \{#update-implementation-of-observer-mode\} Observer Mode を使用している場合は、その実装を更新してください。 以前は、トランザクションを Adapty に報告するために異なるメソッドが使用されていました。新しいバージョンでは、Android と iOS の両方で `reportTransaction` メソッドを一貫して使用する必要があります。このメソッドは各トランザクションを Adapty に明示的に報告し、認識されるようにします。ペイウォールを使用した場合は、バリエーション ID を渡してトランザクションをそのペイウォールに紐付けてください。 :::warning **トランザクションの報告を省略しないでください!** `reportTransaction` を呼び出さない場合、Adapty はトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: ```diff showLineNumbers - if (Platform.OS === 'android') { - try { - await adapty.restorePurchases(); - } catch (error) { - // handle the error - } - } const variationId = paywall.variationId; try { await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` --- # File: migration-to-react-native330 --- --- title: "Adapty React Native SDK を v3.3 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty React Native SDK v3.3 に移行する。" --- Adapty SDK 3.3.1 はメジャーリリースであり、いくつかの改善が加えられています。移行作業が必要な場合があります。 1. Adapty SDK v3.3.x にアップグレードする。 2. モデルを更新する。 3. `getProductsIntroductoryOfferEligibility` メソッドを削除する。 4. 購入処理を更新する。 5. ペイウォールビルダーのペイウォール表示を更新する。 6. 開発者定義タイマーの実装を修正する。 7. ペイウォールビルダーの購入イベント処理を更新する。 8. ペイウォールビルダーのカスタムアクションイベント処理を更新する。 9. `onProductSelected` コールバックを修正する。 10. `updateProfile` メソッドからサードパーティ連携パラメーターを削除する。 11. Adjust、AirBridge、Amplitude、AppMetrica、Appsflyer、Branch、Facebook Ads、Firebase と Google Analytics、Mixpanel、OneSignal、Pushwoosh の連携設定を更新する。 12. オブザーバーモードの実装を更新する。 ## Adapty React Native SDK を 3.3.x にアップグレードする \{#upgrade-adapty-react-native-sdk-to-33x\} バージョン 3.3.1 より前は、`react-native-adapty` SDK がアプリで Adapty を正しく動作させるためのコアかつ必須の SDK でした。`@adapty/react-native-ui` SDK はオプションであり、Adapty ペイウォールビルダーを使用する場合にのみ必要でした。 バージョン 3.3.1 以降、`@adapty/react-native-ui` SDK は非推奨となり、その機能は `react-native-adapty` SDK に統合されました。バージョン 3.3.1 にアップグレードするには、以下の手順に従ってください。 1. `react-native-adapty` パッケージをバージョン 3.3.1 に更新する。 2. プロジェクトの依存関係から `@adapty/react-native-ui` パッケージを削除する。 3. プロジェクトの依存関係を同期して変更を適用する。 ## モデルの変更点 \{#changes-in-models\} ### 新しいモデル \{#new-models\} 1. [AdaptySubscriptionOffer](https://react-native.adapty.io/interfaces/adaptysubscriptionoffer): ```typescript showLineNumbers export interface AdaptySubscriptionOffer { readonly identifier: AdaptySubscriptionOfferId; phases: AdaptyDiscountPhase[]; android?: { offerTags?: string[]; }; } ``` 2. [AdaptySubscriptionOfferId](https://react-native.adapty.io/types/adaptysubscriptionofferid): ```typescript showLineNumbers export type AdaptySubscriptionOfferId = | { id?: string; type: 'introductory'; } | { id: string; type: 'promotional' | 'win_back'; }; ``` ### 変更されたモデル \{#changed-models\} 1. [AdaptyPaywallProduct](https://react-native.adapty.io/interfaces/adaptypaywallproduct): - `subscriptionDetails` プロパティを `subscription` に名前変更しました。 <p> </p> ```diff showLineNumbers - subscriptionDetails?: AdaptySubscriptionDetails; + subscription?: AdaptySubscriptionDetails; ``` 2. [AdaptySubscriptionDetails](https://react-native.adapty.io/interfaces/adaptysubscriptiondetails): - `promotionalOffer` は削除されました。プロモーションオファーは、利用可能な場合にのみ `offer` プロパティ経由で提供されるようになりました。この場合、`offer?.identifier?.type` は `'promotional'` になります。 - `introductoryOfferEligibility` は削除されました(オファーはユーザーが対象の場合のみ返されます)。 - `offerId` は削除されました。オファー ID は `AdaptySubscriptionOffer.identifier` に格納されるようになりました。 - `offerTags` は `AdaptySubscriptionOffer.android` に移動されました。 <p> </p> ```diff showLineNumbers - introductoryOffers?: AdaptyDiscountPhase[]; + offer?: AdaptySubscriptionOffer; ios?: { - promotionalOffer?: AdaptyDiscountPhase; subscriptionGroupIdentifier?: string; }; android?: { - offerId?: string; basePlanId: string; - introductoryOfferEligibility: OfferEligibility; - offerTags?: string[]; renewalType?: 'prepaid' | 'autorenewable'; }; } ``` 3. [AdaptyDiscountPhase](https://react-native.adapty.io/interfaces/adaptydiscountphase): - `identifier` フィールドが `AdaptyDiscountPhase` モデルから削除されました。オファー識別子は `AdaptySubscriptionOffer.identifier` に格納されるようになりました。 <p> </p> ```diff showLineNumbers - ios?: { - readonly identifier?: string; - }; ``` ### 削除されたモデル \{#remove-models\} 1. `AttributionSource`: - `AttributionSource` が以前使用されていた箇所では、文字列が使用されるようになりました。 2. `OfferEligibility`: - このモデルは不要になったため削除されました。オファーはユーザーが対象の場合にのみ返されるようになりました。 ## `getProductsIntroductoryOfferEligibility` メソッドを削除する \{#remove-getproductsintroductoryoffereligibility-method\} Adapty SDK 3.3.1 より前は、プロダクトオブジェクトにはユーザーが対象外であってもオファーが常に含まれていました。そのため、オファーを使用する前に手動で対象資格を確認する必要がありました。 バージョン 3.3.1 以降、プロダクトオブジェクトにはユーザーが対象の場合にのみオファーが含まれます。これにより、オファーが存在する場合はユーザーが対象であると仮定できるため、処理が簡素化されます。 ## 購入処理を更新する \{#update-making-purchase\} 以前のバージョンでは、キャンセルされた購入と保留中の購入はエラーとして扱われ、それぞれコード `2: 'paymentCancelled'` と `25: 'pendingPurchase'` が返されていました。 バージョン 3.3.1 以降、キャンセルされた購入と保留中の購入は成功した結果として扱われ、それに応じて処理する必要があります。 ```typescript showLineNumbers try { const purchaseResult = await adapty.makePurchase(product); switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; } } catch (error) { // Handle the error } ``` ## ペイウォールビルダーのペイウォール表示を更新する \{#update-paywall-builder-paywall-presentation\} 更新されたコード例については、[React Native でのペイウォールビルダーペイウォールの表示](react-native-present-paywalls)ドキュメントをご参照ください。 ```diff showLineNumbers - import { createPaywallView } from '@adapty/react-native-ui'; + import { createPaywallView } from 'react-native-adapty/dist/ui'; const view = await createPaywallView(paywall); view.registerEventHandlers(); // handle close press, etc try { await view.present(); } catch (error) { // handle the error } ``` ## 開発者定義タイマーの実装を更新する \{#update-developer-defined-timer-implementation\} `timerInfo` パラメーターを `customTimers` に名前変更してください。 ```diff showLineNumbers - let timerInfo = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } + let customTimers = { 'CUSTOM_TIMER_NY': new Date(2025, 0, 1) } //and then you can pass it to createPaywallView as follows: - view = await createPaywallView(paywall, { timerInfo }) + view = await createPaywallView(paywall, { customTimers }) ``` ## ペイウォールビルダーの購入イベントを修正する \{#modify-paywall-builder-purchase-events\} 以前の動作: - キャンセルされた購入は `onPurchaseCancelled` コールバックをトリガーしていました。 - 保留中の購入はエラーコード `25: 'pendingPurchase'` を返していました。 現在の動作: - 両方とも `onPurchaseCompleted` コールバックで処理されます。 #### 移行手順: 1. `onPurchaseCancelled` コールバックを削除する。 2. `25: 'pendingPurchase'` のエラーコード処理を削除する。 3. `onPurchaseCompleted` コールバックを更新する。 ```typescript showLineNumbers const view = await createPaywallView(paywall); const unsubscribe = view.registerEventHandlers({ // ... other optional callbacks onPurchaseCompleted(purchaseResult, product) { switch (purchaseResult.type) { case 'success': const isSubscribed = purchaseResult.profile?.accessLevels['YOUR_ACCESS_LEVEL']?.isActive; if (isSubscribed) { // Grant access to the paid features } break; // highlight-start case 'user_cancelled': // Handle the case where the user canceled the purchase break; case 'pending': // Handle deferred purchases (e.g., the user will pay offline with cash) break; // highlight-end } // highlight-start return purchaseResult.type !== 'user_cancelled'; // highlight-end }, }); ``` ## ペイウォールビルダーのカスタムアクションイベントを修正する \{#modify-paywall-builder-custom-action-events\} 削除されたコールバック: - `onAction` - `onCustomEvent` 追加されたコールバック: - 新しい `onCustomAction(actionId)` コールバック。カスタムアクションに使用してください。 ## `onProductSelected` コールバックを修正する \{#modify-onproductselected-callback\} 以前は、`onProductSelected` は `product` オブジェクトを必要としていました。現在は文字列として `productId` を必要とします。 ## `updateProfile` メソッドからサードパーティ連携パラメーターを削除する \{#remove-third-party-integration-parameters-from-updateprofile-method\} サードパーティ連携の識別子は、`setIntegrationIdentifier` メソッドを使用して設定するようになりました。`updateProfile` メソッドはこれらを受け付けなくなりました。 ## サードパーティ連携 SDK の設定を更新する \{#update-third-party-integration-sdk-configuration\} Adapty React Native SDK 3.3.1 以降で連携が正しく機能するよう、以下のセクションで説明する各連携の SDK 設定を更新してください。 また、アトリビューション識別子の取得に `AttributionSource` を使用していた場合は、必要な識別子を文字列として提供するようにコードを変更してください。 ### Adjust \{#adjust\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Adjust 連携の SDK 設定](adjust#connect-your-app-to-adjust)をご確認ください。 ```diff showLineNumbers import { Adjust, AdjustConfig } from "react-native-adjust"; import { adapty } from "react-native-adapty"; var adjustConfig = new AdjustConfig(appToken, environment); // Before submiting Adjust config... adjustConfig.setAttributionCallbackListener(attribution => { // Make sure Adapty SDK is activated at this point // You may want to lock this thread awaiting of `activate` adapty.updateAttribution(attribution, "adjust"); }); // ... Adjust.create(adjustConfig); + Adjust.getAdid((adid) => { + if (adid) + adapty.setIntegrationIdentifier("adjust_device_id", adid); + }); ``` ### AirBridge \{#airbridge\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AirBridge 連携の SDK 設定](airbridge#connect-your-app-to-airbridge)をご確認ください。 ```diff showLineNumbers import Airbridge from 'airbridge-react-native-sdk'; import { adapty } from 'react-native-adapty'; try { const deviceId = await Airbridge.state.deviceUUID(); - await adapty.updateProfile({ - airbridgeDeviceId: deviceId, - }); + await adapty.setIntegrationIdentifier("airbridge_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` ### Amplitude \{#amplitude\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Amplitude 連携の SDK 設定](amplitude#sdk-configuration)をご確認ください。 ```diff showLineNumbers import { adapty } from 'react-native-adapty'; try { - await adapty.updateProfile({ - amplitudeDeviceId: deviceId, - amplitudeUserId: userId, - }); + await adapty.setIntegrationIdentifier("amplitude_device_id", deviceId); + await adapty.setIntegrationIdentifier("amplitude_user_id", userId); } catch (error) { // handle `AdaptyError` } ``` ### AppMetrica \{#appmetrica\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppMetrica 連携の SDK 設定](appmetrica#sdk-configuration)をご確認ください。 ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import AppMetrica, { DEVICE_ID_KEY, StartupParams, StartupParamsReason } from '@appmetrica/react-native-analytics'; // ... const startupParamsCallback = async ( params?: StartupParams, reason?: StartupParamsReason ) => { const deviceId = params?.deviceId if (deviceId) { try { - await adapty.updateProfile({ - appmetricaProfileId: 'YOUR_ADAPTY_CUSTOMER_USER_ID', - appmetricaDeviceId: deviceId, - }); + await adapty.setIntegrationIdentifier("appmetrica_profile_id", 'YOUR_ADAPTY_CUSTOMER_USER_ID'); + await adapty.setIntegrationIdentifier("appmetrica_device_id", deviceId); } catch (error) { // handle `AdaptyError` } } } AppMetrica.requestStartupParams(startupParamsCallback, [DEVICE_ID_KEY]) ``` ### AppsFlyer \{#appsflyer\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppsFlyer 連携の SDK 設定](appsflyer#connect-your-app-to-appsflyer)をご確認ください。 ```diff showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import appsFlyer from 'react-native-appsflyer'; appsFlyer.onInstallConversionData(installData => { try { - const networkUserId = appsFlyer.getAppsFlyerUID(); - adapty.updateAttribution(installData, AttributionSource.AppsFlyer, networkUserId); + const uid = appsFlyer.getAppsFlyerUID(); + adapty.setIntegrationIdentifier("appsflyer_id", uid); + adapty.updateAttribution(installData, "appsflyer"); } catch (error) { // handle the error } }); // ... appsFlyer.initSdk(/*...*/); ``` ### Branch \{#branch\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Branch 連携の SDK 設定](branch#connect-your-app-to-branch)をご確認ください。 ```diff showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import branch from 'react-native-branch'; branch.subscribe({ enComplete: ({ params, }) => { - adapty.updateAttribution(params, AttributionSource.Branch); + adapty.updateAttribution(params, "branch"); }, }); ``` ### Facebook Ads \{#facebook-ads\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Facebook Ads 連携の SDK 設定](facebook-ads#connect-your-app-to-facebook-ads)をご確認ください。 ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import { AppEventsLogger } from 'react-native-fbsdk-next'; try { const anonymousId = await AppEventsLogger.getAnonymousID(); - await adapty.updateProfile({ - facebookAnonymousId: anonymousId, - }); + await adapty.setIntegrationIdentifier("facebook_anonymous_id", anonymousId); } catch (error) { // handle `AdaptyError` } ``` ### Firebase と Google Analytics \{#firebase-and-google-analytics\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Firebase と Google Analytics 連携の SDK 設定](firebase-and-google-analytics)をご確認ください。 ```diff showLineNumbers import analytics from '@react-native-firebase/analytics'; import { adapty } from 'react-native-adapty'; try { const appInstanceId = await analytics().getAppInstanceId(); - await adapty.updateProfile({ - firebaseAppInstanceId: appInstanceId, - }); + await adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId); } catch (error) { // handle `AdaptyError` } ``` ### Mixpanel \{#mixpanel\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Mixpanel 連携の SDK 設定](mixpanel#sdk-configuration)をご確認ください。 ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import { Mixpanel } from 'mixpanel-react-native'; // ... try { - await adapty.updateProfile({ - mixpanelUserId: mixpanelUserId, - }); + await adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelUserId); } catch (error) { // handle `AdaptyError` } ``` ### OneSignal \{#onesignal\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[OneSignal 連携の SDK 設定](onesignal#sdk-configuration)をご確認ください。 <Tabs groupId="current-os" queryString> <TabItem value="v5+" label="OneSignal SDK v5+ (current)" default> ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import OneSignal from 'react-native-onesignal'; OneSignal.User.pushSubscription.addEventListener('change', (subscription) => { const subscriptionId = subscription.current.id; if (subscriptionId) { - adapty.updateProfile({ - oneSignalSubscriptionId: subscriptionId, - }); + adapty.setIntegrationIdentifier("one_signal_subscription_id", subscriptionId); } }); ``` </TabItem> <TabItem value="pre-v5" label="OneSignal SDK v. up to 4.x (legacy)" default> ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import OneSignal from 'react-native-onesignal'; OneSignal.addSubscriptionObserver(event => { const playerId = event.to.userId; - adapty.updateProfile({ - oneSignalPlayerId: playerId, - }); + adapty.setIntegrationIdentifier("one_signal_player_id", playerId); }); ``` </TabItem> </Tabs> ### Pushwoosh \{#pushwoosh\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Pushwoosh 連携の SDK 設定](pushwoosh#sdk-configuration)をご確認ください。 ```diff showLineNumbers import { adapty } from 'react-native-adapty'; import Pushwoosh from 'pushwoosh-react-native-plugin'; // ... try { - await adapty.updateProfile({ - pushwooshHWID: hwid, - }); + await adapty.setIntegrationIdentifier("pushwoosh_hwid", hwid); } catch (error) { // handle `AdaptyError` } ``` ## オブザーバーモードの実装を更新する \{#update-observer-mode-implementation\} ペイウォールとトランザクションのリンク方法を更新してください。以前は `setVariationId` メソッドを使用して `variationId` を割り当てていました。現在は、新しい `reportTransaction` メソッドを使用してトランザクションを記録する際に `variationId` を直接含めることができます。最終的なコード例については、[オブザーバーモードでペイウォールを購入トランザクションに関連付ける](report-transactions-observer-mode-react-native)をご確認ください。 :::warning `reportTransaction` メソッドを使用してトランザクションを記録することを忘れないでください。この手順をスキップすると、Adapty はトランザクションを認識できず、アクセスレベルの付与、アナリティクスへの反映、連携へのデータ送信が行われません。この手順は必須です! ::: :::note `reportTransaction` メソッドのパラメーターの順序は `setVariationId` メソッドの順序と異なることにご注意ください。 ::: ```diff showLineNumbers const variationId = paywall.variationId; try { - await adapty.setVariationId(variationId, transactionId); + await adapty.reportTransaction(transactionId, variationId); } catch (error) { // handle the `AdaptyError` } ``` --- # File: migration-to-react-native-sdk-v3 --- --- title: "Adapty React Native SDK を v3.0 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty React Native SDK v3.0 に移行します。" --- Adapty SDK v3.0 では、ペイウォールをノーコードで作成できる使いやすいツールの新バージョン [Adapty ペイウォールビルダー](adapty-paywall-builder) に対応しました。最大限の柔軟性と豊富なデザイン機能により、ペイウォールの効果と収益性を大幅に高められます。 ## バージョン 3.0.1 へのアップグレード \{#upgrade-to-version-301\} 1. 通常の手順でバージョン 3.0.1 にアップグレードします。 2. フォールバックペイウォールのファイルを差し替えます。 1. Adapty ダッシュボードから[最新バージョンをダウンロード](fallback-paywalls)します。 2. [こちら](react-native-use-fallback-paywalls)の手順に従って、ファイルをユーザーのデバイスに保存し、`.setFallbackPaywalls` メソッドに渡します。 --- # End of Documentation _Generated on: 2026-07-24T13:00:57.729Z_ _Successfully processed: 45/45 files_ # TUTORIAL - 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.731Z Total files: 277 --- # File: is-adapty-right-for-me --- --- title: "Adapty は私に合っていますか?" description: "Adapty があなたのユースケースに合うかどうかを確認してください。新しいアプリを立ち上げる場合、収益を最適化する場合、または別のツールから移行する場合など、ここから始めましょう。" --- Adapty はモバイルアプリ向けのアプリ内課金プラットフォームです。サブスクリプション、買い切り購入、消耗型アイテムを扱い、購入処理やレシート検証から、分析、A/B テスト、各種インテグレーションまでをカバーします。 さまざまなシナリオにおける Adapty の活用方法をご紹介します。 ## アプリ内課金を含む新しいアプリをリリースする \{#im-launching-a-new-app-with-in-app-purchases\} サブスクリプション、買い切り購入、消耗型アイテムのいずれを販売する場合でも、Adapty がすべてをカバーします。 - **7つのプラットフォーム向けSDK**: iOS、Android、React Native、Flutter、Unity、Kotlin Multiplatform、Capacitor。 - **購入処理**: サブスクリプションの更新とリトライロジック、買い切り購入、消耗型アイテム、レシート検証 — すべてお任せ。 - **ノーコードのペイウォールビルダー**: UIコードを書かずにペイウォールをデザインしてリリース。 - **初日からアナリティクス**: 最初のユーザーが来た瞬間から、収益・トライアル・コンバージョンなどを追跡。 さっそく始めましょう。[クイックスタートガイド](quickstart)に従って進めてください。 ## A/Bテスト、アナリティクス、インテグレーションを活用したい \{#i-want-ab-tests-analytics-and-integrations\} Adaptyは、すでに機能しているものをさらに最適化するのに役立ちます: - **A/B テスト**: 価格、ペイウォールデザイン、トライアル期間、プロモーションオファーをテストして、最もコンバージョン率の高い組み合わせを見つけましょう。[AI Growth Advisor](autopilot) を使えば、20,000 以上のサブスクリプションアプリのデータをもとに、あなたのアプリに合った A/B テストの提案が受けられます。 - **アナリティクスチャート**: MRR、LTV、チャーン、リテンションをはじめ、数十種類の指標を追跡できます。 - **オーディエンスセグメンテーション**: 特定のユーザーグループに合わせたペイウォールやオファーを提供できます。 - **ペイウォールのリモート設定**: アプリの新バージョンをリリースせずにペイウォールを改善できます。 - **サードパーティ連携**: Amplitude、AppsFlyer、Adjust、Mixpanel など、チームがすでに使っているツールに購入イベントを送信できます。 [A/B テスト](ab-tests)、[アナリティクス](analytics)、[アナリティクスサービスの統合](analytics-integration)、[アトリビューションサービスの統合](attribution-integration)をぜひご活用ください。 ## LLMを使ってアプリ内課金を実装したい \{#i-want-to-implement-in-app-purchases-with-an-llm\} AdaptyのドキュメントはCursor、Claude、ChatGPTなどのAIコーディングアシスタントで使いやすいよう最適化されています。すべてのページはプレーンMarkdown形式で提供されており、各プラットフォーム向けのLLMアシスト実装ガイドも用意しています。 - **そのままコピペできるガイド**: ガイドをLLMに渡すだけで、実装の各ステップをサポートしてもらえます。 - **Markdownアクセス**: ドキュメントのURLに `.md` を追加するか、**Copy for LLM** をクリックすると、クリーンなテキスト形式で取得できます。 - **Context7 MCPサポート**: AdaptyのドキュメントをLLM搭載IDEに直接接続できます。 プラットフォームを選択して始めましょう:[AIアシスタントでAdaptyを統合する](adapty-cursor)。 ## Apple Ads キャンペーンを実行・最適化したい \{#i-want-to-run-and-optimize-apple-ads-campaigns\} Apple Search Ads を運用しているなら、Adapty Ads Manager を使えば MMP 不要でキャンペーンのパフォーマンスと収益指標を直接つなげることができます。 - **リアルタイムパフォーマンスデータ**: キャンペーン、広告グループ、キーワードのトラッキング。 - **エンドツーエンドの収益トラッキング**: 検索からインストール、トライアル、サブスクリプション、LTVまでの流れを追跡。 - **AI予測とレコメンデーション**: 収益予測とスケーリングの提案を取得。 - **AIエージェント**: アカウントに関する質問を自然な言葉で入力すると、ファネル全体の回答とレコメンデーションを取得。 - **ルールベースの自動化**: CPAとROASの目標値を安定的に維持。 [Adapty Ads Manager](adapty-ads-manager)で始めましょう。 ## ユーザーの流入元を把握したい \{#i-want-to-track-where-my-users-come-from\} Adapty Attribution は、広告費用・アプリインストール・サブスクリプション収益を紐づける組み込みのアトリビューション機能です。 - **統合マーケティングダッシュボード**: すべてのチャネルのROAS、インストール数、収益を一か所で確認できます。 - **組み込みアトリビューション**: 外部のMMPに頼らずに広告キャンペーンとインストール・収益を紐づけられます。 - **トラッキングリンク**: Adaptyでリンクを生成してキャンペーンに追加するだけで、正確なアトリビューションが実現します。 - **遅延ディープリンク**: クリック時にアプリが未インストールでも、インストール後にユーザーを適切なコンテンツへ誘導できます。 - **コホート分析**: 時系列でユーザー獲得のパフォーマンスや行動を分析できます。 [Adaptyアトリビューション](adapty-user-acquisition)の詳細をご覧ください。 ## トライアルユーザーの転換や解約ユーザーの再獲得をメールで行いたい \{#i-want-to-convert-trial-users-and-recover-churned-subscribers-via-email\} Adapty Mail は、Adapty のユーザーデータを活用して、トライアルユーザーや解約したサブスクリプションユーザーなど、ライフサイクルの各段階に合わせた AI 生成メールキャンペーンを実現します。 - **AI生成キャンペーン**: ブランドプロファイルをもとに、各キャンペーンのコピーとデザインをAdaptyが自動生成します。 - **ライフサイクルトリガー**: 主要なライフサイクルイベントに基づいてキャンペーンを自動送信します。 - **Webペイウォールチェックアウト**: 各受信者に合わせたパーソナライズされたチェックアウトリンクを提供し、購入はそのきっかけとなったメールに紐付けられます。 - **独自ドメインからの送信**: すべてのメールは認証済みドメインから送信されます — 別途メールプラットフォームは不要です。 [Adapty Mail](adapty-mail)についてはこちらをご覧ください。 ## アプリのリリースなしに素早くイテレーションしたい \{#i-want-to-iterate-fast-without-app-releases\} Adapty を一度統合してしまえば、日々の作業のほとんどはダッシュボード上で完結します — 新しいアプリバージョンは不要です: - **フロー**: ビジュアルエディターでペイウォールやオンボーディングをデザインし、変更をすぐに公開できます。 - **ダッシュボードからの A/B テスト**: コードに触れることなく、実験の開始・価格の調整・オファーの入れ替えが可能です。 - **ダッシュボード分析**: 収益、チャーン、トライアル、コンバージョンをリアルタイムで確認できます。 - **Slack とメールのレポート**: チームが気にする指標の自動更新を受け取れます。 [フロー](adapty-flow-builder)を探索するか、[アナリティクス](charts)をご確認ください。 ## ウェブで販売していてモバイルアプリが必要な場合 \{#i-sell-on-the-web-and-need-a-mobile-app\} ユーザーがすでにウェブサイトで支払いを行っており、モバイルアプリを追加する場合、Adapty はプラットフォーム間で購入を同期します。 - **Stripe・Paddle 連携**: ウェブでの購入を自動的に Adapty へ同期します。 - **ウェブとモバイルの同期**: ウェブで支払ったユーザーはアプリ内でもアクセスでき、その逆も同様です。 - **統合クロスプラットフォーム分析**: ウェブとモバイルの収益を 1 つのダッシュボードで確認できます。 [Stripe 連携](stripe)や [Paddle 連携](paddle)をセットアップするか、[ウェブとモバイルのサブスクライバーを同期する方法](sync-subscribers-from-web)をご覧ください。 ## 他のツールから移行する場合 \{#im-migrating-from-another-tool\} Adapty を使えば、他のサブスクリプションプラットフォームからの移行も簡単です: - **移行ガイド**: 他のサブスクリプションプラットフォームからの移行手順をステップごとに説明しています。 - **オブザーバーモード**: 既存の課金コードをそのまま使いながら、[オブザーバーモード](observer-vs-full-mode)で Adapty を段階的に導入できます。まずはアナリティクスや A/B テストから始め、準備が整ったら範囲を広げましょう。 - **過去データのインポート**: 既存のトランザクション履歴を Adapty に取り込んで、アナリティクスの継続性を保てます。 [Adapty への移行](migrate-to-adapty-from-another-solutions)や[過去データのインポート](importing-historical-data-to-adapty)について詳しく学びましょう。 --- まだ探索中の場合は、[クイックスタートガイド](quickstart)から始めるのがおすすめです。 --- # File: integrate-payments --- --- title: "ストアまたは決済プラットフォームとの連携" description: "AdaptyをApp Store、Google Play、カスタムストア、Stripe、Paddleと連携します。" --- Adaptyを使い始めるには、まずユーザーがプロダクトを購入するストアとの連携を行います。Adaptyはさまざまなアプリストアやウェブ決済プロバイダーに対応しており、すべてのアプリ内課金とアナリティクスを一か所にまとめることができます。 ## ストアおよびウェブ決済との連携 \{#integrate-with-stores-and-web-payments\} 以下から対象のストアを選んで、詳細な連携手順を確認してください: - [App Store](initial_ios) - [Google Play](initial-android) - ウェブ決済: - [Stripe](stripe) - [Paddle](paddle) - [その他のストア](custom-store) ## 次のステップ \{#next-steps\} ストアまたは決済プラットフォームとの連携が完了したら、[プロダクトの追加](quickstart-products)に進みましょう。 --- # File: quickstart-products --- --- title: "プロダクトを追加する" description: "アプリ内プロダクトやサブスクリプションをAdaptyに追加し、App Store、Google Play、Stripe、Paddle、またはカスタムストアのリストにリンクします。" --- :::tip プログラムでAdaptyを設定しますか?[Developer CLI](developer-cli-quickstart)を使ってこのステップを完了できます。 ::: Adaptyのコア機能を使うには、販売する各プロダクトを追加し、対応するストアや決済プラットフォームにリンクする必要があります。この設定により、ユーザーのデバイスにプロダクトを提供し、後で分析でも追跡できるようになります。 Adaptyでは、アプリで販売するものはすべて**プロダクト**です。同じアイテムがApp Store、Google Play、Stripeに存在する場合、Adaptyで1つのプロダクトにまとめることができます。一度設定すれば、すべてのプラットフォームを一か所から管理できます。 さっそく最初のプロダクトを追加してみましょう。 <Tabs groupId="products" queryString> <TabItem value="no-products" label="ストアにプロダクトがまだない場合" default> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/qUpC2XG-r5E?si=7Komyv4_PUQ4FaEH" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> </TabItem> <TabItem value="products-in-stores" label="ストアにすでにプロダクトがある場合"> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/nlkdKCF0SwY?si=VVigzHcpv3waKJmI" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> </TabItem> </Tabs> ## 最初のプロダクトを追加する \{#add-your-first-product\} :::tip このクイックスタートではプロダクト作成の基本を説明します。詳細は[プロダクトの作成](create-product)のガイドをご覧ください。 ::: 例として、月額サブスクリプションをプロダクトとして追加してみましょう。 1. Adaptyのメインメニューから[Products](https://app.adapty.io/products)に移動します。 2. 右上の **Create product** をクリックします。 <img src={require('./img/products-tab.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important **次のステップは、App StoreやGoogle Playにすでにプロダクトがあるかどうかによって異なります:** ::: <Tabs groupId="products" queryString> <TabItem value="no-products" label="ストアにプロダクトがまだない場合" default> :::important 開始する前に、[App Store](initial_ios)および/または[Google Play](initial-android)との連携を設定済みであることを確認してください。App Storeの場合は、AdaptyがプロダクトをプッシュできるよるようにApp Store Connect APIキーを[追加](app-store-connection-configuration#step-6-add-app-store-connect-api-key)しておいてください。 ::: 3. **Create a new product and push to stores** を選択します。 4. プロダクトの詳細を入力します: - **Product name**:Adaptyダッシュボード内でのみ表示される名前です。 - **Access Level**:購入後にどの機能がアンロックされるかを決める識別子です。アプリの有料ユーザー全員が同じ機能にアクセスできる場合は、デフォルトのアクセスレベル `premium` を使用できます。より複雑な設定の場合は、追加の[アクセスレベル](access-level)を作成してください。 - **Subscription duration**:リストからサブスクリプションの期間を選択します。 - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**:サブスクリプションの期間です。 - **Lifetime**:アプリのプレミアム機能を永久にアンロックするプロダクトにはLifetimeを使用します。 - **Non-Subscriptions**:サブスクリプションではなく期間のないプロダクトにはNon-Subscriptionsを使用します。追加機能のアンロックや消耗型アイテムなどに利用できます。 - **Consumables**:消耗型アイテムは複数回購入できます。アプリ内で使い切るアイテムで、ゲーム内通貨やエクストラなどが例として挙げられます。消耗型プロダクトはアクセスレベルに影響しない点に注意してください。 - **Price (USD)**:USD建てのプロダクト価格です。この価格をベースに全国の価格が自動計算・設定されます。後から[国や地域ごとに価格をカスタマイズ](edit-product#set-country-specific-prices)することもできます。 <img src={require('./img/create-product-push.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Save & Continue** をクリックし、**App Store** または **Google Play** タブに切り替えてストア向けのプロダクト詳細を入力します。 <Tabs> <TabItem value="App Store" label="App Store" default> - **Product ID**:プロダクトの永続的な一意のIDを作成します。 - **Product group**:App Store Connectで作成した既存のプロダクトグループを選択するか、**Create new Product Group** をクリックして名前とIDを設定します。Adaptyが作成した後、ドロップダウンから選択できます。 - **Screenshot**:提供するアイテムやサービスが明確にわかるアプリ内購入のスクリーンショットをアップロードします。このスクリーンショットはApp Storeの審査にのみ使用され、App Storeには表示されません。スクリーンショットのサイズとフォーマットの要件は[こちら](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/)をご覧ください。 :::warning このアプリで初めてのプロダクトの場合は、App Store Connectで手動で審査に提出する必要があります。以降は不要です。審査が完了すると、Adapty上のプロダクトステータスが自動的に更新されます。 ::: </TabItem> <TabItem value="Google Play" label="Google Play" default> - **Base Product ID**:プロダクトの永続的な一意のIDを作成します。 - **Subscription**:Google Play Consoleで作成した既存のサブスクリプショングループを選択するか、**Create new Product Group** をクリックして名前とIDを設定します。Adaptyが作成した後、ドロップダウンから選択できます。 </TabItem> </Tabs> 6. iOSの場合は、ドロップダウンから **Free duration** を選択して初回オファー(無料トライアル)を設定します。この初期設定では無料トライアルの初回オファーを追加できます。メインプロダクトがストアに承認された後、ストアコンソールの既存IDをリンクすることで[さらにオファーを追加](offers)できます(プロモーションオファー、ウィンバックオファーなど)。 :::important 初回オファーはGoogle Playと自動同期されません。App Storeとは異なり、Google Playには独立した「初回オファー」タイプがなく、無料トライアルや割引オファーはすべてベースプランの**オファー**として設定します。[Google Play Consoleでオファーを作成し、Adaptyのプロダクトにリンク](google-play-offers)してください。 ::: </TabItem> <TabItem value="products-in-stores" label="ストアにすでにプロダクトがある場合"> 3. **Connect an existing store product** を選択します。 4. プロダクトの詳細を入力します: - **Product name**:Adaptyダッシュボード内でのみ表示される名前です。 - **Access level ID**:購入後にどの機能がアンロックされるかを決める識別子です。アプリの有料ユーザー全員が同じ機能にアクセスできる場合は、デフォルトのアクセスレベル `premium` を使用できます。より複雑な設定の場合は、追加の[アクセスレベル](access-level)を作成してください。 - **Subscription duration**:リストからサブスクリプションの期間を選択します。 - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**:サブスクリプションの期間です。 - **Lifetime**:アプリのプレミアム機能を永久にアンロックするプロダクトにはLifetimeを使用します。 - **Non-Subscriptions**:サブスクリプションではなく期間のないプロダクトにはNon-Subscriptionsを使用します。追加機能のアンロックや消耗型アイテムなどに利用できます。 - **Consumables**:消耗型アイテムは複数回購入できます。アプリ内で使い切るアイテムで、ゲーム内通貨やエクストラなどが例として挙げられます。消耗型プロダクトはアクセスレベルに影響しない点に注意してください。 - **Price (USD)**:USD建てのプロダクト価格です。プロダクトがすでにストアにある場合、この値は実際のストア価格に影響しませんので、リストから任意の値を選択できます。後から、Adaptyダッシュボード上で[地域ごとの価格をカスタマイズ](edit-product#set-country-specific-prices)することもできます。 <img src={require('./img/product-info.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <br /> 5. ストアの詳細を追加します。ストアを選択してください: <Tabs> <TabItem value="App Store" label="App Store" default> - **App Store Product ID**:デバイス上でプロダクトにアクセスするための一意の識別子です。見つからない場合は、IDが正しく、正しいアプリのものであることを確認してください。 </TabItem> <TabItem value="Google Play" label="Google Play" default> - **Google Play Product ID**:Play Storeのプロダクト識別子です。既存のプロダクトIDのリストから選択します。見つからない場合は、IDが正しく、正しいアプリのものであることを確認してください。 - **Base plan ID**:Play Storeでプロダクトのベースプランを定義するIDです。 - **Legacy fallback product**:フォールバックプロダクトは、古いバージョンのAdapty SDK(バージョン2.5以下)を使用するアプリ専用です。`<subscription_id>:<base_plan_id>` の形式で値を指定してください。 :::important 初回オファーはGoogle Playと自動同期されません。App Storeとは異なり、Google Playには独立した「初回オファー」タイプがなく、無料トライアルや割引オファーはすべてベースプランの**オファー**として設定します。[Google Play Consoleでオファーを作成し、Adaptyのプロダクトにリンク](google-play-offers)してください。 ::: <details> <summary>Google PlayのProduct IDとBase plan IDの確認方法はこちらをクリックしてください。</summary> 1. [Google Play Console](https://play.google.com/console/developers/android/app)アカウントで **Monetize with Play > Products > Subscriptions** に移動します。 2. 対象の購入に関する **Subscription** を開きます。 3. **Subscription details** セクションにProduct IDが、**Base plans and offers** セクションの **ID and duration** 列にBase plan IDが表示されます。 <img src={require('./img/play-store-id.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </details> </TabItem> <TabItem value="Stripe" label="Stripe" default> - **Stripe Product ID**:Stripeの一意のプロダクト識別子です。 - **Stripe Price ID**:プロダクトに関連付けられた価格のStripe固有の識別子です。 <details> <summary>StripeのProduct IDとPrice IDの確認方法はこちらをクリックしてください。</summary> 1. Stripeの[Product Catalog](https://dashboard.stripe.com/products?active=true)に移動します。 2. 対象のプロダクトを開きます。 3. 以下が確認できます: - Stripe Product ID(`prod_...` の形式)は右上に表示されます。 - Stripe Price ID(`price_...` の形式)は **Pricing** セクションの **API ID** 列に表示されます。 <img src={require('./img/product-stripe.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </details> </TabItem> <TabItem value="Paddle" label="Paddle" default> - **Paddle Product ID**:Paddleの一意のプロダクト識別子です。 - **Paddle Price ID**:プロダクトに関連付けられた価格のPaddle固有の識別子です。 <details> <summary>PaddleのProduct IDとPrice IDの確認方法はこちらをクリックしてください。</summary> 1. Paddleの[Product Catalog](https://vendors.paddle.com/products-v2)に移動します。 2. 対象のプロダクトを開きます。 3. 以下が確認できます: - Paddle Product ID(`pro_...` の形式)は **Additional details** セクションに表示されます。 - Paddle Price ID(`pri_...` の形式)は **Prices** セクションの **ID** 列に表示されます。 <img src={require('./img/paddle-product-price.webp').default} style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </details> </TabItem> <TabItem value="Custom" label="Custom store" default> 既存のカスタムストアを選択するか、新しいストアを追加してプロダクトを関連付けることができます。 Adaptyがトランザクションを追跡できるのはApp Store、Google Play、Stripeのみです。カスタムストアの場合は、Adaptyのサーバーサイドapi [Set transaction method](api-adapty/operations/setTransaction)を使ってトランザクションを送信する必要があります。 </TabItem> </Tabs> 6. 必要に応じてプロダクトの[オファーを作成](create-offer)できます。オファーを追加する場合は **Yes, add offers** を、不要な場合は **No, thanks** をクリックします。 プロダクトがプロダクト一覧に表示されます。 <img src={require('./img/created-product.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </TabItem> </Tabs> ## 次のステップ \{#next-steps\} Adaptyにプロダクトを追加したら、[ペイウォールの設定](quickstart-paywalls)に進みましょう。プロダクトを販売するにはペイウォールが必要です。 --- # File: quickstart-paywalls --- --- title: "購入を有効にする" description: "Adapty にフローまたはペイウォールを追加してプロダクトを表示し、プレースメントに紐付けます。" --- :::info このガイドを進めるには、[ストアの連携](integrate-payments)が完了していて、前の[プロダクト追加ガイド](quickstart-products)に従って少なくとも1つのプロダクトを作成していることを確認してください。 ::: プロダクトが用意できたら、次はユーザーへの見せ方を決める必要があります。Adaptyには3つの選択肢があります。 - **フローBuilder(推奨)**: 購入フロー全体を構築できるノーコードのビジュアルエディタです。Adapty SDKがネイティブにレンダリングするため、UIコードを書く必要はありません。 - **手動ペイウォール**: ペイウォールを作成してプロダクトを紐付け、UIはアプリのコードで自分でレンダリングします。 - **Adapty ペイウォールビルダー(レガシー)**: ノーコードのペイウォールエディタです。 どちらの方法も最終的には同じで、作成したコンテンツを[プレースメント](placements)に紐付けます。プレースメントとは、アプリが実行時に呼び出し、適切なユーザーに適切なコンテンツを返すための仕組みです。 <Tabs groupId="purchase-setup" queryString> <TabItem value="flow-builder" label="フローの使用" default> :::important フロービルダーは現在、iOS、Android、React Native、Flutter、および Capacitor SDK v4 以降をサポートしています。他のプラットフォームへの対応は近日中に追加される予定です。 ::: フローとは、プロダクトが直接埋め込まれた 1 つ以上の画面のことです。[フロービルダー](adapty-flow-builder)でデザインでき、コーディングは不要です。 Adapty SDK はフローを各プラットフォームでネイティブにレンダリングします。アプリが `getFlow` を呼び出すと、SDK が画面を表示し、購入を処理し、イベントをレポートします。別途 UI コードを書く必要も、ペイウォールを並行してメンテナンスする必要もありません。 ## 1. フローを作成する \{#1-build-the-flow\} 1. Adapty のメインメニューにある [**Flows**](https://app.adapty.io/flows) に移動します。 2. **Create flow** をクリックし、フローをデザインします。 [Adapty フロービルダー](adapty-flow-builder)について詳しく確認できます。 以下のテンプレートガイドでは、よく使われるパターンをステップごとに解説しています: <CustomDocCardList ids={['basic-paywall-screen', 'show-plans-bottom-sheet', 'paywall-with-tabs', 'paywall-features-per-product', 'onboarding-flow-tutorial']} /> フローを保存して公開したら、次はプレースメントへの組み込みに進みましょう。 :::warning フローを公開することを忘れずに!公開しないと、プレースメントに追加できません。 ::: ### 2. フローをプレースメントに追加する \{#2-add-the-flow-to-a-placement\} <InlineTooltip tooltip="プレースメント">プレースメントとは、フロー、ペイウォール、オンボーディング、またはA/Bテストをアプリ内で表示する特定の場所です。プレースメントを使うと、特定の[オーディエンス](audience)にコンテンツをターゲティングできます。[プレースメント](placements)について詳しく見る。</InlineTooltip>を作成することで、アプリが実行時にフローをリクエストできるようになります。 まずは最も基本的なオンボーディングのプレースメントから始めましょう。その後、ユーザージャーニー全体に[意味のあるプレースメント](choose-meaningful-placements)を追加していくことができます。 1. Adaptyのメインメニューから [**Placements**](https://app.adapty.io/placements) に移動し、**Flows** タブに切り替えます。 2. **Create placement** をクリックします。 3. **Placement name**(例:`main` や `onboarding`)を入力します。これはAdaptyダッシュボード内の内部識別子です。 4. **Placement ID** を入力します。このIDはAdapty SDKでプレースメントのフローを読み込む際に使用します。 5. **Run flow** をクリックし、作成したフローを選択します。 6. **Save & publish** をクリックします。 アプリのコードには、プレースメント ID のみをハードコードします。どのフローを実行するか、どのプロダクトを販売するか、見た目のデザインなど、それ以外のすべてはAdapty ダッシュボードで設定でき、アプリのアップデートなしにいつでも変更できます。 :::tip Adapty では、さまざまなユーザーグループに異なるフローを表示し、パフォーマンスを分析できます。詳しくは[オーディエンス](audience)と[A/B テスト](ab-tests)をご覧ください。 ::: </TabItem> <TabItem value="manual-paywall" label="Implement paywall manually"> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/e4o7Z2tUGL8?si=ipwbW3VVN0fIg0R0" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ペイウォールは、1つ以上のプロダクトをリモートで管理するコンテナです。Adaptyはプロダクトリストと任意の[リモートコンフィグ](customize-paywall-with-remote-config) JSONペイロードを提供し、アプリのコードがそれを読み取ってUIを描画します。 :::tip Adaptyをプログラムで設定しますか?この手順は[Developer CLI](developer-cli-quickstart)を使って行うこともできます。 ::: ### 1. ペイウォールを作成する \{#1-create-a-paywall\} 1. Adapty メインメニューの [**Paywalls**](https://app.adapty.io/paywalls) を開きます。 2. **Create paywall** をクリックします。 3. **Paywall name** を入力します。これは Adapty ダッシュボード内の内部識別子です。 4. **Add product** をクリックして、ペイウォールに表示するプロダクトを選択します。 5. (任意)**Remote config** タブを開き、アプリが必要とする JSON ペイロード(タイトル、コピー、フィーチャーフラグなど)を追加します。詳細は[リモートコンフィグを使ったペイウォールのデザイン](customize-paywall-with-remote-config)を参照してください。 6. **Create as a draft** をクリックし、準備ができたら公開します。 <img src="/assets/shared/img/quickstart-paywall.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このペイウォールはアプリコードで描画します。<InlineTooltip tooltip="ペイウォールを手動で実装する">お使いのプラットフォームのガイドをご覧ください: [iOS](ios-implement-paywalls-manually)、[Android](android-implement-paywalls-manually)、[React Native](react-native-implement-paywalls-manually)、[Flutter](flutter-implement-paywalls-manually)、[Unity](unity-implement-paywalls-manually)。</InlineTooltip> ### 2. ペイウォールをプレースメントに追加する \{#2-add-the-paywall-to-a-placement\} <InlineTooltip tooltip="プレースメント">プレースメントとは、フロー、ペイウォール、オンボーディング、または A/B テストを表示するアプリ内の特定のポイントです。プレースメントを使用すると、特定の[オーディエンス](audience)にコンテンツをターゲティングできます。[プレースメント](placements)の詳細はこちら。</InlineTooltip>を作成することで、アプリが実行時にペイウォールをリクエストできるようになります。 まずは最も基本的なオンボーディングプレースメントから始めましょう。その後、ユーザージャーニー全体にわたってさらに多くの[意味のあるプレースメント](choose-meaningful-placements)を追加できます。 1. Adaptyのメインメニューから [**Placements**](https://app.adapty.io/placements) に移動し、**Paywalls** タブに切り替えます。 2. **Create placement** をクリックします。 3. **Placement name**(例:`main` や `onboarding`)を入力します。これはAdapty ダッシュボード内の内部識別子です。 4. **Placement ID** を入力します。このIDをAdapty SDKで使用して、プレースメントのペイウォールを読み込みます。 5. **Run paywall** をクリックし、作成したペイウォールを選択します。 6. **Save & publish** をクリックします。 <img src="/assets/shared/img/add-placement.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> アプリのコードにはプレースメント ID のみをハードコードします。どのペイウォールを表示するか、どのプロダクトを販売するか、リモートコンフィグの内容はすべて Adapty ダッシュボードで設定でき、アプリを更新することなくいつでも変更できます。 :::tip Adaptyでは、さまざまなユーザーグループに異なるペイウォールを表示し、パフォーマンスを分析できます。[オーディエンス](audience)と[A/B テスト](ab-tests)について詳しくはこちらをご覧ください。 ::: </TabItem> <TabItem value="paywall-builder" label="Adapty Paywall Builder (Legacy)"> [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールは、プロダクトが直接組み込まれたノーコード画面です。Adapty SDKがネイティブでレンダリングするため、UIのコードを書く必要はありません。 :::warning ペイウォールビルダーは引き続き使用できますが、Adapty は今後このビルダーへの機能追加やアップデートの提供を行いません。新規プロジェクトでは、代わりに[フロービルダー](adapty-flow-builder)をご利用ください。 ::: ### 1. ペイウォールを作成する \{#1-build-the-paywall\} 1. Adapty のメインメニューから [**Paywalls**](https://app.adapty.io/paywalls) に移動します。 2. **Create paywall** をクリックします。 3. **Paywall name** を入力します。これは Adapty ダッシュボード内部の識別子です。 4. **Add product** をクリックし、ペイウォールに表示するプロダクトを選択します。 5. **Builder & Generator** タブを開きます。テンプレートからペイウォールを作成するか、AI を使って生成します。 6. **Show on device** トグルをオンにすると、SDK がレンダリングできるようになります。 ### 2. ペイウォールをプレースメントに追加する \{#2-add-the-paywall-to-a-placement\} <InlineTooltip tooltip="プレースメント">プレースメントとは、フロー、ペイウォール、オンボーディング、または A/B テストを表示するアプリ内の特定のポイントです。プレースメントを使うと、特定の[オーディエンス](audience)にコンテンツをターゲティングできます。詳しくは[プレースメント](placements)をご覧ください。</InlineTooltip>を作成して、アプリが実行時にペイウォールをリクエストできるようにします。 1. Adapty のメインメニューで [**Placements**](https://app.adapty.io/placements) を開き、**Paywalls** タブに切り替えます。 2. **Create placement** をクリックします。 3. **Placement name**(例:`main` や `onboarding`)を入力します。これは Adapty ダッシュボード内の内部識別子です。 4. **Placement ID** を入力します。このIDは、Adapty SDK でプレースメントのペイウォールを読み込む際に使用します。 5. **Run paywall** をクリックして、作成したペイウォールを選択します。 6. **Save & publish** をクリックします。 アプリのコード内にハードコードするのはプレースメント ID のみです。どのペイウォールを表示するか、どのプロダクトを販売するか、どのような見た目にするか — これらはすべて Adapty ダッシュボードで設定でき、アプリのアップデートなしにいつでも変更できます。 </TabItem> </Tabs> ## 次のステップ \{#next-steps\} SDK が配信するコンテンツの準備が整いました。次は、アプリに [Adapty SDK を組み込み](quickstart-sdk)、プレースメントの取得を始めましょう。 --- # File: quickstart-sdk --- --- title: "アプリコードへの Adapty SDK の統合" description: "App Store、Google Play、カスタムストア、Stripe、Paddle と Adapty を統合します。" --- Adapty SDK をアプリに統合すると、次のことができます。 - 購入処理、レシート検証、サブスクリプション管理をすぐに利用可能 - アプリのアップデートなしにペイウォールを作成・テスト - 設定不要で詳細な購入アナリティクスを取得(コホート、LTV、チャーン、ファネル分析を含む) - アプリセッションやデバイスをまたいでユーザーのサブスクリプション状態を常に最新に保つ - たった一行のコードでマーケティングアトリビューションやアナリティクスサービスとアプリを統合 ## 仕組み \{#how-does-it-work\} Adapty SDK の基本実装に必要なのは、次の 3 つだけです。 1. SDK のインストールと初期化 2. アプリ内課金の処理を Adapty に委任 3. プロファイルでサブスクリプション状態を監視。サブスクリプションのステータス、種類、有効期限は Adapty が判断し、SDK はその情報を受け取るだけです。 順序や詳細はアプリによって異なりますが、基本的にはこれだけです。 ## はじめる \{#get-started\} プラットフォームを選んでさっそく始めましょう。 **iOS** - **[SDK クイックスタート](ios-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples)** **Android** - **[SDK クイックスタート](android-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app)** **React Native** - **[SDK クイックスタート](react-native-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/)** **Flutter** - **[SDK クイックスタート](flutter-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example)** **Unity** - **[SDK クイックスタート](unity-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)** **Capacitor** - **[SDK クイックスタート](capacitor-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples)** **Kotlin Multiplatform**: - **[SDK クイックスタート](kmp-sdk-overview)** - **[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example)** ## 次のステップ \{#next-steps\} アプリコードで Adapty SDK の設定が完了したら、[実装のテスト](quickstart-test)に進みましょう。 --- # File: quickstart-test --- --- title: "Adaptyとの統合をテストする" description: "SDKのアクティベーション、ペイウォールの取得、App Store・Google Play・Stripe・Paddleでのアプリ内課金をテストして、Adaptyの統合を素早く確認しましょう。" --- 準備完了です!統合が意図した通りに動作しているか確認し、購入がAdaptyダッシュボードに表示されるかチェックしましょう。 テスト購入を実施することが、統合をエンドツーエンドで検証する最善の方法です。アプリ内課金から始めて、結果を確認してください。 ## 1. アプリ内課金をテストする \{#1-test-in-app-purchases\} ご利用のストアや決済プラットフォームに応じたガイドに従ってください。 ### App Store \{#app-store\} テストアカウント(Sandbox Apple ID)を使用し、実機でテストすることをお勧めします。テストの全手順については、[App Store Sandboxテスト](test-purchases-in-sandbox)の詳細記事をご覧ください。 :::warning 最も信頼性の高い結果を得るには、実機でテストしてください。シミュレーターでのテストも可能ですが、信頼性が低いためお勧めしません。 ::: ### Google Play Store \{#google-play-store\} テストユーザーを作成し、実機でアプリをテストしてください。テストの全手順については、[Google Play Storeのテスト](testing-on-android)の詳細記事をご覧ください。 :::note Googleはテストに[実機の使用を推奨](https://support.google.com/googleplay/android-developer/answer/14316361)しています。エミュレーターを使用する場合は、アプリが正常に動作するようGoogle Playがインストールされていることを確認してください。 ::: ### Stripe \{#stripe\} StripeでのテストにはStripeのテストモード用APIキーを使ってAdaptyにStripeを接続する必要があります。StripeのTestモードで行ったトランザクションは、AdaptyではSandboxとして扱われます。 接続の全手順については、[Stripe連携の記事](stripe#6-test-your-integration)をご覧ください。 ### Paddle \{#paddle\} PaddleでのテストにはPaddleのテスト環境用APIキーを使ってAdaptyにPaddleを接続する必要があります。Paddleのテスト環境で行ったトランザクションは、AdaptyではTestとして扱われます。 接続の全手順については、[Paddle連携の記事](paddle#4-test-your-integration)をご覧ください。 ## 2. テスト購入を検証する \{#2-validate-test-purchases\} テスト購入を行った後、Adaptyダッシュボードの[**Event Feed**](https://app.adapty.io/event-feed)で対応するトランザクションを確認してください。購入が**Event Feed**に表示されない場合、Adaptyはその購入をトラッキングできていません。 詳細は[テスト購入の検証](validate-test-purchases)ガイドをご覧ください。 <img src="/assets/shared/img/test-event-feed.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 次のステップ \{#next-steps\} Adaptyへのオンボーディングが完了しました!これでアプリ内課金を伸ばす準備が整いました。 本番リリースの準備をしましょう: <Button id="release-checklist"> リリースチェックリスト </Button> または、以下に進むこともできます: - **[A/Bテスト](ab-tests)**:価格、サブスクリプション期間、トライアル期間、ビジュアル要素をさまざまに試して、最も効果的な組み合わせを見つけましょう。 - **[アナリティクス](how-adapty-analytics-works)**:詳細なマネタイズ指標を分析し、ユーザー行動を理解して収益パフォーマンスを最適化しましょう。 - **インテグレーション**:Adaptyはサブスクリプションイベントを[Amplitude](amplitude)、[AppsFlyer](appsflyer)、[Adjust](adjust)、[Branch](branch)、[Mixpanel](mixpanel)、[Facebook Ads](facebook-ads)、[AppMetrica](appmetrica)、カスタム[Webhook](webhook)などのサードパーティ分析・アトリビューションツールに[サブスクリプションイベント](events)として送信します。 :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: --- # File: release-checklist --- --- title: "リリースチェックリスト" description: "Adaptyのリリースチェックリストに従って、スムーズなアプリのアップデートプロセスを確保しましょう。" --- Adaptyをご利用いただきありがとうございます!実装がうまくいったことを願っています。このガイドでは、アプリをストアに公開する準備が整っているか確認するための手順を説明します。これにより、マネタイゼーションフローが正しく機能していることを安心して確認できます。 ## 事前確認事項 \{#pre-flight-essentials\} バリデーションを始める前に必要なもの: - サンドボックスアカウントを持つ実機デバイス - Adapty ダッシュボードへのアクセス - App Store Connect / Google Play Console へのアクセス :::note サンドボックス購入はシミュレーターでも実行できますが、支払いダイアログや生体認証プロンプトを含むすべてのフローを完全にテストするには実機デバイスが必要です。 ::: <Button id="test-purchases-in-sandbox"> App Store向けテストガイド </Button> <Button id="testing-on-android"> Google Play向けテストガイド </Button> ## 共通バリデーション \{#universal-validations\} - [ ] **ストア接続**: AdaptyをApp StoreおよびGoogle Playに接続していることを確認してください: - [ ] [App Store](initial_ios) - [ ] [Google Play](initial-android) - [ ] **サブスクリプションイベントの配信**: サーバー通知が設定されていることを確認してください: - [ ] [App Serverサーバー通知](enable-app-store-server-notifications) - [ ] [リアルタイム開発者通知(RTDN)](enable-real-time-developer-notifications-rtdn) - [ ] **プロファイルの識別**: ユーザー識別ロジックを検証し、購入が正しいプロファイルに紐付けられていることを確認してください: - [ ] [アプリコードの識別ロジックがユースケースに合っているか確認する](ios-quickstart-identify) - [ ] [ユーザープロファイル間で有料アクセスを共有するための親/継承ロジックを理解しているか確認する](sharing-paid-access-between-user-accounts) - [ ] **オファー**: アプリにApp Storeのプロモーションオファーがある場合、[アプリ内購入キー](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers)をメインフィールドと **App Store promotional offers** セクションの両方に追加していることを確認してください。 - [ ] **データ収集**: プライバシーへの準拠を確保してください: - [ ] GDPRやCCPAなどのプライバシー規制に準拠する必要がある場合、またはアプリが子供向けの場合は、[IDFAおよびIPの収集と共有を有効にするかどうか](sdk-installation-ios#data-policies)を制御してください。 - [ ] アプリがAppTrackingTransparencyを使用している場合は、[認証ステータスをAdaptyに送信](ios-deal-with-att)していることを確認してください。 - [ ] **プライバシーラベル**: Adaptyが収集するデータとレビューに必要なフラグについては、[詳細はこちら](apple-app-privacy)をご覧ください。 ## 購入バリデーション \{#purchase-validations\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: 公開前に、アプリ内購入が正しく機能し、ペイウォールがストアレビューの準備ができていることを確認してください。 アプリ内購入のバリデーション方法は、実装方法によって異なります: - Adapty ペイウォールビルダーで作成したペイウォールを表示する - 独自のペイウォールを実装し、その中で `makePurchase` メソッドを使用して購入を処理する - オブザーバーモードでAdaptyを使用する(Adapty ペイウォールビルダーまたはカスタムペイウォールのどちらでも) <Tabs groupId="paywall" queryString> <TabItem value="builder" label="Adapty Paywall Builder" default> **目標**: Adaptyがペイウォールをレンダリングし、ユーザーがプロダクトを購入でき、アクセスがアンロックされ、購入復元フローが機能すること。 - [ ] アプリが[ペイウォールを表示する](ios-present-paywalls)際、実際にリリースするのと同じプレースメントを使用している。 - [ ] ペイウォールが画面に表示される。読み込みに時間がかかりすぎる場合(不安定なインターネット環境など)は、[フェッチポリシーの調整](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)を検討してください。 - [ ] ペイウォールが期待するバリアント(該当する場合はオーディエンス/ロケール)と一致している。必要に応じて[オーディエンスの優先順位を変更](change-audience-priority)できます。 - [ ] プロダクトと価格がペイウォールに表示される。テスト中(特に異なるリージョン設定の場合)にAppleのAPIが不正確な価格を提供することがあります。AdaptyはStoreの価格に影響を与えないため、価格の正確さよりも購入フローの機能テストを優先してください。 - [ ] サンドボックス購入が正常に完了する。購入成功のコールバックが受信される。 - [ ] アクセスがアンロックされ、維持される。[現在のAdaptyプロファイルに基づいて有料アクセスが付与されていること](ios-check-subscription-status#connect-profile-with-paywall-logic)を確認する。 - [ ] 購入後、Adaptyプロファイルにアクティブなアクセスレベルがある。 - [ ] プロファイルにそのアクセスレベルが含まれている場合に有料機能がアンロックされる(購入コールバックだけでなく)。 - [ ] 購入の復元が機能する。アプリを再インストールするか新しいデバイスにインストールした場合、[有料アクセスの共有](sharing-paid-access-between-user-accounts)設定に従って購入の自動復元が機能する。バックエンド認証がない場合は、設定に関係なく購入が自動的に復元される。それ以外の場合は、アプリの再インストール後にユーザーが購入を復元できることを確認する。 - [ ] ストアレビュー要件: - [ ] **Restore purchases** ボタンがペイウォールに表示されている。ペイウォールビルダーで追加でき、タップ時に購入復元を自動的に処理します。 - [ ] 利用規約とプライバシーポリシーがペイウォール画面からアクセスでき、これらのリンクをクリックするとブラウザで開く。 </TabItem> <TabItem value="makepurchase" label="カスタムペイウォール(makePurchase)" default> **目標**: UIをレンダリングし、AdaptyがPurchase処理、プロファイル更新、および復元を担当する。 - [ ] プロダクトIDがアプリコードにハードコードされていない。ハードコードするのは[プレースメント](placements)IDのみ。 - [ ] アプリが[プロダクトを取得する](fetch-paywalls-and-products)際、実際にリリースするのと同じプレースメントを使用している。 - [ ] プロダクトリストが正常に読み込まれる。読み込みに時間がかかりすぎる場合(不安定なインターネット環境など)は、[フェッチポリシーの調整](fetch-paywalls-and-products#fetch-paywall-information)を検討してください。 - [ ] 取得したプロダクトが期待するバリアント(該当する場合はオーディエンス/ロケール)と一致している。必要に応じて[オーディエンスの優先順位を変更](change-audience-priority)できます。 - [ ] プロダクトと価格がペイウォールに表示される。テスト中(特に異なるリージョン設定の場合)にAppleのAPIが不正確な価格を提供することがあります。AdaptyはStoreの価格に影響を与えないため、価格の正確さよりも購入フローの機能テストを優先してください。 - [ ] [makePurchase](making-purchases)を使用したサンドボックス購入が正常に完了する: - [ ] 購入成功の結果が処理される。 - [ ] 保留中/失敗/キャンセルの結果が適切に処理される。 - [ ] [リモートコンフィグを使用する](present-remote-config-paywalls)場合、その値がペイウォールに正しく反映されている。 - [ ] ペイウォールが表示されたとき、[`logShowFlow`(iOS SDK v4+)/ `logShowPaywall` メソッド](present-remote-config-paywalls#track-paywall-view-events)が呼び出される。 - [ ] サンドボックス購入が正常に完了する。購入成功のコールバックが受信される。 - [ ] アクセスがアンロックされ、維持される。[現在のAdaptyプロファイルに基づいて有料アクセスが付与されていること](ios-check-subscription-status#connect-profile-with-paywall-logic)を確認する。 - [ ] 購入後、Adaptyプロファイルにアクティブなアクセスレベルがある。 - [ ] プロファイルにそのアクセスレベルが含まれている場合に有料機能がアンロックされる(購入コールバックだけでなく)。 - [ ] 購入の復元が機能する。アプリを再インストールするか新しいデバイスにインストールした場合、[有料アクセスの共有](sharing-paid-access-between-user-accounts)設定に従って購入の自動復元が機能する。バックエンド認証がない場合は、設定に関係なく購入が自動的に復元される。それ以外の場合は、アプリの再インストール後にユーザーが購入を復元できることを確認する。 - [ ] ストアレビュー要件: - [ ] **Restore purchases** ボタンがアクセス可能で、[購入復元を処理](restore-purchase)している。 - [ ] 利用規約とプライバシーポリシーがペイウォール画面からアクセスでき、これらのリンクをクリックするとブラウザで開く。 </TabItem> <TabItem value="observer" label="オブザーバーモード"> **目標**: 購入処理、プロファイル更新、復元を自身で行い、Adaptyがトランザクションレポートを受け取る。 - [ ] **アプリが独自の購入フロー(StoreKit / BillingClient / バックエンド)を使用して購入を完了する**: - [ ] サンドボックス購入がストアUIで成功する。 - [ ] 保留中/失敗/キャンセルの結果がアプリ内で適切に処理される。 - [ ] **トランザクションがAdaptyに報告される**。 - [ ] オブザーバーモードが[アプリコードで有効になっている](implement-observer-mode)。 - [ ] 購入がAdaptyのイベントフィードに表示される。 - [ ] 更新、キャンセル、返金が時間の経過とともに反映される(該当する場合)。 - [ ] **ペイウォールビューが追跡される**。ペイウォールが表示されたとき、[`logShowFlow`(iOS SDK v4+)/ `logShowPaywall` メソッド](present-remote-config-paywalls#track-paywall-view-events)が呼び出される。 - [ ] **実装に合わせた購入復元が機能する**。アプリの再インストールやデバイスの切り替えで、アクセスが正しく復元される。 - [ ] **ストアレビュー要件**: - [ ] **Restore purchases** アクションがアクセス可能で、独自の復元フローがトリガーされる。 - [ ] 利用規約とプライバシーポリシーがペイウォールまたは購入画面からアクセスでき、ブラウザで開く。 </TabItem> </Tabs> Adapty SDKの統合についてご不明な点がある場合は、右下のAIチャットボットをご利用いただくか、[support@adapty.io](mailto:support@adapty.io)までお問い合わせください。 --- # File: observer-vs-full-mode --- --- title: "オブザーバーモード" description: "Adaptyのオブザーバーモードとフルモードをサブスクリプション管理の観点から比較します。" --- Adaptyは、収益とサブスクライバー数の拡大を支援する、強力で柔軟なアプリ内課金プラットフォームです。特定のユーザーセグメントに合わせたカスタマイズ可能なペイウォール、価格・期間・トライアル期間・ビジュアル要素のA/B テスト、アプリのマネタイズに向けた充実した分析ツール、そしてサードパーティ連携など、Adaptyはあなたの成長戦略を力強くサポートします。 ただし、すでに独自の購入インフラを持っており、Adaptyのシステムへの移行を検討していない場合は、Adaptyのオブザーバーモードを活用できます。この限定的なモードでは、Adaptyのペイウォール機能(ユーザーオーディエンスへのターゲティング、更新・請求リトライを含むサブスクリプション管理など)は利用できず、分析機能に特化しています。制限はあるものの、アトリビューションシステムとの連携、高度な分析、メッセージング、CRMプロファイルなど、充実した分析機能を引き続き利用できます。 両モードとも料金は同じで、モバイルアプリのアップデートが必要です。したがって、選択の本質は「Adaptyのインフラに移行してフル機能を使うか」「現在のインフラを維持しつつサードパーティ連携と分析機能のみを活用するか」という点にあります。 | 機能 | オブザーバーモード | フルモード | |-------------|-------------|---------| | **充実した分析機能** | ✅ | ✅ | | **サードパーティ連携** | ✅ | ✅ | | **購入イベントへの対応(有料コンテンツのアクセス付与・制限)** | ❌ | ✅ | | **購入インフラの管理者** | お客様 | Adapty | | **A/B テスト** | <p>実施可能ですが、フルモードに比べて追加の実装や設定が大幅に必要になります。</p> | ✅ | | **実装にかかる時間** | <p>分析・連携のみ:1時間未満</p><p>A/B テストあり:十分なテストを含めて最大1週間</p> | 数時間 | ## オブザーバーモードの仕組み \{#how-observer-mode-works\} オブザーバーモードでは、Apple/Googleからの新しいトランザクションをAdapty SDKに報告し、Adapty SDKがそれをAdaptyバックエンドに転送します。有料コンテンツへのアクセス管理、トランザクションの完了、更新処理、請求問題への対応などは、すべてお客様が担当します。 ## オブザーバーモードのセットアップ方法 \{#how-to-set-up-observer-mode\} 1. Adaptyの初期連携を[Google Play](initial-android)および[App Store](initial_ios)と設定します。 2. Adapty SDKの設定時に`observerMode`パラメーターを`true`に設定してオブザーバーモードを有効化します。各プラットフォームの設定手順([iOS](sdk-installation-ios#activate-adapty-module-of-adapty-sdk)、[Android](sdk-installation-android#activate-adapty-module-of-adapty-sdk)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter#activate-adapty-module-of-adapty-sdk)、[Kotlin Multiplatform](sdk-installation-kotlin-multiplatform#activate-adapty-sdk)、[Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk))に従ってください。 3. iOSおよびiOSベースのクロスプラットフォームフレームワークの場合、既存の購入インフラからAdaptyへ[トランザクションを報告](report-transactions-observer-mode)します。 4. (任意)サードパーティ連携を利用する場合は、[サードパーティ連携の設定](configuration)トピックの手順に従って設定してください。 :::warning オブザーバーモードで動作している場合、Adapty SDKはトランザクションを完了させません。この処理はお客様自身で行う必要があります。 ::: ## オブザーバーモードでのペイウォールとA/Bテストの使い方 \{#how-to-use-paywalls-and-ab-tests-in-observer-mode\} オブザーバーモードでは、Adapty SDKは購入の発生元を特定できません(購入処理はお客様独自のインフラ上で行われるため)。そのため、オブザーバーモードでペイウォールやA/B テストを使用する場合は、トランザクションを報告する際に、アプリストアからのトランザクションをモバイルアプリのコード内で対応するペイウォールに紐付ける必要があります。 また、ペイウォールビルダーで作成したペイウォールをオブザーバーモードで使用する際は、特別な表示方法が必要です。 - オブザーバーモードでのペイウォール表示については、[iOS](implement-observer-mode)または[Android](android-present-paywall-builder-paywalls-in-observer-mode)の手順を参照してください。 - トランザクション報告時のペイウォールと購入トランザクションの紐付けについては、[オブザーバーモードでのトランザクション報告](report-transactions-observer-mode)を参照してください。 --- # File: migration-from-revenuecat --- --- title: "RevenueCatからの移行" description: "ステップバイステップガイドでRevenueCatからAdaptyに移行しましょう。" --- 移行は5つのステップで構成されており、平均所要時間は約2時間です。移行の90%は1営業日以内に完了します。 1. 主要な違いを理解し、Adaptyアカウントを作成・準備する _(5分)_; 2. RevenueCat SDKの代わりに、各プラットフォーム向けのAdapty SDKをインストールする([iOS](sdk-installation-ios)、[Android](sdk-installation-android)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter)、[Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)、[Unity](sdk-installation-unity))_(1時間)_; 3. AdaptyへのApple App Storeサーバー通知を設定し、オプションで[rawイベント転送](enable-app-store-server-notifications#raw-events-forwarding)を設定する _(5分)_; 4. アプリのアップデートをテストしてリリースする _(30分)_; 5. (オプション)RevenueCatサポートにCSV形式の過去データをリクエストする _(5分)_; 6. (オプション)Adaptyサポート経由で過去データをインポートする _(30分)_。 :::info サブスクライバーは自動的に移行されます サブスクリプションを有効にしたことがあるすべてのユーザーは、Adapty SDKを搭載した新しいバージョンのアプリを開いた瞬間に自動的にAdaptyへ移行されます。サブスクリプションのステータス検証とプレミアムアクセスは自動的に復元されます。 ::: Adapty SDKを搭載したアプリの新バージョンをリリースする前に、必ず[リリースチェックリスト](release-checklist)を確認してください。 ## 主要な違いを理解し、Adaptyアカウントを作成・準備する \{#learn-the-core-differences-create-and-prepare-an-adapty-account\} AdaptyとRevenueCatのSDKは設計が似ています。最大の違いはネットワーク使用量とスピードです。Adapty SDKは、必要な情報をリクエスト時にできる限り高速に提供するよう設計されています。たとえば、ペイウォールをリクエストする際、オンボーディングやペイウォールの事前構築に使える[リモートコンフィグ](customize-paywall-with-remote-config)がまず返され、その後プロダクトが専用リクエストで取得されます。 名称は少し異なります: | RevenueCat | Adapty | | :---------- | :-------------- | | Package | Product | | Offering | Paywall | | Paywall | Paywall Builder | | Entitlement | Access level | Adaptyには[プレースメント](placements)というコンセプトがあります。これはアプリ内でユーザーが購入できる論理的な場所です。ほとんどの場合、プレースメントは1〜2つです: - オンボーディング(全購入の80%がここで発生するため); - 全般(オンボーディング後の設定画面やアプリ内で表示)。 <img src="/assets/shared/img/2406d97-image.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Adapty SDKのインストールとRevenueCat SDKの置き換え \{#install-adapty-sdk-and-replace-revenuecat-sdk\} 各プラットフォーム向けのAdapty SDKをアプリにインストールしてください([iOS](sdk-installation-ios)、[Android](sdk-installation-android)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter)、[Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)、[Unity](sdk-installation-unity))。 アプリ側でいくつかのSDKメソッドを置き換える必要があります。よく使われる関数とAdapty SDKでの置き換え方法を見ていきましょう。 ### SDKのアクティベーション \{#sdk-activation\} `Purchases.configure` を `Adapty.activate` に置き換えてください。 ### ペイウォール(オファリング)の取得 \{#getting-paywalls-offerings\} `Purchases.shared.getOfferings` を [`Adapty.getPaywall`](fetch-paywalls-and-products#fetch-paywall-information) に置き換えてください。 Adaptyでは、常に[プレースメントID](placements)を使ってペイウォールをリクエストします。実際には1〜2個のペイウォールしか取得しないため、SDKの高速化とネットワーク使用量の削減を目的として意図的にこのような設計にしています。 ### ユーザー(カスタマープロファイル)の取得 \{#getting-a-user-customer-profile\} `Purchases.shared.getCustomerInfo` を `Adapty.getProfile` に置き換えてください。 ### プロダクトの取得 \{#getting-products\} RevenueCatでは、`Purchases.shared.getOfferings`を使い、その後`self.offering?.availablePackages`で取得します。 Adaptyでは、まずペイウォールをリクエストして(上記参照)Adaptyの[リモートコンフィグ](customize-paywall-with-remote-config)にすぐアクセスし、その後[`Adapty.getPaywallProducts`](fetch-paywalls-and-products#fetch-products)でプロダクトを取得します。 ### 購入する \{#making-a-purchase\} `Purchases.shared.purchase` を [`Adapty.makePurchase`](making-purchases#make-purchase) に置き換えてください。 ### アクセスレベル(エンタイトルメント)の確認 \{#checking-access-level-entitlement\} カスタマープロファイルを取得し(上記参照)、 `customerInfo?.entitlements["premium"]?.isActive == true` を以下に置き換えてください: [`profile.accessLevels["premium"]?.isActive == true`](subscription-status#retrieving-the-access-level-from-the-server) ### 購入の復元 \{#restore-purchase\} `Purchases.shared.restorePurchases` を [`Adapty.restorePurchases`](restore-purchase) に置き換えてください。 ### ユーザーのログイン状態を確認する \{#check-if-the-user-is-logged-in\} `Purchases.shared.isAnonymous` を `if profile.customerUserId == nil` に置き換えてください。 ### ユーザーのログイン \{#log-in-user\} `Purchases.shared.logIn` を [`Adapty.identify`](identifying-users#set-customer-user-id-after-configuration) に置き換えてください。 ### ユーザーのログアウト \{#log-out-user\} `Purchases.shared.logOut` を [`Adapty.logout`](identifying-users#logging-out-and-logging-in) に置き換えてください。 ## App Storeのサーバーサイド通知をAdaptyに切り替える \{#switch-app-store-server-side-notifications-to-adapty\} 手順は[こちら](migrate-to-adapty-from-another-solutions#changing-apple-server-notifications)をご覧ください。 ## アプリの新バージョンをテストしてリリースする \{#test-and-release-a-new-version-of-your-app\} ここまで読んでいるということは、すでに以下の作業が完了しているはずです: - [x] Adapty ダッシュボードの設定 - [x] Adapty SDKのインストール - [x] SDKロジックのAdapty関数への置き換え - [x] App StoreのサーバーサイドサービスをAdaptyに切り替え(オプションでRevenueCatへのrawイベント転送を有効化) - [ ] サンドボックスでの購入テスト - [ ] 新しいアプリのリリース 上記の項目を確認したら、サンドボックスでテスト購入を行い、アプリをリリースしてください。 :::info [リリースチェックリスト](release-checklist)を確認してください。 リストを使って既存のインテグレーションを検証し、[アトリビューション](attribution-integration)や[アナリティクス](analytics-integration)インテグレーションなどの追加機能の設定も行いましょう。 ::: ## (オプション)RevenueCatの過去データをCSV形式でエクスポートする \{#optional-export-your-revenuecat-historical-data-in-csv-format\} :::warning 過去データのインポートは慌てないでください 過去データのインポートを行う前に、SDK搭載バージョンのリリース後、少なくとも1週間は待つ必要があります。その間にSDKから購入金額に関する情報がすべて取得されるため、インポートされるデータがより正確になります。 ::: [RevenueCatの公式ドキュメント](https://www.revenuecat.com/docs/integrations/scheduled-data-exports)の手順に従って、RevenueCatからCSV形式で過去データをエクスポートしてください。 ## (オプション)RevenueCatサポートにGoogle Purchase Tokensをリクエストする \{#optional-ask-revenuecat-support-for-google-purchase-tokens\} Google Playのトランザクションをインポートする場合は、RevenueCatの[サポートページ](https://app.revenuecat.com/settings/support)からGoogle Purchase Tokensが含まれたCSVファイルをリクエストしてください。Google Purchase Tokenは、Google Playが各トランザクションに付与する一意の識別子で、Adaptyで購入を正確に追跡・検証するために必要です。この情報は標準のエクスポートファイルには含まれていません。ファイルには以下の3つの列が含まれます: - `user_id` - `google_purchase_token` - `google_product_id` ## 過去データのインポートをご依頼ください \{#write-us-to-import-your-historical-data\} ウェブサイトのメッセンジャーまたは[support@adapty.io](mailto:support@adapty.io)にCSVファイルを添付してご連絡ください。 1. RevenueCatからエクスポートしたCSVファイルをサポートチームに直接送付してください。 2. Google Playのトランザクションをインポートする場合は、RevenueCatサポートから受け取ったGoogle Purchase Tokensが含まれたCSVファイルも添付してください。 3. Customer User ID(AdaptyのメインユーザーID)として使用するユーザーIDをお知らせください:`rc_original_app_user_id` または `rc_last_seen_app_user_id_alias` のいずれかです。 サポートチームがトランザクションをAdaptyにインポートします。各トランザクションについて以下のデータがインポートされます: | パラメータ | 説明 | | ----------------------------- | ------------------------------------------------------------ | | user_id | Customer User ID。Adaptyおよびあなたのシステムにおけるユーザーのメイン識別子。 | | apple_original_transaction_id | サブスクリプションチェーンの場合、`store_original_transaction_id`でリンクされた元のトランザクションの購入日。 | | google_product_id | Google Play StoreのプロダクトID。 | | google_purchase_token | 各トランザクションに対してGoogle Playが発行する一意の識別子。検証に必要。 | | country | ユーザーの国。 | | created_at | ユーザー作成日時。 | | subscription_expiration_date | サブスクリプションの有効期限日時。 | | email | エンドユーザーのメールアドレス。 | | phone_number | エンドユーザーの電話番号。 | | idfa | Appleがユーザーのデバイスに割り当てる広告識別子(IDFA)。 | | idfv | 1人の開発者の全アプリに割り当てられ、デバイス上でそれらのアプリ間で共有されるベンダー識別子(IDFV)。 | | advertising_id | 広告トラッキングのためにAndroid OSが提供する一意の識別子。 | | attribution_channel | マーケティングチャネル名。 | | attribution_campaign | マーケティングキャンペーン名。 | | attribution_ad_group | アトリビューションの広告グループ。 | | attribution_ad_set | アトリビューションの広告セット。 | | attribution_creative | アトリビューションのクリエイティブキーワード。 | また、Amplitude、Mixpanel、AppsFlyer、Adjust、FacebookAdsのインテグレーション識別子もインポートされます。 ## よくある質問 \{#faq\} ### Adapty SDKのインストールとAdapty SDK搭載の新バージョンのリリースが完了しました。Adapty SDKを含む新バージョンにアップデートしていない既存のサブスクライバーはどうなりますか? \{#i-successfully-installed-adapty-sdk-and-released-a-new-app-version-with-it-what-will-happen-to-my-legacy-subscribers-who-did-not-update-to-a-version-with-adapty-sdk\} ほとんどのユーザーは夜間に充電する際にApp Storeが全アプリを自動更新するため、問題にはならないでしょう。アップデートしていない有料サブスクライバーが若干残る可能性はありますが、引き続きプレミアムコンテンツにアクセスできます。強制的にアップデートさせる必要はありません。 ### RevenueCatから過去データをできるだけ早くエクスポートする必要がありますか?それとも失ってしまいますか? \{#do-i-need-to-export-my-historical-data-from-revenuecat-as-quickly-as-possible-or-will-i-lose-it\} 急ぐ必要はありません。まずAdapty SDKでリリースを行い、その後に過去データをご提供ください。ユーザーの支払い履歴を復元し、[プロファイル](profiles-crm)と[チャート](charts)に反映します。 ### MMP(AppsFlyer、Adjustなど)やアナリティクス(Mixpanel、Amplitudeなど)を使用しています。すべて正常に動作するか確認するにはどうすればいいですか? \{#i-use-mmp-appsflyer-adjust-etc-and-analytics-mixpanel-amplitude-etc-how-do-i-make-sure-that-everything-will-work\} まず、データを送信したいサードパーティサービスのIDをSDK経由でAdaptyに渡す必要があります。[アトリビューションインテグレーション](attribution-integration)と[アナリティクスインテグレーション](analytics-integration)のガイドをご参照ください。過去データや既存ユーザーについては、**RevenueCatからエクスポートしたデータからそれらのIDを必ず渡してください。** --- # File: migration-from-superwall --- --- title: "Superwallからの移行" description: "SuperwallからAdaptyへの移行を、SDKの全コールとコンセプトをマッピングしたステップバイステップガイドで行いましょう。" --- SuperwallからAdaptyへの移行は、ほとんどの場合2時間程度で完了します。SDKを入れ替え、ストアのサーバー通知をAdaptyに向け直し、新しいアプリリリースを公開するだけです。有料サブスクライバーはアクセスを維持できます — Adaptyは初回起動時にApp StoreとGoogle Playのレシートからアクセスを復元します。 :::info サブスクライバーは自動的に移行されます サブスクリプションを有効化したことがあるすべてのユーザーは、Adapty SDKを搭載した新バージョンのアプリを開いた時点でAdaptyに移行されます。サブスクリプション状態の検証とプレミアムアクセスは自動的に復元されます。 ::: ## このガイドの構成 \{#how-this-guide-is-organized\} 移行は6つのステップで進みます: 1. [SuperwallのコンセプトをAdaptyにマッピングする](#map-your-superwall-concepts-to-adapty) 2. [Adapty SDKをインストールする](#install-the-adapty-sdk) 3. [SDKの呼び出しを置き換える](#replace-sdk-calls) 4. [App StoreとGoogle Playのサーバー通知を切り替える](#switch-app-store-and-google-play-server-notifications) 5. [テストとリリース](#test-and-release) 6. [(オプション) 過去のデータをインポートする](#optional-import-historical-data) ## SuperwallのコンセプトをAdaptyにマッピングする \{#map-your-superwall-concepts-to-adapty\} Superwallのコンセプトのほとんどは、Adaptyに直接対応するものがあります: | Superwall | Adapty | 変更点 | | :------------------- | :------------------------------------------------ | :--------------------------------------------------------------------------- | | Campaign | [プレースメント](placements) + [オーディエンス](audience) | キャンペーンのロジックは、プレースメント(場所)とオーディエンス(ルール)に分かれます。 | | Placement | [プレースメント](placements) | 同じコンセプト、同じ名前。 | | Audience filter | [オーディエンス](audience) | ルールセットはプレースメント内に存在します。 | | Entitlement | [アクセスレベル](access-level) | 名前付き識別子(例:`premium`)。 | | WebView paywall | [ペイウォールビルダーのペイウォール](adapty-paywall-builder) | `WKWebView`ではなく、Adapty SDKがネイティブにレンダリングします。 | | `PurchaseController` | 組み込み | 実装すべきプロトコルなし — Adaptyが購入処理を担当します。 | | Feature gating | [アクセスレベル](access-level)チェック | `profile.accessLevels["premium"]?.isActive`を確認します。 | コードに触れる前に、2つの考え方の転換を理解しておきましょう: - **フェッチと表示は別ステップです**: Superwallの`register`は、ペイウォールのフェッチ、キャンペーンの評価、UIの表示を1回の呼び出しで行います。Adaptyはこれらのステップを分けています — ペイウォールをフェッチし、その設定を取得してから表示します。手順は増えますが、設定のプリロード、カスタムローディング状態の表示、独自ロジックに基づいた表示のキャンセルが可能になります。 - **サブスクリプション状態はアクセスレベルごとです**: Superwallは単一の`subscriptionStatus`パブリッシュプロパティを公開します。Adaptyは名前付きアクセスレベルを持つ[`AdaptyProfile`](https://swift.adapty.io/documentation/adapty/adaptyprofile)を返すため、1人のユーザーが`sports`と`science`のアクセスレベルを独立して持つことができます。同期的な読み取りには、ビューの読み込みごとに`getProfile()`を呼び出すのではなく、`AdaptyDelegate`からプロファイルをキャッシュしてください。 ## Adapty SDKをインストールする \{#install-the-adapty-sdk\} お使いのプラットフォーム向けのAdapty SDKをインストールしてください — [iOS](sdk-installation-ios)、[Android](sdk-installation-android)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter)、[Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)、[Unity](sdk-installation-unity)、または[Capacitor](sdk-installation-capacitor) — そして同時にSuperwalKitをプロジェクトから削除してください。 ## SDKの呼び出しを置き換える \{#replace-sdk-calls\} インテグレーションの各部分を確認しながら、SupwallのコールをAdaptyの対応するものに置き換えてください。各サブセクションの末尾にあるリンクは7つのプラットフォームSDKすべてをカバーしています — アプリに合うものを参照してください。 ### SDKを初期化する \{#initialize-the-sdk\} `Superwall.configure`を`Adapty.activate`に置き換えます。 お使いのプラットフォームのインストールガイドを参照してください — [iOS](sdk-installation-ios)、[Android](sdk-installation-android)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter)、[Kotlin Multiplatform](sdk-installation-kotlin-multiplatform)、[Unity](sdk-installation-unity)、または[Capacitor](sdk-installation-capacitor)。 ### ユーザーの識別とログアウト \{#identify-and-log-out-users\} `Superwall.shared.identify`を`Adapty.identify`に、`Superwall.shared.reset`を`Adapty.logout`に置き換えます。両SDKとも初回起動時に匿名プロファイルを生成するため、これらの呼び出しはユーザーのサインインまたはサインアウト時のみ必要です。識別後はペイウォールを再フェッチしてください — 新しいユーザーは別のオーディエンスに解決される可能性があります。 お使いのプラットフォームの識別ガイドを参照してください — [iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Kotlin Multiplatform](kmp-identifying-users)、[Unity](unity-identifying-users)、または[Capacitor](capacitor-identifying-users)。 ### ペイウォールのフェッチと表示 \{#fetch-and-present-a-paywall\} `Superwall.shared.register`を2ステップのフローに置き換えます:`Adapty.getPaywall`でペイウォールをフェッチし、`AdaptyUI.getPaywallConfiguration`でビュー設定を読み込み、それから表示します。 2つの違いに注目してください: - **`feature:`クロージャに代わるフィーチャーゲーティング**: ペイウォールが閉じた後、返されたプロファイル(または`Adapty.getProfile`)のアクティブなアクセスレベルを確認し、そこから分岐します。 - **ペイウォールはSDKによってレンダリングされます**: Superwallは`WKWebView`内でペイウォールをレンダリングします。Adaptyはペイウォールビルダーのペイウォールをネイティブにレンダリングします — フォント、プロダクト情報、ボタンはSDKによって描画されます。 お使いのプラットフォームのペイウォールクイックスタートを参照してください — [iOS](ios-quickstart-paywalls)、[Android](android-quickstart-paywalls)、[React Native](react-native-quickstart-paywalls)、[Flutter](flutter-quickstart-paywalls)、[Kotlin Multiplatform](kmp-quickstart-paywalls)、[Unity](unity-quickstart-paywalls)、または[Capacitor](capacitor-quickstart-paywalls)。 ### サブスクリプション状態を確認する \{#check-subscription-status\} `Superwall.shared.subscriptionStatus`を、プロファイルの名前付きアクセスレベルのチェックに置き換えます:`profile.accessLevels["premium"]?.isActive`。変更の監視は`@Published`プロパティパターンの代わりに`AdaptyDelegate.didLoadLatestProfile(_:)`を使用し、同期的な読み取りのためにプロファイルをキャッシュしてください。 お使いのプラットフォームのサブスクリプション状態確認ガイドを参照してください — [iOS](ios-check-subscription-status)、[Android](android-check-subscription-status)、[React Native](react-native-check-subscription-status)、[Flutter](flutter-check-subscription-status)、[Kotlin Multiplatform](kmp-check-subscription-status)、[Unity](unity-check-subscription-status)、または[Capacitor](capacitor-check-subscription-status)。 ### 購入と復元を処理する \{#handle-purchases-and-restores\} ペイウォールビルダーを使用する場合、両SDKともペイウォールUI内で購入を自動的に処理します — **このステップはスキップできます**。 カスタムペイウォールの場合、Superwallは`PurchaseController`の実装を必要とします。Adaptyは不要です:`PurchaseController.purchase`を`Adapty.makePurchase`に、`PurchaseController.restorePurchases`を`Adapty.restorePurchases`に置き換えてください。SDKが自動的に検証を処理します。 お使いのプラットフォームのカスタムペイウォールクイックスタートを参照してください — [iOS](ios-quickstart-manual)、[Android](android-quickstart-manual)、[React Native](react-native-quickstart-manual)、[Flutter](flutter-quickstart-manual)、[Kotlin Multiplatform](kmp-quickstart-manual)、[Unity](unity-quickstart-manual)、または[Capacitor](capacitor-quickstart-manual)。 ### ユーザー属性を設定する \{#set-user-attributes\} `Superwall.shared.setUserAttributes`を`Adapty.updateProfile`に置き換えます。 お使いのプラットフォームのユーザー属性ガイドを参照してください — [iOS](setting-user-attributes)、[Android](android-setting-user-attributes)、[React Native](react-native-setting-user-attributes)、[Flutter](flutter-setting-user-attributes)、[Kotlin Multiplatform](kmp-setting-user-attributes)、[Unity](unity-setting-user-attributes)、または[Capacitor](capacitor-setting-user-attributes)。 ## App StoreとGoogle Playのサーバー通知を切り替える \{#switch-app-store-and-google-play-server-notifications\} ストアのサーバー通知をAdaptyに向け直してください。Adaptyはそれなしでも動作しますが、アナリティクス、サードパーティインテグレーション、A/Bテストの指標はこれに依存しています: - **App Store**: [App Storeサーバー通知を有効にする](enable-app-store-server-notifications)の手順に従ってください。 - **Google Play**: [リアルタイム開発者通知を有効にする](enable-real-time-developer-notifications-rtdn)の手順に従ってください。 ロールアウト中にSuperwallとAdaptyを並行して動かしたい場合は、[rawイベントフォワーディング](enable-app-store-server-notifications#raw-events-forwarding)を使用してください — AdaptyがストアイベントをそのままのかたちでSuperwallに転送する一方で、新しいインテグレーションを検証できます。 ## テストとリリース \{#test-and-release\} リリース前に、各項目を確認してください: - [x] Adapty ダッシュボードを設定済み(プロダクト、ペイウォール、プレースメント、アクセスレベル) - [x] Adapty SDKをインストール済み - [x] Superwall SDKの呼び出しをAdaptyの対応するものに置き換え済み - [x] App StoreとGoogle PlayのサーバーNotificationsをAdaptyに向け直し済み - [ ] サンドボックス購入を実施済み - [ ] 新しいアプリリリースを提出済み 最終検証として[リリースチェックリスト](release-checklist)を確認してください。 ## (オプション) 過去のデータをインポートする \{#optional-import-historical-data\} Superwallはサブスクリプション状態を所有していません — それはApp StoreとGoogle Playが所有しています。Adaptyは初回起動時にレシートを検証するため、有料ユーザーはインポートなしでアクセスを維持できます。 過去のトランザクションをAdaptyアナリティクスにバックフィルしたい場合は、[Adaptyへの過去データのインポート](importing-historical-data-to-adapty)の手順に従ってください。SDKが新しい購入価格を収集する時間を確保するため、SDKリリース後少なくとも1週間待ってください。 ## よくある質問 \{#faq\} ### アプリを更新しないサブスクライバーはどうなりますか? \{#what-happens-to-subscribers-who-dont-update-the-app\} ほとんどのユーザーは夜間に自動更新するため、旧バージョンを使用しているユーザーの割合は急速に減少します。旧バージョンのサブスクライバーは、App StoreまたはGoogle Playを通じて直接アクセスを維持します — 強制更新は必要ありません。 ### Superwallのキャンペーンオーディエンスは引き継がれますか? \{#do-my-superwall-campaign-audiences-carry-over\} いいえ。SuperwallのオーディエンスフィルターとAdaptyのオーディエンスは異なるダッシュボードで設定され、異なる識別子を使用します。ターゲティングをAdaptyの[プレースメント](placements)内の[オーディエンス](audience)として再作成してください。ほとんどのアプリは1〜2つのプレースメント(オンボーディングと一般的なアプリ内トリガー)を使用しているため、再構築は通常短時間で完了します。 ### `getPresentationResult`に相当するものはAdaptyにありますか? \{#does-adapty-have-an-equivalent-to-getpresentationresult\} 単一の呼び出しとしては存在しません。プレースメントがペイウォールを表示するかどうかを確認するには、`Adapty.getPaywall(placementId:)`を呼び出し、結果に基づいて分岐します。呼び出しが成功すれば、そのユーザーのオーディエンスにペイウォールが割り当てられています。ペイウォールが設定されていないために失敗した場合は、表示をスキップしてフォールバックロジックを実行してください。 --- # File: importing-historical-data-to-adapty --- --- title: "Adaptyへの過去データのインポート" description: "詳細なアナリティクスのためにAdaptyへ過去データをインポートします。" --- Adapty SDKをインストールしてアプリをリリースすると、[Profiles](profiles-crm)セクションでユーザーとサブスクライバーを確認できます。しかし、レガシーインフラを持っていてAdaptyへ移行したい場合や、既存のデータをAdaptyで確認したい場合はどうすればよいでしょうか? :::note データのインポートは必須ではありません Adapty SDKが組み込まれたアプリをユーザーが開くと、Adaptyは自動的に過去ユーザーへアクセスレベルを付与し、購入イベントを復元します。このユースケースでは、過去データのインポートは不要です。ただし、大量の過去トランザクションがある場合、データのインポートによってアナリティクスの精度が上がります。移行に際して一般的には必須ではありません。 ::: Adaptyにデータをインポートするには: 1. トランザクションをCSVファイルにエクスポートします(iOS、Android、Stripeごとに別々のファイルを用意してください)。詳細な要件については、下記の[インポートファイルの形式](importing-historical-data-to-adapty#import-file-format)セクションを参照してください。 2. ファイルが1 GBを超える場合は、約100行のデータサンプルを準備してください。 3. すべてのファイルをGoogle Driveにアップロードします(圧縮してもかまいませんが、それぞれ別々のファイルのままにしてください)。 4. iOSトランザクションについては、StoreKit 1を使用している場合でも、[**App settings**](https://app.adapty.io/settings/ios-sdk)の**In-app purchase API**セクションに**Issuer ID**、**Key ID**、**Private key**(.P8ファイル)が入力されていることを確認してください。詳細な手順については、[Issuer IDとKey IDの入力](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id)および[アプリ内購入キーファイルのアップロード](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file)セクションを参照してください。 5. [メール](mailto:support@adapty.io)またはAdapty Dashboardのオンラインチャットでチームにリンクを共有してください。 過去データのインポートは、Adaptyの既存エントリと重複する場合でも、重複が発生することはありませんのでご安心ください。 ## Androidの既知の制限事項 \{#known-limitations-for-android\} 1. アクティブなサブスクリプションのみが復元されます。期限切れのトランザクションは復元されません。 2. サブスクリプションの最新の更新のみが復元されます。購入の全チェーンは復元されません。 3. 購入後にプロダクト価格が変更された場合、現在の価格が使用されるため、価格が正しく表示されないことがあります。 :::note Androidトランザクションの件数が多い場合、デフォルトのAPI制限を超えないよう、インポートを開始する前に[Google Play Developer APIのクォータ増加をリクエスト](google-play-quota-increase)する必要があるかもしれません。 ::: ## インポートファイルの形式 \{#import-file-format\} :::tip RevenueCatから移行する場合、RevenueCatのエクスポートファイルをそのまま送信できます。変換は不要です。エクスポート手順については[RevenueCatのドキュメント](https://www.revenuecat.com/docs/integrations/scheduled-data-exports)を参照してください。 ::: 以下のルールに従ったファイルでデータを準備してください: - [ ] ファイル形式は.CSVです。 - [ ] Android、iOS、Stripeのインポートはそれぞれ別々のファイルを使用します。 - [ ] すべてのインポートファイルに[必須カラム](importing-historical-data-to-adapty#required-fields)がすべて含まれています。 - [ ] インポートファイルのカラムにヘッダーがあります。 - [ ] カラムヘッダーは下記の表の**Column name**列に記載されているものと完全に一致します。タイポがないか確認してください。 - [ ] 必須でないカラムはファイルに含めなくてもかまいません。データがない場合、空のカラムを追加しないでください。 - [ ] インポートファイルには、表に記載されていない余分なカラムを含めないでください。含まれている場合は削除してください。 - [ ] 値はカンマで区切られています。 - [ ] 値は引用符で囲まれていません。 - [ ] 1人のユーザーに対して複数の**apple_original_transaction_id**がある場合、それぞれの**apple_original_transaction_id**ごとに別の行として追加してください。そうしないと、消耗型アイテムの購入を復元できない場合があります。 サンプルファイルとして、[iOS](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_ios_sample.csv)および[Android](https://raw.githubusercontent.com/adaptyteam/adapty-docs/refs/heads/main/Downloads/adapty_import_android_sample.csv)のファイルをご利用ください。 ### インポートファイルの利用可能なカラム \{#available-import-file-columns\} | カラム名 | 必須/任意 | 説明 | |-----------|--------|-----------| | **user_id** | 必須 | ユーザーのID | | **apple_original_transaction_id** | iOSで必須 | <p>オリジナルトランザクションIDまたはOTID([詳細](https://developer.apple.com/documentation/appstoreserverapi/originaltransactionid))。StoreKit 2のインポートメカニズムで使用されます。1人のユーザーが複数のOTIDを持つ場合、インポートを成功させるには少なくとも1つを提供すれば十分です。</p><p></p><p>**注意:** このインポートにはAdapty Dashboardでアプリ内購入APIの資格情報を設定する必要があります。設定方法は[こちら](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file)をご覧ください。</p> | | **google_product_id** | Googleで必須 | Google Play StoreのプロダクトID | | **google_purchase_token** | Googleで必須 | ユーザーと購入したアプリ内プロダクトのプロダクトIDを表す一意の識別子 | | **google_is_subscription** | Googleで必須 | 使用可能な値は `1` \| `0` | | **stripe_token** | Stripeで必須 | 一意の購入を表すStripeオブジェクトのトークン。StripeのSubscription(`sub_...`)またはPayment Intent(`pi_...`)のトークンのいずれかを使用できます。 | | **subscription_expiration_date** | 任意 | サブスクリプションの有効期限日(次の課金日)。タイムゾーン付きの日時(2020-12-31T23:59:59-06:00) | | **created_at** | 任意 | プロファイル作成日時(2019-12-31 23:59:59-06:00) | | **birthday** | 任意 | ユーザーの誕生日(形式:2000-12-31) | | **email** | 任意 | ユーザーのメールアドレス | | **gender** | 任意 | ユーザーの性別 | | **phone_number** | 任意 | ユーザーの電話番号 | | **country** | 任意 | 形式:[ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) | | **first_name** | 任意 | ユーザーの名 | | **last_name** | 任意 | ユーザーの姓 | | **last_seen** | 任意 | タイムゾーン付きの日時(2020-12-31T23:59:59-06:00) | | **idfa** | 任意 | IDFA(広告識別子)は、Appleがユーザーのデバイスに割り当てるランダムなデバイス識別子です。iOSアプリのみに適用されます | | **idfv** | 任意 | IDFV(ベンダー識別子)は、1人の開発者が開発したすべてのアプリに割り当てられる一意のコードです。iOSアプリのみに適用されます | | **advertising_id** | 任意 | 広告IDは、AndroidのOSによって割り当てられる一意のコードで、広告主がユーザーのデバイスを一意に識別するために使用することがあります | | **amplitude_user_id** | 任意 | AmplitudeのユーザーID | | **amplitude_device_id** | 任意 | AmplitudeのデバイスID | | **mixpanel_user_id** | 任意 | MixpanelのユーザーID | | **appmetrica_profile_id** | 任意 | AppMetricaのユーザープロファイルID | | **appmetrica_device_id** | 任意 | AppMetricaのデバイスID | | **appsflyer_id** | 任意 | AppsFlyerの一意識別子 | | **adjust_device_id** | 任意 | AdjustのデバイスID | | **facebook_anonymous_id** | 任意 | Facebookがアプリやウェブサイトに匿名でアクセスするユーザー(Facebookにログインしていない状態)に対して生成する一意識別子 | | **branch_id** | 任意 | Branchの一意識別子 | | **attribution_source** | 任意 | アトリビューションのソースインテグレーション(例:appsflyer) | | **attribution_status** | 任意 | organic | | **attribution_channel** | 任意 | トランザクションをもたらしたアトリビューションチャネル | | **attribution_campaign** | 任意 | トランザクションをもたらしたアトリビューションキャンペーン | | **attribution_ad_group** | 任意 | トランザクションをもたらしたアトリビューション広告グループ | | **attribution_ad_set** | 任意 | トランザクションをもたらしたアトリビューション広告セット | | **attribution_creative** | 任意 | 広告やマーケティングキャンペーンで使用される特定のビジュアルまたはテキスト要素。クリック、コンバージョン、インストールなどの目的のアクションを促進する効果を測定するために追跡されます | | **custom_attributes** | 任意 | キーと値の形式のJSON辞書として最大30個のカスタム属性を定義します:<ul><li>**key**:(文字列)カスタム属性の名前</li><li>**value**:(文字列、整数、浮動小数点数、またはブール値)カスタム属性の値</li></ul><p>形式:`"{'string_value': 'some_value', 'float_value': 123.0, 'int_value': 456}"`</p><p>形式内のダブルクォートとシングルクォートの使い方に注意してください。ブール値と整数は浮動小数点数に変換されることにご注意ください。</p> | ### 必須フィールド \{#required-fields\} 各プラットフォームには、**user_id**と対応するプラットフォーム固有の購入を識別するデータという2つの必須フィールドグループがあります。プラットフォームごとの必須フィールドは下記の表を参照してください。 | プラットフォーム | 必須フィールド | |--------|---------------| | iOS | <p>user_id</p><p>apple_original_transaction_id</p> | | Android | <p>user_id</p><p>google_product_id</p><p>google_purchase_token</p><p>google_is_subscription</p> | | Stripe | <p>user_id</p><p>stripe_token</p> | これらのフィールドがなければ、Adaptyはトランザクションを取得できません。 正確なコホートアナリティクスのために、`created_at`を指定してください。指定しない場合、インストール日は最初の購入日と同じとみなされます。 ### Adaptyへのデータインポート \{#import-data-to-adapty\} [support@adapty.io](mailto:support@adapty.io)または[Adapty Dashboard](https://app.adapty.io/overview)のオンラインチャットからお問い合わせいただき、インポートファイルを共有してください。 --- # File: migrate-integrations-to-adapty --- --- title: "Adaptyへのインテグレーション移行" description: "レガシーソリューションからAdaptyへのアナリティクスおよびアトリビューションインテグレーションの切り替えを、イベントの重複やキャンペーンの中断なく行う方法。" --- Adaptyへの移行はSDKの切り替えだけでは完結しません。AmplitudeやAdjustなどのサードパーティのアナリティクス・アトリビューションインテグレーションも、並行して切り替える必要があります。慎重に進めれば、重複や欠落イベントを最小限に抑え、キャンペーンを中断させることなく移行できます。 ## イベントのマッピング \{#map-your-events\} ほとんどのAdaptyインテグレーションでは、イベント名をカスタマイズできます。ダッシュボードやキャンペーンですでに使用しているイベント名に合わせて設定することが可能です。これにより、切り替え後も同じイベント名でアナリティクスやキャンペーンのレポートを継続して利用できます。Adaptyで利用可能なイベントの一覧は、[イベント](events)をご確認ください。 Adjustの場合、インテグレーションではカスタムイベント名の代わりにイベントIDを使用します。AdjustダッシュボードのイベントIDをAdaptyのインテグレーション設定に移行してください。詳細は[Adjustインテグレーションガイド](adjust)を参照してください。 ## Adaptyによるインテグレーションイベントの作成方法 \{#how-adapty-creates-integration-events\} インテグレーションにイベントを送信するには、Adaptyにユーザーのプロファイルが必要です。プロファイルは以下のいずれかの方法で作成されます: - **過去データのインポート**:SDKが稼働する前に[過去のトランザクションデータをインポート](importing-historical-data-to-adapty)した際にプロファイルが作成されます。 - **SDKとのインタラクション**:ユーザーが初めてAdapty SDKを搭載したアプリを開いたときに自動的にプロファイルが作成されます。 Adaptyはレガシーシステムで行われた購入をリアルタイムで把握しますが、購入者のプロファイルが存在して初めてインテグレーションイベントを送信できます。プロファイルはユーザーがAdapty SDKを搭載したアプリを開いたときに作成されます。新バージョンにアップデートしないユーザーは、インテグレーションイベントを生成しません。 ## 移行前の準備 \{#prepare-before-migration-day\} ### 過去イベントの除外 \{#exclude-historical-events\} [インテグレーション設定](configuration)で **Exclude Historical Events** を有効にしてください。これにより、ユーザーの最初のAdapty SDKセッション以前のイベントがインテグレーションに送信されるのを防ぎます。 この設定は、大量の過去トランザクションをまとめて処理する[過去データのインポート](importing-historical-data-to-adapty)時に特に重要です。有効にしないと、それらのトランザクションがアナリティクスツールに大量のイベントを生成してしまいます。 ### インテグレーションを事前にセットアップする \{#set-up-the-integration-in-advance\} Adaptyでは、インテグレーションを無効のままテストや設定を行うことができます。認証情報、イベントのマッピング、フィルターを設定しておき、準備が整うまでインテグレーションを有効化しないことが可能です。設定は保存されるため、移行当日まで無効にしておいても何も失われません。 インテグレーションの確認方法については、[アトリビューションインテグレーション](attribution-integration)、[アナリティクスインテグレーション](analytics-integration)、[メッセージングサービスインテグレーション](messaging)、または[WebhookおよびETLインテグレーション](webhook-and-etl)を参照してください。 ## 移行当日の切り替え \{#switch-on-migration-day\} レガシーソリューションのインテグレーションを無効にすると同時に、Adaptyのインテグレーションを有効にしてください。両方を同時に動かすと、イベントが重複して送信されます。 移行当日は大規模な獲得キャンペーンを一時停止してください。これにより、切り替えのタイミングで発生するイベントのオーバーラップによるキャンペーン最適化エラーのリスクを軽減できます。 ## 移行後に想定されること \{#what-to-expect\} 移行中にインテグレーションイベントの欠落や重複がある程度発生するのは避けられません。ただし、正しく切り替えを行えば、影響を受けるイベントの数はごくわずかです。 欠落の主な原因は前述のタイミングの問題です。Adaptyは購入者のプロファイルが作成されて初めて、その購入に対するインテグレーションイベントを送信できます。レガシーシステムで行われた購入は、購入者がAdapty SDKを搭載したアプリを開くまでAdaptyのインテグレーションイベントを生成しません。 ## インテグレーションとサーバー間通知の違い \{#integrations-vs-server-to-server-notifications\} Adaptyは、ストアからの生のサーバー間通知をアナリティクスやアトリビューションツールに直接転送するのではなく、インテグレーションを使用することを推奨しています。 インテグレーションを利用するメリット: - **統一されたフォーマット**:App Store、Google Play、Stripeなど、すべてのストアからのイベントが同じイベントフォーマットで送信されます。 - **データの充実**:イベントにはサブスクリプションの状態やユーザー属性など、Adaptyが収集するデータが含まれます。生の通知にはこれらは含まれません。 --- # File: whats-new --- --- title: "最新情報" description: "Adaptyの最新機能と改善内容をご確認ください" --- 最新機能、改善内容、SDKアップデート、ドキュメントの更新情報をまとめています。アプリのマネタイズ戦略を最適化するのに役立つ、毎月の主要リリースをご紹介します。 :::note 新機能へのフィードバックをお聞かせください! ぜひご意見をお寄せください。[プロダクトフィードバックボード](https://adapty.featurebase.app/en?b=69831ba5e82e7a3391632ec2)からお気軽にご連絡ください。 ::: ## 2026年7月 \{#july-2026\} - **仮想通貨**: トークン、コイン、ジェムなどのアプリ内通貨を定義し、ユーザーごとに残高を付与・管理して、サーバーサイドAPIからその残高を読み取れます。[詳細を見る](virtual-currencies) - **Apple Ads ManagerのAIエージェント**: Apple Adsのパフォーマンスについてアドバイザリーチャットエージェントに質問すると、手動でレポートを作成しなくてもキャンペーンデータから回答を得られます。[詳細を見る](ads-manager-ai-agent) - **Apple Ads Manager の新しい自動化**: 既存のキーワードおよび検索語句の自動化に加え、2 つの新しいルールタイプでキャンペーンおよび広告グループレベルの変更を自動化できます。[キャンペーンルール](ads-manager-automations-campaign-rules) | [広告グループルール](ads-manager-automations-ad-group-rules) - **Adapty Mail のプロファイル**: サブスクライバーごとのビューで、各ユーザーのジャーニー、現在のサブスクリプション状態、購読解除ステータスを一か所で確認できます。[詳細を見る](mail-profiles) - **React Native、Flutter、Capacitor、Kotlin Multiplatform 向け SDK v4**: フロー対応の v4 SDK が登場しました。React Native、Flutter、Capacitor は正式リリース(GA)となり、Kotlin Multiplatform v4 もローンチ — それぞれ専用のマイグレーションガイドをご用意しています。[React Native](migration-to-react-native-sdk-v4) | [Flutter](migration-to-flutter-sdk-v4) | [Capacitor](migration-to-capacitor-sdk-v4) | [Kotlin Multiplatform](migration-to-kmp-sdk-v4) - **新しいwebhookフィールド**: webhookのペイロードに各トランザクションの元の価格と割引が含まれるようになりました。これにより、プロモーションオファーや初回オファーの価格をダウンストリームで追跡できます。これらのフィールドはwebhookのみで利用できます。[詳しくはこちら](webhook-event-types-and-fields) - **フローでの取り消し線付き価格**: フローBuilder内で、割引後の価格の横に取り消し線付きの元の価格と割引バッジを直接表示できます。[詳しくはこちら](strikethrough-price) - **フローテンプレートギャラリー**: 空白のキャンバスではなく、プロが作成したテンプレートから新しいフローを開始し、アプリに合わせてカスタマイズできます。[詳細はこちら](paywall-builder-templates) - **インストールツールボタン**: すべてのドキュメント記事のヘッダーに **Install tools** ボタンが追加されました。このボタンをクリックすると、Claude Code、Copilot CLI、Gemini CLI、Codex などの AI コーディングアシスタントに Adapty SDK インテグレーションスキルをインストールするためのコピー可能なコマンドが表示されるモーダルが開きます。[詳細はこちら](adapty-sdk-integration-skill) - **Unityの新しいSDKインストール方法**: Unity SDKをSwift Package Manager経由でインストールできるようになりました。よくあるセットアップ上の問題に対するトラブルシューティングガイダンスも追加されています。[詳細を見る](sdk-installation-unity) - **フロービルダーのフッターコンテナ**: 画面の残りの部分がスクロールしても下部に固定されるスティッキーパネルで、CTAボタン、法的テキスト、リンクの配置に最適です。[詳細を見る](builder-containers#footer) - **新しいフロービルダーの動画チュートリアル**: フローの構築方法をステップバイステップで解説するYouTubeプレイリストが充実しており、フロービルダーのガイド全体に埋め込まれています。[詳細を見る](adapty-flow-builder) ## 2026年6月 \{#june-2026\} - **FlowがAndroidに対応**: ペイウォールとオンボーディングのビジュアルノーコードビルダーが、iOSに加えてAndroid SDK v4以降でも利用できるようになりました。画面はウェブビューなしでネイティブにレンダリングされます。[詳細はこちら](adapty-flow-builder) - **Apple Ads ManagerでCPP A/B テスト**: Apple Ads内でカスタムプロダクトページ同士を比較できます。現在のデフォルトを含む2〜4ページを選択すると、Apple Adsがトラフィックをローテーションし、どのページが最もコンバージョンを獲得できるかをレポートします。[詳細はこちら](ads-manager-cpp-ab-tests) - **Adapty Mail API**: ユーザープロファイルとトランザクションを Adapty Mail へサーバーから直接送信できます。Adapty SDK を経由する必要はありません。購読者ベースの初期データ投入、他のアプリの購読者の再利用、またはバックエンドを信頼できる唯一の情報源として維持する際にご活用ください。[詳細はこちら](mail-send-data-via-api) - **初回起動時にApple Ads向けペイウォールを表示する**: Apple AdsのアトリビューションはSDKのアクティベーション後に届くため、早すぎるタイミングでペイウォールをリクエストするとApple Ads向けオーディエンスを見逃す可能性があります。`AdaptyProfile.appliedAttributionSources`を使って、アトリビューションデータが届いた時点でApple Ads向けペイウォールをすぐに表示しましょう。[iOS](ios-show-aa-targeted-paywall) | [React Native](react-native-show-aa-targeted-paywall) | [Capacitor](capacitor-show-aa-targeted-paywall) - **フロービルダーの自動保存**: フロービルダーが1分ごとに進行状況を自動保存するようになりました。ページを離れても未保存の作業が失われる心配はありません。**Cmd/Ctrl + S** で手動ドラフト保存も引き続き利用できます。[詳細はこちら](builder-save-publish) - **フロービルダーの新しい動画チュートリアル**: フロー画面間のナビゲーション構築と、選択済み・アクティブ・無効などの要素ステートのデザインを解説する2本のウォークスルー動画を追加しました。[フロー内のナビゲーション](onboarding-navigation-branching) | [要素のステート](builder-element-states) - **日本語とベトナム語のドキュメント**: Adaptyのドキュメントが日本語(日本語)とベトナム語(Tiếng Việt)で利用可能になりました。上部ナビゲーションの言語セレクターで切り替えができます。 ## 2026年5月 \{#may-2026\} - **フロー(ベータ版)**: ビジュアルなノーコードビルダーで画面シーケンス全体を作成できます — 単一画面のペイウォール、複数ステップのオンボーディング、そしてその間のあらゆる構成を1つのフローにまとめられます。画面はネイティブにレンダリングされ、ウェブビューは不要です。アプリのリリースなしに、テキスト、デザイン、ロジックを更新できます。現在は iOS、Android、React Native、Flutter、および Capacitor SDK v4 以上をサポートしています。[詳細はこちら](adapty-flow-builder) - **オートパイロットがテスト結果に適応するようになりました**: AI グロースマネージャーとして機能し、ラウンドが完了するたびに成長プランを更新します。次の仮説は、これまでに実施した実験、勝利した実験、まだ探索する価値のある方向性を踏まえて構築されます。固定された順序に従うのではありません。[詳細を見る](autopilot-how-it-works#how-ai-growth-advisor-decides-what-to-recommend) - **Autopilot マーケットインサイトのアクティベーション ARPU**: 新しいチャートで、アプリの新規インストールあたりの平均収益をカテゴリ平均と比較できます。コンバージョンファネルと組み合わせて使うと効果的で、コンバージョンが高いのにアクティベーション ARPU が低い場合は、価格が低すぎる可能性を示している可能性があります。[詳細を見る](autopilot-analysis#activation-arpu) - **Adapty Mail のアナリティクス**: 各キャンペーンの配信指標とメール経由の収益を一画面で比較できます。キャンペーン、セグメント、A/B バリアント、メッセージ、トリガーでグループ化・絞り込み・内訳表示が可能で、任意の行をドリルダウンすることもできます。[詳細を見る](mail-analytics) - **Adapty Mailにおけるブランドプロファイル**: メールのコピー、トーン、ビジュアル、ウェブペイウォールのコンテンツを一元管理するプロファイルです。アプリのストアリスティング、ランディングページ、法的ページ、ソーシャルプロファイルをもとにAdaptyが構築し、各セクションをインラインで確認・編集できます。[詳細を見る](mail-brand) - **Adapty UA の予測**: 各コホートの予測収益、ROAS、広告利益、ARPU、ARPPU を確認できるため、キャンペーンが成熟する前に比較できます。予測はアプリ独自の過去のコホートデータから構築され、毎日更新され、D0 から D360 または任意の日のコホート期間で利用できます。[詳細を見る](ua-predicted-metrics) - **Adapty UA カスタム S3 エクスポートの新しいフィールド**: カスタム S3 エクスポートに `bundle_id`、`device_brand`、`device_model`、`os_version`、`app_version`、`sdk_version` が追加されました。デバイスやアプリバージョンごとにアトリビューションデータをスライス・結合できます。[詳しくはこちら](ua-custom-s3) - **CLI でのプレースメントオーディエンス**: `adapty placements create` および `adapty placements update` コマンドに `--audiences` フラグが追加されました。`{segment_ids, paywall_id, priority}` エントリの JSON 配列を指定することで、ターミナルから異なるセグメントに異なるペイウォールをターゲティングできます。新しい `adapty paywalls placements` コマンドは、指定したペイウォールを使用しているすべてのプレースメントを一覧表示するため、切り替え前に影響を確認できます。[詳細はこちら](developer-cli-reference#placements) - **スペイン語版ドキュメント**: Adapty ドキュメントがスペイン語(Español)でもご利用いただけるようになりました。上部ナビゲーションの言語セレクターから切り替えてください。 ## 2026年4月 \{#april-2026\} - **Adapty Mail**: トライアルユーザーを有料サブスクライバーへ転換するAI生成メールキャンペーン。Adaptyプロジェクトからキャンペーンの作成・送信・アトリビューションをすべて管理でき、別途メールプラットフォームは不要です。[詳細を見る](adapty-mail) - **Autopilot でのペイウォール診断**: テストを始める前に、ペイウォールの改善点を把握できます。スクリーンショットをアップロードすると、Autopilot が同カテゴリの上位アプリのベンチマークに基づく推奨事項と、AI が生成したレイアウト・コピーの提案を返します。ベンチマーク結果はグロースプランの A/B テストラウンドになります。[詳細はこちら](autopilot-analysis#paywall-analysis) - **すべての Autopilot 提案がわかりやすくなりました**: 各仮説に、なぜそれが重要なのか(ペイウォールが確立されたパターンからどう外れているかをデータで説明)、何を変更すべきか・A/B テストの設定方法、そして結果の読み方を解説する「How to interpret your results」セクションが追加されました。[詳細を見る](autopilot-execute-plan#step-1-view-the-hypothesis) - **Autopilot成長プランを最新の状態に保つ**: 分析を更新して最新の市場データや新しい提案を取り込み、バージョン履歴から過去の提案を見直すこともできます。仮説はTop priority、All、Pricing、Visual、Geo-pricing、Archivedタブに分類されています。[詳しくはこちら](autopilot-growth-plan) - **Autopilot の期間別収益分布**: サブスクリプション期間が一つに偏っていないか確認できます。新しい Market Insights チャートでは、カテゴリーと国ごとの業界平均と並べて、期間別の収益構成を表示します。[詳細を見る](autopilot-analysis#revenue-distribution-by-duration) - **LTV と収益予測の更新**: 予測 LTV および収益は、十分な履歴データがある場合はアプリ独自のコホートリテンションデータを使用し、そうでない場合はクロスアプリの平均値を使用するようになりました。これにより、新しいアプリでも分析や A/B テストで実用的な予測が得られます。[詳細はこちら](predicted-ltv-and-revenue) - **Adapty UA でのすべてのイベント送信**: Meta と TikTok にコンバージョンの全体像を提供し、オーディエンスモデリングの精度を高めます。Adapty では、キャンペーンにマッチしたユーザーだけでなく、オーガニックや未アトリビューションユーザーのインストールおよびトランザクションをピクセルに転送できるようになりました。[Meta](ua-facebook#send-all-events) | [TikTok](ua-tiktok#send-all-events) - **ロシア語とトルコ語のドキュメント**: Adapty ドキュメントがロシア語(Русский)とトルコ語(Türkçe)で利用できるようになりました。上部ナビゲーションの言語セレクターで切り替えてください。 ## 2026年3月 \{#march-2026\} - **Developer CLI**: ダッシュボードを開かずにターミナルからAdaptyアカウントを管理できます。CLIを使うと、アプリの作成、アクセスレベルの定義、プロダクトのセットアップ、ペイウォールの作成、プレースメントの設定を行うことができ、自動化された環境でスクリプト化することも可能です。AIコーディングアシスタントがCLIを使いやすくなるための[Adapty CLIスキル](https://github.com/adaptyteam/adapty-cli/tree/main/skills/adapty-cli)も利用できます。[詳細を見る](developer-cli) - **Apple Ads ManagerのOverviewページ**: 主要なApple Ads指標をすべて1か所で確認でき、各指標にはトレンドチャートが表示されます。ヘッダーのドロップダウンでアプリを絞り込み、表示する指標のカスタマイズやチャートの種類・収益表示の調整も可能です。[詳細はこちら](ads-manager-overview) - **Apple Ads ManagerのMarket Intelligence**: 競合他社が50か国以上でどのキーワードに広告を出稿しているかを確認し、パフォーマンスの高いキーワードをキャンペーンに直接追加できます。[詳細はこちら](ads-manager-market-intelligence) - **Apple Ads Managerにおけるキーワードの完全サイクル自動化**: 定義したパフォーマンスルールに基づき、入札額の調整、キーワードの一時停止・有効化、広告グループ間の移動を自動で行えます。[詳細を見る](ads-manager-automations-keyword-rules) - **Apple Ads Managerにおける入札履歴**: 任意のキーワードのCPT入札額の変更ログ(変更日時、変更前後の値、トリガーとなった自動化ルール)を確認できます。[詳細を見る](ads-manager-manage-keywords#bid-history) - **Autopilotのビジュアルラウンド**: ペイウォールデザインの提案が、グロースプランのファーストクラスのラウンドとして追加されました。収益化ラウンドと並んでサイドバーに表示され、各ビジュアルラウンドにはデザインのモックアップ、そのパターンが最も効果的な場面の説明、および対象となる主要な指標が含まれています。[詳しくはこちら](autopilot-growth-plan#view-the-growth-plan) - **Autopilot に独自の仮説を追加する**: カスタムラウンドを追加して成長プランを拡張できます。タイトル、説明、ラウンドタイプ(マネタイゼーションまたはビジュアル)、目標指標、そしてマネタイゼーションラウンドの場合は関連プロダクトを設定できます。[詳細はこちら](autopilot-growth-plan#add-your-own-hypothesis) - **Autopilot ラウンドの並べ替え**: 成長プランのステージをドラッグして並べ替え、戦略に最適な順序で実験を実行できます。[詳細はこちら](autopilot) - **Autopilot のジオプライシングラウンド**: 成長プランの新しいラウンドタイプとして、国別の価格変更をテストできます。Market Insights のデータをもとに、Autopilot が各国で価格を上げるか、下げるか、維持するかを推奨します。推奨事項をジオプライシングラウンドとして追加すると、A/B テストとして実行できます(最大5件を同時実行可能)。[詳細はこちら](autopilot-growth-plan#geo-pricing-hypotheses) - **Apple Ads Managerの検索語句オートメーション**: 手動でレポートをダウンロードすることなく、勝利した検索語句を完全一致キーワードに自動的にプロモートし、ソースで除外できます。ルールはテンプレートから作成することも、カスタム条件やスケジュールを使って一から作成することもできます。[詳しくはこちら](ads-manager-automations-search-terms) - **Apple Ads ManagerのMaximize Conversions入札**: キャンペーン作成時に、入札戦略としてMaximize Conversionsを選択できるようになりました。Appleのアルゴリズムが、オプションの目標CPAをガイドラインとして、予算内でダウンロード数を最大化します。[詳細はこちら](ads-manager-create-campaign) - **Adapty UAでのFunnelFoxインテグレーション**: Adapty UAにFunnelFoxとの新しいインテグレーションが追加されました。[FunnelFox](ua-funnelfox) - **中国語ドキュメント**: Adaptyのドキュメントが中国語(中文)で利用できるようになりました。上部ナビゲーションの言語セレクターで言語を切り替えてください。 ## 2026年2月 \{#february-2026\} - **国別プロダクト価格設定**: Adapty ダッシュボードから直接、国ごとに異なる価格を設定できます。変更は App Store Connect と Google Play に自動で同期され、すべての価格更新は監査ログに記録されるため、変更を見逃すことはありません。[詳細を見る](edit-product) - **Autopilot における国レベルの競合価格比較**: 主要市場での競合他社のサブスクリプション価格と自社の価格を比較できます。[詳細を見る](autopilot-analysis#market-and-competitor-analysis) - **オンボーディングのバージョン管理**: オンボーディングのバージョンを完全な変更履歴とともに管理できます。変更内容を確認し、必要に応じてロールバックも可能です。 - **アナリティクスのペイウォールコンバージョンチャート**: 「ペイウォール表示 → トライアル」と「ペイウォール表示 → 有料」の2つの新しいコンバージョンチャートにより、ペイウォールが閲覧者をサブスクリプション登録者へどのように転換しているかを把握できます。[詳しくはこちら](analytics-conversion) - **セグメントの複製**: 既存のセグメントをすべてのフィルターごとコピーして、類似したセグメントをゼロから作り直す手間を省けます。重複するオーディエンスで複数のキャンペーンや A/B テストを実行する場合に便利です。[詳細を見る](segments#duplicate-segments) - **Adapty モバイルアプリでのプッシュ通知**: Adapty iOS アプリで 14 種類のイベントに対するプッシュ通知を設定することで、ダッシュボードを開かなくてもサブスクリプションの状況を把握できます。[詳細を見る](push-notifications) - **Kotlin Multiplatform SDK 3.15**: オンボーディングサポート、Webペイウォール、APIの改善を追加。[詳細はこちら](migration-to-kmp-315) - **Capacitor SDK 3.16**: Capacitor 8サポートを追加。Capacitor 7を使用しているプロジェクトはSDK v3.15のままにしてください。[詳細はこちら](migration-to-capacitor-316) - **LLM支援SDKインテグレーションガイド**: AIコーディングアシスタントの助けを借りてAdaptyを統合するためのステップバイステップガイド。ダッシュボードのセットアップから購入まで、実装全体をLLMと一緒に進められます。[iOS](adapty-cursor) | [Android](adapty-cursor-android) | [React Native](adapty-cursor-react-native) | [Flutter](adapty-cursor-flutter) | [Unity](adapty-cursor-unity) | [Kotlin Multiplatform](adapty-cursor-kmp) | [Capacitor](adapty-cursor-capacitor)。ワンコマンドの自動フローには、新しい**adapty-sdk-integration skill**(ベータ版)をお試しください: [iOS](adapty-sdk-integration-skill) | [Android](adapty-sdk-integration-skill-android) | [React Native](adapty-sdk-integration-skill-react-native) | [Flutter](adapty-sdk-integration-skill-flutter) | [Unity](adapty-sdk-integration-skill-unity) | [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) | [Capacitor](adapty-sdk-integration-skill-capacitor) ## 2026年1月 \{#january-2026\} - **Capacitor SDKが正式リリース**: Capacitor SDKが十分なテストを経て、プロダクション対応になりました。Adaptyとの完全な統合サポートにより、CapacitorでiOSおよびAndroid向けのサブスクリプションアプリを構築できます。[詳細はこちら](capacitor-sdk-overview) - **新規アプリ向けオートパイロット**: トランザクション履歴が少ないアプリでも、オートパイロット分析が利用できるようになりました。データに基づく価格最適化の提案を受け取り、初日から成長プランを作成できます。[詳細はこちら](autopilot) - **Autopilot のグローバル価格設定機会**: 国別の価格設定の推奨事項により、主要市場での収益ポテンシャルを把握できます。Autopilot は次の上位 5 か国のコンバージョン率と購買力を分析し、Adapty Pricing Index に基づいて価格を上げるべきか、下げるべきか、据え置くべきかについてデータに基づいたインサイトを提供します。[詳しくはこちら](autopilot) - **支払い回収のコンバージョン指標**: 支払い問題やグレース期間から回収された収益を追跡する新しいアナリティクスチャートが追加されました。「Billing issue converted」「Billing issue converted revenue」「Grace period converted」「Grace period converted revenue」の各指標で、リテンション回復の取り組みを測定できます。 - **Apple Ads Manager での広告管理**: プラットフォームを切り替えることなく、Adapty 内で直接 Apple Ads キャンペーンを作成・管理できます。[詳細を見る](ads-manager-manage-ads) - **Apple Ads Manager analytics**: Adapty 内で広告レベルの詳細なパフォーマンス指標とアトリビューションデータにアクセスできます。キャンペーンのパフォーマンス、広告グループのアナリティクス、アトリビューションのインサイトを統合ダッシュボードで確認できます。[詳細はこちら](adapty-ads-manager-analytics) - **Apple Ads アトリビューションチャート**: 複数のアトリビューション指標をカスタマイズ可能なチャートに組み合わせて、サブスクリプションデータと合わせて Apple Ads のパフォーマンスを分析できます。[詳細はこちら](adapty-ads-manager-analytics#charts) - **Apple Ads アトリビューション セグメント**: Apple Ads のアトリビューションデータをもとに、2クリックで素早くユーザーセグメントを作成できます。キャンペーン、広告グループ、またはキーワードでユーザーをターゲティングし、より精度の高い分析や実験を行いましょう。[詳しくはこちら](ads-manager-create-segments) - **新しいドキュメントプラットフォーム**: ドキュメントサイトを新しいプラットフォームに移行しました。検索・ナビゲーション・コンテンツ構成が強化され、機能の更新が迅速に行えるようになり、ユーザー体験が向上しています。 ## 2025年12月 \{#december-2025\} - **Apple Ads Manager ドキュメント**: Apple Search Ads のキャンペーンデータと収益指標を1つのアナリティクスダッシュボードで確認できます。新しいドキュメントでは、キャンペーンの作成、広告グループの管理、サブスクリプションのパフォーマンスと広告費用対効果のトラッキング方法を解説しています。[詳しく見る](ads-manager) - **アプリ内ウェブペイウォール**: アプリ内ブラウザを使ってウェブベースのペイウォールをアプリ内に表示し、外部へのリダイレクトなしでシームレスな体験を提供します。[iOS](ios-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Android](android-web-paywall#open-web-paywalls-in-an-in-app-browser) | [React Native](react-native-web-paywall#open-web-paywalls-in-an-in-app-browser) | [Flutter](flutter-web-paywall#open-web-paywalls-in-an-in-app-browser) - **ローリングセグメント**: 動的なオーディエンスセグメントを作成できます。移動する時間ウィンドウに基づいて自動的に更新されるため、たとえば「過去7日以内にアプリをインストールしたユーザー」というセグメントを作成すると、常に最新のユーザーが表示された状態に保たれます。[詳細はこちら](segments#available-attributes) - **MetaおよびTikTokキャンペーン設定ガイド**: Meta(Facebook & Instagram)およびTikTokでキャンペーンを作成・追跡するためのステップバイステップのドキュメントです。コンバージョントラッキングやアナリティクス連携についても説明しています。[Meta](meta-create-campaign) | [TikTok](tiktok-create-campaign) - **手動ペイウォール実装クイックスタートガイド**: カスタムペイウォール UIにAdapty SDKを組み込む手順をステップバイステップで解説するクイックスタートガイドで、アプリ内課金をすばやく実装できます。[iOS](ios-implement-paywalls-manually) | [Android](android-implement-paywalls-manually) | [React Native](react-native-implement-paywalls-manually) | [Flutter](flutter-implement-paywalls-manually) | [Unity](unity-implement-paywalls-manually) | [Kotlin Multiplatform](kmp-quickstart-manual) | [Capacitor](capacitor-quickstart-manual) - **オンボーディングリンクのアプリ内ブラウザ対応**: オンボーディング内の外部リンクは、デフォルトでアプリ内ブラウザで開くようになり、ユーザーがアプリを離れません。必要に応じて外部ブラウザを使用するよう動作をカスタマイズすることも可能です。 [iOS](ios-present-onboardings#customize-how-links-open-in-onboardings) | [Android](android-present-onboardings#customize-how-links-open-in-onboardings) | [React Native](react-native-present-onboardings#customize-how-links-open-in-onboardings) - **Autopilot の提案が改善されました**: Autopilot がサブスクリプションデータをより詳細に分析し、価格最適化の提案精度が向上しました。[Autopilot を試す](autopilot) - **ドキュメントのダークモード対応**: ドキュメントがダークモードに対応しました。システム設定に合わせて自動切替、または右上のボタンで手動切替ができます。 --- # File: adapty-ecosystem --- --- title: "Adapty エコシステム" description: "Adapty はモバイルアプリ向けのアプリ内課金プラットフォームです。各プロダクトの役割と連携方法について説明します。" --- Adapty はモバイルアプリ向けのアプリ内課金プラットフォームで、「アプリを収益豊かにする」という一つのミッションのもとに構築されています。ユーザーの獲得・コンバージョン・サブスクリプション維持・離脱ユーザーの呼び戻しまで、収益成長に必要なすべてが揃っています。 サインアップ一度で、初日からAdatyのすべてのプロダクトにアクセスできます。Adaptyのロゴをクリックするだけでプロダクトを切り替えられます: - **Core** — StoreKitやGoogle Play Billingを直接触ることなく課金処理を行い、ノーコードでペイウォールをデザインし、収益をリアルタイムで追跡できます。他のプロダクトはこの基盤の上に構築されています。 - **Adapty Ads Manager** — Apple Adsの運用・最適化を、実際のサブスクリプション収益と照らし合わせながら行えます。 - **Adapty Attribution** — MMPなしで、収益を実際に生み出している広告チャネルを把握できます。 - **Adapty Mail** — 自動メールでトライアルユーザーをコンバートし、チャーンしたユーザーをウィンバックできます。 FunnelFox(ウェブからアプリへのファネルとホステッドチェックアウト)と **Adapty Finance**(将来のサブスクリプション収益を担保にした前払い)という2つのプロダクトも、コアの4つとともに提供されています。 ## プロダクトの全体像 \{#how-the-products-fit-together\} 各プロダクトは、ライフサイクルのそれぞれ異なるタイミングでユーザーに関わります。リンク付きの機能名にカーソルを合わせると簡単な説明が表示され、クリックするとドキュメントに移動します。 <ProductMap /> :::link 参照: [Adapty は自分に合っている?](is-adapty-right-for-me) ::: ## AIワークフローのために設計 \{#built-for-ai-workflows\} AdaptyをAIコーディングエージェントから実行できます。エディターを離れることなく、統合・管理・参照が可能です。エージェントをプラットフォーム向けの[SDK統合スキル](adapty-sdk-integration-skill)に向けると、一つのコマンドでセットアップ全体が完了します。または[ステップバイステップのLLMガイド](adapty-cursor)に従って、各ステップを自分で確認することもできます。 AIツールは、最適な方法でドキュメントを取得できます。**Copy for LLM** ボタンを使って任意のページをMarkdownとしてコピーするか、[`llms.txt`](https://adapty.io/docs/ja/llms.txt)(ドキュメント全体のマップ)を参照してください。ライブアクセスには、[Context7](https://context7.com/adaptyteam/adapty-docs) MCPサーバーを利用すると、Cursor、Claude Code、その他のIDEで最も関連性の高いコードスニペットをドキュメントから取得できます。すべてのエントリーポイントについては、[AIでAdaptyを管理する](manage-adapty-with-ai)を参照してください。 ## コア \{#core\} コアはAdaptyプラットフォームの基盤です。ペイウォールの表示、購入の管理、その後の成果の計測を行います。 ### SDK とストア \{#sdks-and-stores\} 決済の複雑な処理はスキップできます。Adapty が購入・レシートの検証・更新を代わりに処理し、すべてのサブスクライバーのステータスをリアルタイムで正確に保ちます。誰がアクセス権を持っていて、その理由も常に把握できます。 アプリ内では、[SDK](installation-of-adapty-sdks)が購入フロー全体を処理するか、[既存の課金システムを監視](observer-vs-full-mode)します。対応プラットフォームは7つ:[iOS](ios-sdk-overview)、[Android](android-sdk-overview)、[React Native](react-native-sdk-overview)、[Flutter](flutter-sdk-overview)、[Unity](unity-sdk-overview)、[Kotlin Multiplatform](kmp-sdk-overview)、[Capacitor](capacitor-sdk-overview)。 サーバーサイドでは、Adapty が各ストアに直接接続するため、更新、返金、課金に関するあらゆるイベントがリアルタイムで届きます — アプリが閉じていても同様です。対応ストア:[App Store](initial_ios)、[Google Play](initial-android)、[Stripe](stripe)、[Paddle](paddle)、およびその他のプロバイダー向けの[カスタムインテグレーション](custom-store)。 ### プロダクト、オファー、アクセスレベル \{#products-offers-and-access-levels\} Adapty では、販売するものとユーザーが利用できるものを分離しています。この分離によって、アプリのアップデートなしに価格変更、プロダクトの入れ替え、オファーの開始が可能です。この仕組みを支える3つの要素があります: - **[プロダクト](product)** — 1つのプロダクトでApp Store、Play Store、ウェブのSKUを統合できます。サブスクリプション、買い切り購入、消耗型アイテムに対応しており、カタログを一元管理できます。 - **[オファー](offers)** — コンバージョンを高める手段として、初回オファー、プロモーションオファー、ウィンバックオファーを利用できます。 - **[アクセスレベル](access-level)** — アクセス権限を個々のプロダクトから切り離して管理できます。 ### フローとプレースメント \{#flows-and-placements\} ペイウォール、オンボーディング、クイズなど、収益を生み出す画面をコードなしで作成できます。[フロー](adapty-flow-builder)はSDKを通じてデバイス上でレンダリングされるため、アプリのリリースなしでいつでもコピー、デザイン、価格を変更できます。[テンプレート](paywall-builder-templates)またはブランクキャンバスから始めて、各フローを[プレースメント](placements)に紐付け、[セグメント](segments)から作成した[オーディエンス](audience)ごとに異なるターゲティングを設定できます。 ### プロファイルとセグメント \{#profiles-and-segments\} [プロファイル](profiles-crm)では、任意のサブスクライバーを検索して全履歴を確認できます。イベントのタイムライン、サブスクリプションの状態、収益、カスタム属性がまとめて管理されています。[セグメント](segments)を使えば、任意の属性でユーザーベースを絞り込み、表示内容のパーソナライズ、アナリティクスのフィルタリング、A/B テストの対象設定が可能です。[イベントフィード](event-feed)では、サブスクリプションイベントをリアルタイムでストリーミング確認できます。 ### A/B テストと AI Growth Advisor \{#ab-tests-and-ai-growth-advisor\} 最も効果的なコンバージョン方法を見つけて収益を伸ばしましょう: - **[A/B テスト](ab-tests)** — 価格、トライアル期間、フローデザインをテストします。 - **[AI Growth Advisor](autopilot)** — 次に何を A/B テストすべきかを的確に教えてくれます。20,000 以上のサブスクリプションアプリに対してペイウォールのベンチマークを行い、期待される収益向上効果が高い順に実験をランク付けします。[仕組みを見る](autopilot-how-it-works)。 ### アナリティクスと予測 \{#analytics-and-predictions\} [アナリティクス](analytics)は、ストア・SDK・アトリビューションのデータをリアルタイムの収益ダッシュボードに変換し、App Store や Google Play が単独で表示するよりもはるかに多くの[数十の指標](metric-comparison-table)を提供します。[コホート](analytics-cohorts)、[ファネル](analytics-funnels)、[リテンション](analytics-retention)、[コンバージョン](analytics-conversion)分析でさらに深く掘り下げることができます。[予測](predicted-ltv-and-revenue)は各コホートの LTV を数ヶ月先まで予測し、統計的有意性に達する前に [A/B テストの勝者](predictions-in-ab-tests)を特定します。スケジュールされた[レポート](reports)はメールボックスに届きます。 ### デベロッパー CLI \{#developer-cli\} [Adapty デベロッパー CLI](developer-cli-quickstart) は、コマンドラインからプロダクト、プレースメント、アクセスレベルを設定できるツールです。ターミナルでの作業を好む開発者向けのダッシュボード代替手段です。 ## Adapty Ads Manager \{#adapty-ads-manager\} [Adapty Ads Manager](adapty-ads-manager) は Apple Ads プラットフォームです。Apple 純正の広告コンソールを、AI 駆動の最適化・リアルタイムの収益アトリビューション・競合インテリジェンスで置き換えます。Core がすべてのインストール・トライアル・サブスクリプション・更新を追跡しているため、Ads Manager は広告費用を LTV に直接結び付けます。MMP は不要です。 主な機能: - **[キャンペーンとキーワード](ads-manager)** — キャンペーン、広告グループ、入札単価をAdapty ダッシュボードから構築・管理できます。 - **[AIエージェント](ads-manager-ai-agent)** — 自然言語によるファネル全体のクエリと提案。 - **[マーケットインテリジェンス](ads-manager-market-intelligence)** — 50か国以上にわたる競合他社のキーワード戦略を把握できます。 - **[CPP A/B テスト](ads-manager-cpp-ab-tests)** — カスタムプロダクトページを直接比較します。 - **[オートメーション](ads-manager-automations)** — キャンペーンが自動で最適化されます。指標が設定したしきい値を超えると、入札単価・キーワード・検索語句が自動的に調整されます。 ## Adapty アトリビューション \{#adapty-attribution\} [Adapty アトリビューション](adapty-user-acquisition)は、アプリのインストールとサブスクリプション収益を、それをもたらした広告キャンペーンに紐付けます。広告プラットフォームの支出、トラッキングリンクのクリック、SDK のインストールイベントを組み合わせて、有料チャネル全体の ROAS・LTV・コホートビューを提供します。外部の MMP は不要です。 主な機能: - **[広告プラットフォーム連携](ua-integrations)** — Meta Ads、TikTok for Business、FunnelFox、S3/GCS パイプ。 - **[トラッキングリンク](ua-tracking-links)** — Adapty で生成し、キャンペーンに追加して、初回起動時にインストールと照合します。 - **[遅延ディープリンク](ua-deferred-data)** — インストール前にクリックされた場合でも、新規ユーザーを初回起動時にアプリ内の適切なコンテンツへ誘導します。 - **[アトリビューションデータ](ua-attribution-data)** — カスタムロジックのためにアプリ内でアトリビューションのペイロードを受け取ります。 ## Adapty Mail \{#adapty-mail\} [Adapty Mail](adapty-mail) は、ユーザーデータをAI生成メールキャンペーンに変換するサービスです。アプリのストアリスティング、ランディングページ、ソーシャルプロフィールから[ブランドプロフィール](mail-brand)を構築し、数分で完全なメールシーケンスを生成します。メールは認証済みドメインから送信され、各購入はそのきっかけとなったメールにアトリビューションされます。別のメールプラットフォームは不要です。 主な機能: - **[キャンペーン](mail-email-campaigns)** — 複数のメールで構成されるシーケンスを一括生成します。フローに紐付けると送信が開始されます。 - **[フロー](mail-flows)** — キャンペーンをセグメントおよび「未購入」「請求エラー」などのサブスクリプションイベントトリガーに紐付け、自動送信を実現します。 - **[ウェブペイウォール](mail-checkout)** — 受信者ごとにパーソナライズされたチェックアウトページを作成し、購入をメール経由で正確にアトリビューションします。 - **[セグメント](mail-segments)**と**[プロファイル](mail-profiles)** — コンバージョンしやすいユーザーにリーチします。購入状況・国・収益などでセグメントを作成し、キャンペーンやフローのトリガーとして活用できます。データはAdapty Coreから取得され、メールアドレスが登録された識別済みプロファイルに限定されます。 ## Adapty を既存のスタックに接続する \{#connect-adapty-to-your-existing-stack\} [サードパーティ連携](configuration)を使うと、サブスクリプションの[イベント](events)を、チームが既に使っているアナリティクス・アトリビューション・メッセージングプラットフォームに転送できます。 - **アナリティクス**: [Amplitude](amplitude)、[Mixpanel](mixpanel)、[PostHog](posthog)、[Firebase / Google Analytics](firebase-and-google-analytics)、[AppMetrica](appmetrica)、[SplitMetrics Acquire](splitmetrics) - **アトリビューション**: [AppsFlyer](appsflyer)、[Adjust](adjust)、[Branch](branch)、[Airbridge](airbridge)、[Apple Ads](apple-search-ads)、[Singular](singular)、[Tenjin](tenjin)、[Asapty](asapty)、[Facebook Ads](facebook-ads) - **メッセージング**: [Braze](braze)、[OneSignal](onesignal)、[Pushwoosh](pushwoosh)、[Slack](slack) - **Webhook と ETL**: カスタム[Webhook](webhook)、[Amazon S3](s3-exports)、[Google Cloud Storage](google-cloud-storage) ## より広いエコシステム \{#the-wider-ecosystem\} Adapty のデータと連携しながら、コアライフサイクル以外のニーズに対応する製品がさらに2つあります。 ### FunnelFox [FunnelFox](https://funnelfox.com/docs/integrations/subscription-management/adapty) は、Web からアプリへの導線を構築するファネルビルダーです。ランディングページやクイズを作成してユーザーをアプリに誘導し、[決済](https://funnelfox.com/docs/billing/integration-billing-funnelfox)エンジンで Web 上の支払いを処理します。FunnelFox を Adapty に接続することで、サブスクリプションの追跡と収益のアトリビューションが可能になります。 ### Adapty Finance [Adapty Finance](https://adapty.io/blog/introducing-adapty-finance/) は、将来のサブスクリプション収益を前払いで提供することで、ストアの支払いを待つ必要がなくなります。 ## 次のステップ \{#next-steps\} - **[Adapty は自分に向いている?](is-adapty-right-for-me)** — ユースケース別にプラットフォームを紹介します。 - **[クイックスタートガイド](quickstart)** — ストアの接続、プロダクトの追加、SDK の組み込みを行います。 - **[AI で Adapty を管理する](manage-adapty-with-ai)** — AI コーディングツールで Adapty を使うためのすべての入口。 --- # File: generate-in-app-purchase-key --- --- title: "App Store ConnectでIn-App Purchase Keyを生成する" description: "安全な取引のためのアプリ内課金キーを生成します。" --- **In-App Purchase Key**は、購入の正当性を確認することで購入を検証するために、App Store Connect内で作成される専用のAPIキーです。 :::note App Store Server APIのAPIキーを生成するには、App Store ConnectでAdminまたはAccount Holderのロールを持っている必要があります。APIキーの生成方法については、[Apple Developer Documentation](https://developer.apple.com/documentation/appstoreserverapi/creating-api-keys-to-authorize-api-requests)でも確認できます。 ::: 1. **App Store Connect**を開きます。[**Users and Access** → **Integrations** → **In-App Purchase**](https://appstoreconnect.apple.com/access/integrations/api/subs)セクションに進みます。 2. **Active**タイトルの横にある追加ボタン **(+)** をクリックします。 <img src="/assets/shared/img/6d737db-generate_in-app_key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 表示された **Generate In-App Purchase Key** ウィンドウで、後から参照しやすいようにキーの名前を入力します。この名前はAdaptyでは使用されません。 4. **Generate** ボタンをクリックします。**Generate in-App Purchase Key** ウィンドウが閉じると、作成されたキーが **Active** リストに表示されます。 <img src="/assets/shared/img/fac066b-download_inapp_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. APIキーを生成したら、**Download In-App Purchase Key** ボタンをクリックして、キーをファイルとして取得します。 <img src="/assets/shared/img/d59faff-download_in-app_purchase_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. **Download in-App Purchase Key** ウィンドウで、**Download** ボタンをクリックします。ファイルがコンピューターに保存されます。 このファイルは、後でAdapty ダッシュボードにアップロードするために安全に保管することが非常に重要です。生成されたファイルはダウンロードが1回しかできないため、アップロードするまで安全に保管してください。**In-App Purchase**セクションで生成した.p8キーは、[AdaptyとApp Storeの初期連携設定](app-store-connection-configuration#step-3-upload-in-app-purchase-key-file)の際に使用されます。 **次のステップ:** - [App Store連携を設定する](app-store-connection-configuration) --- # File: app-store-connection-configuration --- --- title: "App Store 連携を設定する" description: "シームレスなサブスクリプション追跡のために App Store 接続を設定します。" --- <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/VJQbzoTCkqs?si=l7BPX9mIu6GVGZ0Z" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> このセクションでは、iOS アプリの App Store と Adapty の接続を確立する方法について説明します。これは、サブスクリプション分析の表示と購入の検証を行うために必要です。インテグレーションは初回オンボーディング時、または後から Adapty ダッシュボードの **App Settings** で完了できます。 オンボーディング中にモバイルアプリと Adapty のインテグレーションを設定していた場合でも、**App settings** で後からこれらの設定を変更できます。 :::danger 設定の変更は、Adapty SDK をインストールしたモバイルアプリが公開される前のサンドボックスフェーズ中であれば安全に行えます。リリース後に変更すると、アプリの購入フローが壊れる可能性があります。 ::: ## ステップ 1. Bundle ID と Apple app ID を入力する \{#step-1-provide-bundle-id-and-apple-app-id\} **Bundle ID** と **Apple app ID** はどちらも必須です。**Bundle ID** は App Store におけるアプリの一意の識別子で、サブスクリプション処理などの Adapty のコア機能を有効にします。**Apple app ID** は、**Products** ページから[新しいプロダクトを作成してストアにプッシュする](create-product#create-product-and-push-to-store)際にも必要です。 :::note **Apple app ID** がない場合、**Products** ページの **Create a new product and push to stores** オプションは無効になりますが、ダッシュボードにはその理由が表示されません。 ::: 1. [App Store Connect](https://appstoreconnect.apple.com/apps) を開きます。アプリを選択し、**General** → **App Information** セクションに進みます。 2. **General Information** サブセクションで **Bundle ID** をコピーします。 <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 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. Issuer ID と Key ID を入力する \{#step-2-provide-issuer-id-and-key-id\} **In-app purchase Issuer ID**(App Store Connect では **Issuer ID** と表記)は、認証トークンを作成した発行者を識別する特別な ID です。**In-App Purchase Key ID**(App Store Connect では **Key ID** と表記)は、[App Store Connect でアプリ内購入キーを生成する](generate-in-app-purchase-key)セクションで生成した暗号化キーに関連付けられた一意の識別子です。 1. **App Store Connect** を開きます。[**Users and Access** → **Integrations** → **In-App Purchase**](https://appstoreconnect.apple.com/access/integrations/api/subs) セクションに進みます。 2. **Active** リストで、[App Store Connect でアプリ内購入キーを生成する](generate-in-app-purchase-key)セクションで作成したキーを見つけます。 <img src="/assets/shared/img/19a2868-issuer_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Issuer ID** をコピーして、Adapty ダッシュボードの **In-app purchase Issuer ID** フィールドに貼り付けます。 <img src="/assets/shared/img/c2b42e7-issuer_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Key ID** をコピーして、Adapty ダッシュボードの **In-app purchase Key ID** フィールドに貼り付けます。 ## ステップ 3. アプリ内購入キーファイルをアップロードする \{#step-3-upload-in-app-purchase-key-file\} [App Store Connect でアプリ内購入キーを生成する](generate-in-app-purchase-key)セクションでダウンロードした **In-App Purchase Key** ファイルを <img src="/assets/shared/img/88cdfff-download_inapp_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty ダッシュボードの **Private key (.p8 file)** フィールドにアップロードします。 <img src="/assets/shared/img/253b840-in-app_file_upload.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 4. トライアルと特別オファー向け – プロモーションオファーを設定する \{#step-4-for-trials-and-special-offers--set-up-promotional-offers\} :::important このステップは、アプリに[トライアルやその他のプロモーションオファー](offers)がある場合に必要です。 ::: 1. [ステップ 2](#step-2-provide-issuer-id-and-key-id) で使用したのと同じキー ID を、**App Store promotional offers** セクションの **Subscription key ID** フィールドにコピーします。 2. [ステップ 3](#step-3-upload-in-app-purchase-key-file) で使用したのと同じ **In-App Purchase Key** ファイルを、**App Store promotional offers** セクションの **Subscription key (.p8 file)** エリアにアップロードします。 <img src="/assets/shared/img/promo-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 5. App Store 共有シークレットを入力する \{#step-5-enter-app-store-shared-secret\} **App Store shared secret**(App Store Connect Shared Secret とも呼ばれます)は、アプリ内購入とサブスクリプションのレシート検証に使用される 32 文字の16進数文字列です。 1. [App Store Connect](https://appstoreconnect.apple.com/apps) を開きます。アプリを選択し、**General** → **App Information** セクションに進みます。 2. **App-Specific Shared Secret** サブセクションまでスクロールします。 <img src="/assets/shared/img/2bd112a-shared_secret_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::info **App-Specific Shared Secret** サブセクションが表示されない場合は、Account Holder または Admin ロールを持っているか確認してください。Admin ロールを持っているにもかかわらず **App-Specific Shared Secret** サブセクションが表示されない場合は、アプリの Account Holder(App Store Connect でアプリケーションを作成した人)に App Store 共有シークレットを生成するよう依頼してください。その後、Admin にもサブセクションが表示されるようになります。 ::: 3. **Manage** ボタンをクリックします。 <img src="/assets/shared/img/2d8b4c0-shared_secret_apple_copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 開いた **App-Specific Shared Secret** ウィンドウで、**Shared Secret** をコピーします。共有シークレットが表示されていない場合は、まず **Manage** または **Generate** のどちらか利用可能なボタンをクリックしてから、**Shared Secret** をコピーします。 5. コピーした **Shared Secret** を、Adapty ダッシュボードの **App Store shared secret** フィールドに貼り付けます。 <img src="/assets/shared/img/4f9624d-shared_secret.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. Adapty ダッシュボードの **Save** ボタンをクリックして変更を確定します。 ## ステップ 6. App Store Connect API キーを追加する \{#step-6-add-app-store-connect-api-key\} App Store Connect API キーを生成して Adapty に追加すると、[Adapty ダッシュボードから App Store のプロダクトを管理](create-product#create-product-and-push-to-store)できるようになります。 1. App Store Connect で [**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api) に移動し、**+** をクリックします。 <img src="/assets/shared/img/app-store-connect-api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Generate API key** ウィンドウで、キーの名前を入力し、**Admin** アクセス権を付与します。 <img src="/assets/shared/img/generate-api-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. キーの横にある **Download** をクリックします。ダウンロードは一度しか行えません。 <img src="/assets/shared/img/download-api-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Adapty ダッシュボードで [**App settings > iOS SDK**](https://app.adapty.io/settings/ios-sdk) に移動し、**Connect API key** をクリックします。 <img src="/assets/shared/img/connect-api-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. ウィンドウの各フィールドに入力します: - **Issuer ID**:[**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api) からコピーします。**API keys** テーブルの上に表示されています。 <img src="/assets/shared/img/issuer-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **Key ID**:[**Users and Access > Integrations > Team keys**](https://appstoreconnect.apple.com/access/integrations/api) からコピーします。**API keys** テーブルのキーの横に表示されています。 <img src="/assets/shared/img/key-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **API key**:App Store Connect からダウンロードした API キーファイルをアップロードします。 <img src="/assets/shared/img/app-store-connect-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. **Connect** をクリックします。 **次のステップ** - [App Store サーバー通知を有効にする](enable-app-store-server-notifications) --- # File: enable-app-store-server-notifications --- --- title: "App Store サーバー通知を有効にする" description: "App Store サーバー通知を有効にして、サブスクリプションイベントをリアルタイムで追跡します。" --- App Store サーバー通知を設定することは、データの正確性を確保するうえで非常に重要です。これにより、払い戻しやその他のイベントに関する情報を含む更新を App Store からリアルタイムで受け取ることができます。 :::important App Store Server Notifications V2 を完全にサポートするには、Adapty iOS SDK 2.10.0 以降が必要です。 ::: 1. Adapty ダッシュボードで **URL for App Store server notification** をコピーします。 <img src="/assets/shared/img/2901185-app_server_notifications.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. [App Store Connect](https://appstoreconnect.apple.com/apps) を開きます。アプリを選択し、**General** → **App Information** セクションの **App Store Server Notifications** サブセクションに進みます。 3. コピーした **URL for App Store server notification** を **Production Server URL** と **Sandbox Server URL** フィールドに貼り付けます。 <img src="/assets/shared/img/86fb3d2-app_server_notifications_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 生イベントの転送 \{#raw-events-forwarding\} Apple から生の S2S イベントを引き続き受け取りたい場合もあるかもしれません。Adapty を使用しながらこれを続けるには、**URL for forwarding raw Apple events** フィールドにエンドポイントを追加するだけで、Apple からの生イベントをそのままの形式で転送します。 <img src="/assets/shared/img/e9f4bba-CleanShot_2021-03-16_at_19.30.272x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **次のステップ** 以下のプラットフォーム向けに Adapty SDK を設定します: - [iOS](sdk-installation-ios) - [React Native](sdk-installation-reactnative) - [Flutter](sdk-installation-flutter) - [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [Unity](sdk-installation-unity) --- # File: troubleshoot-app-store-integration --- --- title: "App Store インテグレーションのトラブルシューティング" description: "保留中の契約、サーバー通知の遅延、価格の不一致など、Apple App Store のセットアップに関する一般的な問題を解決します。" --- この記事では、App Store インテグレーションに関する一般的な問題を説明します。各セクションでは、症状・根本原因・解決方法を紹介します。 ## プロダクトが表示されない \{#products-dont-appear\} 以下の 2 つの症状は、同じ根本原因を示しています。 - App Store Connect の API キーは正しく設定されているのに、Adapty がプロダクトをまったく取得できない。 - App Store Connect にプロダクトが存在するのに Adapty に表示されない、または期待より少ない数しか表示されない。購入を試みると SDK が「Product Id not found」と報告する。 最も一般的な根本原因は **Apple の契約が未署名** であることです — 有料契約・税務フォーム・銀行口座情報が保留中または未署名の状態になっています。契約が保留中の場合、App Store Connect API はプロダクト関連のエンドポイントに対してサイレントに 403 を返します。Adapty には明確なエラーが表示されず、プロダクトはサイレントに除外されます。 **App Store Connect → Agreements, Tax, and Banking** にアクセスして、保留中の契約にすべて署名してください。その後、Adapty の **App settings → iOS SDK** で再同期を行ってください。 ## App Store Server Notifications が「Delayed」と表示される \{#app-store-server-notifications-show-delayed\} App Store Connect で、App Store Server Notifications のステータスが **Delayed** と表示されることがあります。これは、Apple がサブスクリプションイベントの通知(更新・キャンセル・請求エラーなど)の送信を遅延させており、キューに入れられた通知が遅れて届くことを意味します。 インストール統計には影響しません。Adapty はインストールをサーバー側の通知からではなく、アプリの初回起動時にカウントします。 更新やキャンセルのデータが遅れている場合、Delayed ステータスが最も可能性の高い原因です。Apple がバックログを処理するにつれて、通常は自動的に解消されます。 ## Adapty の価格が App Store と一致しない \{#prices-in-adapty-dont-match-app-store\} Adapty のプロダクト編集ページの **price** フィールドは、プロダクトの追加方法によって動作が異なります。 Adapty でプロダクトを作成してダッシュボードからストアにプッシュする場合、この価格が初期ストア価格として使用されます。 すでにストアに存在するプロダクトを追加する場合、この価格はプレースホルダーです。Adapty のアナリティクス・インテグレーション・SDK は、App Store から取得した実際の価格を使用します。App Store の価格変更はプレースホルダーに同期されません。また、現時点ではダッシュボードからプレースホルダーを編集することもできません。 ## CSV の価格エクスポートが空になる \{#csv-price-export-is-empty\} CSV の価格エクスポートに列ヘッダーしか含まれていない場合、App Store Connect の API キーが完全に設定されていません。[ステップ 6 — App Store Connect API キーを追加する](app-store-connection-configuration#step-6-add-app-store-connect-api-key) を参照してください。 ## 新しいプロダクトを App Store にプッシュできない \{#cant-push-new-products-to-app-store\} Adapty はダッシュボードでプロダクトを作成したときに、App Store Connect にプッシュできます。App Store インテグレーションが完全に設定されていない場合、プッシュオプションはブロックされます。以下の 2 つの設定が必要です。 - **Apple app ID**: [ステップ 1 — Bundle ID と Apple app ID を入力する](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id) で設定してください。 - **App Store Connect API key**: [ステップ 6 — App Store Connect API キーを追加する](app-store-connection-configuration#step-6-add-app-store-connect-api-key) で設定してください。 --- # File: enabling-of-devepoler-api --- --- title: "Google Play ConsoleでDeveloper APIを有効にする" description: "AdaptyのDeveloper APIを有効にして、アプリのサブスクリプション管理を自動化・効率化しましょう。" --- <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/7dN50n5bcLc?si=c2znttIb--4VcrRO" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> アプリがPlay Storeで配信されている場合、Developer APIを有効にすることはAdaptyとの連携に欠かせません。このステップにより、アプリとAdatyプラットフォーム間のシームレスな通信が確立され、自動化処理やリアルタイムのデータ分析によってサブスクリプションモデルの最適化が可能になります。以下のAPIを有効にする必要があります: - [Google Play Android Developer API](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com) - [Google Play Developer Reporting API](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com) - [Cloud Pub/Sub API](https://console.cloud.google.com/marketplace/product/google/pubsub.googleapis.com) アプリをPlay Store経由で配信していない場合は、このステップをスキップできます。Play Storeで販売している場合は、今すぐ行わなくても構いませんが、Adaptyの基本機能には必須です。オンボーディング完了後、**App settings** セクションでアプリストアの設定を行えます。 Google Play ConsoleでDeveloper APIを有効にする手順は以下の通りです: 1. [Google Cloud Console](https://console.cloud.google.com/)を開きます。 2. Google Cloudウィンドウの左上で、使用するプロジェクトを選択するか、新しいプロジェクトを作成します。サービスアカウントのキーファイルをAdaptyにアップロードするまで、同じGoogle Cloudプロジェクトを使用し続けてください。 <img src="/assets/shared/img/fd66a11-google_cloud_project.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. [**Google Play Android Developer API**](https://console.cloud.google.com/apis/library/androidpublisher.googleapis.com) ページを開きます。 <img src="/assets/shared/img/f754f72-google_play_api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Enable** ボタンをクリックし、ステータスが **Enabled** になるまで待ちます。これでGoogle Android Developer APIが有効になります。 <img src="/assets/shared/img/d47ed14-google_play_api_create_credentials.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. [**Google Play Developer Reporting API**](https://console.cloud.google.com/apis/library/playdeveloperreporting.googleapis.com) ページを開きます。 <img src="/assets/shared/img/966cf73-Google_play_developer_reporting_api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. **Enable** ボタンをクリックし、ステータスが **Enabled** になるまで待ちます。 <img src="/assets/shared/img/e776d77-Google_play_developer_reporting_api_enabled.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. [**Cloud Pub/Sub API**](https://console.cloud.google.com/marketplace/product/google/pubsub.googleapis.com) ページを開きます。 <img src="/assets/shared/img/b13f609-enable_Cloud_Pub_Sub_API.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. **Enable** ボタンをクリックし、ステータスが **Enabled** になるまで待ちます。 <img src="/assets/shared/img/3f45602-Cloud_Pub_Sub_API_enabled.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Developer APIが有効になりました。 Google Cloud Consoleの [**APIs & Services**](https://console.cloud.google.com/apis/dashboard) ページで確認できます。ページを下にスクロールし、ページ下部の表に以下の3つのAPIがすべて含まれていることを確認してください: - Google Play Android Developer API - Google Play Developer Reporting API - Cloud Pub/Sub API <img src="/assets/shared/img/b81d174-google_enabled_api.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **次のステップ** - [Google Cloud Consoleでサービスアカウントを作成する](create-service-account) --- # File: create-service-account --- --- title: "Google Cloud ConsoleでServiceアカウントを作成する" description: "Adaptyで安全なAPIアクセスのためのサービスアカウントの作成方法を学びましょう。" --- Adaptyがデータアクセスを自動化するには、Google Play Consoleにサービスアカウントが必要です。 1. Google Cloud Consoleの[**IAM & Admin** -> **Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts)セクションを開きます。正しいプロジェクトを使用していることを確認してください。 <img src="/assets/shared/img/17bbf45-google_cloud_create_service_account.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Service accounts**ウィンドウで、**Create service account**ボタンをクリックします。 <img src="/assets/shared/img/b93eec1-service_account_details.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Create service account**ウィンドウの**Service account details**サブセクションで、任意の**Service Account Name**を入力します。このアカウントの目的を明示するために、名前に「Adapty」を含めることをおすすめします。**Service account ID**は自動的に作成されます。 4. サービスアカウントのメールアドレスをコピーして、後で使用できるように保存しておきます。 5. **Create and continue**ボタンをクリックします。 <img src="/assets/shared/img/e69d713-grant_access_to_project.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. **Grant this service account access to project**サブセクションの**Select a role**ドロップダウンリストで、**Pub/Sub -> Pub/Sub Admin**を選択します。このロールは、リアルタイム開発者通知を有効にするために必要です。 <img src="/assets/shared/img/976299c-service_account_role.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. **Add another role**ボタンをクリックします。 8. 新しい**Role**ドロップダウンリストで、**Monitoring -> Monitoring Viewer**を選択します。このロールは、通知キューの監視を許可するために必要です。 9. **Continue**ボタンをクリックします。 <img src="/assets/shared/img/ffe8d82-grant_user_access.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 10. 変更を加えずに**Done**ボタンをクリックします。**Service accounts**ウィンドウが開きます。 **次のステップ** - [Google Play Consoleでサービスアカウントに権限を付与する](grant-permissions-to-service-account) --- # File: grant-permissions-to-service-account --- --- title: "Google Play ConsoleでサービスアカウントにGoogle Play Consoleを付与する" description: "安全で効率的なAPIアクセスのため、サービスアカウントに権限を付与します。" --- Adaptyがサブスクリプションの管理と購入の検証に使用するサービスアカウントに、必要な権限を付与します。 1. Google Play Consoleの[**Users and permissions**](https://play.google.com/console/u/0/developers/8970033217728091060/users-and-permissions)ページを開き、**Invite new users**ボタンをクリックします。 <img src="/assets/shared/img/7b0e614-users_and_permissions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Invite user**ページで、作成したサービスアカウントのメールアドレスを入力します。 <img src="/assets/shared/img/3afd002-invite_user.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Account permissions**タブに切り替えます。 <img src="/assets/shared/img/4e2717b-account_permissions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 以下の権限を選択します: - View app information and download bulk reports (read-only) - View financial data, orders, and cancellation survey responses - Manage orders and subscriptions - Manage store presence 5. **Invite user**ボタンをクリックします。 6. **Send invite?**ウィンドウで、**Send invite**ボタンをクリックします。サービスアカウントがユーザーリストに表示されます。 **次のステップ** - [Google Play Consoleでサービスアカウントキーファイルを生成する](create-service-account-key-file) --- # File: create-service-account-key-file --- --- title: "Google Play ConsoleでサービスアカウントキーファイルをGoogleする" description: "Adaptyとのシームレスな連携のためのサービスアカウントキーファイルの作成方法を学びましょう。" --- Play StoreのモバイルアプリをAdaptyと連携するには、Google Play Consoleで特別なサービスアカウントキーファイルを生成してAdaptyにアップロードする必要があります。これらのファイルはアプリのセキュリティを強化し、不正アクセスを防ぎます。 :::warning 新しいサービスアカウントが有効になるまで、通常は少なくとも24時間かかります。ただし、[回避策](https://stackoverflow.com/a/60691844)があります。[Google Play Console](https://play.google.com/apps/publish/)でサービスアカウントを作成した後、任意のアプリを開いて **Monetize** -> **Products** -> **Subscriptions/In-app products** に移動します。任意のプロダクトの説明を編集して保存すると、サービスアカウントがすぐに有効化されます。その後、変更を元に戻すことができます。 ::: 1. Google Play Consoleの[**Service accounts**](https://console.cloud.google.com/iam-admin/serviceaccounts)セクションを開きます。正しいプロジェクトが選択されていることを確認してください。 <img src="/assets/shared/img/c3156cb-action_manage_keys.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 開いたウィンドウで **Add key** をクリックし、ドロップダウンメニューから **Create new key** を選択します。 <img src="/assets/shared/img/44b30ee-create_new_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Create private key for [Your_project_name]** ウィンドウで **Create** をクリックします。秘密鍵がJSONファイルとしてコンピューターに保存されます。**Private key saved to your computer** ウィンドウに表示されたファイル名を使って確認できます。 <img src="/assets/shared/img/e7b8101-cretae_private_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Create private key for Your_project_name** ウィンドウで **Create** ボタンをクリックします。これにより、秘密鍵がJSONファイルとしてコンピューターに保存されます。必要に応じて、表示された **Private key saved to your computer** ウィンドウのファイル名を使ってファイルを見つけることができます。 <img src="/assets/shared/img/187ddc6-Private_key_saved.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このファイルは、[Google Play Store連携を設定する](google-play-store-connection-configuration)際に必要になります。 :::warning 新しいサービスアカウントが有効になるまで、通常は少なくとも24時間かかります。ただし、[回避策](https://stackoverflow.com/a/60691844)があります。[Google Play Console](https://play.google.com/apps/publish/)でサービスアカウントを作成した後、任意のアプリを開いて **Monetize** -> **Products** -> **Subscriptions/In-app products** に移動します。任意のプロダクトの説明を編集して保存すると、サービスアカウントがすぐに有効化されます。その後、変更を元に戻すことができます。 ::: **次のステップ** - [Google Play Store連携を設定する](google-play-store-connection-configuration) --- # File: google-play-store-connection-configuration --- --- title: "Google Play Storeとの連携を設定する" description: "AdaptyでGoogle Play Storeの接続を設定し、アプリ内課金をスムーズに処理しましょう。" --- このセクションでは、Google Play経由で販売されているモバイルアプリをAdaptyと連携する手順を説明します。Play StoreのアプリケーションデータをAdapty ダッシュボードに入力する必要があります。この作業は、AdaptyがPlay Storeから購入を検証し、サブスクリプションの更新情報を受け取るために欠かせないステップです。 この設定は初回オンボーディング時に行うか、後からAdapty ダッシュボードの **App Settings** で変更できます。 :::danger 設定の変更は、Adaptyのペイウォールをアプリにリリースするまでのみ許容されます。リリース後に変更すると連携が壊れ、モバイルアプリでペイウォールが表示されなくなります。 ::: ## ステップ1. パッケージ名を入力する \{#step-1-provide-package-name\} パッケージ名は、Google Play StoreにおけるアプリのユニークなIDです。サブスクリプション処理などAdaptyの基本機能に必要です。 1. [Google Play Developer Console](https://play.google.com/console/u/0/developers)を開きます。 2. IDを確認したいアプリを選択します。**Dashboard** 画面が開きます。 <img src="/assets/shared/img/7889edb-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. アプリケーション名の下にあるプロダクトIDを確認し、コピーします。 4. AdaptyトップメニューからA[**App settings**](https://app.adapty.io/settings/android-sdk)を開きます。 <img src="/assets/shared/img/b00066c-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **App settings** 画面の **Android SDK** タブで、コピーした **Package name** を貼り付けます。 ## ステップ2. アカウントキーファイルをアップロードする \{#step-2-upload-the-account-key-file\} 1. [サービスアカウントキーファイルの作成](create-service-account)ステップで作成したサービスアカウントの秘密鍵ファイル(JSON形式)を、**Service account key file** エリアにアップロードします。 <img src="/assets/shared/img/20fdba1-service_key_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 変更を確定するために、**Save** ボタンをクリックするのを忘れずに。 **次のステップ** - [Google Play ConsoleでRTDN(リアルタイム デベロッパー通知)を有効にする](enable-real-time-developer-notifications-rtdn) --- # File: enable-real-time-developer-notifications-rtdn --- --- title: "Google Play ConsoleでリアルタイムデベロッパーNotification(RTDN)を有効にする" description: "Google Play ConsoleでリアルタイムデベロッパーNotification(RTDN)を有効にしてAdaptyのデータ精度を維持しましょう。払い戻しやその他の重要なイベントに関する即時更新を受け取るためのRTDNセットアップ方法を学びます" --- リアルタイムデベロッパーNotification(RTDN)を設定することは、データ精度を確保するうえで非常に重要です。これにより、払い戻しやその他のイベントに関する情報を含む、Play Storeからの更新をリアルタイムで受け取れるようになります。 ## 通知を有効にする \{#enable-notifications\} 1. **Google Cloud Pub/Sub** が有効になっていることを確認してください。[こちらのリンク](https://console.cloud.google.com/flows/enableapi?apiid=pubsub)を開き、アプリのプロジェクトを選択します。**Google Cloud Pub/Sub** をまだ有効にしていない場合は、ここで有効にする必要があります。 <img src="/assets/shared/img/pubsub.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Adaptyのトップメニューから [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) に移動し、**Google Play RTDN topic name** タイトルの横にある **Enable Pub/Sub API** フィールドの内容をコピーします。 <img src="/assets/shared/img/a72ff2d-copy_topic.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note **Enable Pub/Sub API** フィールドの内容が正しくない形式の場合(正しい形式は `projects/...` で始まります)、[Enable Pub/Sub APIフィールドの形式を修正する](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) セクションを参照してください。 ::: 3. [Google Play Console](https://play.google.com/console/) を開き、アプリを選択して、**Monetize with Play** -> **Monetization setup** に進みます。**Google Play Billing** セクションで、**Enable real-time notifications** チェックボックスをオンにします。 4. Adaptyの **App Settings** でコピーした **Enable Pub/Sub API** フィールドの内容を、**Topic name** フィールドに貼り付けます。 5. Google Play Consoleで **Save changes** をクリックします。 <img src="/assets/shared/img/e55ba0e-paste_topic_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 通知をテストする \{#test-notifications\} リアルタイムデベロッパーNotificationへの登録が成功したかどうかを確認するには: 1. Google Play Consoleの設定で変更を保存します。 2. Google Play Consoleの **Topic name** の下にある **Send test notification** をクリックします。 <img src="/assets/shared/img/rtdn-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. AdaptyのメニューにあるトップメニューからAdaptyの [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) に移動します。テスト通知が送信されると、トピック名の上にそのステータスが表示されます。 <img src="/assets/shared/img/rtdn-adapty-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Enable Pub/Sub APIフィールドの形式を修正する \{#fixing-incorrect-format-in-enable-pubsub-api-field\} **Enable Pub/Sub API** フィールドの内容が誤った形式の場合(正しい形式は `projects/...` で始まります)、以下の手順に従って問題を解決してください。 ### 1. APIの有効化と権限を確認する \{#1-verify-api-enablement-and-permissions\} 必要なAPIがすべて有効になっており、サービスアカウントに正しく権限が付与されていることを慎重に確認してください。これらの手順をすでに完了している場合でも、サブステップが抜けていないことを確かめるために再度確認することが重要です。以下のセクションの手順を繰り返してください: 1. [Google Play ConsoleでデベロッパーAPIを有効にする](enabling-of-devepoler-api) 2. [Google Cloud Consoleでサービスアカウントを作成する](create-service-account) 3. [Google Play Consoleでサービスアカウントに権限を付与する](grant-permissions-to-service-account) 4. [Google Play Consoleでサービスアカウントのキーファイルを生成する](create-service-account-key-file) 5. [Google Play Storeインテグレーションを設定する](google-play-store-connection-configuration) ### 2. ドメインポリシーを調整する \{#2-adjust-domain-policies\} **Domain restricted contacts** および **Domain restricted sharing** ポリシーを変更します: 1. [Google Cloud Console](https://console.cloud.google.com/) を開き、アプリを管理するためのサービスアカウントを作成したプロジェクトを選択します。 2. **Quick Access** セクションで、**IAM & Admin** を選択します。 <img src="/assets/shared/img/google-cloud-IAM-and-Admin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 左ペインで **Organization Policies** を選択します。 4. **Domain restricted contacts** ポリシーを見つけます。 <img src="/assets/shared/img/google-cloud-policy-action.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Actions** 列の省略記号ボタンをクリックし、**Edit policy** を選択します。 6. ポリシー編集ウィンドウで: 1. **Policy source** の下で、**Override parent's policy** ラジオボタンを選択します。 2. **Policy enforcement** の下で、**Replace** ラジオボタンを選択します。 3. **Rules** の下で、**ADD A RULE** ボタンをクリックします。 <img src="/assets/shared/img/google-cloud-edit-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **New rule** -> **Policy values** の下で、**Allow All** を選択します。 <img src="/assets/shared/img/google-cloud-allow-all-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **SET POLICY** をクリックします。 7. **Domain restricted sharing** ポリシーについても、手順4〜6を繰り返します。 最後に、**Google Play RTDN topic name** タイトルの横にある **Enable Pub/Sub API** フィールドの内容を再作成します。フィールドは正しい形式になります。 リアルタイムデベロッパーNotification(RTDN)の有効化に成功したら、更新したポリシーの **Policy source** を **Inherit parent's policy** に戻すことを忘れずに行ってください。 ## 生イベントの転送 \{#raw-events-forwarding\} 場合によっては、Googleからの生のS2Sイベントを引き続き受け取りたいこともあるでしょう。Adaptyを使用しながらそれらを受け取り続けるには、**URL for forwarding raw Google events** フィールドにエンドポイントを追加するだけで、Googleからの生イベントをそのまま送信します。 <img src="/assets/shared/img/e388892-001774-September-22-GhkjOFbT.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- **次のステップ** 以下のプラットフォーム向けにAdapty SDKを設定します: - [Android](sdk-installation-android) - [React Native](sdk-installation-reactnative) - [Flutter](sdk-installation-flutter) - [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [Unity](sdk-installation-unity) --- # File: stripe --- --- title: "Stripeとの初期連携" description: "StripeをAdaptyと連携して、サブスクリプション決済をシームレスに処理しましょう。" --- Adaptyは、[Stripe](https://stripe.com/)を通じたウェブ決済・サブスクリプションを追跡することで、web2appのサブスクリプションフローをサポートしています。 この連携は、ウェブ起点の購入(Stripe Checkout、ホスト型決済ページ、またはカスタムウェブフロー)に対応しており、モバイルアプリのアクセスやアナリティクスと同期します。 以下のようなシナリオで役立ちます: - ウェブで購入した後にアプリをインストールしてログインしたユーザーに、有料機能へのアクセスを自動的に付与する - コホート、予測、その他のアナリティクスツールを含む、すべてのサブスクリプションアナリティクスをAdapty ダッシュボード一か所で管理する ウェブ購入はアプリにとってますます一般的になりつつありますが、Apple App Storeがアプリ内課金以外のシステムを許可しているのはアメリカ国内のデジタルコンテンツに限られています。他の国でウェブサブスクリプションをアプリ内で宣伝しないようにしてください。違反するとアプリが審査で却下されたり、BANされる可能性があります。 以下の手順でStripe連携を設定します。 :::important この連携は、Stripeのウェブ購入の追跡と同期を目的としています。アプリからウェブチェックアウトにユーザーを誘導する場合は、[ウェブペイウォール](web-paywall)をご覧ください。 ::: ## 1\. StripeをAdaptyに接続する \{#1-connect-stripe-to-adapty\} この連携は主に、AdaptyがWebhook経由でStripeからサブスクリプションデータを取得することで機能します。そのため、APIキーを提供し、AdaptyのWebhook URLをStripeに設定することで、AdaptyアカウントとStripeアカウントを接続する必要があります。Webhookのセットアップをできるだけラクにするために、StripeにAdatyアプリをインストールしてください: :::note 以下の手順はStripeのProductionモードとTestモードで共通ですが、それぞれ異なるAPIキーを使用する必要があります。 ::: 0. テストモードとライブモードのどちらでStripeを接続するかを決めます。最初にテストモードで設定する場合は、後でライブモードでも同じ手順を繰り返す必要があります。 1. [Stripe App Marketplace](https://marketplace.stripe.com/apps/adapty)にアクセスしてAdatyアプリをインストールします。サンドボックスモードではアプリのインストールに対応していないため、本番環境またはテストモードでのみ実行できます。 <img src="/assets/shared/img/stripe1.png"/> 2. アプリに必要な権限を付与します。これにより、Adaptyがサブスクリプションデータと履歴にアクセスできるようになります。その後、**Continue to app settings** をクリックして続行します。 権限ポップアップの下部で、ライブモードまたはテストモードのどちらでアプリをインストールするかを選択できます。 <img src="/assets/shared/img/stripe2.png"/> 3. ポップアップで新しい制限付きキーを生成します。メール、Touch ID、またはセキュリティキーを使って本人確認が必要です。キーを生成した後は再度確認できないため、パスワードマネージャーや秘密管理ストアに安全に保存してください。 <img src="/assets/shared/img/stripe4.png"/> 4. ポップアップから生成されたキーをコピーし、Adaptyの[App Settings → Stripe](https://app.adapty.io/settings/stripe)に移動します。モードに合わせて **Stripe App Restricted API Key** セクションにキーを貼り付けます。テストモードとライブモードでは異なるキーを生成する必要があることに注意してください。 <img src="/assets/shared/img/Stripe3.png"/> 以上で完了です!次は、Stripeでプロダクトを作成してAdaptyに追加しましょう。 <Details> <summary>非推奨のインストールフロー</summary> 1. Stripeの[Developers → API Keys](https://dashboard.stripe.com/apikeys)に移動します: <img src="/assets/shared/img/6549602-CleanShot_2023-12-06_at_17.29.122x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Secret key** タイトルの横にある **Reveal live (test) key button** をクリックしてキーをコピーし、Adaptyの[App Settings → Stripe](https://app.adapty.io/settings/stripe)に移動します。ここにキーを貼り付けます: <img src="/assets/shared/img/2989508-CleanShot_2023-12-07_at_14.59.122x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 次に、AdaptyのStripe設定ページ下部からWebhook URLをコピーします。Stripeの[**Developers** → **Webhooks**](https://dashboard.stripe.com/webhooks)に移動し、**Add endpoint** ボタンをクリックします: <img src="/assets/shared/img/e7149f5-CleanShot_2023-12-07_at_17.31.392x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. AdaptyのWebhook URLを **Endpoint URL** フィールドに貼り付けます。次にWebhookの **Version** フィールドで **Latest API version** を選択します。その後、以下のイベントを選択します: - charge.refunded - customer.subscription.created - customer.subscription.deleted - customer.subscription.paused - customer.subscription.resumed - customer.subscription.updated - invoice.created - invoice.updated - payment_intent.succeeded <img src="/assets/shared/img/cbc5404-CleanShot_2023-12-07_at_17.36.232x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. "Add endpoint" を押し、"Signing secret" の下にある "Reveal" を押します。これはAdapty側でWebhookデータを復号するために使用されるキーです。表示後にコピーしてください: <img src="/assets/shared/img/0460cbb-CleanShot_2023-12-07_at_17.52.582x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. 最後に、このキーをAdaptyの App Settings → Stripe の "Stripe Webhook Secret" に貼り付けます: <img src="/assets/shared/img/055db20-CleanShot_2023-12-07_at_14.56.212x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Details> ## 2\. Stripeでプロダクトを作成する \{#2-create-products-on-stripe\} :::note テストモードで設定している場合は、この手順を続ける前にStripeもTestモードに切り替えてください。 ::: Stripeの[Product catalog](https://dashboard.stripe.com/products?active=true)にアクセスし、販売したいプロダクトと料金プランを作成します。Stripeでは1つのプロダクトに複数の料金プランを設定できるため、プロダクトを追加作成しなくてもオファーを柔軟に調整できます。 <img src="/assets/shared/img/b202e2e-CleanShot_2023-12-06_at_15.06.262x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning 現時点でAdaptyがサポートしているのは、**Flat rate**(例:$9.99/月)または **Package pricing**(例:$9.99/10ユニット)のみです。これらはアプリストアと同様の動作をします。**Tiered pricing**、**Usage-based fee**、**Customer chooses price** のオプションはサポートされていません。 ::: ## 3\. StripeプロダクトをAdatyに追加する \{#3-add-stripe-products-to-adapty\} :::warning プロダクトは必須です!Adapty ダッシュボードでStripeプロダクトを作成してください。Adaptyはこれらのプロダクトに紐づいたトランザクションのイベントのみ追跡します。このステップをスキップすると、トランザクションイベントが作成されません。 ::: AdaptyではStripeをApp StoreやGoogle Playと同様に扱います。つまり、デジタルプロダクトを販売する別のストアとして設定します。設定方法も同様で、StripeプロダクトのIDを(`product_id`と`price_id`を)AdaptyのProductsセクションに追加するだけです: <img src="/assets/shared/img/stripe-add-product.webp" style={{ border: 'none', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> StripeのプロダクトIDは `prod_...`、価格IDは `price_...` の形式になっています。Stripeの[Product Catalog](https://dashboard.stripe.com/products?active=true)でプロダクトを開けば、簡単に確認できます: <img src="/assets/shared/img/14a72d7-CleanShot_2023-12-06_at_17.32.512x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 必要なプロダクトをすべて追加したら、次はStripeに購入者のユーザーIDを伝える設定をしましょう。これにより、AdaptyがStripeからの情報を正しく取り込めるようになります。 ## 4\. ウェブ購入にユーザーIDを付加する \{#4-enrich-purchases-made-on-the-web-with-your-user-id\} Adaptyは、アクセスレベルの付与・更新において、Stripeからのwebhookを唯一の情報源として利用しています。ただし、この連携を正しく機能させるためには、Stripe連携時にお客様側から追加情報を提供する必要があります。 プラットフォーム(ウェブまたはモバイル)を横断して一貫したアクセスレベルを維持するには、AdaptyがWebhookから認識できる単一のユーザーIDに依存する必要があります。これはユーザーのメールアドレス、電話番号、または利用している認証システムのその他のIDが使えます。 ユーザーを識別するためにどのIDを使用するかを決めてください。次に、Stripeで決済を初期化しているコード部分にアクセスし、そのユーザーIDを[Stripe Subscription](https://docs.stripe.com/api/subscriptions/object#subscription_object-metadata)(`sub_...`)または[Checkout Session](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-metadata)オブジェクト(`ses_...`)の`metadata`に`customer_user_id`として以下のように追加してください: ```json showLineNumbers title="Stripe Metadata contents" {'customer_user_id': "YOUR_USER_ID"} ``` コードに必要な変更はこれだけです。これにより、AdaptyはStripeから受け取ったすべてのWebhookを解析し、この`metadata`を抽出して、サブスクリプションを正しくユーザーに紐付けます。 :::warning ユーザーIDは必須です これがなければ、ユーザーを特定してモバイル側でアクセスレベルを付与する方法がありません。 `metadata`に`customer_user_id`を指定しない場合は、AdaptyがStripeの他の情報からIDを探すよう設定できます:StripeのCustomerオブジェクトの`email`、またはStripeのSessionの`client_reference_id`のいずれかです。 プロファイル作成の挙動の設定方法については[こちら](stripe#profile-creation-behavior)をご覧ください。 ::: :::note StripeのCustomerも必須です Checkout Sessionsを使用している場合は、`customer_creation`を`always`に設定して[Stripe Customerを作成する](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-customer_creation)ようにしてください。 ::: ## 5\. モバイルユーザーへのアクセス付与 \{#5-provide-access-to-users-on-the-mobile\} ウェブから来たモバイルユーザーが有料機能にアクセスできるようにするには、前のステップで提供したのと同じ`customer_user_id`を使って`Adapty.activate()`または`Adapty.identify()`を呼び出すだけです(詳細は<InlineTooltip tooltip="ユーザーの識別">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip>をご覧ください)。 ## 6\. 連携をテストする \{#6-test-your-integration\} サンドボックスと本番環境の両方で上記の手順を完了したことを確認してください。StripeのTestモードで行ったトランザクションは、AdaptyではSandboxとして扱われます。 :::info 以上で完了です! ユーザーはウェブで購入を完了し、アプリで有料機能にアクセスできるようになります。また、すべてのサブスクリプションアナリティクスを1か所で確認できます。 ::: ## プロファイル作成の挙動 \{#profile-creation-behavior\} Adaptyは購入をモバイルで利用可能にするために、[顧客プロファイル](profiles-crm)に紐付ける必要があります。そのため、デフォルトではStripeからWebhookを受信した際にプロファイルを作成します。Adaptyで顧客ユーザーIDとして使用するものを選択できます: 1. **デフォルトかつ推奨:** [上記のステップ4](stripe#4-enrich-purchases-made-on-the-web-with-your-user-id)でmetadataに指定した`customer_user_id` 2. StripeのCustomerオブジェクトの`email`([Stripeのドキュメント](https://docs.stripe.com/api/customers/object#customer_object-email)を参照) 3. StripeのSessionオブジェクトの`client_reference_id`([Stripeのドキュメント](https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-client_reference_id)を参照) 使用するIDは[App Settings → Stripe](https://app.adapty.io/settings/stripe)で設定できます。 :::warning **注意:** 特定のStripeトランザクションに指定したIDが含まれていない場合、プロファイルは一切作成されません。このトランザクションは、何らかのプロファイルに紐付けられるまで匿名のままになります(例えば、後から[S2S validate](api-adapty/operations/validateStripePurchase)を使ってこのトランザクションを手動で通知した場合など)。 アナリティクスには表示されますが、プロファイルのカウントに依存するセクション(LTV、コホート、コンバージョンなど)には反映されず、イベントフィードでも確認できません。 ::: プロファイルをまったく作成しないという4つ目の選択肢もありますが、上記のアナリティクス制限があるため推奨しません。 ## 現在の制限事項 \{#current-limitations\} ### アップグレード、ダウングレード、日割り計算 \{#upgrading-downgrading-and-proration\} サブスクリプションのアップグレードやダウングレードを行うと、日割り計算による請求が発生することがあります。Adaptyはこれらの請求を収益計算に含めません。Stripeダッシュボードからこれらのオプションを手動で無効にするか、Stripe APIで`proration_behaviour`属性の値を`none`に設定して無効にすることをお勧めします。 ### キャンセル \{#cancellations\} Stripeにはサブスクリプションのキャンセルオプションが2つあります: 1. 即時キャンセル:日割り計算の有無にかかわらず、サブスクリプションが即座にキャンセルされます 2. 期間終了時のキャンセル:現在の請求期間の終了時にキャンセルされます(アプリストアのアプリ内サブスクリプションと同様)。 Adaptyはどちらのオプションにも対応していますが、即時キャンセルの場合、収益計算で日割り計算オプションは考慮されません。 ### 請求の問題とグレース期間 \{#billing-issues-and-grace-period\} 顧客の支払いに問題が発生すると、Adaptyは請求問題イベントを生成し、アクセスが取り消されます。Stripeのグレース期間はまだサポートしていませんが、将来のリリースで対応予定です。 ### 返金 \{#refunds\} Adaptyが追跡するのは全額返金のみです。日割り計算による返金や部分返金は現在サポートしていません。 ### トランザクションIDの一意性 \{#transaction-id-uniqueness\} Adaptyは`store_transaction_id`と`store_original_transaction_id`を使用してプロファイルとトランザクションを照合します。これらはテスト環境と本番環境の間で**一意である必要があります**。 #### なぜ重要なのか \{#why-this-matters\} 同じトランザクションIDが両方の環境に存在すると、Adaptyはそれらを1つのトランザクションとして扱い、以下の問題が発生します: - 本番環境の購入がテスト環境のアクセスレベルとプロダクトIDを引き継ぐ - APIレスポンスでプロダクトIDと環境の情報が誤って表示される - プロファイルの紐付けとサブスクリプションイベントが正しく機能しない #### 一意性を確保する方法 \{#how-to-ensure-uniqueness\} StripeのインボイスIDはテスト環境とライブ環境で重複する可能性があります。環境をまたいだIDの衝突を防ぐには、以下のいずれかの方法を選択してください。 #### オプション1:環境プレフィックス付きのアカウントレベルの採番 \{#option-1-account-level-numbering-with-environment-prefixes\} 各環境に対して個別にプレフィックスを設定します: 1. Stripeダッシュボードでテストモードに切り替えます。 2. [Settings → Billing → Invoices](https://dashboard.stripe.com/settings/account/?support_details=true)に移動します。 3. **Invoice numbering** を **Sequentially across your account** に設定します。 4. **Invoice prefix** を TEST-(またはテスト環境固有の任意のプレフィックス)に設定します。 5. ライブモードに切り替えて、手順2〜4を繰り返します。プレフィックスには LIVE-(またはライブ環境固有の任意のプレフィックス)を使用します。 #### オプション2:顧客レベルの採番 \{#option-2-customer-level-numbering\} [**Stripe settings** -> **Billing** -> **Invoices** タブ](https://dashboard.stripe.com/settings/account/?support_details=true)の **Invoice numbering** を **Sequentially for each customer (customer-level)** に設定します。 上記の設定を行っても、インボイスを削除するとStripeが同じ顧客の新しいインボイスに同じIDを再利用する場合があります。インボイスはできるだけ削除しないようにすることをお勧めします。 ### Stripe CheckoutまたはPayment Linksを使った買い切り購入 \{#one-time-purchases-via-stripe-checkout-or-payment-links\} AdaptyがStripe Checkout(`mode=payment`)またはPayment Linksを通じた買い切り(非サブスクリプション)購入を追跡するのは、Stripeがその購入に対してインボイスを生成した場合のみです。デフォルトでは、Stripeは買い切りのCheckout購入に対してインボイスを作成しません。この場合、`payment_intent.succeeded`はインボイスデータなしで到達するため、Adaptyがトランザクションを記録するには不十分です。 Adaptyで買い切りCheckout購入を追跡するには、セッション作成時に[インボイスの作成を有効にして](https://docs.stripe.com/payments/checkout/receipts?payment-ui=stripe-hosted#paid-invoices-hosted)ください。これにより、Stripeがインボイスを生成し、関連する`invoice.created`および`invoice.updated`イベントを送信します。Adaptyはこれらのイベントを処理してトランザクションを記録します。 ## Stripeデータをさらに活用する \{#get-more-from-your-stripe-data\} Stripeと連携すると、Adaptyはすぐにインサイトを提供できる状態になります。Stripeデータを最大限に活用するには、追加のAdapty連携を設定してStripeのイベントを転送しましょう。これにより、すべてのサブスクリプションアナリティクスをAdapty ダッシュボード一か所に集約できます。 :::tip アナリティクスをさらに強化するために、Stripeのmetadataに`variation_id`を含めると、購入を特定のペイウォールインスタンスに紐付けることができます。これは、特定のペイウォールの表示がコンバージョンにつながったかどうかを追跡したい場合など、自社製ウェブペイウォールの実装時に特に有用です。 `variation_id`は、Stripe Subscription(`sub_...`)とCheckout Session(`ses_...`)オブジェクトのmetadataからのみ読み取られます: ```json showLineNumbers title="Stripe Metadata with variation_id" { 'customer_user_id': "YOUR_USER_ID", 'variation_id': "YOUR_VARIATION_ID" } ``` ::: Stripeイベントの転送・分析に使用できる連携: - [Amplitude](amplitude/) - [Webhook](webhook) - [Firebase](firebase-and-google-analytics) - [Mixpanel](mixpanel) - [Posthog](posthog) ### サポートしているStripeイベント \{#supported-stripe-events\} Adaptyは以下のStripeイベントをサポートしています: - charge.refunded - customer.subscription.created - customer.subscription.deleted - customer.subscription.paused - customer.subscription.resumed - customer.subscription.updated - invoice.created - invoice.updated - payment_intent.succeeded --- # File: paddle --- --- title: "Paddleとの初期連携" description: "AdaptyとPaddleを連携して、サブスクリプション決済をシームレスに処理しましょう。" --- Adaptyは、[Paddle](https://www.paddle.com/)を通じて行われたウェブ決済とサブスクリプションを追跡することで、web2appのサブスクリプションフローをサポートしています。 この連携では、ウェブ経由の購入を管理し、アプリ内課金と並行して、モバイルアプリへのアクセスと分析データを同期します。 以下のようなケースで役立ちます: - アプリ内課金とウェブサイト購入の両方のサブスクリプションデータを一元管理する - ウェブサイトで購入したユーザーに、モバイルアプリの有料機能へのアクセスを付与する - すべての販売チャネルの分析データとサブスクリプションデータを1つのダッシュボードで確認する :::note Appleは現在、米国のApp Storeアプリに外部決済システムへのリンクを含めることを許可していますが、アプリ内購入と外部オプションの両方を提供する必要がある場合もあります。お使いの地域とアプリカテゴリに適用される最新のApp Storeガイドラインをご確認ください。 ::: :::note この連携は、PaddleのウェブからのアプリへのAの追跡と同期に焦点を当てています。ユーザーをアプリからウェブチェックアウトに誘導する必要がある場合は、Adaptyの[ウェブペイウォール](web-paywall)をご利用ください。 ::: Paddle連携を設定するには、以下の手順に従ってください: ## 1. PaddleをAdapyに接続する \{#1-connect-paddle-to-adapty\} この連携では、ウェブフックを使用してPaddleからAdapyにサブスクリプションデータを送信します。AdapyとPaddleアカウントを接続するには、以下が必要です: 1. Paddle APIキーを提供する 2. AdapyのウェブフックURLをPaddleに追加する :::note 以下の手順は、本番環境とテスト環境の両方に適用されます。同時に両方を設定できます。記載のリンクは本番環境用です。テスト環境のリンクを取得するには、各URLの先頭に`sandbox-`を追加してください。例えば、`https://vendors.paddle.com/authentication-v2`の代わりに`https://sandbox-vendors.paddle.com/authentication-v2`を使用します。 ::: ### 1.1. Paddle APIキーの取得と追加 \{#11-get-and-add-paddle-api-keys\} 1. Paddleで[Developer Tools → Authentication](https://vendors.paddle.com/authentication-v2)に移動し、**New API key**をクリックします。 <img src="/assets/shared/img/paddle-new-key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. キーに名前を付け、有効期限を設定します。AdapyでAPIキーを機能させるには、すべてのエンティティに対して**Read**権限を付与する必要があります。**Save**をクリックします。 <img src="/assets/shared/img/paddle-key.webp" style={{ border: 'none', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Copy key**をクリックします。 <img src="/assets/shared/img/copy-paddle-key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Adaptyで[App Settings → Paddle](https://app.adapty.io/settings/paddle)に移動し、**Paddle API key**セクションにキーを貼り付けます。 :::warning Paddle APIキーに有効期限を設定した場合、有効期限が切れる前に手動で新しいキーを生成し、Adaptyで更新する必要があります。キーが期限切れになると、警告なしに連携が停止し、ユーザーが購入できなくなります。 ::: <img src="/assets/shared/img/paddle-api-keys-adapty.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 1.2. Adaptyに送信するイベントの追加 \{#12-add-events-that-will-be-sent-to-adapty\} 1. AdapyのPaddleページから**Webhook URL**をコピーします。 2. Paddleで[**Developer Tools → Notifications**](https://vendors.paddle.com/notifications-v2)に移動し、**New destination**をクリックしてウェブフックを追加します。 <img src="/assets/shared/img/paddle-webhook.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ウェブフックにわかりやすい名前を付けます。後で簡単に見つけられるよう、名前に「Adapty」を含めることをお勧めします。 4. AdapyからコピーしたWebhook URLを**URL**フィールドに貼り付けます。正しい環境のウェブフックを使用していることを確認してください。 5. **Notification type**を**Webhook**に設定します。 <img src="/assets/shared/img/paddle-create-webhook.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. 以下のイベントを選択します: - `subscription.created` - `subscription.updated` - `transaction.created` - `transaction.updated` - `adjustment.created` - `adjustment.updated` <img src="/assets/shared/img/paddle_events.png" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. **Save destination**をクリックしてウェブフックの設定を完了します。 ### 1.3. ウェブフックシークレットキーの取得と追加 \{#13-retrieve-and-add-the-webhook-secret-key\} 1. **Notifications**ウィンドウで、作成したウェブフックの横にある三点ドットをクリックし、**Edit destination**を選択します。 2. **Edit destination**パネルに**Secret key**という新しいフィールドが表示されます。それをコピーします。 <img src="/assets/shared/img/paddle-webhook-secret-key-copy.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Adaptyで[App Settings → Paddle](https://app.adapty.io/settings/paddle)に移動し、**Notification secret key**フィールドにキーを貼り付けます。このキーはAdapyでウェブフックデータを検証するために使用されます。 <img src="/assets/shared/img/paddle-webhook-secret-key.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 1.4. PaddleのカスタマーとAdapyのプロファイルを対応付ける \{#14-match-paddle-customers-with-adapty-profiles\} Adaptyは、アプリ内で使用できるよう各購入を[カスタマープロファイル](profiles-crm)に紐付ける必要があります。デフォルトでは、AdapyがPaddleからウェブフックを受信したときにプロファイルが自動的に作成されます。Adaptyの`customer_user_id`として使用する値を選択できます: 1. **デフォルト・推奨:** `custom_data`フィールドで渡す`customer_user_id`([Paddleドキュメント](https://developer.paddle.com/build/transactions/custom-data)参照) 2. PaddleのCustomerオブジェクトの`email`([Paddleドキュメント](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters)参照) 3. `ctm-...`形式のPaddle Customer ID([Paddleドキュメント](https://developer.paddle.com/paddle-js/methods/paddle-checkout-open/#parameters)参照) 4. プロファイルを作成しない。カスタマープロファイルをより細かく制御して自分で管理したい場合はこのオプションを選択します。 使用する値は[App Settings → Paddle](https://app.adapty.io/settings/paddle)の**Profile creation behavior**フィールドで設定できます。 <img src="/assets/shared/img/paddle-users.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 2. AdapyにPaddleプロダクトを追加する \{#2-add-paddle-products-to-adapty\} :::warning PaddleプロダクトをAdapty ダッシュボードに追加するか、既存のプロダクトにPaddleプロダクトIDを追加してください。Adaptyは、これらのプロダクトに紐付いたトランザクションのイベントのみを追跡します。この手順をスキップすると、トランザクションイベントが作成されません。 ::: PaddleはApp StoreやGoogle Playと同様にAdapyで動作します。つまり、デジタルプロダクトを販売するもう一つのプラットフォームです。設定するには、Adaptyの[Products](https://app.adapty.io/products)セクションで、Paddleの関連する`product_id`と`price_id`の値を追加します。 <img src="/assets/shared/img/paddle-create-product.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Paddleでは、プロダクトIDは`pro_...`、価格IDは`pri_...`の形式です。特定のプロダクトを開くと、[Paddleプロダクトカタログ](https://vendors.paddle.com/products-v2)で確認できます: <img src="/assets/shared/img/paddle-product-price.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> プロダクトを追加したら、次のステップはAdapyが購入を正しいユーザーに紐付けられるようにすることです。 ## 3. モバイルでユーザーにアクセスを付与する \{#3-provide-access-to-users-on-the-mobile\} ウェブで購入したユーザーがモバイルでもアクセスできるようにするには、購入時に渡したものと同じ`customer_user_id`を使って`Adapty.activate()`または`Adapty.identify()`を呼び出します。詳細は[ユーザーの識別](identifying-users)をご覧ください。 ## 4. 連携をテストする \{#4-test-your-integration\} すべての設定が完了したら、連携をテストできます。PaddleのTest環境で行われたトランザクションはAdapyに**Test**として表示されます。本番環境のトランザクションは**Production**として表示されます。 連携が完了しました。ユーザーはウェブサイトでサブスクリプションを購入し、モバイルアプリのプレミアム機能に自動的にアクセスできるようになります。また、統合されたAdapy ダッシュボードですべてのサブスクリプション分析を追跡できます。 ## 重要な注意事項 \{#important-considerations\} - Adaptyの分析では、トランザクション金額に税金とPaddle手数料が含まれます。これはPaddleダッシュボードとは異なり、Paddleでは税金と手数料を差し引いた金額が表示されます。そのため、Adaptyに表示される数値はPaddleダッシュボードの数値より高くなります。 - 他のストアとは異なり、Paddleでの返金は特定のトランザクションのみに影響し、サブスクリプションを自動的にキャンセルしません。サブスクリプションは明示的にキャンセルされない限り有効なままです。 - `custom_data`フィールドに`variation_id`を含めることで、購入を特定のペイウォールインスタンスに紐付けることもできます。Adaptyはウェブフックからこのデータを処理し、分析に含めます。 ### 有料トライアル \{#paid-trials\} Paddleで有料トライアルを使用する場合、Adaptyで2つのプロダクトを作成する必要があります: 1. 非サブスクリプションプロダクトを作成し、トライアル期間の料金を請求するPaddle価格に紐付けます。 2. サブスクリプションプロダクト(月次/週次など)を作成し、無料トライアルコンポーネントを持つPaddle価格に紐付けます。 Paddleの観点では、これは1つのプロダクトに2つの価格が含まれる単一のトランザクションです。1つはトライアル料金(例:$0.99)、もう1つは無料トライアル($0.00)の価格です。 Adaptyの観点では、これにより2つの別々のイベントが作成されます:トライアル支払いの非サブスクリプション購入と、サブスクリプションプロダクトのトライアル開始イベントです。 例えば、ユーザーが月額$9.99のサブスクリプションに対して$0.99の有料トライアルを開始すると、Paddleは両方の価格を含む1つのトランザクションを作成しますが、Adaptyはこれを$0.99の非サブスクリプション購入(即時支払い)と$0.00のトライアル開始イベント(将来的に月額$9.99のサブスクリプション)として処理します。 :::note ユーザーが有料トライアルをキャンセルすると、**Trial expired**と**Trial renewal canceled**イベントが発生します。 ::: ## Paddleデータをさらに活用する \{#get-more-from-your-paddle-data\} :::important PaddleイベントをインテグレーションS(integrations)で動作させるには、ユーザーが少なくとも一度App Store / Google Playアカウントでアプリにログインする必要があります。 ::: Paddleとの連携が完了すると、Adaptyはすぐに分析情報を提供できる状態になります。Paddleデータを最大限に活用するには、追加のAdapy連携を設定してPaddleイベントを転送し、すべてのサブスクリプション分析を単一のAdapy ダッシュボードに集約できます。 Paddleイベントの転送と分析に使用できる連携: - [AppsFlyer](appsflyer) - [Webhook](webhook) - [Posthog](posthog) ## 現在の制限事項 \{#current-limitations\} - **キャンセル**: Paddleにはサブスクリプションキャンセルの2つのオプションがあります: 1. 即時キャンセル:サブスクリプションが即座にキャンセルされます。 2. 期間終了時のキャンセル:現在の請求期間が終了した時点でサブスクリプションがキャンセルされます(アプリストアのアプリ内サブスクリプションと同様)。 - **返金**: Adaptyは全額返金と部分返金を追跡します。 - **グレース期間**: デフォルトでは、Paddleは請求の問題に対して30日間の固定グレース期間を適用し、その間サブスクリプションは有効なままです。[グレース期間の長さと期間終了後のアクション(サブスクリプションの一時停止またはキャンセル)はカスタマイズできます](https://developer.paddle.com/build/retain/configure-payment-recovery-dunning#prerequisites)。 **トライアル**: トライアル終了後に支払いの収集が失敗した場合、サブスクリプションのステータスは`past_due`に変わります。本番環境では、PaddleのRetainがダニングウィンドウを適用してサブスクリプションがキャンセルまたは一時停止される前に支払い回収を試みます。サンドボックスではRetainが利用できないため、支払いの再試行は行われず、サブスクリプションは無期限で`past_due`のままになります。 --- **関連情報:** - [PaddleでのPurchaseを検証し、アクセスレベルを取得し、PaddleのトランザクションHistory をサーバーサイドAPIでインポートする](api-adapty/operations/validatePaddlePurchase) --- # File: custom-store --- --- title: "他のストアとの初期連携" description: "App StoreとのAdapty初期連携:クイックガイド" --- Adaptyへようこそ!アプリで最高の成果を達成できるよう、スムーズなスタートをサポートします。 初期連携が必要なのは [App Store](initial_ios)、[Google Play](initial-android)、[Stripe](stripe)、[Paddle](paddle) のみです。Adaptyはこれらのストアでアプリ、プロダクト、オファーを検証するためです。 Adaptyは他のアプリストアとのデータ検証や購入処理は行いません。ただし、他のストアで販売されたプロダクトをAdaptyに登録することで、購入完了後に有料コンテンツへのアクセス付与、アナリティクスへのトランザクション反映、インテグレーション経由での共有が可能です。 <img src="/assets/shared/img/Adapty-Communication-Scheme.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::important バックエンドで購入を処理し、[Adaptyサーバーサイドコンフィグ](getting-started-with-server-side-api)を使用してトランザクションをAdaptyに送信してください。Adaptyはトランザクションを受信して初めて、アクセスの付与、トランザクションイベントのトリガー、インテグレーションへの送信、アナリティクスへの反映を行います。 ::: プロダクトをカスタムアプリストア経由で販売するものとしてマークするには、プロダクト作成時にアプリストアを選択します。必要なストアが一覧にない場合は、以下の手順で作成してください。 1. **Products** ページで、カスタムアプリストア経由で販売したいプロダクトを開きます。 2. 販売先のアプリストアを選択します。一覧にない場合は、**Create Custom Store** ボタンをクリックします。 <img src="/assets/shared/img/create_custom-appstore.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ストアの **Title** と **Store ID** を入力します。 4. **Create store** ボタンをクリックします。 バックエンドが正しく設定されていれば、Adaptyはこのカスタムストアからのプロダクトトランザクションを受信し、アナリティクス、[**Event Feed**](event-feed)、[インテグレーション](https://app.adapty.io/integrations)に反映し、適切にアクセスを付与します。 ## カスタムストアデータをさらに活用する \{#get-more-from-your-custom-store-data\} :::important カスタムストアのイベントをインテグレーションで機能させるには、ユーザーが少なくとも1回はApp Store / Google Playアカウントでアプリにログインしている必要があります。 ::: カスタムストアのインテグレーションをセットアップすると、Adaptyはすぐにインサイトを提供できる状態になります。データを最大限に活用するために、追加のAdaptyインテグレーションを設定してカスタムストアのイベントを転送し、すべてのサブスクリプションアナリティクスを一つのAdapty ダッシュボードに集約できます。 カスタムストアのイベントを転送・分析するために利用できるインテグレーション: - [AppsFlyer](appsflyer) - [Webhook](webhook) - [Posthog](posthog) --- # File: transfer-apps --- --- title: "アプリを別のアカウントに移管する" description: "Adapty でアプリのオーナーを変更する" --- 会社が買収された場合、アプリを売却する場合、または事業体を再編する場合に、アプリを別のオーナーに移管できます。移管プロセスでは、サービスを継続するために Adapty、App Store Connect、Google Play Console での変更を連携して行う必要があります。 ## アプリのオーナーシップを移管する \{#transfer-app-ownership\} ストアでの移管を先に完了してから、Adapty でのアプリ移管を行ってください。この順序により、移管中も購入が正常に機能し続けます。 :::note 移管プロセス中はプロダクトを削除・再作成しないでください。移管が正常に完了したことを確認するまで、プロダクト ID を変更しないでください。 ::: ### App Store(iOS)の移管 \{#app-store-ios-transfer\} :::important App Store Connect の API キー(Issuer ID、Key ID、.p8 ファイル)はアプリ単位ではなくアカウント単位でスコープされています。移管後は、新しいオーナーのアカウントから新しい API キーを生成し、Adapty で更新する必要があります。 アプリ固有の共有シークレットは移管期間中もレシートの検証を継続しますが、移管完了後に新しいオーナーが再生成して Adapty を更新する必要があります。 ::: 1. **新しいオーナー:** アカウントをお持ちでない場合は、[app.adapty.io](https://app.adapty.io) で Adapty アカウントを作成してください。 2. **旧オーナー:** Apple の[移管ガイド](https://developer.apple.com/help/app-store-connect/transfer-an-app/overview-of-app-transfer)に従って、App Store Connect でアプリの移管を開始してください。 3. **新しいオーナー:** App Store Connect で移管を承認してください。 4. **旧オーナー:** Adapty でのアプリ移管を依頼するため、[support@adapty.io](mailto:support@adapty.io) にメールを送ってください。アプリ名と新しいオーナーのメールアドレスを記載してください。 5. **新しいオーナー:** Adapty でアプリを受け取ったら、[App Store 連携ガイド](initial_ios)を参照して、自分のアカウントで必要なすべての認証情報を生成・設定してください。 ### Google Play(Android)の移管 \{#google-play-android-transfer\} 1. **新しいオーナー:** アカウントをお持ちでない場合は、[app.adapty.io](https://app.adapty.io) で Adapty アカウントを作成してください。 2. **両オーナー:** 両方の Google Play デベロッパーアカウントが完全に登録済みであることを確認してください。 3. **旧オーナー:** Google Play Console または Google Play デベロッパーサポートから移管リクエストを送信してください。Google から DUNS 番号、契約書、売却証明書などの追加書類の提出を求められる場合があります。 4. **新しいオーナー:** 移管リクエストを確認して承認してください。 5. **Google:** Google サポートチームが移管を処理します。通常数営業日かかりますが、アカウントの確認、サブスクリプションの複雑さ、支払い設定によってはさらに時間がかかる場合があります。 6. **旧オーナー:** Google が移管を完了したら、Adapty でのアプリ移管を依頼するため、[support@adapty.io](mailto:support@adapty.io) にメールを送ってください。アプリ名と新しいオーナーのメールアドレスを記載してください。 7. **新しいオーナー:** Adapty でアプリを受け取ったら、[Google Play 連携ガイド](initial-android)を参照して、自分のアカウントで必要なすべての認証情報を生成・設定してください。 移管にはユーザー、サブスクリプション、統計情報、評価、ストアのリスティングが含まれます。既存のサブスクライバーへの課金は継続されますが、収益の振り込みは移管完了後に新しいオーナーのマーチャントアカウントに切り替わります。移管前の支払いレポートと注文は元のアカウントに残ります。詳細な要件については、Google の[移管ガイド](https://support.google.com/googleplay/android-developer/answer/6230247)を参照してください。 ## リスクの軽減とタイミング \{#risk-mitigation-and-timing\} **移管中も継続して機能するもの:** - 購入と更新(アプリ固有の共有シークレットが移管期間中もレシートを検証し続けます) - 既存のサブスクライバーのアクセス - SDK の動作 **一時的に機能しなくなるもの:** - App Store Connect の API 呼び出し(新しいキーが設定されるまで) - サーバー通知(エンドポイントが再設定されるまで) - 認証情報の移行中はアナリティクスに欠損が生じる場合があります **推奨タイミング:** - 主なユーザーのタイムゾーンで午前3時〜6時など、トラフィックの少ない時間帯に移管を完了させてください - ストアの移管を承認した後、すぐに認証情報を設定できるよう新しいオーナーが準備しておいてください - ストアの移管承認から Adapty の連携完了まで、15〜30 分の余裕を見てください **移管完了後:** - レシート検証をすぐにテストしてください - 48 時間、自動更新の成功率を監視してください - サーバー通知がシステムに届いていることを確認してください - 新しい購入が正しくトラッキングされていることを確認してください ## 移管が正常に完了したことを確認する \{#verify-transfer-completed-successfully\} Adapty とストアの両方で移管が完了したら: 1. **ダッシュボードへのアクセスを確認する:** 新しいオーナーが自分の Adapty ダッシュボードにアプリが表示されていることを確認してください。 2. **API キーの接続を確認する:** 新しい App Store Connect API キーまたは Google Play サービスアカウントが Adapty で正常に接続されていることを確認してください。 3. **SDK の接続をテストする:** アプリを実行して、Adapty SDK がエラーなく初期化されることを確認してください。 --- # File: installation-of-adapty-sdks --- --- title: "Adapty SDK のインストール" description: "iOS、Android、クロスプラットフォームアプリ向けの Adapty SDK をインストールします。" --- 始め方は、以下の3つのパスから選べます: - **プラットフォーム別のクイックスタートガイドに従う**: ガイドにはプロダクション対応のコードスニペットが含まれているため、実装はすぐに完了します。 - [iOS](ios-sdk-overview) - [Android](android-sdk-overview) - [React Native](react-native-sdk-overview) - [Flutter](flutter-sdk-overview) - [Unity](unity-sdk-overview) - [Kotlin Multiplatform](kmp-sdk-overview) - [Capacitor](capacitor-sdk-overview) - **LLM を活用する**: ドキュメントは LLM フレンドリーな設計です。Adapty ドキュメントで LLM を最大限に活用する方法については、[ガイド](adapty-cursor)をご覧ください。 - **サンプルアプリを試す**: - [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples) - [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app) - [React Native (純粋な RN によるベーシックなサンプル)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample) - [React Native (アドバンストサンプル – より複雑なケースを扱えるため、開発時に便利)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools) - [React Native (Expo dev ビルド)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo) - [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock) - [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example) - [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets) - [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example) - [Capacitor](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples) --- # File: sample-apps --- --- title: "サンプルアプリ" description: "" --- Adapty SDK をすぐに使い始められるよう、主要な機能の統合方法と使い方を示したサンプルアプリを用意しています。ペイウォール、購入処理、アナリティクスのトラッキングすぐに使える実装例が揃っています。 <img src="/assets/shared/img/adapty-scheme.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## サンプルアプリを使う理由 \{#why-use-sample-apps\} - **すぐに統合できる:** 実際のアプリで Adapty SDK の動作を確認できます。 - **ベストプラクティス:** 推奨される実装パターンに従えます。 - **デバッグ・テスト:** 自分のプロジェクトに Adapty を統合する前に、サンプルアプリを使ってトラブルシューティングや実験ができます。 ## 利用可能なサンプルアプリ \{#available-sample-apps\} - [iOS (Swift)](https://github.com/adaptyteam/AdaptySDK-iOS/tree/master/Examples) - [Android (Kotlin)](https://github.com/adaptyteam/AdaptySDK-Android/tree/master/app) - [React Native (純粋な RN によるベーシックな例)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/BasicExample) - [React Native (より複雑なケースにも対応した開発向けの高度な例)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/AdaptyDevtools) - [React Native (Expo dev ビルド)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/FocusJournalExpo) - [React Native (Expo Go & Web)](https://github.com/adaptyteam/AdaptySDK-React-Native/tree/master/examples/ExpoGoWebMock) - [Flutter (Dart)](https://github.com/adaptyteam/AdaptySDK-Flutter/tree/master/example) - [Unity (C#)](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets) - [Kotlin Multiplatform](https://github.com/adaptyteam/AdaptySDK-KMP/tree/main/example) - [Capacitor (React)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-react-example) - [Capacitor (Vue.js)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-vue-example) - [Capacitor (Angular)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/basic-angular-example) - [Capacitor (高度な開発ツール)](https://github.com/adaptyteam/AdaptySDK-Capacitor/tree/master/examples/adapty-devtools) --- # File: paywall-builder-templates --- --- title: "フローを作成する" description: "カスタムデザインのギャラリーテンプレートまたはシンプルなスターターから新しいフローを始めましょう。" --- フローはテンプレートから作成することも、一から作成することもできます。 :::link フローの作成についてさらに詳しく知りたいですか?[YouTubeプレイリスト](https://www.youtube.com/playlist?list=PLMksWqaZiWtM)でステップバイステップの動画チュートリアルをご覧ください。 ::: ## フローを作成する \{#create-flow\} 1. **Flows** ページを開きます。 2. **Create flow** をクリックします。 3. オプションを選択します: - **Browse templates**(テンプレートライブラリを開く) - **Start from scratch**(空のフローを作成する) 4. エディターでフローの名前を変更します。ヘッダーのフロー名をクリックして新しい名前を入力してください。 :::warning Adapty では同じ名前のフローを複数作成できます。新しいフローを作成するたびに名前を変更しないと、区別しにくい **Untitled** フローが複数できてしまいます。 ::: ### テンプレートを使う \{#use-a-template\} テンプレートライブラリには、フローの出発点として使えるテンプレートが複数用意されています。それぞれのテンプレートは複数のスクリーン、インタラクティブな要素、ナビゲーション機能を備えた完成済みのフローです。任意の要素を編集してカスタマイズできます。 テンプレートを適用するには: 1. テンプレートライブラリでテンプレートカードを確認します。各カードにはフローのプレビュースクリーンショットが表示されます。 2. 使いたいカードの **Use as template** をクリックします。 テンプレートがビルダーに読み込まれます。ここから、任意の要素、画面、またはプロパティを変更できます。 ### ゼロから始める \{#start-from-scratch\} 「ゼロから始める」を選ぶと、空白の画面が1つだけあるフローが作成されます。[エレメントライブラリ](builder-elements)のエレメントを使って画面をデザインしてください。 ## テンプレートを変更する \{#change-the-template\} ビルダー内からテンプレートを切り替えられます。Screens パネルを開き、**Templates** Templates ボタンをクリックしてテンプレートライブラリを再度開き、新しいテンプレートを選んでください。 :::warning 新しいテンプレートを適用すると、現在のフローの下書きが置き換えられます。Adapty が確認を求めるので、続行する場合は **Use template** を、下書きを残す場合は **Cancel** をクリックしてください。確定後は以前の下書きを復元できません。公開済みのフローはそのまま有効です。 ::: ## テンプレートのカスタムフォント \{#custom-fonts-in-templates\} :::link 関連記事:[フローボルダーのカスタムフォント](using-custom-fonts-in-flow-builder) ::: **Custom font** チップが付いているテンプレートはカスタムフォントを使用しています。これらのフォントは SDK には同梱されていません。チップにカーソルを合わせると、テンプレートで使用されているフォントを確認できます。 デバイス上で意図したタイポグラフィを表示するには、フォントファイルをアプリバンドルに追加してください。フォントが同梱されていない古いバージョンのアプリでは、システムフォントにフォールバックします。 フォントを変更しても古いバージョンに影響を与えないようにするには、フローを複製し、コピー側でフォントを変更して、そのコピーを[該当フォントが含まれるアプリバージョンのユーザー](segments)に限定してください。 --- # File: builder-ui --- --- title: "フロービルダーUI" description: "フロービルダーのインターフェースとワークスペースの概要。" --- フロービルダーのメインUIには、ビジュアル要素の追加、プロパティの編集、ユーザーフローのロジック変更に必要なすべてのツールが揃っています。この記事では、インターフェースの各エリアについて、その機能と場所を説明します。 :::link フローの作成についてさらに詳しく知りたいですか?[YouTubeプレイリスト](https://www.youtube.com/playlist?list=PLMksWqaZiWtM)でステップバイステップの動画チュートリアルをご覧ください。 ::: ## プロジェクトのコントロールと便利なショートカット(上部ツールバー) \{#project-controls-and-useful-shortcuts-top-toolbar\} * **Close** Close: フローエディターを終了してフロー一覧ページに戻ります。 * **App name** App: そのフローが属するアプリを識別します。 * **All flows** Flows: このアプリのすべてのフロー一覧を開きます。 * **Flow status**: フロー名の左側にあるアイコンは、現在の[フローのステータス](builder-save-publish#flow-status)を示します: - **Draft** Draft - **Publishing**(スピナー) - **Failed** Failed - または **Live** Live。 * **フローの名前変更**: フロー名をクリックして名前を変更します。複数のフローが同じ名前を持つことができますが、[各フローには固有の名前をつけてください](paywall-builder-templates#create-flow)。 * **表示モードの切り替え**: デザインビュー Cursor と[リモートコンフィグビュー](customize-flow-with-remote-config)Remote Config を切り替えます。 * **元に戻す / やり直す**: 矢印アイコンをクリックしてフローの変更を元に戻す Undo か、やり直す Redo ことができます。⌘Z / Ctrl+Z で元に戻すこともできます。 * **下書き保存 / 公開**: **Save draft** をクリックすると、公開せずに進捗を保存できます(⌘ / Ctrl+S)。ドロップダウン Open dropdown を開いて [**Publish**](builder-save-publish) ボタンにアクセスします。フローを[プレースメント](create-placement)に追加できるのは、公開後のみです。 ## プレビューエリア(中央) \{#preview-area-center\} ワークスペースの中央エリアでは、フローがモバイルデバイス上でどのように表示されるかをシミュレートできます。 * 要素を選択してプロパティを編集するには、その要素をクリックします。コンテナ内の子要素を選択するには、まずコンテナをクリックし、次に子要素をクリックします。 * 画面自体のプロパティを編集するには、要素の外側をクリックするか、**Screens and Layers** パネルで画面を選択します。 * 要素の順序を変更するには、**Screens and Layers** パネルでその要素のエントリを上下にドラッグします。 :::warning フローエディターはレスポンシブレイアウトを作成するために設計されています。そのため、**要素の位置を手動で変更することはできません** — 変更できるのは順序のみです。各コンテナのレイアウト設定によって、内部の要素の配置方法が決まります。 ::: ### アクティブスクリーンバー(デバイスプレビューの上部) \{#active-screen-bar-above-the-device-preview\} - **Screen name** — 現在のスクリーン名が表示されたピル。 - **Toggle animations** Toggle animations — 要素のアニメーションプレビューのオン/オフを切り替えます。オフにするまで継続的に再生されます。アクティブなスクリーンに[アニメーション](builder-styling#animation)が含まれている場合のみ表示されます。実機上のアニメーション表示には影響しません。 - **Add element** Plus — 現在のスクリーンの[要素ライブラリ](builder-elements)を開きます。スクリーンとレイヤーパネル上部の **+** と同じ機能で、パネルが折りたたまれているときに便利です。 ### 表示コントロール(下部ツールバー) \{#view-controls-bottom-toolbar\} 下部ツールバーのツールを使って、プレビューを操作できます。 * **Device**: 利用可能な iPhone および Android の端末モデルを選択して、ビューポートのサイズやデバイスの外枠を変更できます。 * **Screen orientation**: 縦向き Portrait と横向き Landscape を切り替えて、フローをさまざまな向きでプレビューできます。 * **Color scheme**: ライト Light mode とダーク Dark mode を切り替えて、デザインがテーマに応じてどのように変わるか確認できます。 * **Locale**: ロケールを選択して、ローカライズされたコンテンツでフローをプレビューできます。 * **View options**: デバイスのベゼルおよびセーフエリアガイドの表示・非表示を切り替えられます。 ## 画面と要素のプロパティ(右パネル) \{#screen-and-element-properties-right-panel\} ### 画面の設定とレイアウト \{#screen-settings-and-layout\} :::link 関連記事:[スクリーンとレイヤー](paywall-layout-and-products) ::: 要素が選択されていない状態では、右パネルでアクティブな[フロー画面](paywall-layout-and-products)のプロパティを調整できます。設定できる項目は次のとおりです: * システム UI との連携(ステータスバーの表示・非表示など) * 自動レイアウトのルール * 背景(色・画像・動画) * パディングサイズ * 縦方向のスクロール動作 画面に[インタラクティブクイズ](onboarding-quizzes)などの要素が含まれている場合、このリストには関連するプロパティが追加されます。 ### 要素のプロパティ \{#element-properties\} 要素を選択すると、右パネルからスタイルやインタラクティブなプロパティを変更できます。 #### デザインプロパティ \{#design-properties\} :::link 詳細はこちら: [レイアウトと配置](manage-paywall-ui-elements)、[スタイルと外観](builder-styling) ::: **Design** タブでは、選択した要素のビジュアル外観とレイアウトを設定できます。 * **Visibility**: 要素の表示・非表示を切り替えます。**Conditional** visibility を有効にすると、要素を表示する条件を設定できます。 * **Position**: Relative、Absolute、Fixed のいずれかのポジションを選択します。 * **Content**(テキスト要素のみ): 要素のテキストを編集し、[変数](#variables)を挿入して、ローカライズを管理します。 * **Typography**(テキスト要素のみ): フォント、ウェイト、サイズ、カラー、配置、装飾、省略設定を行います。 * **Spacing**: 要素のマージンとパディングを設定します。 * **Effects**: ドロップシャドウ、インナーシャドウ、背景ブラー、レイヤーブラーを追加します。 * **Animation**: アニメーション効果(Pulse など)を追加し、タイミングや強度を設定します。 * **Appearance**: 不透明度と回転を調整します。 * **Layout**: レイアウトの方向(縦または横)を選択し、子要素の配置方法を決定します。 #### インタラクションのプロパティ \{#interactions-properties\} :::link 詳細情報: [アクション](onboarding-actions)、[ナビゲーションとインタラクション](onboarding-navigation-branching) ::: **Interactions** タブでは、選択した要素にユーザーが操作したときの動作を定義できます。各インタラクションは **トリガー** と1つ以上の **アクション** で構成されています。 * **トリガー**は「*いつ*」何かが起きるかを定義します。例えば **On Tap**(ユーザーがその要素をタップしたとき)などです。 * **アクション**は「*何が*」起きるかを定義します。例えば別の画面に遷移したり、変数の値を変更したりします。1つのトリガーに複数のアクションを追加すると、それらを順番に連鎖実行できます。 同じ要素に複数のトリガーを追加して、複数のアクションを順に実行することも可能です。 ## 左パネル \{#left-panel\} 左パネルはアクティブなボタンに応じて機能が変わります。以下から選択できます: * [スクリーンとレイヤー](#screens-and-layers) * [要素の追加](#element-selection) * [プロダクト](#products) * [スタイル](#saved-styles) * [変数](#variables) * [ローカライズ](#localization) ### スクリーンとレイヤー \{#screens-and-layers\} :::link メイン記事:[スクリーンとレイヤー](paywall-layout-and-products) ::: レイヤー Layers ボタンを押すと「スクリーンとレイヤー」が開きます(フロービルダーを開いたときにデフォルトで表示されます)。 各画面がレイヤーのツリーとして表示されます。画面上の各要素がレイヤーとなり、コンテナにはその子要素がネストされています。レイヤーをドラッグ&ドロップして並べ替えることができます。 ### 要素の選択 \{#element-selection\} :::link メイン記事:[要素](builder-elements) ::: プラス Plus ボタンをクリックすると、左パネルに利用可能な UI 要素とそのバリエーションが表示されます。エントリをクリックすると、現在の画面に新しいレイヤーとして追加されます。 ### プロダクト \{#products\} :::link メイン記事:[プロダクト](paywall-product-block) ::: プロダクト Products ボタンを押すとプロダクト一覧が開きます。フロー内の各画面に割り当てられたプロダクトが表示されます。 この一覧は読み取り専用です。画面にプロダクトを割り当てるには、Product 要素を追加して右パネルで設定してください。プロダクトの作成・編集は、Adapty ダッシュボードの **Products** ページで行います。 ### 保存済みスタイル \{#saved-styles\} :::info 詳細はこちら: - [スタイルと外観](builder-styling) - [テキストコンテンツ](onboarding-text) - [ダークモード](paywall-dark-mode) ::: スタイル Styles ボタンをクリックすると、保存済みスタイルが開きます。 ここでは、グローバルスタイルを編集・管理できます。フロー内の複数の要素で同じタイポグラフィやカラーを使用している場合は、そのデータをグローバルスタイルとして保存しておきましょう。保存しておけば、ワンクリックで再利用できます。 現在、フローのビルダーは、フォントスタイルとカラースタイルという2種類のグローバルスタイルをサポートしています。各カラースタイルには、ダークモード用の個別の値をオプションで設定できます。 ### 変数 \{#variables\} :::link メイン記事:[変数](onboarding-variables) ::: ブラケット Variables ボタンをクリックすると、変数パネルが開きます。 ここでは、フローで使用する変数を作成・管理できます。実行時、SDKは変数プレースホルダーをユーザー属性、プロダクト価格、ローカライズ済み文字列などの実際の値に置き換えます。 変数は2つのタブに分類されます: * **カスタム**: アクションを通じて自分で作成・管理する変数です。 * **要素**: クイズの回答、トグルの状態、タブの選択など、ユーザー操作によって決まる値です。 価格、名称、その他のプロダクトデータなどのプロダクト変数は、このパネルには表示されません。テキスト要素を編集する際に直接参照してください。 変数の主な用途: * **テキストのバインド**: 静的な文字列の代わりに動的なコンテンツを表示する。 * **表示の制御**: 条件に基づいて要素の表示・非表示を切り替える(例:プレミアムユーザーにはアップグレードボタンを非表示にする)。 * **ユーザーとのインタラクション**: フォームやクイズなどのユーザー入力フィールドからデータを取得する。 ### ローカライゼーション \{#localization\} :::link メイン記事: [ローカライゼーション](add-flow-remote-config-locale) ::: ローカライゼーションビューでは、フロー内のすべての翻訳可能なコンテンツを一元管理できます。テキスト文字列と画像を画面ごとに整理したテーブルが表示され、各ロケールの列が並んでいます。このビューからできることは次のとおりです: * 新しいロケールの追加と、ローカライズされた文字列のインライン編集。 * 翻訳ステータスの確認 — 各行は **Done** または **Missing** としてマークされます。 * 画面でのフィルタリングや、未翻訳のコンテンツのみ表示。 * **AI Translate** による自動翻訳、または **Import/Export** を使った一括インポート/エクスポート。 --- # File: flow-builder-recipes --- --- title: "よくあるフローのレシピ" description: "フロービルダーでよく使われる画面テンプレートを作成するためのステップバイステップガイド。" --- このセクションでは、フロービルダーでよく使われる画面テンプレートの作り方を、レイアウトの選択からインタラクションまで、要素ごとに順を追って説明します。各ガイドは独立した内容で、標準的なフロービルダーの要素を使用しています。 <CustomDocCardList /> 基本的なパーソナライズされたフローの作成方法については、こちらのクイックスタート動画をご覧ください: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/aa-m459VIuY?si=zN_Co6B6qB88UPZP" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> :::link フローの作成についてさらに詳しく知りたいですか?[YouTubeプレイリスト](https://www.youtube.com/playlist?list=PLMksWqaZiWtM)でステップバイステップの動画チュートリアルをご覧ください。 ::: --- # File: basic-paywall-screen --- --- title: "基本的なペイウォール画面を作成する" description: "フロービルダーで標準的なペイウォール画面を構築するためのステップバイステップガイド。" --- これは最も一般的なペイウォールテンプレートです。単独の画面として使用することも、マルチ画面[フロー](adapty-flow-builder)の最後に配置することもできます。 標準的なペイウォール画面には、見出し、価値の説明、機能一覧、プロダクト一覧、購入ボタン、そして購入の復元・利用規約・プライバシーポリシーへのフッターリンクが含まれています。 ## はじめる前に \{#before-you-start\} - Adapty ダッシュボードで[プロダクトを作成する](create-product)。 - [Adapty を App Store と Google Play に接続する](integrate-payments)。 ## 1. 再利用可能なスタイルを設定する \{#1-set-up-reusable-styles\} 再利用可能なスタイルを使うと、同じタイポグラフィやカラーをすべての画面にワンクリックで適用できます。新しいフローにはデフォルトのテキストスタイル(H1、Body、Button Label など)があらかじめ用意されているので、要素を追加する前にデザインに合わせて調整しておきましょう。画面全体で使うブランドカラーもカラースタイルとして追加しておくと便利です。 詳しい手順については、[スタイルと外観 — 再利用可能なスタイル](builder-styling#reusable-styles)を参照してください。 スタイルを設定するには: 1. 左パネルで **Styles** Styles パネルを開きます。 2. **Text** タブで既存のスタイルをクリックし、フォント・ウェイト・サイズ・カラーを編集します。デフォルトのスタイルでは対応できない場合にのみ、新しいスタイルを追加してください。 3. **Colors** タブで **Plus Create style** をクリックし、画面全体で繰り返し使う予定のカラーを追加します。 ## 2. 画面レイアウトを設定する \{#set-up-the-screen-layout\} 画面自体は、追加するすべての要素のコンテナとして機能します。後から追加する要素が正しく配置されるよう、まずレイアウト、背景、パディングを設定しておきましょう。 画面のプロパティの完全なリストについては、[画面とレイヤー — 画面の設定](paywall-layout-and-products#screen-settings)を参照してください。 画面を設定するには: 1. キャンバスの空白部分をクリックして画面を選択します。右パネルが画面設定に切り替わります。 2. **System UI** の **Safe area** を無効にして、コンテンツが画面の端まで広がるようにします。 3. **Layout** で、方向を **Vertical** Vertical に、配置を **Space evenly** に設定します。 4. **Fill** の下で、背景の種類を選択します — 単色、グラデーション、または画像。この例では、2つのカラーストップを持つ **Gradient** Gradient を使用します。 ## 3. 閉じるボタンを追加する \{#3-add-the-close-button\} 閉じるボタンはペイウォールを閉じます。**Close** プリセットはあらかじめ設定済みなので、アクションの設定は不要です。 1. キャンバス上で **+** をクリックする。 2. **Buttons** > **Close** を選択する。 ## 4. タイトルを追加してクローズボタンと組み合わせる \{#add-the-title-and-pair-it-with-the-close-button\} H1はスクリーン上部のクローズボタンの横に配置します。水平方向に並べるため、両方を横方向のコンテナで囲みます。 タイトルを追加するには: 1. **+** > **Text** > **H1** をクリックします。 2. H1を選択した状態で、右パネルの **Design** タブを開き、**Content** フィールドのテキストを編集します。 タイトルをクローズボタンとグループ化するには: 1. **Layers** パネルで、閉じるボタンのレイヤーにある三点メニュー Context menu をクリックし、**Wrap** > **Wrap in Horizontal Container** を選択します。 2. H1 レイヤーを新しい水平コンテナにドラッグします。 2つの要素を揃えるには: 1. 閉じるボタンのサイズとH1のフォントサイズを調整して、同じ行に収まるようにします。 2. 水平コンテナを選択した状態で、右パネルの配置と分布の設定を行い、要素が正しく整列するようにします。 ## 5. 価値説明を追加する \{#5-add-the-value-description\} タイトルの下にある短いボディテキストで、ユーザーがサブスクリプションから得られるものを説明します。 1. **+** > **Text** > **Body** をクリックする。 2. body 要素を選択した状態で、**Design** タブの **Content** フィールドでテキストを編集する。 ## 6. 機能リストを追加する \{#add-the-feature-list\} 機能リストは、サブスクリプションを解除することで利用できる機能を一覧表示します。各行にはアイコン、機能タイトル、簡単な説明が含まれます。 リストプリセットの全一覧については、[Elements — List](builder-elements#list) を参照してください。 機能リストを追加するには: 1. **+** > **List** をクリックして、リストプリセットを選択します。ペイウォールでは Icon List が最もよく使われます。 2. 各行を選択した状態で、**Content** フィールドでタイトルと説明を編集します。 3. 行を追加・削除するには、リストを選択して **Layers** パネルの行コントロールを使用します。 ## 7. プロダクトリストを追加する \{#add-the-product-list\} プロダクトリストには、ユーザーが選択できるサブスクリプションの選択肢が表示されます。Products 要素は、画面に割り当てられたプロダクトごとに1枚のカードをレンダリングし、1枚のカードが自動的にデフォルトとしてマークされます。 プロダクトの管理について詳しくは、[購入の設定](paywall-product-block)を参照してください。 プロダクトを追加・設定するには: 1. **+** > **Products** をクリックし、レイアウトプリセットを選択します。最もよく使われるのは Vertical List です。 2. キャンバス上の各プロダクトカードを選択し、**Design** タブのドロップダウンからプロダクトを選びます。ドロップダウンには Adapty ダッシュボードで設定済みのすべてのプロダクトが表示されます。 3. デフォルトの選択を変更するには、対象のカードを選択し、**Design** タブで **Set as default product** を有効にします。 4. 割引バッジをカスタマイズするには、**Layers** パネルでプロダクトカードを展開し、バッジレイヤーを選択して、**Content** フィールドでテキストを編集します。他のカードのバッジを非表示にするには、各バッジレイヤーの横にある目のアイコン Show をクリックします。 ## 8. 購入ボタンを追加する \{#add-the-purchase-button\} 購入ボタンは、ユーザーが選択したプロダクトのアプリ内課金を開始します。`products.selectedProduct` 変数は、常に画面上で現在選択されているプロダクトに解決されます。 購入ボタンを追加するには: 1. **+** > **Buttons** をクリックし、ボタンのプリセットを選択します。 2. ボタンを選択した状態で、右パネルの **Interactions** タブを開きます。 3. **Add trigger** > **On tap** をクリックし、**Add action** をクリックします。 4. **Action** を **Purchase** に、**Product** を `products.selectedProduct` に設定します。 ## 9. フッターリンクを追加する \{#add-footer-links\} フッターには、利用規約とプライバシーポリシーへのリンク(アプリストアの要件)、および以前の購入を復元するボタンが含まれています。 フッターリンクを追加するには: 1. **+** > **Buttons** > **Links** をクリックします。これにより、Restore Purchases、Terms of Use、Privacy Policy の行が追加されます。 2. **Layers** パネルで **Terms of Use** ボタンを選択します。**Interactions** タブを開くと、**Open URL** アクションがすでに設定されています。アクションをクリックして、対象の URL を入力します。 3. **Privacy Policy** ボタンでも同様に、プライバシーポリシーの URL を入力します。 4. **Restore Purchases** ボタンはそのままにします。このボタンのアクションはあらかじめ設定済みです。 :::tip 要素の位置が高すぎる・低すぎると感じる場合や、余白を追加したい場合は、その要素のマージンとパディングを調整してください。 ::: ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish)。 - [プレースメントにフローを追加する](create-placement)ことで、ユーザーへの表示を開始できます。 --- # File: show-plans-bottom-sheet --- --- title: "すべてのプランをボトムシートに表示する" description: "シングルCTA、「すべてのプランを表示」リンク、プロダクト一覧を展開するボトムシートを備えたヒーローペイウォールを作成します。" --- このテンプレートは、まず1つのハイライトされたオファーを前面に出し、プラン一覧への控えめなリンクを添えます。**Show all plans** をタップすると、他のプロダクト、購入ボタン、フッターリンクを含むボトムシートがスライドアップします。 特定のプランが突出したコンバージョン率を持つ場合に活用してください。ボトムシートにより、メイン画面をすっきり保ちながら、代替プランにワンタップでアクセスできます。 ## 始める前に \{#before-you-start\} - Adapty ダッシュボードで[プロダクトを作成](create-product)します。 - [Adapty を App Store および Google Play に接続](integrate-payments)します。 ## 1. 画面レイアウトを設定する \{#1-set-up-the-screen-layout\} ヒーロー画像を画面の背景として使用し、残りのコンテンツを下部にグループ化することで、画像が画面の上部を占めるようにします。 画面プロパティの完全なリストについては、[画面とレイヤー — 画面設定](paywall-layout-and-products#screen-settings)を参照してください。 画面を設定するには: 1. キャンバスの空白領域をクリックして画面を選択します。 2. **System UI** の下にある **Safe area** を無効にして、ヒーロー画像が画面の端まで広がるようにします。 3. **Fill** の下で **Image** Image を選択し、ヒーロー画像をアップロードします。 4. **Layout** の下で、方向、ギャップ、配置を設定して、コンテンツを好みの位置に固定します。このテンプレートでは、**Vertical** Vertical 方向に小さいギャップと **bottom-middle** 配置を使用して、見出しとボタンを画面下部にグループ化します。 ## 2. CTAの見出しを追加する \{#2-add-the-cta-heading\} 見出しは画面の下部、サブスクライブボタンのすぐ上に配置されます。ヒーロー画像はその上の領域を埋めます。 1. **+** > **Text** > **H1** をクリックします。 2. H1 を選択した状態で、**Design** タブを開き、**Content** フィールドのテキストを編集します。 ## 3. ボトムシートとそのタイトルを追加する \{#3-add-the-bottom-sheet-and-its-title\} ボトムシートは、画面の下部からスライドアップするレイアウトコンテナです。今は表示状態で追加してください — 次のいくつかのステップでコンテンツを追加してから、完成したら非表示にします。非表示の要素は編集できないため、コンテンツを追加し終えるまでシートを表示状態に保つ必要があります。 ボトムシートやその他のレイアウトコンテナの詳細については、[エレメント — レイアウト](builder-elements#layout)を参照してください。 ボトムシートとそのタイトルを追加するには: 1. **+** > **Layout** > **Bottom Sheet** をクリックします。 2. **Layers** パネルでボトムシートを展開し、**Title** レイヤーを選択して、**Design** タブの **Content** フィールドを編集します(例:`Choose your plan`)。 ## 4. ボトムシート内にプロダクト一覧を追加する \{#4-add-the-product-list-inside-the-bottom-sheet\} すべてのプロダクトをボトムシート内に配置します。そのうちの1つはメインのCTAボタンに表示される価格にも使用されます。 プロダクトの管理について詳しくは、[購入の設定](paywall-product-block)を参照してください。 プロダクトを追加・設定するには: 1. **+** > **Products** をクリックし、レイアウトプリセットを選択します。ほとんどの場合、Vertical List が適しています。要素が画面上に表示されますが、ボトムシートの外側になります。 2. **Layers** パネルで、Products レイヤーをボトムシート内の **Content** コンテナにドラッグします。 3. キャンバス上の各プロダクトカードを選択し、**Design** タブのドロップダウンからプロダクトを選択します。 ## 5. ボトムシート内に購入ボタンを追加する \{#5-add-the-purchase-button-inside-the-bottom-sheet\} ボトムシートには、ユーザーがリストから選択したプランを購入するための専用の購入ボタンが必要です。 1. **+** > **Buttons** をクリックし、ボタンプリセットを選択します。 2. **Layers** パネルで、新しいボタンをボトムシート内の **Content** コンテナにドラッグします。 3. ボタンを選択した状態で、右パネルの **Interactions** タブを開きます。 4. **Add trigger** > **On tap** をクリックし、**Add action** をクリックします。 5. **Action** を **Purchase**、**Product** を `products.selectedProduct` に設定します。 ## 6. ボトムシート内にフッターリンクを追加する \{#6-add-the-footer-links-inside-the-bottom-sheet\} :::important ボタン内にネストされたテキストには[インラインリンク](onboarding-text#inline-link)を使用しないでください。代わりに、ボタン自体に **Open URL** アクションを設定してください。 ::: 利用規約、プライバシーポリシー、購入の復元はシートの下部に配置されます — メイン画面はすっきりと保たれます。 1. **+** > **Buttons** > **Links** をクリックします。これにより、Restore Purchases、Terms of Use、Privacy Policy の行が追加されます。 2. **Layers** パネルで、Links の行をボトムシート内の **Content** コンテナにドラッグします。 3. **Layers** パネルで、**Terms of Use** ボタンを選択します。**Interactions** タブを開き、**Open URL** フィールドに利用規約の URL を貼り付けます。 4. **Privacy Policy** ボタンでも同様に、プライバシー URL を設定します。 5. **Restore Purchases** リンクはそのままにしておきます。アクションは事前に設定されています。 ## 7. ボトムシートを非表示にする \{#7-hide-the-bottom-sheet\} シートのコンテンツが揃ったら、デフォルトで画面に表示されないように非表示にします。ユーザーは最後のステップで **Show all plans** をタップすることで表示できます。 **Layers** パネルでボトムシートを選択し、状態を **Hide** Hide に設定します。シートはレイヤーツリーに残りますが、キャンバスにはレンダリングされなくなります。 ## 8. メインのサブスクライブボタンを追加する \{#8-add-the-main-subscribe-button\} 画面上のメインボタンは、ワンタップでユーザーを月額プランに登録します。ラベルには月額プロダクトの価格変数を使用するため、ボタンは常にプロダクトと同期されます。 1. **Layers** パネルでスクリーンをクリックして、新しい要素がボトムシート内ではなくルートに追加されるようにします。 2. **+** > **Buttons** をクリックし、ボタンプリセットを選択します。 3. ボタンを選択した状態で、**Design** タブを開き、**Content** フィールドにカーソルを置きます。Variable icon をクリックして、メインプロダクトの価格変数を選択します。残りのラベルで囲んでください — 例:`Subscribe for {price}/month`。 4. **Interactions** タブに切り替え、**Add trigger** > **On tap** > **Add action** をクリックします。 5. **Action** を **Purchase**、**Product** を必要なプロダクトに設定します。ボトムシートのボタンとは異なり、こちらは `products.selectedProduct` ではなく特定のプロダクトを対象とします。 ## 9. 「すべてのプランを表示」リンクを追加する \{#9-add-the-show-all-plans-link\} サブスクライブボタンの下にあるテキストリンクをタップすると、ボトムシートが表示されます。**Button Label** スタイルのテキスト要素として追加することで、見た目をミニマルに保ちながらアクションを設定できます。 Show/Hide アクションの詳細については、[アクション — 要素の表示/非表示](onboarding-actions#showhide-elements)を参照してください。 リンクを追加するには: 1. **Layers** パネルでスクリーンを選択した状態で、**+** > **Text** > **Button Label** をクリックします。 2. テキスト要素を選択した状態で、**Content** フィールドを `Show all plans` に編集します。 3. **Interactions** タブを開き、**Add trigger** > **On tap** > **Add action** をクリックします。 4. **Action** を **Show** に設定し、ドロップダウンからボトムシート要素を選択します。 ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish)。 - [プレースメントにフローを追加して](create-placement)、ユーザーへの表示を開始する。 --- # File: paywall-with-tabs --- --- title: "タブ付きペイウォールを作成する" description: "2つのタブで異なるフィーチャーリスト、プロダクトグループ、購入アクションを切り替えるペイウォール画面を作成します。" --- このテンプレートは、タブを使って1つの画面で同じオファーの2つのバリアントを切り替えます。各タブには独自のフィーチャーリスト、プロダクトリスト、購入ボタンが含まれています。タブをタップすると画面を離れることなく表示コンテンツが切り替わります。プラン階層、請求期間、またはオーディエンスセグメントでプランを分けるのに便利です。 ## 始める前に \{#before-you-start\} - Adapty ダッシュボードで[プロダクトを作成する](create-product)。 - [Adapty を App Store および Google Play に接続する](integrate-payments)。 ## 1. 画面レイアウトを設定する \{#set-up-the-screen-layout\} 画面は、閉じるボタン・見出し・タブ・タブコンテンツを収めるコンテナとして機能します。この例では背景に画像を使っていますが、単色やグラデーションでも同じように設定できます。 画面プロパティの全一覧は、[画面とレイヤー — 画面の設定](paywall-layout-and-products#screen-settings) を参照してください。 画面を設定するには: 1. キャンバスの空白エリアをクリックして、スクリーンを選択します。 2. **System UI** の下にある **Safe area** を無効にして、背景が画面の端まで広がるようにします。 3. **Fill** の下で背景の種類を選択して設定します。この例では **Image** Image を使用していますが、単色やグラデーションでも同じように設定できます。 4. **Layout** の下で方向を **Vertical** Vertical に設定し、要素が上から縦に並び、タブのコンテンツが残りのスペースを埋めるようにギャップと整列を設定します。 ## 2. 閉じるボタンを追加する \{#2-add-the-close-button\} 閉じるボタンはペイウォールを閉じます。**Close** プリセットはあらかじめ設定済みのため、アクションの設定は不要です。 1. キャンバスで **+** をクリックします。 2. **Buttons** > **Close** を選択します。 ## 3. タイトルを追加して閉じるボタンと組み合わせる \{#add-the-title-and-pair-it-with-the-close-button\} 見出しは画面上部の閉じるボタンの横に配置します。横並びにするには、両方を水平方向のコンテナで囲みます。 タイトルを追加するには: 1. **+** > **Text** > **H1** をクリックします。 2. H1 を選択した状態で **Design** タブを開き、**Content** フィールドでテキストを編集します。 タイトルと閉じるボタンをグループ化するには: 1. **レイヤー**パネルで、閉じるボタンのレイヤーにある3点メニュー Context menu をクリックし、**Wrap** > **Wrap in Horizontal Container** を選択します。 2. H1 レイヤーを新しい水平コンテナにドラッグします。 2つの要素を整列させるには: 1. 閉じるボタンのサイズとH1のフォントサイズを調整して、同じ行に収まるようにします。 2. 横方向のコンテナを選択した状態で、右パネルの配置と分布を設定して、要素が正しく並ぶようにします。 ## 4. タブを追加してラベルを設定する \{#4-add-the-tabs-and-configure-their-labels\} Tabs 要素は、画面のセクションを切り替え可能なコンテンツパネルに分割します。各タブには独自のコンテンツコンテナがあり、ユーザーがそのタブを選択したときに表示されます。 Tabs 要素の詳細については、[Elements — Tabs](builder-elements#tabs) を参照してください。選択可能なグループの詳細については、[選択可能な要素とグループ](flow-selectable-elements) を参照してください。 タブを追加するには: 1. **+** > **Tabs** をクリックし、プリセット(Segment control、Button Tabs、Underline)を選択します。 2. キャンバスまたは **Layers** パネルで各タブの名前を選択した状態で、**Design** タブの **Content** フィールドを編集してラベルを変更します(例:`Premium`、`Pro`)。 ## 5. 最初のタブにフィーチャーリストを追加する \{#5-add-a-feature-list-to-the-first-tab\} 最初のタブ内に短くコンパクトなフィーチャーリストを追加することで、そのプランに含まれる内容をユーザーに伝えられます。 リストのプリセット一覧については、[Elements — List](builder-elements#list) を参照してください。 フィーチャーリストを追加するには: 1. **+** > **List** をクリックしてリストのプリセットを選択します。ペイウォールではIcon Listが最もコンパクトです。要素はレイヤーツリーの末尾に追加されます。 2. 各行を選択した状態で、**Content** フィールドのタイトルを編集します。 3. **Layers** パネルで、リストを最初のタブの **Content** コンテナにドラッグします。 ## 6. 最初のタブにプロダクトリストを追加する \{#add-the-product-list-to-the-first-tab\} プロダクトリストは、最初のタブにサブスクリプションオプションを表示します。Products 要素は、スクリーンに割り当てられたプロダクトごとに1枚のカードをレンダリングし、独自の選択可能なグループを作成します。 プロダクトの管理について詳しくは、[購入の設定](paywall-product-block)を参照してください。 プロダクトを追加・設定するには: 1. **+** > **Products** をクリックしてレイアウトのプリセットを選択します。縦並びのプランには Vertical List がおすすめです。要素はレイヤーツリーの末尾に追加されます。 2. キャンバス上の各プロダクトカードを選択し、**Design** タブのドロップダウンからプロダクトを選択します。 3. **Layers** パネルで、Products レイヤーを最初のタブの **Content** コンテナにドラッグします。 ## 7. 購入ボタンを最初のタブに追加する \{#add-the-purchase-button-to-the-first-tab\} 購入ボタンは、最初のタブでユーザーが選択したプロダクトのアプリ内課金を開始します。ボタンのラベルには選択中のプロダクトの価格が表示されるため、ユーザーの選択と常に同期した状態になります。 Purchase アクションの詳細については、[アクション — Purchase](onboarding-actions#purchase) を参照してください。 購入ボタンを追加して設定するには: 1. **+** > **Buttons** をクリックし、ボタンのプリセットを選択します。要素はレイヤーツリーの末尾に追加されます。 2. ボタンを選択した状態で **Design** タブを開き、**Content** フィールドにカーソルを置きます。変数アイコン Variable icon をクリックし、`products.selectedProduct` を選択してから `prod_price` 属性を選択します。変数は `products.selectedProduct.prod_price` として解決されます。残りのラベルテキストで囲んでください。例: `Subscribe for {prod_price}`。 3. **Interactions** タブに切り替え、**Add trigger** > **On tap** > **Add action** をクリックします。 4. **Action** を **Purchase**、**Product** を `products.selectedProduct` に設定します。 5. **Layers** パネルで、ボタンを最初のタブの **Content** コンテナにドラッグします。 ## 8. 最初のタブのコンテンツを2番目のタブにコピーする \{#8-copy-the-first-tabs-content-into-the-second-tab\} 最初からまったく同じ構造を作り直す代わりに、最初のタブから機能リスト・プロダクトリスト・購入ボタンを2番目のタブにコピーしましょう。その後、値を更新するだけで済みます。 コンテンツをコピーするには: 1. **Layers** パネルで、最初のタブの **Content** コンテナを展開します。 2. その中の各要素(機能リスト、プロダクト、購入ボタン)を選択し、⌘C / Ctrl+C でコピーして ⌘V / Ctrl+V で貼り付けます。コピーがレイヤーツリーの末尾に追加されます。 3. コピーした各要素を2番目のタブの **Content** コンテナにドラッグします。 ## 9. 2つ目のタブのコンテンツを更新する \{#update-the-second-tabs-content\} 現在、2つ目のタブは1つ目のタブと同じ内容になっています。各要素を2つ目のプランの内容に更新しましょう。 2つ目のタブを更新するには: 1. 2番目のタブ内のフィーチャーリストを編集し、行が2番目のプランの機能と一致するようにします。 2. 2番目のタブの Products 要素で各プロダクトカードを選択し、ドロップダウンから2番目のプランのプロダクトを割り当てます。この Products 要素は自動的に別の選択可能なグループ(`products2`)になります。 3. 2番目のタブの購入ボタンを選択します。**Design** タブの **Content** フィールドで、価格変数を `products.selectedProduct.prod_price` から `products2.selectedProduct.prod_price` に変更します。 4. **Interactions** タブに切り替え、**Purchase** アクションの **Product** を `products.selectedProduct` から `products2.selectedProduct` に更新します。 ## 10. フッターリンクを追加する \{#add-the-shared-footer-links\} 利用規約、プライバシーポリシー、購入履歴の復元は、どのタブがアクティブな場合でも表示されます。これらはタブコンテンツのコンテナの外側、つまり画面レベルに配置することで、タブ間で共有されます。 フッターリンクを追加する手順: 1. **+** > **Buttons** > **Links** をクリックします。これにより、レイヤーツリーの末尾に「Restore Purchases」「Terms of Use」「Privacy Policy」の行が追加されます。タブの内側にネストされるのではなく、スクリーンのルートに配置されるため、ここが適切な位置です。 2. **Layers** パネルで **Terms of Use** ボタンを選択します。**Interactions** タブを開き、**Open URL** フィールドに利用規約の URL を貼り付けます。 3. **Privacy Policy** ボタンについても、プライバシーポリシーの URL を使って同じ手順を繰り返します。 4. **Restore Purchases** リンクはそのままにしておきます。アクションはあらかじめ設定されています。 ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish)。 - [プレースメントにフローを追加する](create-placement)ことで、ユーザーへの表示を開始します。 --- # File: paywall-features-per-product --- --- title: "プロダクトごとに異なる機能を表示する" description: "条件付き表示を使って、ユーザーが選択したプロダクトに応じて異なる機能一覧を表示します。" --- このテンプレートは条件付き表示を使って、プランごとに異なる機能リストを表示します。画面には2つのプロダクト(例:Pro と Pro+)が表示され、ユーザーが選択したプロダクトに応じて異なる機能リストが表示される仕組みです。一方のプロダクトがデフォルトとして設定されているため、画面を最初に開いたときはそのプロダクトの機能リストが表示されます。 ## 始める前に \{#before-you-start\} - Adapty ダッシュボードで[プロダクトを作成](create-product)する。 - [AdaptyをApp StoreおよびGoogle Playに接続](integrate-payments)する。 ## 1. 画面レイアウトを設定する \{#1-set-up-the-screen-layout\} 画面は、追加したすべての要素を入れるコンテナとして機能します。この例では背景に画像を使用していますが、単色やグラデーションでも同じように設定できます。 画面プロパティの全一覧については、[画面とレイヤー — 画面設定](paywall-layout-and-products#screen-settings)を参照してください。 画面を設定するには: 1. キャンバスの空白部分をクリックして、スクリーンを選択します。 2. **System UI** の下にある **Safe area** を無効にして、背景が画面の端まで広がるようにします。 3. **Fill** の下で背景の種類を選択して設定します。この例では **Image** Image を使用していますが、単色やグラデーションでも同じように設定できます。 4. **Layout** の下で方向を **Vertical** Vertical に設定し、要素が上から積み重なってコンテンツが残りのスペースを埋めるよう、ギャップと配置を設定します。 ## 2. 閉じるボタンを追加する \{#2-add-the-close-button\} 閉じるボタンはペイウォールを閉じます。**Close** プリセットはあらかじめ設定済みなので、アクションの設定は不要です。 1. キャンバスで **+** をクリックします。 2. **Buttons** > **Close** を選択します。 ## 3. タイトルを追加してクローズボタンと組み合わせる \{#add-the-title-and-pair-it-with-the-close-button\} 見出しは画面上部のクローズボタンの隣に配置します。横並びにするには、両方を横方向のコンテナでラップします。 タイトルを追加するには: 1. **+** > **Text** > **H1** をクリックします。 2. H1 を選択した状態で **Design** タブを開き、**Content** フィールドでテキストを編集します。 タイトルをクローズボタンとグループ化するには: 1. **Layers** パネルで、閉じるボタンのレイヤーにある三点メニュー Context menu をクリックし、**Wrap** > **Wrap in Horizontal Container** を選択します。 2. H1 レイヤーを新しい水平コンテナにドラッグします。 2つの要素を整列させるには: 1. 閉じるボタンのサイズとH1のフォントサイズを調整して、同じ行に収まるようにします。 2. 水平コンテナを選択した状態で、右パネルの配置と分布を設定し、要素が正しく並ぶようにします。 ## 4. プロダクトリストを追加する \{#add-the-product-list\} ユーザーが選択できるプロダクトを追加します。画面が最初に読み込まれたときに意味のある状態になるよう、1つをデフォルトとして設定してください。 プロダクトの管理について詳しくは、[購入のセットアップ](paywall-product-block)を参照してください。 プロダクトを追加・設定するには: 1. **+** > **Products** をクリックし、レイアウトプリセットを選択します。このテンプレートには「Vertical List」が適しています。 2. キャンバス上の各プロダクトカードを選択し、**Design** タブのドロップダウンからプロダクトを選択します。 3. デフォルトで選択状態にしたいカード(例:Pro+)を選択し、**Design** タブで **Set as default product** を有効にします。 ## 5. 最初のプロダクトのフィーチャーリストを追加する \{#add-the-feature-list-for-the-first-product\} 最初のフィーチャーリストはデフォルトのプロダクトを説明するものです。ユーザーが最初のプロダクトを選択しているときのみ表示されます。 条件付き表示の詳細については、[条件付き表示](onboarding-element-visibility)を参照してください。 :::tip 2つの別々のリストを用意する代わりに、1つのリストを追加してその中のテキスト要素を条件付きにすることもできます。そうすると、1つのリストで選択されたプロダクトに応じて表示が切り替わります。詳しくは[条件付きテキストの追加](onboarding-text#add-conditional-text)を参照してください。 ::: フィーチャーリストを追加して設定するには: 1. **+** > **List** をクリックし、コンパクトなリストプリセットを選択します。アイコンリストはペイウォールに最適です。 2. 各行を選択した状態で、**Content** フィールドのタイトルを編集して最初のプロダクトの特徴を説明します。 3. リストを選択したまま、**Design** タブを開きます。**Visibility** の下で **Conditional** Conditional を選択します。 4. 最初のプロダクトが現在選択されているプロダクトである場合にのみリストが表示されるよう条件を設定します。`products.selectedProduct.prod_title` 変数と照合します。**Value** については、変数アイコン `{}` をクリックし、最初のプロダクトカードを選んで、その `prod_title` 属性を選択します。比較はそのプロダクトのタイトルに解決されます。 ## 6. 2つ目のプロダクトにフィーチャーリストを追加する \{#add-the-feature-list-for-the-second-product\} 同じ手順を2つ目のプロダクトにも繰り返します。2つのリストは相互排他的で、どちらのプロダクトが選択されているかに応じて、一度に表示されるのは1つだけです。 2つ目のフィーチャーリストを追加するには: 1. **+** > **List** をクリックし、見た目の統一感を保つために同じコンパクトプリセットを選択します。 2. 各行を編集して、2つ目のプロダクトの特徴を説明します。 3. **Visibility** で **Conditional** Conditional を選択し、ステップ5と同じ条件を設定します。ただし、**Value** の変数ピッカーは2つ目のプロダクトカードの `prod_title` を指定してください。 ## 7. 購入ボタンを追加する \{#add-the-purchase-button\} 購入ボタンは、ユーザーが選択したプロダクトのアプリ内課金を開始します。ボタンのラベルには選択中のプロダクトの価格が表示されるため、プランを切り替えると自動的に更新されます。 Purchase アクションの詳細については、[アクション — Purchase](onboarding-actions#purchase) を参照してください。 購入ボタンを追加・設定するには: 1. **+** > **Buttons** をクリックし、ボタンのプリセットを選択します。 2. ボタンを選択した状態で **Design** タブを開き、**Content** フィールドにカーソルを置きます。変数アイコン Variable icon をクリックし、`products.selectedProduct` を選択してから `prod_price` 属性を選択します。変数全体は `products.selectedProduct.prod_price` に解決されます。残りのラベルで囲んでください。例: `Subscribe for {prod_price}`。 3. **Interactions** タブに切り替え、**Add trigger** > **On tap** > **Add action** をクリックします。 4. **Action** を **Purchase**、**Product** を `products.selectedProduct` に設定します。 ## 8. フッターリンクを追加する \{#add-the-footer-links\} 利用規約、プライバシーポリシー、購入の復元はメインコンテンツの下に配置します。 フッターリンクを追加するには: 1. **+** > **Buttons** > **Links** をクリックします。これにより、レイヤーツリーの末尾に「Restore Purchases」「Terms of Use」「Privacy Policy」の行が追加されます。 2. **Layers** パネルで **Terms of Use** ボタンを選択します。**Interactions** タブを開き、**Open URL** フィールドに利用規約の URL を貼り付けます。 3. **Privacy Policy** ボタンにも同様の手順でプライバシーポリシーの URL を設定します。 4. **Restore Purchases** リンクはそのままにします。このリンクのアクションはあらかじめ設定済みです。 ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish)。 - [プレースメントにフローを追加して](create-placement)ユーザーへの表示を開始する。 --- # File: show-offer-on-close --- --- title: "ユーザーが閉じるボタンをタップしたときにオファーを表示する" description: "最初の閉じるボタンのタップを検知して、ユーザーがペイウォールを離れる前にラストチャンスオファーを表示します。" --- ユーザーが閉じるボタンをタップすると、購入せずに離脱しようとしています。このレシピでは最初の閉じるボタンのタップを検知します。ペイウォールを閉じる代わりに、ラストチャンスオファーのオーバーレイを表示します。ユーザーがオファーを閉じると、閉じるボタンが通常どおり機能してフローが閉じます。 このロジックには、カスタムのBoolean変数が1つと、条件付きアクションが1つ必要です。 - `close_tapped` は最初 `False` です。 - 最初にクローズをタップすると、オファーオーバーレイが表示され、`close_tapped` が `True` に設定されます。 - それ以降のクローズタップでフローが閉じます。 ## 始める前に \{#before-you-start\} - 閉じるボタン付きのペイウォール画面を作成してください。例として、[基本的なペイウォール画面の作成](basic-paywall-screen)を参考にしてください。 - オーバーレイで宣伝する[オファー](offers)付きの[プロダクトを作成](create-product)してください。 ## 1. 変数を作成する \{#1-create-the-variable\} カスタム変数の詳細については、[変数](onboarding-variables#custom-variables)を参照してください。 1. 左パネルの **{ }** アイコンをクリックして **Variables** を開きます。 2. **Custom** タブで **+** をクリックします。 3. 変数名を `close_tapped` に設定し、**Value Type** を **Boolean** にします。**Initial Value** は **False** のままにしておきます。 4. **Create variable** をクリックします。 ## 2. オファーオーバーレイを作成する \{#2-build-the-offer-overlay\} オーバーレイとは、デバイスの画面に固定され、ペイウォールの上に重なるコンテナです。最初は表示状態で作成してください。非表示の要素は編集できないため、コンテンツを配置した後のステップ4で非表示にします。 1. **+** > **Layout** > **Vertical Container** をクリックします。 2. コンテナを選択した状態で **Design** タブを開き、**Position** を **Fixed** に設定します。水平方向の配置を **Left & Right**、垂直方向の配置を **Top** に設定します。垂直方向の中央揃えオプションはないため、上部オフセット(例:`300`)を入力してオーバーレイを画面中央付近に移動させます。 3. **Fill** の下で背景を設定します(単色またはイメージ)。コンテナはデフォルトで透明なため、塗りつぶしを設定しないとオーバーレイの下にペイウォールが透けて見えます。 4. オファーのコンテンツを追加します。**Layers** パネルでコンテナを選択した状態で、**+** > **Text** > **H2** をクリックします。割引価格を表示するには、**Content** フィールドに `offer_price` などの[オファー変数](onboarding-variables#product-variables)を挿入します。 5. **+** > **Products** をクリックしてレイアウトのプリセットを選択し、オーバーレイにドラッグします。キャンバス上のプロダクトカードを選択し、**Design** タブでプロダクトとオファーを選択します。 6. **+** > **Buttons** をクリックしてボタンのプリセットを選択し、オーバーレイにドラッグします。**Interactions** タブで **Add trigger** > **On tap** > **Add action** をクリックし、**Action** を **Purchase**、**Product** をオファープロダクトに設定します。 ## 3. オーバーレイに閉じるボタンを追加する \{#3-add-the-dismiss-button-to-the-overlay\} オーバーレイには専用の閉じるボタンが必要です。このボタンのアクションはフローを閉じるのではなく、オーバーレイを非表示にするものでなければなりません。 1. オーバーレイを選択した状態で、**+** > **Buttons** > **Close flow** をクリックします。 2. ボタンを選択した状態で、**Interactions** タブを開きます。プリセットにはあらかじめ **Close Flow** アクションが設定されています。そのアクションをクリックし、タイプを **Hide element** に変更します。ターゲットにオーバーレイコンテナを設定してください。 :::important オーバーレイの閉じるボタンに事前設定された **Close Flow** アクションをそのまま残さないでください。フロー全体が閉じられてしまいます。 ::: ## 4. オーバーレイを非表示にする \{#hide-the-overlay\} オーバーレイは、最初の閉じるタップが行われるまで非表示のままにする必要があります。 **Layers** パネルでオーバーレイコンテナを選択し、その状態を **Hide** Hide に設定します。オーバーレイはレイヤーツリーに残りますが、キャンバス上には表示されなくなります。 ## 5. 閉じるボタンを設定する \{#5-set-up-the-close-button\} 閉じるボタンのデフォルトアクションを、`close_tapped` で分岐する条件付きアクションに置き換えます。 条件付きアクションの詳細については、[アクション — 条件付きアクション](onboarding-actions#conditional-actions) を参照してください。 1. ペイウォールの閉じるボタン(オーバーレイの閉じるボタンではなく、画面上のもの)を選択します。 2. **Interactions** タブを開き、あらかじめ設定されている **Close Flow** アクションをクリックして、タイプを **Conditional Action** に変更します。 3. **if** ブロックで **Add condition** をクリックし、`close_tapped` **Equals** **False** と設定します。 4. **then** ブロックに2つのアクションを追加します: - **Set Variable**:`close_tapped` を **True** に設定する。 - **Show element**: ターゲットをオファーオーバーレイに設定します。 5. **else** ブロックに **Close Flow** アクションを追加します。 これで、最初の閉じるタップでオファーが表示されます。ユーザーがそれを閉じた後、もう一度閉じるをタップすると **else** ブランチにマッチし、フローが終了します。 ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish)。 - [プレースメントにフローを追加する](create-placement)ことで、ユーザーへの表示を開始します。 --- # File: strikethrough-price --- --- title: "打ち消し線価格と割引バッジを表示する" description: "年間プランの実質月額価格の横に月額プランの価格を打ち消し線付きで表示して、割引をひと目でわかるようにします。" --- 実際の価格の横に打ち消し線付きの価格を並べると、割引がひと目でわかります。このレシピでは、年間プロダクトのカードを改造して、月額プランでの月額料金を打ち消し線付きで表示し、その横に年間プランの実質月額価格を並べ、さらに割引バッジを追加します。 取り消し線のフォーマットはテキスト要素全体に適用されるため、大きなテキストの中の変数だけに取り消し線を引くことはできません。そのため、取り消し線が引かれた価格は独立したテキスト要素として配置し、水平コンテナの中で割引価格と横に並べます。 :::tip 同じプロダクトの「以前の価格」として価格を高く表示するだけで十分な場合(例:現在の価格を2倍にして取り消し線を引くなど)は、あらかじめ用意された[旧価格要素](onboarding-text#add-an-old-price)を使いましょう。このレシピは、取り消し線の価格が別プロダクトの実際の価格である場合を対象としています。 ::: ## 始める前に \{#before-you-start\} - プロダクトを表示するペイウォール画面を作成してください。たとえば、[基本的なペイウォール画面の作成](basic-paywall-screen)を参考にしてください。このレシピでは、ペイウォールが年間プランと月間プランの2つのプロダクトを提供していることを前提としています。 ## 1. 価格行を重ねる \{#1-stack-the-price-rows\} 年間カードは最初、単一の価格行(年間プロダクトの `prod_price` 変数に `/year` を付けたもの、例: `$29.99/year`)だけで始まります。その上に月額換算の価格行を追加しましょう。 1. **Layers** パネルで、年額プロダクトカード内の価格テキストを選択します。テキストはすでにカードの縦方向コンテナ内にあるため、コピーはその下に積み重なります。 2. レイヤーの3点メニュー Context menu をクリックし、**Duplicate** を選択します。コピーが元のテキストの下に表示されます。次のステップで、上のテキストが月額価格の行になり、下のテキストが年額価格のままになります。 ## 2. 月次行を2つの価格に分割する \{#2-split-the-monthly-row-into-two-prices\} 月次行には、取り消し線付きの月額プランの価格と、年間プランの1か月あたりの価格という2つのテキスト要素が含まれています。 :::important 変数ピッカーには、フロースクリーンに存在するプロダクトの価格のみが表示されます。フローに含まれていないプロダクトを参照するには、空のスクリーンを作成して **Products** 要素を追加し、そのプロダクトを割り当ててください。そのスクリーンへのナビゲーションアクションが設定されていないことを確認してください。 ::: 1. 上部のテキスト要素を選択し、三点メニューをクリックして、**Wrap** > **Wrap in Horizontal Container** を選択します。 2. 新しいコンテナ内のテキストレイヤーの三点メニューをクリックし、**Duplicate** を選択します。 3. 最初のテキスト要素を選択し、**Content** フィールドをクリアします。変数アイコン Variable icon をクリックし、月次プロダクトを選択してから `prod_price_per_month` 属性を選びます。変数の後に `/month` と入力します。 4. **Design** タブの **Typography** で、**Decoration** を **Strikethrough** Strikethrough に設定します([スタイルと外観 — Decoration](builder-styling#decoration) を参照)。 5. 2つ目のテキスト要素を選択し、同じ方法でコンテンツを置き換えます。ただし、年次プロダクトの `prod_price_per_month` 属性を選択してください。変数の後に `/month` と入力します。 ## 3. 年間価格の表示を控えめにする \{#tone-down-the-yearly-price\} 複製した月額価格は元のスタイルを引き継いでいるため、3つの価格がすべて同じサイズ・ウェイトで表示されています。月額行が目立つよう、年間価格をより控えめなスタイルに変更しましょう。 1. キャンバス上で、一番下のテキスト要素(年間価格)を選択します。 2. 要素上部のツールバーでテキストスタイルのドロップダウンを開き、より控えめなスタイルを選択します(例:**Caption**)。または、**Design** タブの **Typography** から別のスタイルを選んでください。 ## 4. 割引バッジを追加する \{#add-the-discount-badge\} バッジは価格の横に節約額を強調表示します。 1. **+** > **Badge** をクリックします。 2. **Layers** パネルで、バッジを年間プロダクトの内部(価格の縦方向コンテナとラジオボタンの間)にドラッグします。 3. バッジのテキストレイヤーを選択し、**Content** フィールドを編集します(例:`Save 75%`)。 割引率の変数はないため、価格から計算して静的テキストとして入力してください。 これで年間カードは月額プランを基準価格として表示します。打ち消し線付きの月額料金、年間プランの月換算料金、割引バッジが1行に並び、その下に年間の合計金額が表示されます。 ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish) - [プレースメントにフローを追加する](create-placement)ことで、ユーザーへの表示を開始できます。 --- # File: onboarding-flow-tutorial --- --- title: "パーソナライズされたオンボーディングフローを構築する" description: "実例を通じて、マルチスクリーンのオンボーディングフローを構築する全プロセスを解説します。スクリーン、コンテンツ、ナビゲーション、条件分岐について説明します。" --- フローは、ナビゲーションアクションによって連結された複数のスクリーンのシーケンスです。フローは直線的な構成にすることも、前のスクリーンで収集したユーザー入力に基づいて分岐させることもできます。このチュートリアルでは、4スクリーン構成のオンボーディングフローを実例として、スクリーンの作成・コンテンツの構築・ナビゲーションの設定・条件分岐の追加という一連のプロセスを説明します。 この例では次のものを使用します: - ユーザーの名前をパーソナライゼーション用の変数として取得する**名前入力**。 - 回答によって次に表示される画面を分岐させる**一択クイズ**。 - 各オーディエンスセグメント向けに最適化されたコピーを持つ**2つの分岐パス**。 - 最終画面としての**ペイウォール**。 同じパターンは、ユーザーの入力に基づいてコンテンツをパーソナライズするあらゆるフローに応用できます。 動画形式をご希望の方には、同じプロセスをエンドツーエンドで説明するクイックスタートチュートリアルもあります: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/aa-m459VIuY?si=zN_Co6B6qB88UPZP" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## 始める前に \{#before-you-start\} - Adapty ダッシュボードで[プロダクトを作成](create-product)してください。この例のフローでは、年間と月間の2つのサブスクリプションを使用します。 - [Adapty を App Store と Google Play に接続](integrate-payments)してください。 ## 1. 再利用可能なスタイルを設定する \{#1-set-up-reusable-styles\} 再利用可能なスタイルを使うと、一貫したタイポグラフィとカラーをすべての画面に一クリックで適用できます。カラースタイルにはライトとダークの2バリアントが含まれているため、フローは両方のテーマに自動対応します。 詳細な手順については、[スタイルと外観 — 再利用可能なスタイル](builder-styling#reusable-styles) を参照してください。 スタイルを設定するには: 1. 左パネルで **Styles** Styles パネルを開きます。 2. **Colors** タブで **Plus Create style** をクリックして、再利用する色を追加します。各色について、Light の値を選択してから Dark タブに切り替え、Dark の値を選択します。 3. **Text** タブで、既存のスタイルをクリックしてフォント・ウェイト・サイズを編集するか、**Plus Create style** をクリックしてカスタムプリセットを追加します。 ## 2. スクリーンを作成する \{#2-create-the-screens\} フローはスクリーンの連続で構成されます。まず最初のスクリーンに共通のベース(レイアウト、背景、セーフエリア)を設定し、それを複製して残りのスクリーンを作成しましょう。こうすることで、すべてのスクリーンが同じ基盤を共有し、設定は一度で済みます。 スクリーンの管理についての詳細は、[スクリーンとレイヤー — スクリーンを管理する](paywall-layout-and-products#manage-screens)を参照してください。 スクリーンを設定するには: 1. キャンバスの空白部分をクリックして、最初の画面のスクリーン設定を開きます。 2. **System UI** の下にある **Safe area** を無効にして、背景やエッジに配置された要素が画面の端まで広がるようにします。 3. **Fill** の下で背景の種類を選択して設定します — たとえば、フローのすべての画面の背景に表示される **Image** Image などです。 4. **Layout** の下で方向を **Vertical** Vertical に設定し、デザインに合ったレイアウト方式を選択します。 5. 左パネルの **Screens** セクションで、最初のスクリーンの三点メニュー Context menu をクリックし、**Duplicate** を選択します。合計4つのスクリーンができるまで繰り返してください。2つ目の分岐パスは、後で最初のスクリーンを複製して追加します。 6. 各スクリーンの役割に合わせて名前を変更します。今回の例では、`Welcome`、`Quiz`、`Rock path`、`Paywall` とします。 ## 3. イントロダクション画面を作成する \{#build-the-introduction-screen\} 最初の画面はトーンを決める重要な画面です。ヘッドライン、機能一覧、そしてフローの残りを開くコールトゥアクションを配置します。今回の例ではこれが「Welcome」画面です。 **Screens** パネルで **Welcome** 画面をクリックし、次の要素を追加します。 1. メイン画像を追加します。**+** > **Media** > **Image** をクリックし、画像をアップロードして、必要に応じてマージンを調整します。 2. 見出しを追加する:**+** > **Text** をクリックし、保存済みのテキストスタイルから見出しスタイルを選択して、**Content** フィールドを編集します。 3. 機能リストを追加する:**+** > **List** > **Icon Cards** をクリックし、各カードのアイコンとラベルを編集します。 4. 画面下部にメインのナビゲーションボタンを追加します。アクションの設定はナビゲーションのステップで行います。 ## 4. 入力画面とクイズ画面を作成する \{#build-the-input-and-quiz-screen\} 2番目の画面では、ユーザーから入力を収集します。この例では、名前と単一選択の回答を求め、その回答に基づいてユーザーが次に見るパスが決まります。 入力やクイズの詳細については、[入力とフォーム](builder-inputs-and-forms)および[アンケートとクイズ](onboarding-quizzes)を参照してください。 **Screens**パネルで**Quiz**画面をクリックし、要素を追加します。画面上の各グループ(イントロ、質問+入力、質問+クイズ)は、関連する要素をまとめて視覚的に整理するために、それぞれ独自の縦方向コンテナに配置されています。 1. イントロのヘッドラインと本文を追加します。ヘッドラインは **+** > **Text** > **H1**、サポートコピーは **+** > **Text** > **Body** を選択してください。 2. イントロをグループ化します。**+** > **Layout** > **Vertical Container** をクリックし、新しいコンテナをレイヤーツリーの最上部にドラッグしてから、H1 と本文をその中にドラッグします。 3. 最初の質問と入力フィールドを追加します。質問のキャプションは **+** > **Text**、入力フィールドは **+** > **Inputs** > **Text** をクリックしてください。 4. **Design** タブで入力フィールドの **Element ID** を設定します。この例では `name` とします。これにより、この値が変数として他のスクリーンから参照できるようになります。 5. キャプションと入力欄を、イントロと同じようにVertical Containerでグループ化します。 6. 2つ目の質問とクイズを追加します。**+** > **Text** でキャプションを追加し、**+** > **Quiz** をクリックしてIcon Optionsのようなレイアウトプリセットを選択します。オプションを設定します。この例では `Rock` と `Hip hop` です。 7. キャプションとクイズを同じようにVertical Containerでグループ化します。 8. オプションのIDを設定します。各クイズオプションを選択し、**Interactions** タブを開いて **Element ID** を設定します。これらのIDは、後述の条件付きナビゲーションで参照されます。 9. クイズを単一選択に切り替えます。キャンバスの空白部分をクリックして **Screen settings** を開き、下にスクロールして **Selectable Groups** を表示し、クイズグループ名をクリックして、タイプを **Single choice** に設定します。 10. 画面下部にプライマリボタンを追加します。これが分岐をトリガーする「次へ」ボタンになります。 ## 5. 最初の分岐パスを作成する \{#build-the-first-branching-path\} 各パスのスクリーンは、特定のオーディエンスセグメント向けにコンテンツをカスタマイズします。この例では、Rockパスにロック系のコンテンツ(プレイリスト、アーティスト、おすすめ)が表示されます。 変数の詳細については、[変数](onboarding-variables)を参照してください。 スクリーンを作成するには: 1. **スクリーン**パネルで、**Rock path**スクリーンをクリックします。 2. ヘッドラインを追加します。パーソナライズを表示したい位置に**コンテンツ**フィールドでカーソルを置き、変数アイコン Variable icon をクリックして、**Elements**タブを開きます。入力が配置されているスクリーンを選択します(この例では**Quiz**)。次に、その入力の値変数を選択します。ピッカーは`<elementId>.value`の形式で解決します(この例では`name.value`)。実行時に、ユーザーが入力した内容でヘッドラインが更新されます。 3. ボディコピーを追加のテキスト要素として追加し、このパスのオーディエンスセグメントに合わせて調整します。 4. 下部にプライマリボタンを追加します。 ## 6. 2つ目の分岐パスを作成する \{#build-the-second-branching-path\} パス画面は通常レイアウトを共有しており、コピーのみが異なります。最初のパス画面を複製して内容を更新しましょう。 複製して更新するには: 1. **Screens** パネルで最初のパス画面を選択し、⌘D / Ctrl+D を押して複製します。コピーはスクリーンリストの末尾に表示されます。 2. コピーの名前を変更します(この例では `Hip hop path`)。スクリーンリストの適切な位置にドラッグして、複製元の画面の隣に配置します。 3. もう一方のオーディエンスセグメント向けに本文を更新します。パーソナライズされた見出しはそのまま機能します。変数は引き継がれます。 ## 7. ペイウォールを作成する \{#build-the-paywall\} 最後の画面はペイウォールです。ここでユーザーはサブスクリプションを購入できます。ペイウォールの仕組みについて詳しくは、[基本的なペイウォール画面の作成](basic-paywall-screen)をご覧ください。以下はその手順を簡潔にまとめたものです。 **Screens** パネルで **Paywall** 画面をクリックし、以下の要素を追加します: 1. 上部に **Horizontal Container** を追加し、その中に **Close** ボタンを追加します。Close プリセットはあらかじめ設定済みです。 2. メイン画像、見出し(パス画面と同じパーソナライズ変数を使用)、補足テキストとしてサブ見出しを追加します。 3. プロダクトを追加します:**+** > **Products** をクリックし、**Vertical List** を選択します。**Design** タブのドロップダウンから各カードにプロダクトを割り当てます。 4. デフォルトプロダクトのカードをクリックし、**Set as default product** を有効にすると、画面読み込み時に事前選択された状態になります。 5. 購入ボタンを追加します。**+** > **Buttons** をクリックしてプリセットを選択します。**Interactions** タブで **Add trigger** > **On tap** > **Add action** をクリックし、**Action** を **Purchase**、**Product** を `products.selectedProduct` に設定します。 6. **Button** > **Links** テンプレートをスクリーンに追加します。このテンプレートには、Restore Purchases、Terms of Use、Privacy Policy の 3 つのフッターリンクが含まれています。 Restoreリンクはあらかじめ設定されています。その他のリンクを設定するには、ボタン要素を選択し、**Interactions**タブを開いて、**Open URL**アクションのターゲットを設定してください。 ## 8. 画面間のナビゲーションを設定する \{#wire-navigation-between-the-screens\} 画面は自動的には接続されません。**On tap** トリガーと **Navigate to** アクションを使って、各画面のメインボタンを次の画面に接続します。ユーザーの入力によって分岐する画面には、代わりに **Conditional action** を使います。 ナビゲーションと条件付きアクションの詳細については、[ナビゲーションとインタラクション](onboarding-navigation-branching) および [アクション — 条件付きアクション](onboarding-actions#conditional-actions) を参照してください。 サンプルフローのナビゲーションを設定するには、次の手順に従います。 1. **イントロ画面からの静的ナビゲーション。** ウェルカム画面を開き、プライマリボタンを選択して、**Interactions** タブに切り替えます。**Add trigger** > **On tap** > **Add action** をクリックし、**Action** を **Navigate to** に設定して、次の画面(この例ではクイズ画面)を選択します。 2. **クイズからの条件付きナビゲーション。** Quizスクリーンを開き、Nextボタンを選択して、**On tap**トリガーに**Conditional action**を追加します。IF/ELSEルールを次のように設定します: - 変数ピッカーで**Elements**タブを開き、**Quiz**スクリーンを選択して`quiz.selectedOptionId`を選びます。 - **Equals**演算子を使用し、いずれかのオプションのID(この例ではRockオプション)と比較します。 - 条件が一致する場合(**IF**)、**Navigate to**を実行して最初のパススクリーンを選択します。 - 一致しない場合(**ELSE**)、**Navigate to**を実行して2番目のパススクリーンを選択します。 3. **各分岐パスからペイウォールへの静的ナビゲーション。** ペイウォールを遷移先として、手順1と同じパターンを各パス画面で繰り返します。 ## 次のステップ \{#next-steps\} - [フローを保存して公開する](builder-save-publish) - [フローをプレースメントに追加する](create-placement)ことで、ユーザーへの表示を開始できます。 - オーディエンス別のフロー(フロー内の分岐ではなく)を使用する場合は、オーディエンスセグメントを作成し、プレースメントページで異なるフローを割り当ててください。 :::link フローの作成についてさらに詳しく知りたいですか?[YouTubeプレイリスト](https://www.youtube.com/playlist?list=PLMksWqaZiWtM)でステップバイステップの動画チュートリアルをご覧ください。 ::: --- # File: migrate-to-flows --- --- title: "フローへの移行" description: "個別のオンボーディングとペイウォールをひとつの Adapty フローにまとめる方法を解説します。何が変わるのか、そして古いバージョンのアプリを使っているユーザーに影響を与えずにどう展開するかを説明します。" --- Adapty では、*フロー*はオンボーディングとペイウォールをひとつのエンティティとしてまとめ、単一のプレースメントで提供します。フローは、現在それぞれ個別に構築・配信しているオンボーディングとペイウォールを置き換えるものです。 このガイドでは、フローへの移行時に何が変わるか、また古いバージョンのアプリのユーザーに影響を与えずに変更をロールアウトする方法について説明します。 :::important フローは現在、iOS、Android、React Native、Flutter、Capacitor SDK v4 以上でサポートされています。他のプラットフォームおよびフレームワークのサポートは近日公開予定です。 ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/8Cby6lVGI0o?si=rYA1HtdayyF1ffWd" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## フローとオンボーディング・ペイウォールの比較 \{#flows-vs-onboardings-and-paywalls\} オンボーディングとペイウォールを別々に管理する場合、2つのビルダーと2つのプレースメントを維持する必要があります。また、オンボーディングからペイウォールへのユーザーの受け渡しも自分のコードで実装しなければなりません。 フローはその両方を1つのエクスペリエンスに置き換えます。イントロ画面、クイズ、購入画面をひとつのエディターで作成し、ひとつのプレースメントから配信できます。 以下の表は、各オプションの違いを比較したものです: | | フロー | ペイウォールビルダーのペイウォール | オンボーディング | |---|---|---|---| | 複数画面 | あり | なし(単一画面) | あり | | レンダリング | ネイティブ | ネイティブ | WebView | | プロダクトとプレースメント | プレースメント1つ。プロダクトをフローに直接追加する | プレースメント1つ。プロダクトをペイウォールに直接追加する | プレースメント1つだが、独自のプロダクトは持たない。販売するには別途ペイウォールを作成し、独立したプレースメントから提供する | ## 移行すべきか? \{#should-you-migrate\} 既存のオンボーディングとペイウォールは引き続き動作し、Adaptyもそれらのサポートを続けます。ただし、新機能はスタンドアロンのオンボーディングビルダーやペイウォールビルダーではなく、フローに対して追加されるようになっています。 **長期的な視点で構築するなら、フローの方が優れた基盤です** — リリーススケジュールに合わせてタイミングよく移行してください。 ## 移行方法 \{#how-to-migrate\} 移行は4つのステップで構成されています。作業のほとんどはSDKの一度きりのアップグレードです。フローのビルドとプレビューはノーコードで行えます。 1. **[フローを作成する](#build-your-flow)**: ノーコードエディタでフローを作成します。開発者は不要です。 2. **[デバイスでプレビューする](#preview-on-device)**: Adapty モバイルアプリを使って実機でフローを確認します。アプリのビルドは不要です。 3. **[フロー用の新しいプレースメントを作成する](#create-a-new-placement-for-your-flow)**: 固有の ID を持つ新しいフロープレースメントを作成し、既存のプレースメントとの共存方法を決めます。 4. **[SDK を更新する](#update-the-sdk)**: iOS、Android、React Native、または Capacitor の SDK v4 にアップグレードし、プレースメントからフローを取得して、サンドボックス購入を確認します。これが開発者の主な作業です。 ### フローを作成する \{#build-your-flow\} **Flows** ページで **Create flow** をクリックして、オンボーディングとペイウォールをひとつの体験として構築しましょう。ビルダーについて詳しく知りたい場合は、以下をご覧ください。 - **[フロードキュメント](adapty-flow-builder)**:ビルダーの使い方と作成できるコンテンツを説明しています。 - **[よくあるフローのレシピ](flow-builder-recipes)**:よく使われる画面を作成するためのステップバイステップガイドです。 - **AI に質問する**:詰まったときは、ドキュメントの各ページにあるチャットを活用してください。 :::note フローテンプレートからのフロー作成やAIによる自動生成はまだ利用できません。どちらも近日公開予定です。現時点では、すべての新しいフローはよく使われるいくつかの画面から始まり、必要に応じて編集やスタイルの調整が可能です。 ::: ### デバイスでプレビューする \{#preview-on-device\} 実際のデバイスで、アプリに触れることなくフローをプレビューできます。App Store から [Adapty アプリ](https://apps.apple.com/us/app/adapty/id6739359219)をダウンロードしてください。次に、フロービルダーで **Test on device** をクリックし、ロケールを選択して、デバイスで QR コードをスキャンします。実際の画面、分岐、コピー、デザインを確認できます。 :::note プレビューモードでは、Adapty はストア内のプロダクトにアクセスできないため、プレビューに表示される価格は実際のものではありません。実際の購入確認は後ほど、サンドボックスアカウントを使った v4 ビルドで行います。詳しくは [SDK を更新する](#update-the-sdk)を参照してください。 ::: ### フローの新規プレースメントを作成する \{#create-a-new-placement-for-your-flow\} プレースメントは、フロー、ペイウォール、オンボーディングのいずれか1種類のコンテンツのみを扱います。既存のオンボーディングやペイウォールのプレースメントをフロー用に変換することはできません([プレースメントタイプ](create-placement)を参照)。フローには専用の新しいプレースメントが必要です。 **新しいフロープレースメントには、完全に新しいユニークなプレースメントIDを付けてください。** 既存のペイウォールまたはオンボーディングのプレースメントのIDと一致したり、再利用したりすることはできません。 :::warning 移行中は古いプレースメントをそのまま稼働させておいてください 古いアプリバージョンのユーザーは、オンボーディングとペイウォールのプレースメントIDがアプリにコンパイルされています。そのため、アプリを更新するまでは既存のオンボーディングやペイウォールが表示されます。SDK v4 の導入率が十分に高まってから、古いプレースメントを廃止してください。 ::: SDKのすべてのプレースメントを一度にフローへ移行する必要はありません。SDK v4では、`getFlow`メソッドがフロープレースメントとペイウォールプレースメントの両方からデータを取得するため、アプリはどこでも同じメソッドを呼び出せます。ペイウォールビルダーのペイウォールは使いたいプレースメントにそのまま残し、それ以外のプレースメントにフローを使いましょう。 移行期間中、各プレースメントタイプはそれぞれ独自の指標を追跡します。旧バージョンと新バージョンのアプリが同時に稼働している間、データは2つのプレースメントセットに分かれます。旧オンボーディングおよびペイウォールプレースメントは古いバージョンをカバーし、新しいフロープレースメントはSDK v4以降をカバーします。これらを別々のコホートとして比較し、ユーザーがアップデートするにつれてフロープレースメントのシェアが増加することを見込んでください。 フローを使ったA/Bテストも引き続き実行できます。フロープレースメントのフローバリアント間で[通常のA/Bテスト](ab-tests)を実施できます。クロスプレースメントA/Bテストは現在ペイウォールのみ対応しているため、フロープレースメント間では実行できません。新しいフローと既存のペイウォールを比較する場合は、単一のテストではなくコホート比較となります。これは異なるプレースメントタイプに存在するためです。 ### SDKのアップデート \{#update-the-sdk\} フロープレースメントの準備ができたら、アプリをそこに向けましょう。フローはAdapty SDK v4以降でのみ動作します。SDKをアップグレードして、新しいプレースメントから`getFlow`でフローを取得してください。プラットフォームごとのv4移行ガイド — [iOS](migration-to-ios-sdk-v4)、[Android](migration-to-android-sdk-v4)、[React Native](migration-to-react-native-sdk-v4)、[Capacitor](migration-to-capacitor-sdk-v4) — で具体的なアップグレード手順を確認してください。 フローの接続が完了したら、通常の購入フローと同様に確認しましょう。デバイスまたはシミュレーターで実行し、サンドボックス購入([iOS](ios-test) / [Android](testing-on-android))を行って、プロダクト、購入処理、アクセスレベルがすべて正常に動作するか確認してください。 :::note フローが表示されるのは、SDK v4+ でビルドされたアプリをインストールしたユーザーのみです。古いバージョンのアプリを使用しているユーザーには、引き続き既存のオンボーディングとペイウォールが表示されます。これが、移行期間中に古いプレースメントを稼働させたままにしておく理由です。フローをまだサポートしていないプラットフォームでも同様です。 ::: --- # File: paywall-layout-and-products --- --- title: スクリーンとレイヤー description: "フローを構成する各スクリーンと、スクリーン内の要素階層を管理します。" --- フローは1つ以上のスクリーンで構成されます。各スクリーンは、ユーザーのジャーニーにおける1つのステップを表します。たとえば、ペイウォール、クイズ、プロダクト情報のスライドなどがこれにあたります。 各スクリーン上の要素はレイヤー階層で管理されます。 スクリーン、レイヤー、エレメントを管理するには、デフォルトの **Screens and Layers** ビューを開きます。ここでは、スクリーンの順序と各スクリーンのレイヤー構造が表示されます。 ## スクリーンの管理 \{#manage-screens\} 左パネルの上部には、フロー内のすべてのスクリーンが一覧表示されます。各エントリには番号付きのラベルとサムネイルプレビューが表示されます。 * **スクリーンを選択する**: スクリーンのエントリをクリックしてアクティブにします。ビジュアルエディターに選択したスクリーンが表示され、下部の Layers セクションがそのレイヤー階層を表示するよう更新されます。 * **スクリーンを追加する**: Screens セクション上部の Plus ボタンをクリックして、フローに新しい空のスクリーンを追加します。 * **テンプレートライブラリを開く**: Screens セクション上部の Templates ボタンをクリックして、[フローテンプレート](paywall-builder-templates)を閲覧・適用します。 * **スクリーンを並べ替える**: スクリーンのエントリをドラッグ&ドロップして、フロー内の順序を変更します。 :::important フローに未使用の空のスクリーンがある場合、公開できません。公開前にドラフトのスクリーンをすべて削除してください。 ::: ### スクリーンのアクション \{#screen-actions\} スクリーンエントリの三点アイコン Context をクリックすると、コンテキストメニューが開きます。 | アクション | ショートカット | 説明 | |--------|----------|-------------| | **Play Animation** | | このスクリーンに設定されたアニメーションをプレビューする | | **Copy** | ⌘C / Ctrl+C | スクリーンをクリップボードにコピーする | | **Paste here** | ⌘V / Ctrl+V | コピー済みのスクリーンを貼り付ける | | **Duplicate** | ⌘D / Ctrl+D | スクリーンのコピーを作成してフローに追加する | | **Rename** | | スクリーンの表示名を変更する | | **Delete** | ⌘⌫ / Ctrl+Del | スクリーンをフローから削除する | :::tip クリップボードはフローをまたいで保持されます。あるフローでスクリーンや要素をコピーし、別のフローを開いて貼り付けることができます。 ::: :::warning スクリーンを削除すると、そのスクリーンを指定していた[スクリーンへ移動](onboarding-navigation-branching)アクションは**遷移先を失います**が、アクション自体は**削除されません**。新しい遷移先を設定するか、アクションを削除してください。そうしないと、[フローのプレビューや公開](builder-save-publish#publish-a-flow)ができなくなります。 ::: ## スクリーン間の移動 \{#navigate-between-screens\} :::link メイン記事:[ナビゲーションとインタラクション](onboarding-navigation-branching) ::: リスト内のスクリーンの順序だけでは、ナビゲーションは決まりません。スクリーンを接続するには、要素のインタラクションを使用してください。ボタンを設定して、ユーザーを別のスクリーンに移動させます。 ## スクリーン設定 \{#screen-settings\} アクティブなスクリーンのプロパティと設定を表示するには、スクリーンプレビューの空白部分をクリックしてください。右パネルがスクリーン設定ビューに切り替わります。 ### システムUI \{#system-ui\} スクリーンがデバイスのハードウェアとどのように連携するかを制御します。 * **Safe area** は、ノッチやシステムバーからコンテンツを保護するパディングを追加します。 * **Status bar** は、システムのステータスバー(時刻、バッテリー、信号アイコン)の表示と非表示を切り替えます。 ### プログレスインジケーターへのスクリーンの含め方 \{#include-screen-in-progress-indicator\} フローに[プログレスインジケーター](builder-loaders-and-progress-bars#progress-indicators)要素を追加すると、Adaptyはすべてのスクリーンに表示します。 **Include screen in progress indicator** のチェックを外すと、特定のスクリーンからプログレスインジケーターが非表示になります。ウェルカムスクリーン、最終的なペイウォール、または進行状況として登録したくないステップに使用してください。 ### 画面レイアウト \{#screen-layout\} :::link 詳細記事:[レイアウトと配置](manage-paywall-ui-elements) ::: **Layout** セクションでは、画面上の子要素をどのように配置するかを設定します。これらのプロパティはすべてのコンテナ要素で利用できます。 * **Free**:子要素が独立した位置に配置されます。 * **Vertical**:要素が上から下へ、フレックスボックスのカラムのように並びます。 * **Horizontal**:要素が左から右へ、フレックスボックスの行のように並びます。 縦横のレイアウトでは、スペーシングと配置も設定できます。 * **Alignment**:クロス軸に沿った要素の位置。 * **Gap**:隣接する要素間のスペース。 * **Distribution**:子要素間およびその周囲のスペースの配分。 #### RTL レイアウト \{#rtl-layout\} **Mirror for RTL** チェックボックスをオンにすると、右から左に読む書記体系向けにレイアウトが左右反転します。横並びコンテナ内の要素の順序が入れ替わります。 ### スクリーンの背景 \{#screen-background\} :::link 関連記事:[背景](paywall-head-picture) ::: **Fill** は[スクリーンの背景](paywall-head-picture)を単色、グラデーション、画像、または動画に設定します。背景はデバイスのビューポート全体(ノッチやシステムバーの後ろの領域を含む)に広がります。**Safe area** が有効な場合でも同様です。 #### 背景動画のループ再生 \{#loop-background-video\} **Loop** トグルを有効にすると、背景動画を繰り返し再生できます。 #### カスタムメディア ID の割り当て \{#assign-a-custom-media-id\} [カスタムメディア](custom-media)と同様に、スクリーンの背景にカスタムメディアIDを割り当て、SDK から参照することができます。 ### スクリーンの余白 \{#screen-spacing\} 各辺(上、右、下、左)のスクリーンパディングを調整します。 ### スクロール \{#scroll\} オーバーフローの動作を制御します。**Vertical scroll** を有効にすると、スクリーンコンテンツがビューポートの高さを超えたときにスクロールできるようになります。 ### 選択可能なグループ \{#selectable-groups\} :::link 関連記事:[選択可能な要素とグループ](flow-selectable-elements) ::: **Selectable groups** セクションには、現在の画面上のすべての選択可能なグループが一覧表示されます。[クイズ](onboarding-quizzes)、[プロダクト](paywall-product-block)、[タブ](builder-tabs)、[トライアルトグル](builder-toggles)、または任意の[カスタム選択可能要素](flow-selectable-elements#make-an-element-selectable)が対象です。 グループのエントリをクリックすると、名前の変更、タイプの変更、公開される変数の確認、または削除ができます。 ## レイヤーを管理する \{#manage-layers\} スクリーン上の各要素はレイヤーとして表示されます。**Layers** セクションには、アクティブなスクリーン上の要素の順序が表示されます。 :::important フローのレイヤーは、グラフィックデザインソフトのレイヤーのように重なり合うわけではありません。各レイヤーはスクリーンの個別コンポーネントを表します。要素が重なるのは、[絶対配置または固定配置](manage-paywall-ui-elements)を使用している場合に限られます。重なり順は、レイヤーツリー内の位置ではなく `z-index` プロパティによって決まります。 ::: ツリー構造は親子関係を表しています。親レイヤーの矢印をクリックすると、子要素を展開・折りたたむことができます。 レイヤーを直接作成することはできません。[要素を追加](builder-elements)ビューから追加したすべての要素は、ツリー内に新しいレイヤーとして表示されます。 * **レイヤーを選択する**: レイヤーをクリックして選択します。ビジュアルエディターはキャンバス上の対応する要素をハイライトし、右パネルにその[デザイン](builder-styling)と[インタラクション](onboarding-navigation-branching)プロパティが表示されます。 * **レイヤーを並べ替える**: ツリー内でレイヤーをドラッグ&ドロップして、親コンテナ内の順序を変更します。ツリー上の順序が画面上の表示順序と一致します。 * **レイヤーを表示/非表示にする**: レイヤーにカーソルを合わせると、右側に目 Eye アイコンが表示されます。クリックするとレイヤーの表示/非表示を切り替えられます。非表示にしたレイヤーはツリーに残りますが、ビジュアルエディターやデバイス上には表示されません。実行時にロジックで表示を制御するには、[条件付き表示](onboarding-element-visibility)を使用してください。 * **すべてのレイヤーを折りたたむ**: Layers セクションの右上にある折りたたみ Collapse ボタンをクリックすると、ツリー全体が折りたたまれます。 ### レイヤーのアクション \{#layer-actions\} 3点アイコン Context をクリックしてコンテキストメニューを開きます。 | アクション | ショートカット | 説明 | |--------|----------|-------------| | **Copy** | ⌘C / Ctrl+C | レイヤーをクリップボードにコピーする | | **Paste here** | ⌘V / Ctrl+V | コピーしたレイヤーを子要素として貼り付ける | | **Duplicate** | ⌘D / Ctrl+D | 同じコンテナ内にレイヤーのコピーを作成する | | **Rename** | | レイヤーの表示名を変更する。デフォルトでは、レイヤー名にはコンテンツまたはコンポーネントの種類が使用される | | **Delete** | ⌘⌫ / Ctrl+Del | レイヤーとそのすべての子要素を削除する | | **Wrap** | | レイヤーを新しいコンテナで囲む: **Wrap in Horizontal Container** または **Wrap in Vertical Container** | | **Unwrap / Ungroup** | | 囲んでいるコンテナを削除し、その子要素を一段階上に移動する | | **Move up** | ↑ | 親コンテナ内でレイヤーを1つ上の位置に移動する | | **Move down** | ↓ | 親コンテナ内でレイヤーを1つ下の位置に移動する | --- # File: manage-paywall-ui-elements --- --- title: "レイアウトと配置" description: "レイアウト、位置モード、サイズ、スペーシングを使って要素を画面上に配置します。" --- フローは、レスポンシブなレイアウトを作成します。要素を特定の座標にドラッグするのではなく、**コンテナ**の中に要素をネストして、子要素を自動的に整列させます。 コンテナは、要素の方向(縦または横)、配置、間隔を決定します。個々の要素は、サイズや余白を細かく調整したり、必要に応じて絶対位置固定位置でフローから外れることもできます。 :::link 塗りつぶし、ボーダー、エフェクトなどの視覚的なプロパティについては、[スタイルと外観](builder-styling)をご覧ください。 ::: <Tabs groupId="video"> <TabItem value="align" label="配置と位置調整"> <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/aRS4Bzb6W4I?si=qH7B6t3kMab70gBi" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ``` </TabItem> <TabItem value="layout" label="レイアウト、サイズ、スペーシング"> ``` <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/WQ9fpxrndok?si=ROMdIPvJ32tSwUX6" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> </TabItem> </Tabs> ## レイアウト \{#layout\} レイアウトは、画面上の要素を配置するための主要なツールです。各コンテナは、方向・配置・間隔といったルールに従って子要素を自動的に配置します。ビルダーで利用できるレイアウト要素は次のとおりです。 * **[縦方向コンテナ](builder-containers#containers)**:子要素を上から下へ並べる * **[横方向コンテナ](builder-containers#containers)**:子要素を左から右へ並べる * **[区切り線](builder-containers#dividers)**:要素間を視覚的に区切るセパレーター * **[カルーセル](builder-containers#carousel)**:横方向にスクロールできるスライドのセット * **[ボトムシート](builder-containers#bottom-sheet)**:ユーザーがボタンをタップしたときに追加コンテンツを表示するスライド式のオーバーレイパネル コンテナは画面の主要な構成要素です。コンテナを入れ子にすることで、複雑なレイアウトを構築できます。各コンテナには右パネルに **Layout** セクションがあり、子要素の配置方法を制御します。 要素を新しいコンテナにグループ化するには、**Wrap** [レイヤーアクション](paywall-layout-and-products#layer-actions)を使用してください。コンテナを削除して子要素を昇格させるには、**Unwrap** を使用してください。 :::link スクリーンとレイヤーの階層について詳しくは、[スクリーンとレイヤー](paywall-layout-and-products)をご覧ください。 ::: ### 方向 \{#direction\} * Free **Free**: 自動レイアウトなし。子要素は独立して配置されます(子要素が絶対配置を使用する場合に便利です) * Vertical **Vertical**: 子要素が上から下へ積み重なります(列の行のように) * Horizontal **Horizontal**: 子要素が左から右へ並びます(行のアイテムのように) ### 要素の順序 \{#element-order\} 子要素は **Layers** パネルに表示されている順序でレンダリングされます。縦方向のコンテナでは、リストの一番上にある項目が画面の上部に表示されます。横方向のコンテナでは、一番上の項目が左側に表示されます。要素を並び替えるには、Layers パネルでドラッグするか、**Move Up** や **Move Down** の[レイヤーアクション](paywall-layout-and-products#layer-actions)を使用してください。 ### アライメント \{#alignment\} アライメントグリッドは、子要素がコンテナのクロス軸に沿ってどこに配置されるかを制御します。縦方向のコンテナでは、アライメントは子要素の水平方向の配置(左、中央、右)を制御します。横方向のコンテナでは、垂直方向の配置(上、中央、下)を制御します。 ### 配置 \{#distribution\} 配置(Distribution)は、メイン軸に沿って子要素間のスペースをどのように分割するかを決定します: * **Gap** Gap(デフォルト): 隣接する子要素間の固定ピクセル値 * **Space Between**: 子要素が両端に広がり、間に等間隔のギャップが表示される * **Space Around**: 各子要素の周囲に等しいスペースが配置され、端のギャップは半分のサイズになる * **Space Evenly**: すべての子要素の前後および間に等しいスペースが配置される ### コンテンツのクリッピング \{#clip-content\} コンテナの境界を超えたコンテンツを視覚的にクリップします。これを無効にすると、オーバーフローが許可されます(例:カードの端を意図的にはみ出すバッジなど)。 ## 位置 \{#position\} デフォルトでは、各要素の位置はコンテナのレイアウトによって自動的に決まります。**Position** トグルを使うと、通常のフローから切り離して手動で位置を指定できます。 ### 相対位置(デフォルト)\{#relative-default\} 要素は通常のレイアウトフロー内に配置されます。位置は親コンテナのレイアウトルールによって自動的に決まるため、自由にドラッグすることはできません。相対要素の周囲のスペースを調整するには**Margin**を使用してください。 テキストブロック、画像、カード、ボタン、リストアイテムなど、ほとんどのコンテンツには相対位置を使用してください。 ### 絶対位置 \{#absolute\} 要素は通常のフローから切り離され、他のコンテンツに重なって表示されます。隣接する要素のレイアウトには影響しません。 **Absolute** を選択すると、追加のコントロールが表示されます。 * **オフセットフィールド**(T、L、R、B):親コンテナの各辺から要素までの距離をピクセル単位で設定します * **アンカーグリッド**:3×3グリッドのポイントをクリックして、要素が親のどのコーナー・辺・中心にアンカーするかを選択します * **水平アンカー** Horizontal positioning(左 / 中央 / 右)と **垂直アンカー** Vertical positioning(上 / 中央 / 下):グリッドと同じアンカーポイントを操作するドロップダウン * **Z-index**:兄弟要素に対する要素の[重なり順序](#stacking-order)を制御する数値フィールドです。値が大きいほど前面に表示されます 装飾的なオーバーレイ、バッジ、閉じるボタン、画像上に配置するアイコンには、絶対位置指定を使用してください。 :::tip 絶対配置の要素を親要素の横幅いっぱいに広げるには、水平アンカーを **Left** に設定し、**Right** オフセットに 0 を指定します。これにより、要素が両端にピン留めされます。 ::: ### 固定 \{#fixed\} このエレメントは親コンテナを完全に無視し、画面上に固定されます。ユーザーがスクロールしても常に表示され続け、ページのコンテンツがその下で動きます。 固定位置指定は絶対位置指定と同じコントロール(オフセット、アンカーグリッド、Z-index)を使用します。すべてのオフセットは、親要素ではなく画面のセーフエリアを基準に計算されます。たとえば、下からのオフセットを0にすると、ホームインジケーターの上に要素が配置されます。物理的な画面端からオフセットを計算したい場合は、[セーフエリアを無視する](#ignore-safe-area)を有効にしてください。 スクロールするコンテンツの上に浮かせたい要素(閉じるボタン、復元ボタン、常時表示のトップバナー、トップへ戻るボタン、ナビゲーションバーなど)には、固定位置を使用してください。専用のボトムアクションエリアには、代わりに[フッター](builder-containers#footer)を使用してください。 ### セーフエリアを無視する \{#ignore-safe-area\} セーフエリアとは、ノッチ・ステータスバー・ホームインジケーターにかからないよう確保された画面領域のことです。デフォルトでは、配置された要素はこの領域内に収まるように制御されます。 位置タイプセレクターの下にある **Ignore safe area** チェックボックスをオンにすると、要素のオフセットが物理的な画面端から計測されるようになります。これにより、要素がノッチやホームインジケーターの裏側まで広がることができます。 フルブリードのメディアを表示するには、画像または動画のポジションを **Fixed** に設定し、四辺すべてのオフセットを 0 にして、**Ignore safe area** を選択します。これでメディアが画面全体をエッジからエッジまでカバーします。 このチェックボックスは、absolute および fixed ポジションのみで使用できます。relative 要素では無効化されており、要素を **Relative** に戻すとこの設定はクリアされます。 ## サイズ調整 \{#sizing\} 各要素には **Width** と **Height** のコントロールがあります。ドロップダウンをクリックしてサイズ調整モードを選択してください。 * **Fill**: 親要素の利用可能なスペースをすべて占めるよう要素が伸長します。表示されるピクセル値は計算結果です。 * **Hug**: コンテンツに合わせて要素が縮小します。表示されるピクセル値は計算結果です。 * **Fixed**: 親要素やコンテンツのサイズに関係なく、指定した正確なピクセル値を使用します。絶対配置または固定配置の要素で使用できる唯一のモードです。 ## スペーシング \{#spacing\} 各辺のスペーシング値を個別に設定できます。 * **Margin**:要素とその隣接要素の間のスペース。値にかかわらず、親コンテナの境界を超えることはありません。 * **Padding**:要素の境界とそのコンテンツの間のスペース。 テキスト要素にはマージンのみ設定できます。スクリーンにはパディングのみ設定できます。コンテナや子コンテンツを持つその他の要素には、両方が使用できます。 ## 重ね合わせ順序 \{#stacking-order\} 相対配置された要素同士は互いに重なりません — 各コンテナは子要素を順番に並べます。重なりが発生するのは、**Absolute** または **Fixed** 配置によって要素が通常のフローから外れた場合のみです。 要素が重なる場合、**Layers** パネルで後に来る兄弟要素は前の要素の上に描画されます — 後の兄弟が相対配置で、前の要素が絶対配置であっても同様です。 **Absolute** と **Fixed** 要素には、細かい制御のための **Z-index** フィールドがあります。値が高いほど前面に表示されます。**Relative** 要素には Z-index がなく、レイヤーの順序だけでスタックが決まります。 **Move up** と **Move down** の[レイヤーアクション](paywall-layout-and-products#layer-actions)を使って要素の順序を変更できます。 --- # File: builder-styling --- --- title: "スタイルと外観" description: "要素の視覚的な外観(塗りつぶし、ボーダー、エフェクト、タイポグラフィ、状態、プロジェクト全体のスタイル)を設定します。" --- **Design** タブ(右パネル)では、各要素の見た目を調整できます。利用できるプロパティは要素の種類によって異なりますが、ほとんどの要素には共通のスタイルオプションがあります。 :::link サイズ、間隔、配置については、[レイアウトと配置](manage-paywall-ui-elements)を参照してください。 ::: ## 表示設定 \{#visibility\} **Visibility** トグルは、画面上に要素を表示するかどうかを制御します。 * Show **Show**(デフォルト): 要素は常に表示されます。 * Conditional **Conditional**: 特定の条件が満たされた場合にのみ要素が表示されます。詳しくは[条件付き表示](onboarding-element-visibility)を参照してください。 * Hide **Hide**: 要素は常に非表示になります。要素を削除せずにフローから一時的に除外したい場合に使用します。 <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/3w3YSOmI3tQ?si=vPhoQGt44SI285Ru" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## 塗りつぶし \{#fill\} **Fill** セクションでは、要素の背景を設定できます。ソリッドカラー、グラデーション、画像、動画の4種類の塗りつぶしタイプが使用可能です。 このプロパティを使って、画面全体のヒーロー画像や動画を設定できます。 * **単色** Solid color。カラーピッカーを使うか、16進数値を入力するか、[プロジェクト全体のカラースタイル](#color-styles)を割り当てます。**不透明度**を調整して背景を半透明にすることもできます。 * **グラデーション** Gradient。2つ以上のカラーストップを使ってグラデーションの塗りつぶしを追加します。ストップをドラッグして色の変化を調整し、グラデーションの角度を変えて方向をコントロールします。 * **Image** Image または **Video** Video。要素の背景として[画像・動画](custom-media)を設定します。 ## ボーダー \{#border\} ボーダーはデフォルトでオフになっています。右パネルの **Border** の横にある Plus をクリックして追加してください。ボーダーを削除するには、**Border** 見出しの横にある Close をクリックします。 ボーダーを追加した場合、以下の設定を行えます: * **Color**:カラーピッカーを使用するか、16進数値を入力するか、[プロジェクト全体のカラースタイル](#color-styles)を割り当てます。**opacity** を調整してボーダーを半透明にすることもできます。 * **Width**:ボーダーの太さをピクセル単位で指定します。 ## コーナー \{#corners\} **Corners** セクションはボーダー半径(角丸)を設定します。 * **Radius スライダー**: 4つすべてのコーナーに同じ半径を設定します * **コーナーごとの切り替え** Per Corner: 有効にすると、各コーナーに異なる半径を個別に設定できます ## エフェクト \{#effects\} **Effects** の横にあるプラスボタン Plus をクリックすると、1つ以上のビジュアルエフェクトを追加できます。 * **Drop shadow**: 要素の背後に影を表示します * **Inner shadow**: 要素の境界内に影を表示します * **Background blur**: 背景をぼかします * **Layer blur**: 要素とその子要素をぼかします 同じ要素に複数のエフェクトを重ねて適用できます。表示アイコン Show をクリックすると、エフェクトを一時的に無効にできます。 ## アニメーション \{#animation\} **Animation** の横にある Plus ボタンをクリックすると、アニメーション効果を追加できます。現在利用できるアニメーションは **Pulse** のみで、要素がリズミカルに拡大・縮小して注目を集めます。 Pulse アニメーションは以下のパラメーターで設定できます。 | パラメーター | 説明 | |-----------|-------------| | Scale amount (%) | 元のサイズに対して要素がどれだけ拡大するか | | Duration (ms) | 1回のアニメーションサイクルの長さ | | Delay between loops (ms) | 繰り返しの間の一時停止 | | Shadow color | パルスする影エフェクトの色 | | Shadow size (px) | パルスする影のサイズ | ### アニメーションのプレビュー \{#preview-the-animation\} ビルダーはデフォルトで静止したスクリーンを表示します。アニメーションを確認するには、以下のいずれかの方法でオンにします。 - デバイスプレビューの上にある **Toggle animations** Toggle animations ボタンをクリックします。スクリーンのアニメーションのオン・オフを切り替え、オンにすると再度クリックするまでアニメーションが連続再生されます。このボタンは、アクティブなスクリーンに少なくとも1つのアニメーションが含まれている場合にのみ表示されます。 - スクリーンレイヤーの横にある三点アイコンからスクリーンの[コンテキストメニュー](paywall-layout-and-products#screen-actions)を開き、**Play Animation** を選択します。 ## 外観 \{#appearance\} * **Opacity**: 0%(透明)から100%(不透明)の範囲で設定します * **Rotation**: 度数値を入力してエレメントを回転させます ## タイポグラフィプロパティ(テキストエレメント) \{#typography-properties-text-elements\} テキストエレメントには以下のコントロールを含む **Typography** セクションが表示されます。 ### フォント \{#font\} :::link 関連情報:[カスタムフォント](using-custom-fonts-in-flow-builder) ::: フォントのドロップダウン Font select をクリックしてフォントピッカーを開きます。タブは2つあります: * **Styles**:プロジェクトに保存済みの[テキストスタイル](#text-styles)の一覧が表示されます。スタイルを選択すると、そのタイポグラフィ設定がすべて一括で適用されます。 * **Fonts**:利用可能なフォントファミリーの一覧が表示されます。検索またはスクロールして目的のフォントを探してください。組み込みフォントは**デバイスによって表示が異なる場合があります**。表示を統一するには、[カスタムフォント](using-custom-fonts-in-flow-builder)をアップロードしてください。 ### サイズとウェイト \{#size-and-weight\} :::warning [カスタムフォント](using-custom-fonts-in-flow-builder)の場合、**Weight**、**Bold**、**Italic** のコントロールはエディタの組み込みプレビューにのみ影響します。異なるウェイトやスタイルを表示するには、フォントのバリエーションごとに別々のファイルをアップロードしてください。 ::: * **Weight**: ドロップダウンからフォントウェイトを選択します * **Size**: ドロップダウンからサイズを選択するか、カスタム値を入力します ### 色 \{#color\} カラースウォッチをクリックしてカラーピッカーを開きます。16進数値を入力するか、パレットを使用するか、[再利用可能なスタイル](#reusable-styles)から選択します。不透明度スライダーを調整してテキストを半透明にできます。 ### 揃え \{#alignment\} 2グループの揃えコントロールがあります。 * **水平**: 左揃え Align left、中央揃え Align center、右揃え Align right * **垂直**: 上揃え Align top、中央揃え Align middle、下揃え Align bottom ### 装飾 \{#decoration\} * **None** None: 装飾なし(デフォルト) * **Underline** Underline: テキストに下線を追加します * **Strikethrough** Strikethrough: テキストに取り消し線を追加します ### トランケーション \{#truncation\} トランケーションを有効にすると、**Max Lines** の設定を超えたテキストを切り捨てます。 複数の言語をサポートする場合に便利です。翻訳後の文字列が元の文字列より長くなっても、 トランケーションによってレイアウトが崩れるのを防ぎます。 :::note テキストエレメントを選択すると、キャンバス上でその上部に**インラインツールバー**も表示されます。このツールバーから、右パネルをスクロールせずにフォント、ウェイト、サイズ、揃えにすばやくアクセスできます。 ::: ## 状態別設定(インタラクティブエレメント) \{#state-specific-settings-interactive-elements\} インタラクティブエレメントは複数のビジュアル状態をサポートします。該当するエレメントを選択すると、右パネルに **States** セクションが表示されます。状態を切り替えて、それぞれに異なるビジュアルプロパティを設定します。 各状態では、塗りつぶし、ボーダー、タイポグラフィの色、不透明度など、あらゆるビジュアルプロパティを上書きできます。 ### 選択可能な状態 \{#selectable-states\} :::link メイン記事: [選択可能な要素](flow-selectable-elements) ::: 選択可能なグループに属する要素(クイズの選択肢、プロダクト、タブ、トライアルのトグルなど)は、デフォルトで2つの状態を持ちます: * **Default**: 要素の通常の外観 * **Selected**: ユーザーがその選択肢を選んだときの外観。塗りつぶし、ボーダーカラー、テキストカラーなどのプロパティを上書きして、アクティブな選択肢を強調できます 選択可能な要素が操作不可の状態をスタイリングするには、3番目のステートを手動で追加します。**States settings** Settings を開き、**Disabled state** を追加してください。 **Disabled** ステートは条件によって制御されます。これを選択し、**Set conditions** set conditions をクリックして、実行時に要素が無効になる条件(例:必須フィールドが空の場合など)を定義します。 ### インプット状態 \{#input-states\} 入力フィールドには追加の状態があります。 * **Default**: 通常の未フォーカス状態の外観 * **Active**: フィールドがフォーカスされ、入力可能な状態 * **Invalid**: 入力値がバリデーションに失敗した状態 * **Disabled**: フィールドがインタラクティブでない状態 ### その他の状態を持つエレメント \{#other-state-bearing-elements\} 一部のエレメントは、標準の **Default / Selected / Disabled** パターン以外で状態別スタイリングを公開しています。 - **[プログレスインジケーターのステップ](builder-loaders-and-progress-bars#step-states)** — ステップごとに3つの状態: **Completed**、**Current**、**Upcoming**。 - **[カルーセルのドット](builder-containers#dots)** — 2つのカラーバリアント: 非アクティブなドットの **Color** と現在のスライドのドットの **Active Color**。 ## 再利用可能なスタイル \{#reusable-styles\} 左サイドバーの **Styles** Styles パネルでは、フロー全体に適用される再利用可能なスタイルを定義できます。テキストスタイルとカラースタイルの2種類が使用できます。ダークモードのサポートを有効にするにはカラースタイルを使用する必要があります。 ### テキストスタイル \{#text-styles\} :::link メイン記事: [テキストコンテンツ](onboarding-text) ::: テキストスタイルには、フォントファミリー、ウェイト、サイズ、行の高さ、配置、装飾といったタイポグラフィの設定がまとめて保存されています。すべてのフローテンプレートにはデフォルトのプリセットが含まれており、カスタムスタイルを作成することもできます。 テキストスタイルを作成するには: 1. **Styles** Styles パネルを開き、**Text** タブを選択します。 2. **Plus Create style** をクリックします。 3. 名前を入力し、タイポグラフィの設定を行います。 4. **Create** をクリックします。 テキストスタイルを適用するには、テキスト要素を選択し、**Typography** セクションのフォントドロップダウンからスタイルを選んでください。 ### カラースタイル カラースタイルとは、フロー全体で参照できる名前付きカラーのことです。各カラースタイルには、名前("Primary text" や "Brand" など)、16進数カラーコード、そしてそのカラーを参照している要素数を示す使用数が含まれます。 カラースタイルを作成するには: 1. **Styles** Styles パネルを開き、**Colors** タブを選択します。 2. **Plus Create style** をクリックします。 3. 名前を入力し、カラーを選択します。 色スタイルを更新すると、それを参照するすべての要素が自動的に更新されます。 ### ダークモード \{#dark-mode\} :::link 関連記事: [ダークモード](paywall-dark-mode) ::: 必要に応じて、各カラースタイルにライトモード Light mode とダークモード Dark mode の2つのバリアントを追加できます。SDKはデバイスの現在のカラースキームに基づいて、自動的に適切なバリアントを適用します。 ビルダーでダークモードをプレビューするには、[ボトムツールバー](builder-ui#view-controls-bottom-toolbar)の**テーマ切り替え** Dark mode を使用してください。 --- # File: paywall-product-block --- --- title: "購入の設定" description: "フロービルダーでスクリーンにプロダクトを割り当て、プロダクト要素を追加し、購入ボタンを接続します。" --- スクリーンで購入を設定するには、購入ボタンを追加して **Purchase** アクションを設定します。このアクションは、特定のプロダクトを対象にするか、スクリーン上のプロダクト要素からユーザーが選択したプロダクトを対象にすることができます。 <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/LLIZCd94PlE?si=t_8BitA1FBpbd8ue" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## プロダクトを追加する \{#add-products\} プロダクト要素は、キャンバス上にプロダクトを表示するビジュアルカードです。 プロダクト要素を追加するには: 1. キャンバスで、対象のスクリーンの **+** をクリックします。 2. **Products** を選択します。 3. レイアウトのプリセットを選択します: 縦リスト、横リスト、フィーチャーカルーセル、フィーチャーカード、バナーリスト、またはボトムシート。 4. 各プロダクトカードを選択し、**Design** パネルのドロップダウンでプロダクトを割り当てます。 :::important プロダクトが紐付けられていないプロダクト要素は、[プレビューや公開をブロック](builder-save-publish#troubleshooting)します。プロダクトを割り当てるか、要素を削除してください。 ::: カードに取り消し線付きのアンカー価格を表示するには、カード内に[旧価格要素](onboarding-text#add-an-old-price)を追加してください。 :::note プロダクトカードの**タップ時**インタラクションに**購入**アクションを直接アタッチすることもできます。カードをタップするだけで購入がトリガーされるため、別途購入ボタンを用意する必要はありません。 ::: :::important プロダクトグループを削除して新しいグループに置き換えた場合は、すべてのアクションと変数が新しいグループを参照しているか確認してください。削除済みのグループへの参照が残っていると、[プレビューと公開がブロックされます](builder-save-publish#troubleshooting)。 ::: ## 購入ボタンを追加する \{#add-a-purchase-button\} 購入ボタンは、ユーザーがタップしたときに **Purchase** アクションをトリガーします。 購入ボタンを追加するには: 1. キャンバス上で、画面の **+** をクリックします。 2. **Button** を選択し、ボタンのプリセットを選びます。 3. ボタンを選択した状態で、右パネルの **Interactions** タブを開きます。 4. **Add trigger** > **On tap** をクリックし、**Add action** をクリックします。 5. **Action** を **Purchase** に設定し、**Product** を以下のいずれかに設定します: - `products.selectedProduct`:画面上の Products 要素でユーザーが選択したプロダクトを購入します。 - 特定のプロダクト:画面上の選択内容に関わらず、常にそのプロダクトを購入します。 ### ボタンに価格を表示する \{#show-the-price-on-the-button\} 選択中のプロダクトの価格をボタンのラベルに挿入するには、変数を使います: 1. ボタンを選択した状態で、右パネルの **Design** タブを開きます。 2. **Content** フィールドで、価格を表示したい位置にカーソルを置きます。 3. 変数アイコンをクリックして `products.selectedProduct` を選択し、続けて `prod_price` 属性を選択します。完全な変数は `products.selectedProduct.prod_price` になります。 4. 変数の前後に固定テキストを追加します。例: `Subscribe for {prod_price}`。 ユーザーが別のプロダクトを選択するたびに、ラベルが自動的に更新されます。 ## 購入を復元する \{#restore-purchases\} ユーザーが以前の購入を復元できるようにするには、画面に復元ボタンまたはリンクを追加します。 購入を復元する要素を追加するには: 1. キャンバス上で、画面の **+** をクリックします。 2. **Button** を選択し、テキストリンクの場合は **Links**、スタイル付きボタンの場合は他のボタンタイプを選択します。 3. 要素を選択した状態で、右パネルの **Interactions** タブを開き、**Add trigger** をクリックします。 4. **On tap** を選択して、**Add action** をクリックします。 5. **Action** ドロップダウンから **Restore purchases** を選択します。 ## 選択されたプロダクトに基づいて追加要素を表示する \{#display-additional-elements-based-on-the-selected-product\} 画面にプロダクトが表示されている場合、ユーザーが選択したプロダクトに応じて他の要素を表示・非表示にできます。 条件付き表示を設定するには: 1. **Products** 要素でプロダクトカードを選択します。 2. 右パネルの **Interactions** タブを開き、**Add trigger** をクリックします。 3. **On tap** を選択し、**Add action** をクリックします。 4. **Action** ドロップダウンから **Show** または **Hide** を選択します。 5. そのプロダクトが選択されたときに表示または非表示にする要素を選択します。 ## フロー内のプロダクトを確認する \{#review-products-in-flow\} 左サイドバーの **Products** パネルには、フロー内の各画面に紐付いた既存プロダクトが表示されます。 各画面には2つのセクションがあります: - **Default** — 画面が読み込まれたときにあらかじめ選択されている1つのプロダクト。 - **Other** — 同じ画面で利用可能な追加プロダクト。 --- # File: flow-selectable-elements --- --- title: "選択可能な要素とグループ" description: "要素を選択可能にし、グループにまとめ、その状態をフロー全体の条件として活用しましょう。" --- 選択可能な要素とは、ユーザーがタップして選択・選択解除できるフローの要素です。その状態は、フロー全体のナビゲーション、表示/非表示、その他のロジックに活用できます。できることは次のとおりです。 - [デフォルトの選択可能要素を使用する](#default-selectable-elements) — クイズの選択肢、プロダクト、タブ、トライアルトグルはそのまま選択可能 - [任意の要素を選択可能にする](#make-an-element-selectable) — 任意の要素を選択可能な要素に変換してグループに割り当てる - [グループを作成・管理する](#create-a-group) — 選択可能な要素を単一選択、複数選択、またはトグルグループに整理する - [条件で選択済み状態を使用する](#use-selectable-state-in-conditions) — フロー内の任意の画面の条件でグループの値を参照する ## デフォルトの選択可能な要素 \{#default-selectable-elements\} 一部の要素タイプはデフォルトで選択可能です。自動作成されたグループにすでに属しており、追加設定は不要です: - **クイズの選択肢**:各クイズの回答はクイズグループ内の選択可能な要素です。[クイズ](onboarding-quizzes)を参照してください。 - **プロダクト**:プロダクトグループ内のプロダクトカード。[プロダクトブロック](paywall-product-block)を参照してください。 - **タブ**:タブグループ内のタブアイテム。[タブ](builder-tabs)を参照してください。 - **トライアルトグル**:グループに属し、選択状態を持つコンテナ。[トグル](builder-toggles)を参照してください。 ## 要素を選択可能にする \{#make-an-element-selectable\} <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/btpZPOm9VRY?si=1P959iwNfIJ1ZP7N" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> 場合によっては、追加の要素を選択可能にしたいことがあります。たとえば、クイズグループ内の要素として機能する **Don't ask me again** チェックボックスを追加できます。 要素を選択可能にするには: 1. スクリーン上または **Layers** パネルで要素を選択します。 2. 右側で **Interactions** パネルに切り替えます。 3. **Turn into selectable element** を選択します。 4. **Group** ドロップダウンで、既存のグループを選択するか[新しいグループを作成](#create-a-group)します。 5. **Element ID** を設定します — グループ内でこの要素を一意に識別するIDです。 6. この要素をデフォルトで選択状態にしたい場合は、**Set as default in group** チェックボックスをオンにします。 ## グループを作成する \{#create-a-group\} グループは画面上の選択可能な要素を整理し、ユーザーが1つだけ選べるか、複数選べるか、トグルできるかといった選択の仕方を定義します。 グループを作成するには: 1. 要素を選択して[選択可能にします](#make-an-element-selectable)。 2. **Group** ドロップダウンで **Create group** を選択します。 3. **Group name** を入力します。 4. [グループタイプ](#group-types)を選択します。 これで、同じ画面上の他の選択可能な要素の **Group** ドロップダウンでこのグループが使えるようになります。 ## グループタイプ \{#group-types\} :::important ほとんどの[クイズプリセット](onboarding-quizzes)はデフォルトで **multi-choice** になっています。1つだけ回答できるようにするには、[グループタイプ](#manage-groups)を変更してください。 ::: - **Single choice**:グループ内で一度に選択できる要素は1つだけです。新しい要素を選択すると、前の選択が解除されます。 - **Multi-choice**:複数の要素を同時に選択できます。 - **Toggle**:各要素はタップするたびに選択・解除を切り替え、他の要素とは独立して動作します。 ## グループを管理する \{#manage-groups\} グループを表示・編集するには、**Screen settings** パネルを開いて **Selectable groups** セクションを確認します。現在の画面上のすべてのグループが一覧表示されます。 グループIDをクリックすると: - グループIDを変更できます - [グループタイプ](#group-types)を変更できます - グループ要素が条件でどのように参照されているかを確認できます ## 条件で選択状態を使う \{#use-selectable-state-in-conditions\} グループの選択状態は、フロー内の任意の画面の条件から参照できます — グループが定義されている画面だけでなく、どの画面からでも参照可能です。たとえば:`IF quiz.photo is selected, THEN navigate to the Photo screen` のように使います。 :::important グループ内のすべての要素は同じ画面上に配置する必要があります。異なる画面の要素を1つのグループに追加することはできません。ただし、グループの値はフロー内の任意の画面の条件から参照できます。 ::: 選択状態は以下の場面で使えます: - **[条件付きアクション](onboarding-actions#conditional-actions)**:選択された要素に基づいて、ユーザーを異なる画面にルーティングしたり、異なるアクションをトリガーしたりします。 - **[動的ナビゲーション](onboarding-navigation-branching)**:クイズの回答、トグルの状態、その他の選択に基づいてフローを分岐させます。 - **[条件付き表示](onboarding-element-visibility)**:前の画面でユーザーが選択した内容に基づいて要素を表示または非表示にします。 --- # File: builder-element-states --- --- title: "要素のステート" description: "ステートごとに要素をスタイリングし、条件を使って実行時に要素を無効化します。" --- インタラクティブなフロー要素は、ユーザーのアクションに応じて見た目が変わります。たとえば、タップしたクイズの選択肢は**選択済み**になり、フォーカスされた入力フィールドは**アクティブ**になります。条件によって変わるステートもあります。たとえば、ボタンを**無効化**することができます。各ステートを個別にスタイル設定することで、アプリのコードを書かずにユーザーへの視覚的なフィードバックを実現できます。 <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/gdsNfHpKAqQ?si=VY5mqZgH1j0RB6fE" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## 要素の種類別に使用可能な状態 \{#available-states-by-element-kind\} | 要素の種類 | 組み込み状態 | 追加可能な状態 | |---|---|---| | [選択可能な要素](#selectable-element-states) | **デフォルト**、**選択済み** | **無効** | | [入力欄](#input-states) | **デフォルト**、**アクティブ**、**無効** | **無効** | | [タップ操作が設定された任意の要素](#condition-driven-disabled-state) — ボタン、画像、アイコン、コンテナなど | **デフォルト** | **無効** | | [プログレスインジケーターのステップ](#step-states-for-progress-indicators) | **完了**、**現在**、**未達** | — | **Addable** ステートはデフォルトでは表示されません — **States settings** Settings を開いて追加してください。これらは [**条件駆動型**](#condition-driven-disabled-state) です: どのタイミングで有効化するかを自分で定義します。 ## 状態をスタイルする方法 \{#how-to-style-a-state\} 1. 要素を選択します。右パネルの **States** セクションに、その要素がサポートする状態の一覧が表示されます。 2. **States** セクションで対象の状態を有効にします。必要に応じて[条件ベースの「Disabled」状態](#condition-driven-disabled-state)を追加してください。 3. 塗りつぶし、ボーダー、タイポグラフィなどのプロパティを変更します。変更はその状態にのみ適用されます。 ネストされた要素は親と一緒にステートフルになります。子への変更は、親のアクティブな状態にスコープされます。 4. ビルダーは実行時に一致するスタイルを適用します。 ## 選択可能な要素のステート \{#selectable-element-states\} クイズの選択肢、プロダクト、タブ、トライアルトグル、そして[カスタム選択可能要素](flow-selectable-elements#make-an-element-selectable)など、選択可能な要素にはデフォルトで2つのステートが用意されています。 - **Default**:要素の通常時の外観。 - **Selected**:ユーザーが要素をタップしたときに適用されます。ユーザーが選択を解除すると、ビルダーはDefaultに戻ります。 単一選択グループでは、ある要素を選択すると他の要素の選択が解除されます。複数選択グループでは、複数の要素を同時に選択できます。トグルは独立しており、一つを選択しても他の要素には影響しません。詳しくは[グループタイプ](flow-selectable-elements#group-types)を参照してください。 :::tip 複数の要素(クイズの選択肢など)に同じ状態のスタイルを適用したい場合は、まず1つの要素にスタイルを設定してから複製してください。状態のスタイルは兄弟要素間で引き継がれないため、現時点では複製がその回避策となります。 ::: ## 入力の状態 \{#input-states\} - **デフォルト**: 入力欄の通常時の外観。 - **アクティブ**: 入力欄にフォーカスが当たっている間に適用される。 - **無効(Invalid)**: 入力内容がバリデーションに失敗したときに適用される。たとえば、メールアドレス欄に `@` が含まれていない場合など。詳しくは[入力のバリデーション](builder-inputs-and-forms#input-validation)を参照。 - **無効化(Disabled)**: 入力欄が操作できない状態。手動でこの状態を追加する。[条件に基づく Disabled 状態](#condition-driven-disabled-state)を参照。 各状態のスタイル設定は、選択可能な要素と同じ方法で行う。対象の状態をアクティブにしてから、プロパティを変更する。 ## 条件によるDisabledステート \{#condition-driven-disabled-state\} Disabledステートは、ユーザーが要素を操作できないようにします。Default・Selected・Active・Invalidとは異なり、Disabledステートは自動的に有効になりません — ユーザーが定義したトリガー条件が必要です。 Disabledは以下で使用できます: - **入力フィールド**: テキスト、メール、パスワード、数値、電話番号、日付・時刻など、あらゆる[入力フィールド](builder-inputs-and-forms)。 - **選択可能な要素**: クイズの選択肢、プロダクト、タブ、トライアルトグル、および任意の[カスタム選択可能要素](flow-selectable-elements#make-an-element-selectable)。 - **タップ操作のある要素**: ナビゲーションアクションを起動するボタン、画像、アイコンなど。 ### Disabled ステートを追加する \{#add-the-disabled-state\} Disabled ステートを追加して設定するには: 1. 対象の要素を選択します。 2. **States** セクションで、**Settings** Settings をクリックします。 3. **Add Disabled state** を選択します。Disabled ステートが **States** セクションに表示されます。 4. 新しい Disabled ステートの横にある **Edit conditional state** Edit conditional state をクリックします。 5. 条件を追加します。入力が検証をパスしない限り **submit** ボタンを無効にしたい場合は、入力の `isValid` 変数を `false` と比較します。 6. Disabled ステートに制限を視覚的に伝えるスタイルを設定します(例:不透明度を下げるなど)。 { } Adapty SDKは実行時に条件を評価し、必要に応じてDisabled状態を適用します。アプリのコードは不要です。 ## プログレスインジケーターのステップ状態 \{#step-states-for-progress-indicators\} :::link メイン記事:[プログレスインジケーター](builder-loaders-and-progress-bars#step-states) ::: プログレスインジケーターは、オンボーディングフローのどこまで進んだかをユーザーに示します。各ステップには3つの状態があります: - **完了(Completed)**:ユーザーがすでに通過したステップ。 - **現在(Current)**:ユーザーが現在いるステップ。 - **未到達(Upcoming)**:まだ到達していないステップ。 --- # File: builder-containers --- --- title: "レイアウト要素:コンテナ、カルーセル、ボトムシート" description: "フローレイアウト内でコンテナ、カルーセル、ボトムシートに要素をグループ化します。" --- レイアウト要素は、他の要素をまとめてグループ化し、画面上のレイアウトを制御します。 フロービルダーには、5種類のレイアウト要素があります: - **コンテナ**: 子要素を縦または横の軸に沿って配置します - **カルーセル**: 一度に1枚のスライドを表示するスワイプ可能なコンテナ - **ボトムシート**: 画面下部からスライドアップして、既存のコンテンツの上に表示されるパネル - **フッター**: スクロール領域の外側に、画面下部に固定されるパネル - **区切り線**: 行や列を区切る細い線 :::link **タブ**もこのカテゴリに含まれますが、別記事で説明しています。詳細は[タブ](builder-tabs)を参照してください。 ::: ## コンテナ \{#containers\} :::link メイン記事:[要素の配置](manage-paywall-ui-elements) ::: コンテナは要素を縦または横にグループ化します。**縦コンテナ**は要素を行として並べ、**横コンテナ**は列として並べます。 :::tip コンテナを入れ子にすることで、より複雑なレイアウトを構成できます。 ::: ### コンテナの方向を変更する \{#change-container-direction\} コンテナの方向は固定ではありません。右パネルの **Layout** セクションで **Vertical**、**Horizontal**、**Free** をいつでも切り替えられます。コンテナを削除して作り直す必要はありません。 同じ **Layout** セクションで、スペーシング、アライメント、配置を設定できます。子要素は **Layers** パネルに表示される順に描画されます。ドラッグして並び替えましょう。 ### ラップとアンラップ \{#wrap-and-unwrap\} 既存の要素をコンテナに変換するには、要素を選択して **Wrap** [レイヤーアクション](paywall-layout-and-products#layer-actions)を使います。**Layers** パネルから新しいコンテナに追加の要素をドラッグして入れられます。スタックを削除して子要素を1つ上のレベルに昇格させるには、**Unwrap** を使います。 ## カルーセル \{#carousel\} **カルーセル**は、一度に1枚のスライドを表示するスワイプ可能なコンテナです。ユーザーが横にスワイプすると次のスライドが表示され、タイマーによる自動送りにも対応しています。 カルーセルには複数の**スライド**レイヤーが含まれます。スライドがアクティブになると、そのレイヤー上の要素が画面に表示されます。 タブとは異なり、カルーセルのアクティブなスライドは[選択可能なグループ](flow-selectable-elements)として公開されません。スライドは条件や動的テキストで参照できません。カルーセルはビジュアルのローテーションに使用し、ユーザー主導の分岐には使用しないでください。 ### アクティブなスライドを変更する \{#change-active-slide\} カルーセルを選択すると、ビルダーに **Slide** ドロップダウンと **+ Add Slide** ボタンを含むポップアップコントロールバーが表示されます。 - **+ Add Slide** をクリックして新しい空のスライドを追加できます。 - **Slide** ドロップダウンでキャンバス上のアクティブスライドを切り替えるか、**Layers** パネルで対応するスライドレイヤーをクリックします。 スライドの順序を変更するには、Layers パネル内のカルーセル内でドラッグします。 {/* TODO: on-device GIF */} ### プロパティ \{#properties\} #### 自動スクロール \{#auto-scroll\} 自動スクロールは、スライドを自動的に切り替えます。ユーザーがスワイプしなくても、すべてのコンテンツを確認できます。 タイミングを制御する項目が2つあります: - **Delay** — 各スライドが表示される時間(ms)。 - **Duration** — スライド間のトランジションにかかる時間(ms)。 #### カルーセルのサイズ \{#carousel-sizing\} カルーセルのサイズやスライド間のスペースは専用のコントロールで設定できます。ユーザーがコンテンツの長さが異なるスライド間をスワイプしてもレイアウトがずれないよう、**Height** を **Fixed** に設定してください。 #### スライドのサイズ設定 \{#slide-sizing\} スライドごとの **Width** と **Height** を設定します。デフォルトは Fill で、各スライドがカルーセルのサイズに合わせて追従します。固定の幅を設定すると、隣接するスライドが一部見える「ピーク効果」を作れます。 #### ドット \{#dots\} カルーセル下部に表示されるページインジケーターです。スライドの総数と現在アクティブなスライドをユーザーに伝えます。 **Show dots** トグルをオフにするとスライドインジケーターが非表示になります。ドットが表示されている場合、以下のプロパティで外観を調整できます: - **Color** — 非アクティブなドットの塗りつぶし色。 - **Active Color** — 現在表示中のスライドのドットの塗りつぶし色。 - **Size** — 各ドットの直径(ピクセル単位)。 - **Gap** — 隣接するドット間のスペース。 - **Padding** — ドット行とその上のカルーセルコンテンツとの間のスペース。 ## ボトムシート \{#bottom-sheet\} :::link ウォークスルー:[ボトムシートですべてのプランを表示する](show-plans-bottom-sheet) ::: **ボトムシート**は、画面の下から上にスライドして背後のコンテンツの上に重なって表示されるレイアウトパネルです。 シートは常に背後のコンテンツをぼかします。このぼかしはオフにできません。画面読み込み時ではなく、**Show all plans** リンクなどのタップ操作をトリガーにして表示してください。 ### 構造 \{#structure\} ボトムシートには2つのトップレベルレイヤーが含まれます: - **Heading** — シート上部のコンテナ。**Title** テキストレイヤーと **Close button** Close が事前に配置されています。必要に応じて編集または削除できます。 - **Content** — メインコンテナ。プロダクト、ボタン、リンク、その他の要素を配置できます。 {/* TODO: on-device GIF */} ### 初期表示 \{#initial-visibility\} デフォルトでは、ボトムシートは画面が描画されると同時に表示されます。必要なときだけ開くようにするには: 1. **シートのコンテンツを先に構築する** — 非表示レイヤーは編集できないため、コンテンツを入れ終わるまでシートを表示したままにする必要があります。 2. **Layers** パネルでボトムシートを選択します。 3. **Visibility** を **Hide** Hide に設定します。 シートはレイヤーツリーに残りますが、画面への描画は停止します。 ### ボトムシートのトリガー設定 \{#triggering-the-bottom-sheet\} 非表示のボトムシートを開くには、別の要素に **Show** アクションを設定します: 1. トリガーとなる要素(ボタンやテキストリンクなど)を選択します。 2. 右パネルの **Interactions** タブを開きます。 3. **Add trigger** > **On tap** をクリックし、**Add action** をクリックします。 4. **Action** を **Show** に設定し、ドロップダウンからボトムシートを選択します。 ## フッター \{#footer\} **フッター**は、画面の下部を占めるスティッキーコンテナです。高さは自由に設定でき、シングルボタンから複数行のテキストまで、さまざまなコンテンツを配置できます。CTAボタンや法的テキスト、リンクなど、画面の残りの部分がスクロールしても常に表示しておきたいコンテンツに使いましょう。 通常の要素とは異なり、フッターはデバイスの下部セーフエリアまで伸びます。背景は画面の端まで広がります。 1つの画面に設定できるフッターは1つだけです。既存のフッターを複製したり、新しいフッターを追加したりすることはできません。 ### フッターと通常の固定要素の違い \{#footer-vs-a-regular-fixed-element\} Both stay on screen while content scrolls. Pick the option that matches what you need: - **フッターを使用する**:画面のメインボトムバー(CTAボタン、法的テキスト、リンク)に使用します。フッターは自分自身の高さを確保するため、コンテンツは常にスクロールしてフッターの後ろに隠れることなく表示され、ボトムセーフエリアも自動的にカバーします。 - **[固定要素](manage-paywall-ui-elements)を使用する**:スクロールするコンテンツの上に浮かせたい場合や、ボトム以外のエッジに固定したい場合(フローティングの閉じる/復元ボタン、常時表示のトップバナー、スクロールトップコントロールなど)に使用します。セーフエリアのスペーシングは自分で管理する必要があります。 ## ディバイダー \{#dividers\} **水平ディバイダー**と**垂直ディバイダー**は、コンテンツを区切る細い線です。行を分割するには水平ディバイダーを、横コンテナ内の列を分割するには垂直ディバイダーを使います。右パネルで太さ、色、長さを調整できます。 --- # File: using-custom-fonts-in-flow-builder --- --- title: "フローにカスタムフォントを追加する" description: "フローにカスタムフォントをアップロードして使用する方法を説明します。" --- フローを作成するとき、アプリ全体のデザインに合わせてカスタムフォントを使いたい場合があります。ここでは、カスタムフォントを追加してフローで使用する方法を説明します。 :::tip フローのデザインを始める前に、**Styles** パネルで[フォントを設定](onboarding-text)しておきましょう。こうすることで、変更がグローバルに反映されます。 ::: ## 組み込みフォント \{#built-in-fonts\} ビルダーでフローを作成すると、Adapty はデフォルトでシステムフォントを使用します。通常、iOS では SF Pro、Android では Roboto になりますが、端末によって異なる場合があります。Arial、Times New Roman、Courier New、Georgia、Helvetica など、よく使われるフォントも選択できます。これらのフォントにはいくつかのスタイルオプションが用意されています。 これらのフォントは Adapty SDK には含まれておらず、プレビュー目的でのみ使用されます。すべてのデバイスで完全に動作することを保証することはできません。ただし、私たちのテストでは、ほとんどのデバイスで追加の設定なしに認識されています。[iOS でデフォルトで利用可能なフォントを確認する](https://developer.apple.com/fonts/system-fonts/)こともできます。 ## カスタムフォントを追加する \{#add-a-custom-font\} :::warning アップロードするファイルは**エディタのプレビュー専用**です — Adapty はユーザーのデバイスにファイルを配信しません。デバイス上でフォントを表示するには、[アプリのバンドルにファイルを含めてください](#add-the-font-files-to-your-apps-bundle)。含めない場合、SDK は実行時に SF Pro(iOS)または Roboto(Android)にフォールバックします。 ::: システムのデフォルト以外のフォントを使いたい場合は、カスタムフォントを追加できます。 カスタムフォントを追加するには: 0. フォントが可変フォントの場合は、固有の名前を持つ単一スタイルのファイルに分割してください。ウェイト、ボールド、イタリックのコントロールはカスタムフォントには適用されません。Adapty はカスタムフォントファイルごとに1つのスタイルのみを登録します。テキストのスタイルを変更するには、[テキストのスタイリング](onboarding-text)を参照して、正しいバリエーションのフォントに切り替えてください。 1. フォントのドロップダウンのいずれかで **Upload new font** を選択します。 2. **Add custom font** ウィンドウで、以下のフィールドを入力します。 :::warning **Font name in Builder**、**iOS font name**、**Android font name** はそれぞれ、アプリ内のすべてのカスタムフォントファイルにわたって一意である必要があります。 ::: - **Font name in Builder**: ビルダーでのフォントの表示名を入力します。この名前はビルダー全体のフォントドロップダウンに表示されます。 - **iOS font name**: フォントのPostScript名を入力します。Font Book → PostScript nameから確認するか、[`UIFont` API](https://developer.apple.com/documentation/uikit/uifont)で調べることができます。 - **Android font name**: `res/font/` のファイル名を入力します。小文字、数字、アンダースコアのみ使用できます。 - **Font file**: フォントファイルをドラッグ&ドロップするか、**Select files** をクリックします。サポートされているフォーマット:`.ttf`、`.otf`、`.woff`、`.woff2`。 3. **Save font** をクリックします。 フォントファイルをAdaptyにアップロードすることで、そのフォントをアプリ内で使用する権利を有することを確認したものとみなされます。 ### カスタムフォントを削除する \{#delete-a-custom-font\} カスタムフォントをダッシュボードから削除すると、下書き・公開済みを問わず、すべてのフローでそのフォントへの参照がシステムフォントに自動的に置き換えられます。警告は表示されず、この操作は取り消せません。削除する前に、そのフォントを使用しているライブのフローがないことを確認してください。 ## フローテンプレートのカスタムフォント \{#custom-fonts-in-flow-templates\} [フローテンプレートライブラリ](paywall-builder-templates)には、カスタムフォントを使ったテンプレートが含まれています。テンプレートカードの **Custom font** チップにカーソルを合わせると、使用しているフォントを確認できます。 Adapty はこれらのフォントをバンドルしていません。チップに表示されているフォント名に合わせて、自分でフォントを用意する必要があります。フォントによっては商用ライセンスが必要な場合があります。 フォントファイルを用意したら、以下のバンドル手順に従ってください。 ## フォントファイルをアプリのバンドルに追加する \{#add-the-font-files-to-your-apps-bundle\} すでにアプリ内でカスタムフォントを使用している場合は、同じ方法でペイウォール用のフォントを追加するだけです。まだ使用していない場合は、フォントファイルをアプリのプロジェクトとバンドルに含める必要があります。詳しくは以下をご覧ください: - iOS の場合:[Apple 公式ドキュメント](https://developer.apple.com/documentation/uikit/adding-a-custom-font-to-your-app) - Android の場合:[Android 公式ドキュメント](https://developer.android.com/develop/ui/views/text-and-emoji/fonts-in-xml) --- # File: paywall-head-picture --- --- title: "背景" description: "フローBuilder でスクリーンを単色、グラデーション、画像、または動画の背景で塗りつぶします。" --- [**Screen settings**](paywall-layout-and-products#screen-settings) の **Fill** パネルから、任意のスクリーンに背景を設定できます。単色、グラデーション、画像、動画の4種類の背景タイプから選べます。 ## 画像 \{#image\} `.JPG`、`.PNG`、`.GIF`、`.WEBP` ファイルを最大 20 MB までアップロードできます。画像は背景全体を覆うようにスケーリングされます。 :::note 背景画像と動画は、**Safe area** が有効になっている場合でも、ノッチやシステムバーの裏側を含むビューポート全体に広がります。端のコンテンツが切れないよう、重要なコンテンツは端から離して配置してください。 ::: アプリのコードから実行時に背景画像を差し替えるには、[カスタムメディア ID](custom-media#custom-media-id) を有効にしてください。 ## 動画 \{#video\} `.MP4` または `.WEBM` ファイルを最大 50 MB までアップロードできます。プレビューは静止フレームで表示されますが、実機では実行時に動画が再生されます。 **Loop** を切り替えると、動画を繰り返し再生できます。 実行時に背景動画を差し替えるには、[カスタムメディア ID](custom-media#custom-media-id) を有効にしてください。 ## 単色 \{#solid-color\} 16進数の値を入力し、不透明度を 0〜100% で設定します。スウォッチから保存済みの[カラースタイル](builder-styling)を選ぶと、ブランドカラーを適用できます — 背景はライトテーマとダークテーマに自動的に追従します。 ## グラデーション \{#gradient\} 複数のストップを持つ線形グラデーションを作成できます。 - **Direction** — グラデーションの角度を 0〜360° で回転します。 - **Stops** — バー上をドラッグして位置を調整します。ストップをクリックすると、16進数の値と不透明度を編集できます。 --- # File: custom-media --- --- title: "画像、動画、アイコン" description: "フロービルダーの画面に画像・動画・アイコン要素を追加し、カスタムメディアIDを使って実行時にメディアを切り替えます。" --- フロービルダーの **Media** カテゴリには、Image、Video、Icon の3種類のメディア要素があります。 :::tip 画像や動画を、ノッチやホームインジケーターの背後を含む画面全体に表示するには、すべてのオフセットを0に設定して固定配置し、**Ignore safe area** を選択します。詳しくは[レイアウトと配置](manage-paywall-ui-elements#ignore-safe-area)をご覧ください。 ::: ## 画像 \{#image\} `.JPG`、`.PNG`、`.GIF` ファイルを最大 20 MB までアップロードできます。 - **Aspect** — 画像をコンテナに合わせる方法を設定します: - **Fit** — 画像をトリミングせずにコンテナ内に収まるようにスケーリングします。 - **Fill** — 画像をコンテナに合わせて引き伸ばします。 - **Cover** — 必要に応じてトリミングしながら、コンテナ全体を覆うようにスケーリングします。デフォルト値です。 - **Use custom media ID** — 後述の[カスタムメディアID](#custom-media-id)を参照してください。 ## ビデオ \{#video\} `.MP4` または `.WEBM` ファイルをアップロードできます。ファイルサイズは最大50 MB、長さは最大30秒です。最小解像度は640x640ピクセルです。 - **Aspect** — Fit、Fill、またはCover。デフォルトはFillです。 - **Loop** — ビデオをループ再生します。デフォルトでオンです。 - **Use custom media ID** — 下記の[カスタムメディアID](#custom-media-id)を参照してください。 ビデオはエディタのプレビューでは再生されません。キャンバスには静止フレームが表示されます。デバイス上での実行時、ビデオはデフォルトでミュートで再生されます。Loopがオンの場合、無限に繰り返されます。 ### 動画終了時にアクションをトリガーする \{#trigger-an-action-when-the-video-ends\} :::link メイン記事:[アクション](onboarding-actions) ::: Video 要素は、動画が末尾に達したときに発火する **On playback finished** トリガーをサポートしています。**Interactions** パネルで設定して、別の画面へ遷移したり、CTAを表示したり、その他のアクションを実行できます。 ## アイコン \{#icon\} バンドルされている [Tabler Icons](https://tabler.io/icons) ライブラリから、2種類のビジュアルスタイルで数千のアイコンを選択できます: - **Stroke** — アウトラインのみ。 - **Filled** — 塗りつぶし。 ピッカーでキーワード検索してアイコンを探せます。アイコンの色は **Color** ピッカーで設定します。保存済みの[カラースタイル](builder-styling)を選択するか、カスタムカラーを設定してください。 ## カスタムメディアID \{#custom-media-id\} :::important 画像や動画の[背景](paywall-head-picture)にもカスタムメディアIDを設定できます。 ::: 画像や動画の要素にカスタムメディアIDを付けておくと、アプリのコードから実行時に差し替えることができます。たとえばユーザーが選んだアバターを表示するなど、[パーソナライズされたビジュアル](get-pb-paywalls#customize-assets)に活用してください。 フローBuilder でアップロードしたメディアはフォールバックとして機能します。実行時にコードからそのIDのメディアが提供されなかった場合、フォールバックが表示されます。 ImageまたはVideo要素でカスタムメディアIDを有効にするには: 1. アップロードエリアの下にある **Use custom media ID** チェックボックスを選択します。 2. メディア ID を入力します。 3. フォールバック画像または動画をアップロードします。 アプリのコードでは、メディア ID を使ってメディアを取得します。SDK API の詳細については、[アセットのカスタマイズ](get-pb-paywalls#customize-assets) を参照してください。 --- # File: paywall-buttons --- --- title: "フローBuilder のボタン" description: "フローBuilderでアクションボタンを追加・設定する方法。" --- :::info このセクションでは、Adapty SDK バージョン 4.0 以降で動作する新しいフロービルダーについて説明します。 ::: ボタンはフローのビルダーで、ユーザーのタップに反応するインタラクティブな要素です。次の用途に使用できます: - プロダクトと連携して自動的に決済を処理する購入 CTA - 画面間を移動するナビゲーション(次へ、戻る、閉じる、スキップ) - 購入を復元する、利用規約、プライバシーポリシーなどのユーティリティリンク :::tip 購入 CTA、購入復元リンク、法的リンクは [フッター](builder-containers#footer) 内に配置してください。フッターは画面の下部に固定され、スクロールする要素の上に重なって表示されます。 ::: ## ボタンを追加する \{#add-buttons\} ボタンを追加するには: 1. **+** をクリックして **Button** を選択します。 2. ボタンの種類を選択します。 <img src="/assets/shared/img/button-type.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 購入ボタン、リンク、閉じるボタンにはあらかじめアクションが設定されています。リンクについては、[ユーザーの遷移先URLを設定してください](#links)。その他のボタンタイプについては、**Interactions** パネルに移動してください。そこの **Button triggers** セクションで、ボタンが実行する[アクション](onboarding-actions)を設定します。 <img src="/assets/shared/img/button-action.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Design** パネルで[ボタンのデザイン](builder-styling)を設定します。 ## ボタンの種類 \{#button-types\} ### 購入ボタン \{#purchase-buttons\} :::link 購入ボタンを機能させるには、プロダクトをスクリーンに紐付けて **Products** 要素を追加してください。詳しくは[ガイド](paywall-product-block)をご覧ください。 ::: 購入ボタンは、ユーザーがスクリーンで選択したプロダクトのアプリ内課金を開始します。SDK がトランザクションを自動で処理するため、アプリのコードで購入処理を実装する必要はありません。 購入ボタンを追加するには: 1. **+** をクリックして **Button** を選択し、ボタンのプリセットを選びます。 2. ボタンを選択した状態で、右パネルの **Interactions** タブを開きます。 3. **Add trigger** > **On tap** をクリックし、**Add action** をクリックします。 4. **Action** を **Purchase**、**Product** を `products.selectedProduct` に設定します。`products.selectedProduct` 変数は、画面上で現在選択されているプロダクトに常に解決されます。 :::tip 購入ボタンにアニメーションを追加すると、より注目を集められます。ペイウォールビルダーは現在、**Pulse** アニメーションタイプをサポートしています。 **デザイン**パネルでアニメーションスタイルを設定します。 ::: <img src="/assets/shared/img/purchase-button.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### リンク \{#links\} :::important **Terms of Use** および **Privacy Policy** ボタンには、**Open URL** アクションが組み込まれています。リンク先の URL はそこで設定してください。Open URL が空のままの場合や[インラインリンク](onboarding-text#inline-link)が未設定の場合、プレビューと公開がブロックされます。 ::: 一部のストア要件に対応するため、以下へのリンクを追加できます: - 利用規約 - プライバシーポリシー - 購入の復元 リンクを追加するには: 1. **+** をクリックし、**Button > Links** を選択します。これにより、購入の復元またはURLを開くといったアクションがあらかじめ設定されたインラインボタンの行が追加されます。含まれているボタンがすべて必要でない場合は、レイヤーパネルで不要なものを削除してください。 <img src="/assets/shared/img/add-links.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 次に、ボタンのアクションを設定します: - **Restore purchases** ボタンは、すでに購入の復元を処理します。 - 残りの各リンクについて: 1. ボタンをクリックして選択し、右側の **Interactions** タブに切り替えます。 2. フィールドにURLを貼り付けます。 3. デフォルトでは、URLはシームレスなユーザー体験のためにアプリ内ブラウザで開かれます。外部ブラウザに遷移させたい場合は、**Open in external browser** チェックボックスを選択してください。 <img src="/assets/shared/img/pb-links.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### フローを閉じる \{#close-flow\} **Close** ボタンをクリックすると、フローが自動的に閉じます。 閉じるボタンを追加するには、**+** をクリックして **Button > Close flow** を選択してください。 <img src="/assets/shared/img/close-flow.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::tip **Absolute** ポジションを使用すると、閉じるボタンを画面の隅に配置できます。 ::: フローを閉じる[アクション](onboarding-actions)を使って、他のボタンでもフローを閉じるよう設定できます。 ### カスタムボタン \{#custom-buttons\} 追加できるすべてのボタンは、タップ時に任意のアクションを実行するように設定できます: - 次の画面へ移動する - アラートを表示する - [変数](onboarding-variables)を設定する - [画面要素の表示・非表示を切り替える](onboarding-element-visibility) - URLを開く - 購入を復元する - 条件付きアクションを実行する --- # File: builder-tabs --- --- title: "タブ" description: "フロー内でコンテンツパネルを切り替えるタブナビゲーションを追加します。" --- **タブ**は、画面のセクションを切り替え可能なコンテンツパネルに分割します。ユーザーがタブヘッダーをタップすると、その下のパネルが対応する内容に切り替わります。 {/* TODO: on-device GIF */} ## タブの追加・削除・選択 \{#add-remove-and-select-tabs\} 各タブは2つのパーツで構成されています。 - **タブヘッダー** — クリックできるラベル(Tab 1、Tab 2 など)。 - **タブコンテンツ** — タブごとに1つのコンテナ。コンテンツコンテナに配置したものが、そのタブが選択されたときに表示されます。 **Add tab** をクリックすると、新しいタブが追加されます。追加した各タブには、対応するコンテンツコンテナが自動的に作成されます。 画面が最初に表示されたときに特定のタブをアクティブにするには、**Selected by default** をオンにしてください。 ## タブのスタイル設定 \{#style-the-tabs\} ### テンプレート \{#templates\} フロービルダーでは、すぐに使える3種類のタブテンプレートを用意しています。 - **Segment control** — 選択中のタブに角丸の枠が付いた、ピル形状のスイッチャー。 - **Button Tabs** — ボタン風のスタイルを持つ独立したタブ。 - **Underline** — 選択中のタブをアンダーラインで示すテキストラベル。 ### タブの状態 \{#tab-states\} 各タブには状態切り替え(**Default / Selected**)があり、アクティブ状態と非アクティブ状態のスタイルをそれぞれ個別に設定できます。テキストスタイル、色、塗りつぶし、ボーダーを状態ごとに変更できます。 ## 選択グループ \{#selectable-group\} タブは**単一選択グループ**です。常にひとつのタブだけがアクティブになります。グループの管理は **Screen settings** パネルの [Selectable groups](paywall-layout-and-products#selectable-groups) セクションから行えます。 グループは2つの変数を提供します。 - `tabs.selectedOptionId` — 選択中のタブのID。条件式で使用できます。 - `tabs.selectedOptionTitle` — 選択中のタブのラベル。動的テキストで使用できます。 グループ名を変更した場合は、`tabs` の部分をカスタムの **Group ID** に置き換えてください。 詳細は [選択可能な要素とグループ](flow-selectable-elements) をご覧ください。 --- # File: builder-toggles --- --- title: "トグル" description: "ペイメントフローにトグルスイッチを追加します。" --- :::warning デフォルトでオンに設定されたトライアルトグルを使用するアプリは、Appleに拒否される可能性があります。デフォルトで「オン」になっているトグルは、App Store Review Guidelinesに基づき、ユーザーの明示的な選択なしにフライアルへの同意を示す不正なダークパターンとみなされる場合があります。 拒否を避けるため、トグルはデフォルトで **オフ** に設定し、ユーザー自身がトライアルを選択できるようにしてください。 ::: トライアルトグルは、ペイウォール上で標準プロダクトとトライアルベースのプロダクトをユーザーが切り替えられるバイナリスイッチです。ユーザーが状態を変更すると、プロダクトグループの入れ替え、変数の更新、要素の表示・非表示といったアクションを即座にトリガーできます。 トライアルトグルを追加するには、対象の画面で **+** をクリックし、**Trial toggle** を選択します。 各トライアルトグルは **Toggle** タイプの選択可能な要素です。選択可能な要素にはそれぞれ状態を反映する変数が割り当てられており、たとえば `trial` という名前のトグルには `True` または `False` の値を持つ `trial.is_selected` 変数が付与されます。 他の要素をトグルの状態に連動させるには、この変数を基にした条件付き[アクション](onboarding-actions)または[条件付き表示](onboarding-element-visibility)を設定してください。 --- # File: builder-reviews-and-testimonials --- --- title: "レビューと口コミ" description: "ペイウォールにレビュー、評価、ソーシャルプルーフを追加します。" --- **User Engagement** 要素カテゴリには、ペイウォールにレビュー、評価、ソーシャルプルーフを表示するための4つのテンプレートが用意されています。各テンプレートは完全に編集可能なコンポジションです。プレースホルダーテキストを置き換え、フローの他の部分に合わせて[カラースタイル](builder-styling)と[タイポグラフィ](onboarding-text)を適用してください。 ## レビュー \{#review\} 1つの評価、引用文、著者のクレジットを含むカードです。印象的なユーザーの言葉を紹介するのに使用します。 ## 評価 \{#rating\} 「17000+ rating」のような件数と星のリストです。評価の数の多さを強調するのに使用します。 ## アプリ評価 \{#app-rating\} 「4.9 / Based on 1000+ reviews」のようなサンプルサイズ付きのスコア表示です。高い総合評価を際立たせるのに使用します。 ## ソーシャルプルーフ \{#social-proof\} 「Join 50,000+ users」のようなメンバー数付きのアバターグループです。コミュニティの規模を強調するのに使用します。 --- # File: flow-timer --- --- title: "カウントダウンタイマー" description: "ペイウォールにカウントダウンタイマーを追加します。" --- **カウントダウンタイマー**は、設定した時間からゼロに向かってカウントダウンし、ゼロに達すると表示が停止します。 ## テンプレート \{#templates\} このカテゴリーには4つのビジュアルバリアントがあります: - **Blocks** — 日・時・分・秒をそれぞれラベル付きのセルに分けて表示します。 - **Inline Units** — 単位のサフィックスを付けた1行テキスト表示です。 - **Inline** — 数字のみの表示です。 - **Badge** — ピル形状の数字表示です。 ## 設定 \{#settings\} ### 時間を設定する \{#set-the-duration\} 右パネルの **Countdown** セクションで、開始時間を日・時・分・秒で入力します。 ### 動作を設定する \{#configure-the-behavior\} **Behavior** ドロップダウンでタイマーの開始タイミングを設定します: - **Every appear** — ユーザーが画面を開くたびに再スタートします。デフォルト設定です。 - **First appear** — 現在のアプリセッション中にユーザーが初めて画面を表示したときにスタートします。同じセッション中に戻ってきた場合はカウントを継続し、アプリを新たに起動するとリセットされます。 - **First appear (persisted)** — ユーザーが初めて画面を開いたときにスタートし、アプリを再起動してもカウントを継続します。 ### タイマー終了時にアクションをトリガーする \{#trigger-an-action-when-the-timer-ends\} :::link 関連記事:[アクション](onboarding-actions) ::: カウントダウンがゼロになったときにアクションを実行するには、**On timer end** トリガーを追加します。たとえば、別の画面に遷移したり、割引バッジを非表示にしたりすることができます。 --- # File: onboarding-quizzes --- --- title: "フローのクイズ" description: "Adapty フローにインタラクティブなクイズを追加して、ユーザーの好みを収集し、パーソナライズされたフローを実現しましょう — コード不要です。" --- クイズを使うと、あらかじめ定義した選択肢をユーザーに提示できます。入力フィールドと異なり、クイズにはテキスト入力欄がなく、ユーザーは用意された選択肢から選ぶだけです。好みの収集、ユーザーのセグメント分け、回答に基づくフローの分岐などに活用できます。 ### クイズを追加する \{#add-a-quiz\} 1. 左上の **+** をクリックします。 2. **Quiz** を選択します。 3. クイズの種類を選択します。 - **Icon/image/emoji options:** アイコン、画像、または絵文字とテキストラベルがセットになった選択肢を縦並びで表示します。 - **Icon/image/emoji grid:** アイコン、画像、または絵文字付きの選択肢をグリッド形式で表示します。 - **Rating:** 数値またはスター形式でユーザーが評価を表現できるスケールです。 ### 条件付きナビゲーションを設定する \{#set-up-conditional-navigation\} ユーザーの選択に応じて異なる画面へ誘導するには、クイズのオプションではなく**ナビゲーションボタン**に条件付きアクションを設定します。 1. ナビゲーションボタンを選択します。 2. **Interactions** パネルで、**On Tap** トリガーに **Conditional** アクションを追加します。 3. **Edit Action** ダイアログで **if** 行を設定します。 - 左側の `{}` をクリックし、**Elements → Screen → `<quizElementId>.selectedOptionId`** を選択してユーザーの選択を参照します。 - 演算子は `=` のままにします。 - 右側に一致させる elementId を入力します(例: `rock`)。 4. **then** の下で、アクションを **Navigate to** に設定し、遷移先の画面を選択します。 5. **else** の下で、フォールバックの **Navigate to** の遷移先を設定するか、**+ Add else/if** をクリックして他のオプション用の条件を追加します。 :::link クイズの回答の活用方法については、以下のガイドをご参照ください。 - [条件付きナビゲーション](onboarding-navigation-branching) - [変数](onboarding-variables) - [アクション](onboarding-actions) ::: ### クイズの種類を変更する \{#change-quiz-type\} デフォルトでは、クイズは **multi choice**(複数選択)です — ユーザーは複数の選択肢を同時に選べます。1つだけ選ばせたい場合は **single choice** に切り替えます。 1. クイズを含む画面を選択します。 2. **Screen settings** で **Selectable groups** までスクロールし、対象のクイズをクリックします。 3. **Edit group** ダイアログで **Group type** を開き、以下から選択します。 - **Single choice** — 一度に1つの選択肢しか選べません。 - **Multi choice** — 複数の選択肢を選べます。 4. **Save** をクリックします。 --- # File: builder-inputs-and-forms --- --- title: "フロービルダーでのインプットとフォーム" description: "テキストフィールドやチェックボックスなどのインタラクティブなフォーム要素を追加する。" --- インプットを使用すると、名前、メールアドレス、生年月日などのテキストデータをユーザーから収集できます。入力された値を保存して、フロー内の別の箇所(例:後のスクリーンでユーザーを名前で呼びかけるなど)で参照することもできます。 ## インプットを追加する \{#add-an-input\} 1. 左上の **+** をクリックします。 2. **Input** を選択します。 3. インプットタイプを選択します: - **Text:** 任意の短いテキスト入力。 - **Email:** メールアドレス。オプションで形式バリデーションあり。 - **Password:** セキュアなテキスト入力。要件を設定可能。 - **Number:** 数値。形式を設定可能。 - **Phone number:** 電話番号。 - **Date:** 日付ピッカーを開く。 - **Time:** 時刻ピッカーを開く。 - **Date and time:** 日付と時刻の複合ピッカーを開く。 ## 入力フィールドの設定 \{#configure-an-input\} :::link レイアウト、スタイル、表示に関する詳細は、[スタイルと外観](builder-styling)をご覧ください。 ::: すべての入力タイプについて、**Design** タブで次の設定が可能です。 - **Type:** 入力タイプを変更します(Text、Email、Password、Number、Phone number、Date、Time、Date and time)。 - **Element ID:** フロー内の他の場所で入力値を参照するための識別子です。後述の[入力値を使用する](#use-input-values)を参照してください。 - **Placeholder:** 空のフィールド内に表示されるヒントテキストです。 - **State:** さまざまな状況での入力の見た目を定義します。**Default**、**Active**、**Invalid**、**Disabled** を切り替えて、それぞれに異なるビジュアルを適用できます。 - **Typography:** フィールドに表示される値のテキストスタイルです。 - **Leading and trailing icons:** 入力フィールド内にアイコンを追加します。 一部の設定は特定の入力タイプに固有のものです: | 設定 | 入力タイプ | |----------------------------|---------------------------| | クリアボタン | テキスト、メール | | メール形式の検証 | メール | | パスワード表示アイコン | パスワード | | パスワード要件の編集 | パスワード | | 数値フォーマット | 数値 | | 日付/時刻フォーマット | 日付、時刻、日付と時刻 | | 最小・最大日付 | 日付、日付と時刻 | ## 入力値を使用する \{#use-input-values\} すべての入力は自動的に変数として利用できます。設定や **On Submit** アクションは不要です。値は、**Input Settings** で設定した入力の **Element ID** を通じて参照されます。 フロー内の別の場所で入力値を使用するには(たとえば、テキストのパーソナライズ、別のフィールドへの入力、または条件付きナビゲーションの制御など)、変数を挿入して次を選択します: **Element > Screen > `<elementId>.value`** :::link 保存された入力値の使い方については、関連ガイドを参照してください: - [条件付きナビゲーション](onboarding-navigation-branching) - [変数](onboarding-variables) ::: ## 入力バリデーション \{#input-validation\} バリデーションの動作は入力タイプによって異なります。すべての入力には読み取り専用のBoolean変数 `<elementId>.isValid` が用意されており、入力値が検証ルールを満たしているかどうかを反映します。条件アクションや条件付き表示に活用できます。たとえば、メールアドレスのフォーマットが正しくなるまで「次へ」ボタンを非表示にするといった使い方が可能です。 :::note - `isValid` 変数は読み取り専用です。値をセットすることはできません。 - 空の入力は常に有効とみなされます。 - テキスト入力にはバリデーションルールがありません。`textInput.isValid` は常に `True` を返します。 ::: | 入力タイプ | バリデーションの動作 | |---|---| | テキスト | 組み込みのバリデーションルールはありません。 | | メール | 任意設定。**Design** パネルの **Validate email format** を有効にすると、入力値をメール形式でチェックします。 | | 電話番号 | 組み込みの電話番号フォーマットチェックがあります。ビルダーでは設定できません — ルールはランタイム時に評価されます。 | | パスワード | 設定可能。下記の[パスワード要件](#password-requirements)を参照してください。 | | 数値 | フォーマットベース。入力値は選択した数値フォーマットに一致する必要があります。下記の[数値フォーマット](#number-format)を参照してください。 | | 日付、時刻、日時 | 組み込み。ピッカーは有効な日付または時刻の値のみ受け付けます。 | **Invalid** [ビジュアル状態](builder-styling#input-states)は、ユーザーがフォームを送信したとき(例:キーボードの Enter や Done を押したとき)に有効になります。それまでは、**Active** または **Default** の状態が表示されます。 ### パスワード要件 \{#password-requirements\} パスワード入力フィールドでは、バリデーションルールを設定できます。**Design** パネルの **Edit password requirements** をクリックするとルールエディターが開きます。有効なルールは入力フィールドの下にリアルタイムのチェックリストとして表示され、条件が満たされるとその項目にチェックマークが付きます。 利用可能なルール: - **Min length** — 最小文字数。デフォルト: 8。 - **Max length** — 最大文字数。デフォルト: 32。 - **Uppercase letter** — 大文字(A〜Z)を1文字以上含む。 - **Lowercase letter** — 小文字(a〜z)を1文字以上含む。 - **Number** — 数字を1文字以上含む。 - **Special character** — 英数字以外の文字(例: `!@#$%`)を1文字以上含む。 パスワードは、有効なすべてのルールを満たした場合にのみ有効となります。 ### 数値形式 \{#number-format\} **Number** インプット設定の **Format** ドロップダウンで、入力値の解析方法を制御します: - **Integer** — 整数のみ(例:`4`)。 - **Decimal (Point)** — ピリオドを小数点区切り文字とする小数(例:`4.89`)。 - **Decimal (Comma)** — カンマを小数点区切り文字とする小数(例:`4,89`)。 選択した形式と一致しない値は無効と見なされます。 ## インプットイベントでアクションをトリガーする \{#trigger-actions-on-input-events\} :::link メイン記事:[アクション](onboarding-actions) ::: **Interactions** パネルで、ユーザーの入力に応じたアクションを実行できます: - **On changed** — ユーザーがインプットの値を変更したときに発火します。すべてのインプットタイプで利用可能です。 - **On submit** — ユーザーがキーボードで Enter または Done を押してテキストインプットを送信したときに発火します。日付と時刻のピッカーにはこのトリガーはありません。 --- # File: onboarding-navigation-branching --- --- title: "ナビゲーションと分岐" description: "静的ルートと動的分岐を使って、ユーザーを画面ごとにガイドします。" --- ナビゲーションと分岐を使うと、フローの各ステップでユーザーを案内できます。静的ルートで全ユーザーをコア画面に誘導し、動的ナビゲーションでユーザーの選択に応じてフローを変化させることが可能です。 :::link ナビゲーションはアクションタイプの一つです。アクションの詳細については、[アクション](onboarding-actions)を参照してください。 ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/OLl-WziDMhU?si=_eUtsmbEuFAaLj1r" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ## 画面間を移動する \{#navigate-between-screens\} 静的・動的ナビゲーションは、さまざまなフロー要素を使って設定できます。 ### 静的ナビゲーション \{#static-navigation\} 静的ナビゲーションは、すべてのユーザーを同じ画面に誘導します。設定手順は以下のとおりです。 1. ユーザーがタップできる任意の要素(ボタン、クイズの回答、トグルなど)を選択します。 2. 右側の **Interactions** パネルを開き、**Add trigger** をクリックします。 クイズの選択肢をタップした際に、別途ボタンをタップしなくてもすぐに画面遷移させたい場合は、ボタンではなくクイズオプションの要素をここで選択してください。 3. **On tap** トリガーを設定します: - **Action**: **Navigate to screen** を選択します。 - **Destination**: 遷移先の画面を選択します。 ### ダイナミックナビゲーション \{#dynamic-navigation\} ダイナミックナビゲーションは、クイズの回答・トグル要素の状態・カスタム属性に基づいてユーザーをルーティングします。 [選択可能な要素](flow-selectable-elements)はどれでもダイナミックナビゲーションの条件として使用できます。 設定手順: 1. ユーザーをナビゲートする要素を選択します。 2. 右側の **Interactions** パネルを開き、**Add trigger** をクリックします。 クイズの選択肢をタップした瞬間に(別途ボタンをタップしなくても)ユーザーをナビゲートしたい場合は、ボタンの代わりにクイズ選択肢の要素をここで選択してください。 3. **On tap** トリガーを設定します: - **Action**: **Conditional** を選択します。 - **Conditions**: 条件付きナビゲーションアクションを設定します。詳細は[こちら](onboarding-actions#conditional-actions)をご覧ください。 ## フローを閉じる \{#close-flow\} ユーザーの操作フローでフローを閉じる必要がある場合、ボタンまたは単一回答クイズを使って設定できます。 1. タップ時にフローを閉じる要素を追加・選択します。 2. 右側の **Interactions** パネルを開き、**Add trigger** をクリックします。 3. **On tap** トリガーを設定します。 - **Action**: **Close flow** を選択します。 --- # File: onboarding-actions --- --- title: "アクション" description: "ビルダーでユーザー操作によってトリガーされるアクションを定義します。" --- **Interactions** パネルでは、タップ、要素の表示、フォーム送信などのイベントに対して、フロー要素がどのように応答するかを定義できます。各イベントに対して、画面間の移動、要素の表示・非表示、URL を開く、変数の設定など、1 つ以上のアクションを割り当てます。条件を使えば、ユーザーデータに基づいてフローをカスタマイズできます。 各インタラクションは 3 つのチェーンで構成されています。 1. **要素(Element)**: インタラクションを開始する画面コンポーネント — ボタン、クイズの回答、入力フィールドなど。 2. **トリガー(Trigger)**: ロジックを起動するイベント — タップ、要素の表示、フォームの送信など。 3. **アクション(Action)**: トリガーに応じてフローが実行するタスク。1つのトリガーで複数のアクションを順番に実行できます。 ## インタラクションの設定 \{#set-up-interactions\} インタラクションを設定するには、次の手順に従います。 1. 画面上または **Layers** パネルで要素を選択します。 2. 右側の **Interactions** パネルに切り替え、**Add trigger** をクリックします。 3. **Button triggers** セクションで、[トリガーのタイプ](#trigger-types)を選択します。 4. **Add action** をクリックし、アクション名をクリックして、**Edit action** ウィンドウのドロップダウンから[アクションのタイプ](#action-types)を選択します。 5. 選択した[アクションタイプ](#action-types)に基づいて、アクションのプロパティを設定します。 6. 必要に応じて、**Add action** をクリックして同じトリガーにアクションを追加します。 ## トリガーの種類 \{#trigger-types\} トリガーは、ユーザーの操作、要素の状態変化、または画面の読み込みに反応して発火します。**On screen appear** はすべての要素に対して使用できる汎用トリガーです。それ以外はすべて特定の要素に紐づいたトリガーです。 | トリガー | 発火タイミング | 対応要素 | |---|---|---| | **On screen appear** | 画面が読み込まれたとき | すべての要素 | | **On tap** | ユーザーが要素をタップしたとき | [ボタン](paywall-buttons)、[クイズオプション](onboarding-quizzes)、[トグル](builder-toggles)、[カウントダウン](flow-timer)、[動画](custom-media) | | **On changed** | ユーザーが入力値を変更したとき(テキスト入力、日付・時刻の選択) | すべての[入力要素](builder-inputs-and-forms) | | **On submit** | ユーザーがキーボードのEnterまたは完了を押してテキスト入力を送信したとき | [テキスト系入力要素](builder-inputs-and-forms) | | **On timer end** | [カウントダウン](flow-timer)要素がゼロに達したとき | [カウントダウン](flow-timer) | | **On playback finished** | [動画](custom-media)が最後まで再生されたとき | [動画](custom-media) | インタラクションが組み込まれていない要素([ローダー](builder-loaders-and-progress-bars)など)では、**On screen appear** が唯一利用可能なトリガーです。 ## アクションの種類 \{#action-types\} :::important **画面を切り替えるナビゲーション系のアクション**は、常にアクションリストの最後に配置してください。その後に配置されたアクション(「変数の設定」など)は、すでに画面が切り替わっているため実行されない場合があります。 ::: ### 画面への遷移 \{#navigate-to-screen\} これはユーザーを画面間で移動させるための主要なアクションです。指定した遷移先の画面にユーザーを誘導します。 このアクションでは、遷移先の画面を設定するだけで十分です。動的なナビゲーションを有効にしたい場合は、[ナビゲーションと分岐](onboarding-navigation-branching)または[条件付きアクション](#conditional-actions)セクションをご覧ください。 ### 次の画面に進む \{#navigate-next\} フロー内の画面順序に従って、ユーザーを次の画面に進めます。エディターでの画面の並び順がそのまま表示順になる、リニアなフローに適しています。 ### 前の画面に戻る \{#navigate-back\} シーケンス上の前の画面ではなく、ナビゲーション履歴上の前の画面にユーザーを戻します。 ### URLを開く \{#open-url\} :::tip テキストにリンクを埋め込む場合は、[インラインリンク](onboarding-text#inline-link)を使用してください。 ::: 指定したウェブアドレスを開きます。アプリのネイティブ画面外のウェブページ、記事、SNSプロフィールなどにユーザーを誘導する際に使用します。 このアクションでは、以下の2つの設定を行えます: - **URL address**:URLアドレスを設定します。また、動的にすることも可能です。たとえば、クイズの回答に基づいて異なるページへ誘導したり、ユーザーが入力したデータを活用したりできます。設定するには、Variable icon をクリックして使用する変数を選択してください。 - **Open in external browser**:外部リンクを開く場所を指定します。デフォルトではアプリ内ブラウザで開き、ユーザーがアプリ内に留まるようになっています。外部ブラウザで開きたい場合は、**Open in external browser** チェックボックスを選択してください。 ### フローを閉じる \{#close-flow\} 現在のフローを閉じます。 ### 要素の表示/非表示 \{#showhide-elements\} 画面上の特定の要素を表示または非表示にします。 このアクションは、**Design** パネルの **Visibility** で設定された初期状態を上書きします。**Visibility** が **Hide** に設定されている場合、**Show** アクションを使うと要素が表示されます。 :::important 対象要素が指定されていない **Show** または **Hide** アクションがあると、[プレビューと公開がブロックされます](builder-save-publish#troubleshooting)。対象を選択するか、アクションを削除してください。 ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/3w3YSOmI3tQ?si=vPhoQGt44SI285Ru" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> ### アラートを表示する \{#show-alert\} ネイティブのシステムポップアップウィンドウを表示します。ユーザーは **Ok** をタップして続行する必要があります。 アラートには、**Title** と **Message** を設定する必要があります。どちらにも、変数を使ってコンテンツを動的にすることができます。変数を使用するには、Variable icon をクリックして、使用したい変数を選択してください。 :::important 設定が空または不完全な **Show alert** アクションは、[プレビューと公開をブロックします](builder-save-publish#troubleshooting)。両方のフィールドに入力するか、アクションを削除してください。 ::: ### 変数を設定する \{#set-variable\} フロー内の変数の値を更新します。このアクションを追加する前に、左側の **Variables** パネルで変数を作成してください([変数](onboarding-variables)を参照)。 **Add variable** をクリックして、必要な数だけ変数とその値を設定します。 :::important 割り当てのない **Set variable** アクションは、[プレビューと公開をブロックします](builder-save-publish#troubleshooting)。少なくとも1つの割り当てを設定するか、アクションを削除してください。 ::: ### 購入 \{#purchase\} オンボーディング内のボタンやインタラクションから直接購入フローを起動します。フローを離れることなく、ユーザーがサブスクリプションに登録したりプロダクトを購入したりできるようにします。 このアクションには、2つの動作を設定できます: - **In-app store**:ネイティブ購入を開始します。**Product** に特定のプロダクトを設定するか、画面上でユーザーが現在選択しているプロダクトを使用する場合は `products.selectedProduct` を設定します。 - **Web payment**:ネイティブ購入をトリガーする代わりに、ユーザーを[ウェブペイウォール](web-paywall)に送ります。ウェブベースのサブスクリプションオファーなど、アプリ外でトランザクションを処理したい場合に使用します。 :::important ターゲットの**プロダクト**または**Web Paywall URL**が設定されていない**Purchase**アクションは、[プレビューおよび公開をブロックします](builder-save-publish#troubleshooting)。ターゲットを割り当てるか、アクションを削除してください。 ::: ### 購入を復元する \{#restore-purchases\} デバイス上で購入の復元フローを起動します。ユーザーが別のデバイスで以前に購入したサブスクリプションや、アプリを再インストールした後にアクセス権を回復したい場合に使用します。 このアクションに設定項目はありません。復元はAdaptyがネイティブのストアフローを通じて処理します。 **Restore purchases** アクションは、**Links** ボタンプリセットの **Restore** リンクにもあらかじめ設定されています([購入の設定](paywall-product-block#restore-purchases)を参照)。 ## カスタムアクション \{#custom-actions\} カスタムアクションは、自分のアプリコードが処理する **Action ID** という名前のアクションを発火させます。組み込みのアクションタイプでは対応できない場合に使用します。 Adapty がトリガーを提供し、アプリが実際の動作を実装します: 1. ビルダーで、要素のインタラクションに **Action ID** を割り当てます。 2. ユーザーがそのインタラクションを起こすと、フローがそのIDをアプリに渡します。 3. アプリはIDを照合し、対応するコードを実行します。 ### カスタムアクションを設定する \{#set-up-a-custom-action\} 1. **Edit action** ウィンドウで、**Action ID** を割り当てます。これはアプリが認識する文字列です(例:`show_discount`)。 2. アプリのコードで、この Action ID に対応するハンドラーを実装します。実装の詳細とコード例については、[ペイウォールアクションの処理](handle-paywall-actions)を参照してください。 :::important **Action ID** が設定されていない **Custom** アクションは、[プレビューと公開をブロックします](builder-save-publish#troubleshooting)。Action ID を割り当てるか、アクションを削除してください。 ::: ### カスタムアクションでできること \{#what-you-can-do-with-custom-actions\} カスタムアクション自体は何もしません。ビルダーで静的なアクション ID を設定し、そのIDを受け取ったときの処理はアプリのコードが担います。以下のユースケースはすべて同じパターンです。フローでIDを割り当て、コードで処理する。 - **アプリ内イベントのトリガー**: `viewed_special_offer` などのIDを発火させ、アプリがそれを受け取ったときにアナリティクスへイベントを記録します。 - **システム権限のリクエスト**: `request_location` などのIDを発火させ、アプリからOSの権限プロンプトを呼び出します。プロンプトで付与できない権限の場合は、スマートフォンのシステム設定を開いてください。プロンプトを表示するのはAdaptyではなく、あなたのアプリです。 - **ネイティブ認証の開始**: `login_google` などのIDを発火させ、独自のログイン画面を表示します。フローはユーザーをサインインさせることができません。 - **ビジネスロジックの適用**: `apply_discount` などのIDを発火させ、コンテンツをアンロックしたり、アプリの状態を変更したりします。 - **クイズの回答をアプリに渡す**: 各選択肢に異なるアクションIDを割り当て(例: `goal_weight_loss`、`goal_muscle`)、コード内でそのIDを読み取ります。このIDを使って[カスタムユーザー属性](setting-user-attributes#custom-user-attributes)を設定し、後からセグメント化できます。アクションが持つのは固定のIDのみなので、選択内容を伝える唯一の方法がこれです。フローは選択された値を送信することができません。 :::important カスタムアクションは、ユーザーがオプションを選択した瞬間に発火します。ユーザーが回答を変更した場合、フローは新しいアクション ID も発火します。アプリはその両方を順番に受け取ります(例:`goal_weight_loss`、次に `goal_muscle`)。最後のシグナルが優先されるよう、ハンドラーをべき等にしてください。 ::: ### カスタムアクションでできないこと \{#what-custom-actions-cant-do\} カスタムアクションは静的です。アクション ID はフローをビルドする際に固定されるため、[変数](onboarding-variables)や[ユーザー入力](builder-inputs-and-forms)を読み取ることはできません。アクションが発火したとき、アプリが受け取るのはその ID のみであり、ユーザーが入力したメールアドレスや電話番号などの情報は一切渡されません。入力フィールドは、分岐やパーソナライゼーションのための変数としてフロー内に留まります。これらの値をアプリで利用するには、独自の UI や API を通じて収集してください。 カスタムアクションも一方向です。アプリがフローに結果を返すことはできず、フローはあなたのコードの完了を待ちません。カスタムアクションの後に **Navigate next** アクションが続く場合、コードが失敗しても(たとえばユーザーがログイン画面をサインインせずに閉じた場合でも)、ユーザーは次の画面に進みます。静的な Action ID と組み合わせると、アプリ側でのユーザー入力の検証(たとえばユーザーが入力した SMS コードを確認して結果に応じて分岐する)は行えません。フローの続きがコードの実行結果に依存する場合は、[フローを2つのプレースメントに分割してください](#continue-the-flow-based-on-the-result)。 ### 結果に基づいてフローを継続する \{#continue-the-flow-based-on-the-result\} カスタムアクションが成功した場合にのみ表示されるべき画面がある場合(例:ログイン後に続く画面)、フローを2つの[プレースメント](placements)に分割し、2番目の部分をいつ表示するかはアプリ側で判断します: 1. 最初のプレースメントで、カスタムアクション(例:`login`)で終わるフローを作成します。 2. アプリ側でアクションIDを処理します:ログイン画面を表示し、ユーザーがサインインしたかどうかを確認します。 3. ユーザーがサインインした場合、2番目のプレースメントのフローを続きの画面とともに表示します。 このようにすることで、フローが結果に関係なく画面を進めてしまうのではなく、実際の処理結果に基づいてアプリ側で画面遷移を制御できます。 ## 条件付きアクション \{#conditional-actions\} <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/xmWSEPxnI0s?si=mazHQHE89qEDxvPA" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> 条件付きアクションを使うと、ユーザーデータに基づいてフローを異なるパスに分岐させることができます。 よくある使用例を以下に挙げます。 - スクリーン上にクイズがあり、回答に応じて異なるスクリーンへ誘導したい場合。この場合は、ボタンに条件付きアクションを追加します。 - ユーザーグループごとに異なるプロダクトやオファーを提示したい場合。それぞれ別のスクリーンに配置し、ナビゲーションボタンに条件を設定します。 - 前回のアプリセッションでチュートリアルを完了済みのユーザーに対して、特定のステップをスキップしたい場合。 条件アクションは if / else-if / else チェーンのように機能します。アプリはルールを上から下へ順番に読み取り、最初に一致した条件で処理を停止します。 1. **IF**: フローがメインの条件をチェックします。 - True の場合?フローは THEN アクションをすぐに実行し、停止します。 - False の場合?フローは次のセクションにスキップします。 2. **ELSE IF**: ここに追加のチェックを設定できます(例:「プレミアムでない場合、ユーザーはトライアル中か?」)。 3. **ELSE**(フォールバック): 上記のいずれのルールにも一致しなかった場合、フローはこの最後のセクションのアクションを実行します。 :::important - ルールが追加されていても、アクションが割り当てられていない場合、条件に一致しても何も実行されません。 - 不完全なルール(オペレーターや値が設定されていない)は[プレビューや公開をブロックします](builder-save-publish#troubleshooting)。 ::: 各ルールに対して、評価する変数とアクションを選択してください。1つのルールに複数のアクションを設定することもできます。 :::important フローが実行するのは、最初に一致した1つのルールのみです。**IF** と **ELSE IF** を同時に実行する必要がある場合は、両方のアクションを **IF** に追加してください。 ::: 要素を選択可能にしたり、条件で使用するためにグループ化する方法については、[選択可能な要素とグループ](flow-selectable-elements)を参照してください。 ## トラブルシューティング \{#troubleshooting\} 必須フィールドが未入力の場合、プレビューや公開がブロックされます。詳細は[フローの保存と公開](builder-save-publish#troubleshooting)をご覧ください。 --- # File: builder-loaders-and-progress-bars --- --- title: "プログレスインジケーターとローダー" description: "フローのステップ進行状態とビジー状態を表示します。" --- **Progress** カテゴリには、マルチスクリーンフローのステップ進行を示すタイプと、その場でビジー状態を示すタイプの2種類の要素があります。 ## プログレスインジケーター \{#progress-indicators\} ### インジケーターのスタイル \{#indicator-styles\} **Progress** 要素は、複数画面のフローにおけるユーザーの現在位置を示します。このカテゴリには3つの視覚的なバリアントがあります: - **Linear** — ユーザーが進むにつれて塗りつぶされる1本のバー。 - **Segmented** — 各ステップを表す個別のバーが順番に塗りつぶされていく。 - **Connectors** — 線でつながれたラベル付きの円(例:Step 1、Step 2、Step 3 の順序)。 ### ステップとスクリーンの対応を設定する \{#match-steps-to-screens\} デフォルトでは、プログレスインジケーターはフロー内のすべてのスクリーンをトラッキングします。特定のスクリーンのみに限定したい場合は、**Screens** ドロップダウンから選択してください。または、除外したいスクリーンを開き、**Include screen in progress indicator** チェックボックスのチェックを外してください。 ステップ数をより細かく制御したい場合は、**One segment per screen** をオフにしてください。 :::warning ステップの位置は、ユーザーが実際に見る順番ではなく、画面リストに従って決まります。非線形フローでは、インジケーターに表示されるステップが先に進んだり戻ったりすることがあります。 ::: ### ステップの状態 \{#step-states\} 各ステップには **Completed**、**Current**、**Upcoming** の3つの状態があります。Progress Indicator 内のステップを選択すると、右パネルで状態のスタイルを編集できます。**Apply changes to all states** を使用すると、編集内容を他の2つの状態にコピーできます。 1つのステップを編集すると、同じインジケーター内のすべてのステップに影響します。 ### レイアウトと配置 \{#layout-and-positioning\} プログレスインジケーターはグローバル要素のため、[コンテナ](builder-containers)の内側に配置することはできません。また、位置の設定も不可で、デフォルトで絶対配置が使用されます。ユーザーが画面をスクロールしても、インジケーターは固定されたまま、コンテンツがその下でスクロールします。 インジケーター周囲のスペースを調整するには、要素を移動するのではなく、**Spacing** セクションの **Margin** および **Padding** コントロールを使用してください。レイアウトがずれて見える場合は、インジケーターと隣接する要素の両方でマージンまたはパディングを調整してください。 ## ローダー \{#loaders\} **ローダー**は、処理が進行中であることを示すアニメーション要素です。たとえば、パーソナライズされたプランを作成するためにクイズの回答を処理している場合などに使用します。 このカテゴリには3つのテンプレートがあります。 - **Spinner** — 円形のスピナー。 - **Spinner with label** — キャプション付きの円形スピナー(例:「読み込み中...」)。 - **Loader** — 処理の進行に合わせて塗りつぶされる横バー。 {/* - **Loader with label** — A horizontal bar with a caption and percentage (e.g., "Analyzing... 47%"). */} :::warning ローダーを表示・非表示にするには**トリガー**が必要です。**Interactions**タブを開いてロジックを設定してください。たとえば、ユーザーがクイズを送信した後に表示するなどが可能です。 ::: --- # File: onboarding-variables --- --- title: "変数" description: "フローで動的なデータを表示するために変数を使用します。" --- 変数を使うと、フロー内に動的なコンテンツ(プロダクトの価格、オファーの詳細、各ユーザーのコンテキストに応じて更新されるデータなど)を表示できます。要素の表示制御や画面コンテンツのパーソナライズにも活用できます。 変数パネルを開くには、左パネルの **{ }** アイコンをクリックします。パネルには3つのタブがあります: - **[カスタム](#custom-variables)**: 自分で作成・管理する変数です。 - **[プロダクト](#product-variables)**: ストアからローカライズされたプロダクトおよびオファーのデータを取得する組み込み変数です。 - **[エレメント](#element-variables)**: キャンバス上のエレメントの状態に紐付けられた変数です。 ## カスタム変数 \{#custom-variables\} ### カスタム変数を作成する \{#create-a-custom-variable\} 1. 変数パネルで **+** をクリックします。 2. 変数の名前を入力します。 3. タイプを選択します:String、Number、または Boolean。 4. 初期値を設定します。これはフローが開始したときに変数が保持する値です。 5. **Create variable** をクリックします。 :::tip ドット付きの名前を使うと関連する変数をグループ化できます。例:`user.score` や `user.goal`。 ::: ### インタラクションを通じて変数を更新する \{#update-a-variable-via-an-interaction\} :::link 詳しくは[アクション](onboarding-actions)の記事をご覧ください。 ::: 任意の要素に **Set up variables** アクションを追加することで、実行時に変数の値を更新できます。 1. キャンバス上の要素を選択します。 2. **Interactions** タブで **Add trigger** をクリックします。 3. **On tap** を選択し、**Add action** をクリックします。**Action type** ドロップダウンから **Set up variables** を選択します。 4. **Add variable** をクリックします。変数を選択し、新しい値を設定します。 :::tip 例えば、ユーザーがクイズで選んだ回答に応じて `user.goal` に異なる値を設定し、その変数を使って別の画面へ誘導することができます。 ::: ## プロダクト変数 \{#product-variables\} プロダクト変数は、アプリストアからローカライズされたデータを直接取得します。テキストフィールドで使用すると、ローカライズされた価格、タイトル、オファーの詳細を表示できます。また、条件に使用すると、オファーの対象資格に基づいてコンテンツを表示または非表示にできます。 | 変数 | 説明 | 例 | | :--- | :--- | :--- | | `prod_title` | プロダクトのローカライズされたタイトル | Premium Subscription | | `prod_price` | 1請求期間あたりのローカライズされた価格 | $9.99 | | `prod_price_per_day` | サブスクリプション価格を請求期間の日数で割った値。サブスクリプション以外は空。 | $0.33 | | `prod_price_per_week` | サブスクリプション価格を請求期間の週数で割った値。サブスクリプション以外は空。 | $2.33 | | `prod_price_per_month` | サブスクリプション価格を1か月に換算した値。サブスクリプション以外は空。 | $9.99 | | `prod_price_per_year` | サブスクリプション価格を1年に換算した値。サブスクリプション以外は空。 | $119.88 | | `offer_price` | 初回オファーまたはプロモーションオファーのローカライズされた価格。ユーザーがいずれのオファーも対象外の場合は空。 | $0.99 | | `offer_billing_period` | オファーのローカライズされた請求期間。トライアルおよび一括払いオファーの場合は `offer_full_duration` と同じ。対象外の場合は空。 | 1 week | | `offer_full_duration` | オファーのローカライズされた合計期間。対象外の場合は空。 | 1 month | | `is_free_trial` | ユーザーが無料トライアル付きオファーの対象である場合に `true` を返す。 | true | | `is_pay_up_front` | ユーザーが一括払いオファーの対象である場合に `true` を返す。 | true | | `is_pay_as_you_go` | ユーザーが従量払いオファーの対象である場合に `true` を返す。 | true | :::tip `is_free_trial`、`is_pay_up_front`、`is_pay_as_you_go` を条件付き表示と組み合わせることで、ユーザーが対象となるオファーに応じて要素の表示・非表示を切り替えられます。たとえば、`is_free_trial` が `true` の場合のみ無料トライアルのタイムラインを表示する、といった使い方が可能です。 ::: オファー変数の値は、ユーザーが対象となるオファーの種類によって異なります。例として、週次サブスクリプション「Premium Subscription」($5)に3種類のオファーがある場合を見てみましょう。 - **Pay As You Go**: 最初の3週間は3ドル(週ごとに請求)、その後は週5ドル。 - **Pay Up Front**: 最初の3週間は8ドル(即時請求)、その後は週5ドル。 - **Free Trial**: 最初の1週間無料、その後は週5ドル。 この例では、`prod_title` は「Premium Subscription」を返し、`prod_price` は5ドルを返します。オファー変数の値は、ユーザーが対象となるオファーによって異なります: | 変数 | Pay As You Go | Pay Upfront | Free Trial | | :--- | :--- | :--- | :--- | | `offer_price` | $3 | $8 | $0 | | `offer_billing_period` | 1週間 | 3週間 | 1週間 | | `offer_full_duration` | 3週間 | 3週間 | 1週間 | Pay Upfront および Free Trial オファーの場合、`offer_billing_period` と `offer_full_duration` は同じ値を返します。Pay As You Go の場合、請求期間は1週間ですが全期間は3週間となるため、両者の値は異なります。 :::note オファーの詳細や設定方法については、[オファー](offers)をご覧ください。 ::: ## 要素変数 \{#element-variables\} 要素変数は、ユーザーの選択内容(クイズでの選択、現在のタブ、トライアルトグルのオン/オフなど)を記録します。 要素変数のタイプはグループによって異なります: - **単一選択(Single choice)**: 単一選択クイズとタブ: - `selected_id`: 条件で使用する要素ID - `selected_title`: 動的テキストで使用する要素タイトル - **複数選択(Multi-choice)**: 複数選択クイズ: - `selected_ids`: 条件で使用する要素IDのリスト - `selected_titles`: 動的テキストで使用する要素タイトルのリスト - **トグル(Toggle)**: トライアルトグル: - `is_selected`: Boolean値 よくあるユースケースとしては、以下のようなものがあります: - トライアルトグルが有効かどうかに応じて異なるコンテンツを表示する。 - クイズの回答に基づいて[ユーザーを異なる画面に誘導する](onboarding-navigation-branching) ## テキストに変数を使用する \{#use-variables-in-text\} テキスト要素に変数を挿入するには: 1. キャンバス上のテキスト要素を選択します。 2. **Design** タブで **Content** フィールドを見つけ、テキストを入力します。 3. フィールド内の **{ }** アイコンをクリックします。 4. リストから変数を選択します。 :::tip 変数は他の要素でも使用できます: - リンクやアラートに変数を使って動的にする - 変数に基づいた動的な条件を作成する。例えば、`if experience.current > experience.target, navigate to...` のような条件が作れます ::: ### スタイル変数 \{#style-variables\} 変数単体にリッチテキスト書式を適用することはできません。**Content** フィールドで変数を選択して太字、斜体、下線、取り消し線、色の変更を適用しても、効果はありません。 リッチテキストの設定はテキストブロック全体にのみ適用されます。テキストにスタイルを設定するには、**Design** タブの **Typography** セクションを使用するか、保存済みの[テキストスタイル](onboarding-text#set-up-text-styles)を適用してください。 ### フロー内でコンテンツを再利用する \{#reuse-content-across-screens\} ボタンのラベル「Continue」、繰り返し使うコール・トゥ・アクション、複数の画面に表示する免責事項など、フロー内で同じコンテンツが何度も登場することがあります。機能説明のような長めのテキストを複数の画面で使い回す場合も同様です。各要素にいちいち入力する代わりに、カスタム変数に保存しておきましょう。ユーザーによって異なる画面に誘導する場合でも、表示される文言を統一できます。 1. [カスタム変数を作成](#create-a-custom-variable)して、タイプを String に設定し、初期値に再利用したいテキストを入力します。たとえば、変数名を `button.navigation`、値を `Continue` にします。 2. テキストを表示したい各要素の **Content** フィールドにこの変数を挿入します。 テキストをすべての箇所で変更するには、変数の初期値を一度更新するだけです。その変数を使用しているすべての要素が自動的に更新されるため、各画面を手作業で編集する必要はありません。 --- # File: onboarding-element-visibility --- --- title: "条件付き表示" description: "条件に基づいて要素を表示または非表示にします。" --- <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/3w3YSOmI3tQ?si=vPhoQGt44SI285Ru" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> 条件を追加することで、要素の表示・非表示を制御できます。条件付き要素は、指定した条件を満たすユーザーにのみ表示されます。 :::important **Show** または **Hide** [アクション](onboarding-actions) を使って要素を表示・非表示にした場合、そのアクションはその要素に設定された **Visibility** 条件を上書きします。 固定の基準に基づいて常に表示または非表示にする要素には **Visibility** 条件を使用してください。ユーザーの操作に応じて表示状態が変わる場合(例:ユーザーがクイズに回答した後にボタンを表示するなど)にはアクションを使用してください。 ::: 要素に条件を追加するには: 1. キャンバスまたはレイヤーパネルで要素を選択します。 2. 右パネルの **Visibility** セクションで、**Conditional** を選択します。 3. 3つのタブからプロパティタイプを選択して条件を設定します: - **Custom**:自分で作成・管理する変数で、ユーザーの操作によって値を更新できます。詳細は[変数](onboarding-variables)を参照してください。 - **Products**:価格や名前など、フロー内のプロダクトのプロパティです。 - **Elements**:トライアルトグルがオンかどうかなど、フロー内の他の要素の状態です。 4. 照合する**Value**を入力します。 5. 必要に応じてオペレーターをクリックして変更します。 6. (任意)**Add condition**をクリックして条件を追加します。セレクターを使って、すべての条件を満たす必要があるか、いずれか1つを満たせばよいかを設定します。 --- # File: paywall-dark-mode --- --- title: "ダークモード" description: "Adaptyのフローにダークモードを設定して、ユーザー体験を向上させる方法を説明します。" --- Adapty のフローはダークモードをデフォルトでサポートしています。カラースタイルにはライトとダークの2つのカラーが設定されており、スタイルを要素に適用すると、デバイスの現在のモードに応じて適切な値が自動的に使用されます。Adapty にはあらかじめ設定済みのカラースタイルが用意されており、独自のスタイルを作成することもできます。 ## カラースタイルを設定する \{#configure-color-styles\} 各**カラースタイル**では、ライトとダークのカラーをそれぞれ定義します。要素に名前付きスタイルを適用すると、2つのカラーが自動的に切り替わります。 カラースタイルは左側の **Style** > **Colors** で管理できます。 カラースタイルを追加するには: 1. **Style** > **Colors** で **Create style** をクリックします。 2. ライトとダークのカラーをそれぞれ選択します。 スタイルの名前を変更するには、スタイルの横にある **⋮** をクリックして **Rename** を選択します。 ## ステータスバーのテーマを設定する \{#set-the-status-bar-theme\} **Screen settings** パネルで **Status bar** が有効になっている場合、テーマを個別に設定できます。**Status bar theme** オプションから **Light**、**Dark**、または **Auto** を選択してください。 ## ライト&ダークモードをプレビューする \{#preview-light--dark-modes\} フローが各モードでどのように表示されるかを確認するには、プレビューエリア下部の太陽/月アイコンのトグルを使用します。 ## ダークモードを削除する \{#remove-dark-mode\} ダークモードのサポートを完全に削除するには、**Style** > **Colors** パネルで **⋮** > **Delete dark theme** をクリックします。 --- # File: add-paywall-locale-in-adapty-paywall-builder --- --- title: "フローの言語設定を追加する(フローBuilder)" description: "Adaptyのフローbuilderでローカライズされたコンテンツを追加し、ユーザーの言語で世界中にリーチしましょう。" --- フローをローカライズすると、複数の言語で利用できるようになります。フロービルダーでは、ローカライズは画面ごとに管理され、各画面には翻訳の進捗を確認できる完了率が表示されます。 :::tip 他の言語を追加する前に、デフォルトのロケールでフローの設定を完成させておきましょう。 ::: ## ローカライズの追加と設定 \{#add-and-set-up-localization\} 1. 左パネルで Localizations をクリックし、次に **Add locale** をクリックします。追加する言語を選択してください。 2. 追加した各ロケールは、ローカライズテーブルの列として表示され、デフォルト言語の値があらかじめ入力されています。 3. 未翻訳の項目だけに絞り込みたい場合は、左パネルの **Missing only** トグルをオンにします。テーブルが未翻訳の行だけを表示するようにフィルタリングされます。 ## 外部翻訳のためのエクスポートとインポート \{#export-and-import-for-external-translation\} ローカライズファイルをエクスポートして翻訳者と共有し、翻訳済みの結果をインポートできます。 上部のツールバーで **Import / Export** をクリックします。 ### エクスポートファイルの形式 \{#export-file-format\} エクスポートすると、翻訳可能な要素ごとに1行ずつ記録された `.tsv`(タブ区切り)ファイルが生成されます。列の内容は以下のとおりです: | 列 | 説明 | |--------|-------------| | `Screen` | その要素が属する画面(例:`Welcome`、`Quiz`) | | `Element` | 画面内の要素を示す自動生成の識別子。**Interactions** > **Element ID** で変更できます。 | | `Property` | プロパティの種類(例:`content`) | | `[default_locale]` | デフォルト言語コード(例:`en`) | | `[locale]` | 追加したロケールごとの列(例:`fr`、`es`) | 例: ``` Screen Element Property en fr es Welcome title content Turn words into art Transformez les mots en art Welcome subtitle content Create stunning images in seconds with AI Créez des images en quelques secondes Quiz quiz-title content What will you create? ``` :::note 未翻訳の行はロケール列を空白のままにしておいてください — Adapty は未翻訳として扱います。 ::: ### インポートファイルの要件 \{#import-file-requirements\} - **形式**:`.tsv`(タブ区切り値) - **ヘッダー**:`Screen`、`Element`、`Property`、および少なくとも1つのロケール列が必要です - **ロケール列名**:フローにすでに追加されているロケールコードと一致している必要があります。フローに存在しないロケールコードが含まれるファイルをインポートするとエラーになります。 - **部分インポート**:行の一部だけを含めることもできます。ファイルに含まれていない行は現在の値が保持されます。 ## 手動で翻訳する \{#translate-manually\} ローカライズテーブルの任意のセルに直接翻訳を入力することもできます。 特定の行を操作するには、コンテキストメニュー(**⋮**)を開いてください: - **Reset to default**:その行の翻訳をデフォルト言語の値に戻します。 ## ローカライズをプレビューする \{#preview-the-localization\} 翻訳を確認するには、フロービルダーでアクティブなロケールを切り替え、各画面を確認します。 --- # File: add-flow-remote-config-locale --- --- title: "リモートコンフィグでフローをローカライズする" description: "フローのリモートコンフィグにロケールを追加して、言語や地域ごとに異なる値を提供する方法を説明します。" --- フローのリモートコンフィグには、ロケールごとに個別の JSON ペイロードを持たせることができます。実行時に SDK はユーザーのロケールに一致するペイロードを返すため、新しいアプリバージョンをリリースすることなく、翻訳済みのテキスト、異なる画像、その他のロケール固有の値を提供できます。 ## ロケールを追加する \{#add-a-locale\} フローのリモートコンフィグにロケールを追加するには: 1. Flow Builder でフローを開きます。 2. 画面プレビュー上部のリモートコンフィグアイコンをクリックします。 3. エディタ上部の **Add locale** をクリックします。 4. ダイアログに入力します: - **Code**: ロケールコード(例: `en`、`fr`、`de`)。 - **Name**: 表示名(例: English、French)。 Adapty はロケール用の新しい列を JSON エディタに追加します。 ## ロケールごとに値を編集する \{#edit-values-per-locale\} 各ロケールの列は独自の JSON 形式のデータを受け付けます。列をまたいで同じキーを使い、各ロケールの値を翻訳してください。 たとえば、英語の列: ```json showLineNumbers { "title": "Try for free!", "cta": "Continue", "trial_days": 7 } ``` スペイン語の列: ```json showLineNumbers { "title": "¡Prueba gratis!", "cta": "Continuar", "trial_days": 7 } ``` 列は独立しており、一方を編集しても他方には影響しません。 ## アプリで一致するロケールを読み取る \{#read-the-matching-locale-in-your-app\} SDK は `AdaptyFlow.remoteConfigs` 上の各ロケールに対して 1 つの `AdaptyRemoteConfig` エントリを公開します。ユーザーのロケールに一致する `locale` を持つエントリを選び、その `dictionary` または `jsonString` を読み取って実行時に値を使用します。 ## ロケールをバックアップまたは移動する \{#back-up-or-move-locales\} エディタ上部の **Import/Export** メニューを使うと、リモートコンフィグのバックアップや、フロー間でのコピーができます。エクスポートされた JSON ファイルにはすべてのロケールのペイロードが含まれます。ファイル形式については[リモートコンフィグでフローをカスタマイズする](customize-flow-with-remote-config)を参照してください。 --- # File: customize-flow-with-remote-config --- --- title: "リモートコンフィグでフローをカスタマイズする" description: "リモートコンフィグの JSON ペイロードを使って、フロービルダーのフローをカスタマイズします。" --- :::important このガイドはフロービルダーのリモートコンフィグについて説明しています。フロービルダーを使わずに作成したクラシックなペイウォールについては、[リモートコンフィグでペイウォールをデザインする](customize-paywall-with-remote-config)を参照してください。 ::: リモートコンフィグを使うと、カスタム JSON ペイロードをストアし、SDK がランタイムで読み取れるようになります。新しいアプリリリースなしに、タイトル・画像・フォント・カラー・フィーチャーフラグといった値を設定するために活用できます。 ## リモートコンフィグの操作 \{#work-with-remote-config\} フローのリモートコンフィグを開くには、フローエディターのスクリーンプレビュー上部にある Remote Config アイコンをクリックします。 **JSON** ビューでは、JSON 形式のデータを自由に入力できます。エディターには、追加したロケールごとに 1 列ずつ表示されます。 :::warning リモートコンフィグに無効な JSON が含まれている場合、フローを**保存**することも**公開**することもできません。プレビューや公開をブロックする問題の完全なリストについては、[フローの保存と公開](builder-save-publish#troubleshooting)を参照してください。 ::: このデータには、後から SDK を通じて `AdaptyFlow` の `remoteConfigs` 配列としてアクセスできます。Adapty はロケールごとに 1 件の `AdaptyRemoteConfig` エントリを保存します。ユーザーのロケールに一致するエントリを選択し、パース済みの `dictionary` または生の `jsonString` を読み取ることで、実行時にフローを調整できます。リモートコンフィグの使用例をいくつか紹介します。 <Tabs> <TabItem value="Titles" label="タイトル" default> ```json showLineNumbers { "screen_title": "Today only: Subscribe, and get 7 days for free!" } # Test titles or other texts ``` </TabItem> <TabItem value="Images" label="画像"> ```json showLineNumbers { "background_image": "https://adapty.io/media/paywalls/bg1.webp" } # Test images on your flow ``` </TabItem> <TabItem value="Fonts" label="フォント"> ```json showLineNumbers { "font_family": "San Francisco", "font_size": 16 } # Test fonts ``` </TabItem> <TabItem value="Color" label="カラー"> ```json showLineNumbers { "subscribe_button_color": "purple" } # Test colors of buttons, texts etc. ``` </TabItem> <TabItem value="HTML" label="HTML"> ```json showLineNumbers { "photo_gallery": "https://adapty.io/media/paywalls/link-to-html-snippet.html" } # Any HTML code that can be displayed in the flow ``` </TabItem> <TabItem value="Soft/Hard Paywall" label="ソフト/ハードペイウォール"> ```json showLineNumbers { "hard_paywall": true } # By setting it to true, you disallow skipping the paywall without subscribing # You have to handle this logic in your app ``` </TabItem> <TabItem value="Translations" label="翻訳"> ```json showLineNumbers { "title": { "en": "Try for free!", "es": "¡Prueba gratis!", "ru": "Попробуй бесплатно!" } } ``` </TabItem> </Tabs> これらのパターンを自由に組み合わせたり、独自のキーを定義して、代替のコピー、レイアウト、または動作をテストしたりすることもできます。 次に、[プレースメントを作成](create-placement)してフローを追加します。その後、アプリ内でフローをレンダリングします:[iOS](present-remote-config-paywalls) または [Android](present-remote-config-paywalls-android)。 ## ロケールを追加する \{#add-a-locale\} フローをローカライズするには、エディター上部の **Add locale** をクリックしてロケールを選択します。 Adapty はそのロケール用の新しい列をエディターに追加します。各列は独立して編集できます。実行時には、SDK がユーザーの選択に一致する `locale` を持つ `AdaptyRemoteConfig` エントリを返します。 ## JSON のインポートとエクスポート \{#import-and-export-json\} エディター上部の **Import/Export** メニューを使うと、すべてのロケールのリモートコンフィグをまとめてバックアップ・共有・一括編集できます。 - **Export JSON**: すべてのロケールを含む JSON ファイルをダウンロードします。 - **Import JSON**: 同じ形式の JSON ファイルをアップロードします。アップロードしたファイルで現在のリモートコンフィグが置き換えられます。 ファイルはロケールコードをトップレベルのキーとし、各ロケールのペイロードを値として使用します: ```json showLineNumbers { "en": { "title": "Get Premium", "cta": "Continue", "trial_days": 7, "features": ["sync", "export", "ai"] }, "fr": { "title": "Passez à Premium", "cta": "Continuer", "trial_days": 7, "features": ["synchronisation", "exportation", "IA"] } } ``` 各ロケールブロックは、ロケール列に直接入力するのと同じ JSON 構造に従っています。 --- # File: paywall-device-compatibility-preview --- --- title: "フローのプレビュー" description: "最適なエクスペリエンスを実現するため、デバイス間でのフローの互換性をプレビューします。" --- フローをさまざまな画面タイプでプレビューする方法は2つあります。 - **デバイスでのプレビュー**: 開発のどの段階でも、実機でフローの見え方を確認できます。 - **Adapty ダッシュボードでのプレビュー**: デザイン中にフローをプレビューできます。 ## デバイスでのプレビュー \{#preview-on-devices\} 実機でフローをプレビューするには: 1. [App Store から Adapty アプリをダウンロードします](https://apps.apple.com/us/app/adapty/id6739359219)。 2. フロービルダーで **Test on device** をクリックします。 3. フローのロケールを選択します。 4. デバイスのカメラで QR コードをスキャンするか、リンクを開きます。これにより、Adapty モバイルアプリでフローが開きます。 :::note テストモードでは、Adapty はストア内のプロダクトにアクセスできないため、フローに表示される価格は実際のものではありません。 ::: ### トラブルシューティング \{#troubleshooting\} 以下のいずれかの問題がある場合、フローを公開またはプレビューすることはできません。 - 設定が不完全なインタラクション。よくある例: - ターゲットURLが設定されていない **Open URL** アクション。 - 遷移先が設定されていない **Navigate to screen** アクション — アクション設定後に遷移先のスクリーンが削除された場合も発生します。 - 演算子または値が設定されていない **conditional action**。 - 変数や値の割り当てがない **Set Variable** アクション。 - プロダクトが未設定(アプリ内ストア)またはWeb Paywall URLが未設定(Web決済)の **Purchase** アクション。 - Action IDが設定されていない **Custom** アクション。 - タイトルまたはメッセージが空の **Show alert** アクション。 - 要素が選択されていない **Show** または **Hide** アクション。 - **要素のないスクリーン**。 - **プロダクトが紐付けられていない**プロダクト要素 — 参照しているプロダクトを削除した場合に発生することがあります。 - 無効な**リモートコンフィグ**のJSONはデリバリープロセス全体を破壊します — ドラフトの保存さえできなくなります。 ## Adapty ダッシュボードでのプレビュー \{#preview-in-the-adapty-dashboard\} :::tip フローが公開の準備ができているか確認するには、[実機でプレビュー](#preview-on-devices)してエラーなく表示されることを確認してください。 ::: フロービルダーのプレビューエリアを使って、さまざまな画面タイプでフローをプレビューできます。これにより、さまざまなデバイスや画面サイズでフローが適切に表示されることを確認できます。 プレビュー下のコントロールを使うと、次のことができます。 - プレビューするデバイスを選択する。 - 横向きと縦向きのプレビューモードを切り替える。 - ライトモードとダークモードを切り替える。 - ロケールを切り替える。 :::tip - 言語によって単語の長さが異なり、画面レイアウトが変わることがあるため、必ず各ロケールをプレビューしてください。 - カスタム変数をプレビューするには、初期値を設定してください。たとえば、`name` 変数を追加した場合、初期値を `Jane Doe` に設定してプレビューできます。 ::: --- # File: builder-save-publish --- --- title: "フローの保存と公開" description: "フローをドラフトとして保存し、ユーザーに公開する" --- [フロービルダー](adapty-flow-builder)では、保存と公開が分かれています。ドラフトは Adapty ダッシュボード上での作業内容を保持し、公開すると現在のバージョンが SDK を通じてユーザーに提供されます。この記事では、両方の操作とその使い分けについて説明します。 ## フローをドラフトとして保存する \{#save-a-flow-as-a-draft\} :::warning 無効な[リモートコンフィグ](customize-flow-with-remote-config)がある場合、ドラフトを保存できません。 ::: フロービルダーは1分ごとに進行状況を自動保存します。 手動でドラフトを保存するには、フロービルダーの右上にある **Save draft** をクリックするか、**Cmd/Ctrl + S** を押してください。 ドラフトはダッシュボード内でのみ有効です。フローがすでに[プレースメント](placements)に割り当てられている場合でも、ユーザーがアプリで見る内容には影響しません。 ## フローを公開する \{#publish-a-flow\} 公開すると、フローの現在のバージョンが SDK を通じてユーザーに提供されます。公開後は、同じフローの以前に公開されたバージョンが新しいバージョンに置き換えられます。 :::note フローを[プレースメント](placements)に追加するには、先に公開する必要があります。ドラフト状態のフローは追加できません。 ::: フローを公開するには、ペイウォールビルダー右上の **Publish to Live** をクリックしてください。 次に何が起こるかは、フローがすでにプレースメントに割り当てられているかどうかによって異なります。 - **フローがすでにプレースメントにある場合**: 次回そのプレースメントへのリクエスト時から、ユーザーには新しいバージョンが表示されます。 - **フローがプレースメントにない場合**: フローを[プレースメント](create-placement)に追加して、ユーザーへの表示を開始してください。 :::tip すべてのアクション、スクリーン、プロダクト要素が完全に設定されると、フローを公開できる状態になります。よくある不備については[トラブルシューティング](#troubleshooting)をご覧ください。 ::: :::warning [カスタムフォント](using-custom-fonts-in-flow-builder)はフローに同梱されません。各フォントファイルをアプリバンドルに追加する必要があります。ファイルがない場合、ユーザーにはシステムのフォールバックが表示されます。 公開済みのフローで古いバージョンを壊さずにフォントを変更するには、フローを複製し、コピー側でフォントを変更してから、そのフォントを含むアプリバージョンを対象とする[オーディエンス](add-audience-paywall-ab-test)にコピーを割り当ててください。 ::: ## フローのステータス \{#flow-status\} 各フローには、フロー一覧にステータスが表示されます。ステータスは、フローの保存・公開ライフサイクルにおける現在の状態を示します。 | ステータス | 意味 | | :----- | :------ | | **Draft** | フローはまだ一度も公開されていません。ドラフトのみが存在するため、ユーザーにはまだ表示されません。[プレースメント](placements)に追加するには、まずドラフトを公開する必要があります。 | | **Dirty** | フローは公開済みですが、まだ公開されていない保存済みの編集があります。再度公開するまで、ユーザーには最後に公開されたバージョンが表示されます。 | | **Publishing** | 公開処理が進行中です。 | | **Failed** | 最後の公開試行が失敗しました。公開済みのバージョンがある場合、ユーザーには引き続きそのバージョンが表示されます。 | | **Published** | 最新の保存済みバージョンが公開されています。未公開の編集はありません。 | | **Archived** | フローは削除されました。 | ## トラブルシューティング \{#troubleshooting\} 以下のいずれかの問題がある場合、フローを公開またはプレビューすることはできません。 - 設定が不完全なインタラクション。よくある例: - ターゲットURLが設定されていない **Open URL** アクション。 - 遷移先が設定されていない **Navigate to screen** アクション — アクション設定後に遷移先のスクリーンが削除された場合も発生します。 - 演算子または値が設定されていない **conditional action**。 - 変数や値の割り当てがない **Set Variable** アクション。 - プロダクトが未設定(アプリ内ストア)またはWeb Paywall URLが未設定(Web決済)の **Purchase** アクション。 - Action IDが設定されていない **Custom** アクション。 - タイトルまたはメッセージが空の **Show alert** アクション。 - 要素が選択されていない **Show** または **Hide** アクション。 - **要素のないスクリーン**。 - **プロダクトが紐付けられていない**プロダクト要素 — 参照しているプロダクトを削除した場合に発生することがあります。 - 無効な**リモートコンフィグ**のJSONはデリバリープロセス全体を破壊します — ドラフトの保存さえできなくなります。 公開前に問題を確認するには、[Adapty アプリ](paywall-device-compatibility-preview)でフローをプレビューしてください。プレビューでフローが読み込めない場合は、エラーメッセージで詳細を確認してください。 --- # File: flow-metrics --- --- title: "フローの指標" description: "フローのパフォーマンス指標を追跡・分析して、サブスクリプション収益を改善しましょう。" --- Adapty はフローのパフォーマンスを測定するための各種指標を収集しています。ペイウォールの指標とは異なり、フロー指標にはコンプリーション(完了)トラッキングが含まれているため、フローの各画面でユーザーがどこで離脱しているかを把握できます。ビューは数分ごとに更新されますが、それ以外の指標はリアルタイムで更新されます。このドキュメントでは、利用可能な指標の概要、定義、および計算方法について説明します。 :::important フローの収益は、フローが表示された後に発生したすべてのトランザクションから計算されます。 ::: フロー指標はフロー一覧ページで確認でき、すべてのフローのパフォーマンスの概要を提供します。この統合ビューでは、各フローの集計指標が表示され、効果を比較して改善点を特定できます。 各フローのより詳細な分析を行うには、フロー詳細指標に移動してください。選択したフローに特有の包括的な指標が表示され、パフォーマンスを深く把握できます。 ## 指標のコントロール \{#metrics-controls\} システムは選択した期間に基づいて指標を表示し、左側の列のパラメーターに従って3段階のインデントレベルで整理します。 公開済みフローの指標は、フローの公開日から現在の日付までの期間をカバーします。下書きおよびアーカイブ済みのフローも指標テーブルに含まれますが、データがない場合は指標が表示されません。 ### 指標データの表示オプション \{#view-options-for-metrics-data\} フローページでは、指標データに対して2つの表示オプションが用意されています。 - プレースメント別表示:フローに関連付けられた[プレースメント](placements)ごとに指標がグループ化されます。同じフローが異なるプレースメントでどのようなパフォーマンスを発揮しているかを比較する際に使用します。 - オーディエンス別表示:フローのターゲット[オーディエンス](audience)ごとに指標がグループ化されます。異なるオーディエンスセグメントに特有の指標を評価する際に使用します。 フローページ上部のドロップダウンで、希望する表示方法を選択できます。 ### インストール日で指標をフィルタリング \{#filter-metrics-by-install-date\} **Filter metrics by install date** チェックボックスを使用すると、トランザクションやビューが発生した日時ではなく、ユーザーがアプリをインストールした日時に基づいてデータを分析できます。特定のコホートのユーザー獲得パフォーマンスを測定する際に便利です。 ### 期間の設定 \{#time-ranges\} 時間範囲を使用して指標データを分析でき、日・週・月・カスタム日付範囲などの特定の期間に絞り込むことができます。 ### フィルターとグループ \{#filters-and-groups\} Adapty はニーズに合わせた指標分析のフィルタリングとカスタマイズツールを提供しています。指標ページでは、さまざまな時間範囲、グループ化オプション、フィルタリング機能を利用できます。 - フィルター項目:アトリビューション(ソース、広告グループ、広告セット、クリエイティブ、キャンペーン)、国、ストア。 - グループ項目:フロー(デフォルト)、国、またはストア。グループ化オプションは、そのディメンションにデータがある場合にのみドロップダウンに表示されます。たとえば、すべてのフロービューが単一の国からの場合、「国」は表示されません。 利用可能なコントロール、フィルター、グループ化オプション、およびその使用方法の詳細については、[こちらのドキュメント](controls-filters-grouping-compare-proceeds)をご参照ください。 ### 単一指標チャート \{#single-metric-chart\} チャートセクションでは、データをシンプルな棒グラフで表示します。チャートを使うと次の情報をすばやく確認できます。 - 各指標の正確な数値。 - 期間ごとのデータ。 チャートの横には合計値が表示され、全体像を一目で把握できます。 矢印アイコンをクリックするとチャートを拡大できます。 ### 指標の合計サマリー \{#total-metrics-summary\} 単一指標チャートの横には、指標の合計サマリーセクションがあります。このセクションでは、特定の時点での選択した指標の累計値が表示されます。ドロップダウンメニューを使って表示する指標を変更できます。 ## 指標の定義 \{#metrics-definitions\} ### ビューとユニークビュー \{#views--unique-views\} **ビュー**は、ユーザーがフローを開始した(最初の画面に到達した)回数をカウントします。同じユーザーが2回開始した場合、ビューは2としてカウントされますが、ユニークビューは1となります。この指標は、フローが表示された頻度を把握するのに役立ちます。 ### コンプリーションとユニークコンプリーション \{#completions--unique-completions\} **コンプリーション**は、ユーザーがフローの最後の画面に到達した回数をカウントします。同じユーザーが2回完了した場合、コンプリーションは2としてカウントされますが、ユニークコンプリーションは1となります。 ### ユニーク完了率 \{#unique-completions-rate\} ユニーク完了数をユニーク表示数で割った値です。この指標を使って、ユーザーがフローをどのように進んでいるかを把握し、どこで離脱しているかを特定しましょう。 :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: ### 収益(Revenue) \{#revenue\} **収益(Revenue)** は、フローに紐づいた購入および更新からの総収益(USD)を表示します。これはApp Store / Google Play コミッションを含む、控除前の金額です。 ### 手取り収益(Proceeds) \{#proceeds\} [**手取り収益(Proceeds)**](analytics-cohorts#revenue-vs-proceeds) は、App Store / Google Play がコミッションを差し引いた後、税金控除前に受け取る金額を示します。 :::important アプリが手数料軽減プログラムに登録されている場合は Adapty にお知らせください。正確な計算のために、[アプリの設定](general)で[スモールビジネスプログラム](app-store-small-business-program)および[手数料軽減サービスプログラム](google-reduced-service-fee)のステータスを指定してください。 ::: ### 純手取り収益(Net proceeds) \{#net-proceeds\} ストアのコミッションと税金の両方が差し引かれた最終的な収益です。 ### ARPPU \{#arppu\} ARPPU は課金ユーザー1人あたりの平均収益です。総収益をユニーク課金ユーザー数で割って計算されます。例:$15,000 の収益 ÷ 1,000 人の課金ユーザー = ARPPU $15。 ### ARPU \{#arpu\} ARPU はフローを視聴したユーザー1人あたりの平均収益です。総収益をユニークビューアー数で割って計算されます。 ### ARPAS \{#arpas\} ARPAS はアクティブサブスクライバー1人あたりの平均収益です。総収益を、トライアルまたはサブスクリプションを有効化したサブスクライバー数で割って計算されます。例:$5,000 の収益 ÷ 1,000 人のサブスクライバー = ARPAS $5。 ### CR purchases と Unique CR purchases \{#cr-purchases--unique-cr-purchases\} **購入へのコンバージョン率**は、フローのビューのうち何パーセントが購入につながったかを示します。例:100 ビューから 10 件の購入 = 10% のコンバージョン率。 **Unique CR purchases** は、フローを視聴したユニークユーザーのうち何パーセントが購入を行ったかを測定します。ユーザーが何度視聴しても1回としてカウントされます。 ### CR trials と Unique CR trials \{#cr-trials--unique-cr-trials\} **トライアルへのコンバージョン率**は、フローのビューのうち何パーセントがトライアル開始につながったかを示します。例:100 ビューから 10 件のトライアル = 10% のコンバージョン率。 **Unique CR trials** は、フローを視聴したユニークユーザーのうち何パーセントがトライアルを開始したかを測定します。ユーザーが何度視聴しても1回としてカウントされます。 ### 購入(Purchases) \{#purchases\} **購入(Purchases)** は更新を除く、フローでのすべてのトランザクションをカウントします。対象は以下のとおりです。 - 新規直接購入。 - フローで有効化されたトライアルのコンバージョン。 - プラン変更(アップグレード、ダウングレード、クロスグレード)。 - フローでのサブスクリプション復元(自動更新なしで期限切れになった後に再開した場合など)。 この指標は、フローからの新規トランザクションの全体像を把握するのに役立ちます。 ### トライアル(Trials) \{#trials\} **トライアル(Trials)** は、フローを通じて無料トライアル期間を開始したユーザー数をカウントします。この指標を使用して、トライアルオファーが有料化前にどれだけのユーザーを引き付けているかを追跡できます。 ### キャンセルされたトライアル(Trials cancelled) \{#trials-cancelled\} **キャンセルされたトライアル(Trials cancelled)** は、トライアル期間中に自動更新をオフにしたユーザー数を示します。サービスを試した後、有料サブスクリプションへの継続を断ったユーザーの数を把握できます。 ### 返金(Refunds) \{#refunds\} **返金(Refunds)** は、理由を問わず返金が行われた購入およびサブスクリプションの件数をカウントします。 ### 返金率(Refund rate) \{#refund-rate\} **返金率(Refund rate)** は、初回購入のうち返金された割合を示します。例:1,000 件の初回購入から 5 件の返金 = 0.5% の返金率。更新はこの計算に含まれません。 --- # File: fallback-flows --- --- title: "フォールバックフロー" description: "デバイスがオフラインのときもフローを表示し続けるために、Adapty でローカルフォールバックフローを設定しましょう。" --- スムーズなユーザー体験を維持するために、[フロー](adapty-flow-builder)の**フォールバックバージョン**を設定することが重要です。 アプリケーションがフローをリクエストすると、Adapty SDK はサーバーに接続してその設定を取得します。デバイスが Adapty に到達できない場合(ネットワーク障害やサーバー障害など)、SDK はローカルデータにフォールバックします: - ユーザーがすでに一度フローを表示したことがある場合、SDK はキャッシュされたコピーを提供します。 - キャッシュが存在しない場合、SDK はアプリにバンドルされたフォールバック設定ファイルを読み込みます。 Adapty はこれらのフォールバックファイルを自動的に生成します。フローのフォールバックバンドルはペイウォールと共有されており、プラットフォームごとに 1 つの JSON ファイルに両方のフォールバックバリアントが含まれています。SDK は必要なセクションを読み取ります。 :::important フローのフォールバックは **Adapty SDK 4.0以上** のバンドルに含まれています。ダウンロードダイアログで以前のSDKバージョンを選択した場合、ファイルにはペイウォールとオンボーディングのバリエーションのみが含まれ、フローは含まれません。フローのフォールバックを使用する前に、アプリがフロー対応のSDKリリースを使用していることを確認してください。 ::: ## 始める前に \{#before-you-start\} 1. フロービルダーで[フロー](adapty-flow-builder)を作成します。 2. フロー用の[プレースメントを作成](create-placement)します。 ## フォールバックファイルのダウンロード \{#download-the-fallback-file\} 1. **[Placements](https://app.adapty.io/placements)** ページを開きます。 2. 右上の **Fallbacks** ボタンをクリックします。 3. ドロップダウンからターゲットプラットフォームを選択します。 4. アプリに組み込まれているSDKのバージョンに合ったSDKバージョンを選択します。フローを含むバンドルを受け取るには、**Adapty SDK v4.0.0 and higher**(またはそれ以降のオプション)を選択してください。 ブラウザがプラットフォームごとにJSONファイルをダウンロードします。例:`ios_4_0_0_fallback.json` <details> <summary>フローフォールバックエントリの例(クリックして展開)</summary> ```json "PLACEMENT_ID": { "data": [ { "developer_id": "PLACEMENT_ID", "variation_id": "cb1c0ef8-aecd-4a53-a6f3-b98266e66884", "flow_id": "daf25858-3fa2-4981-8500-9c8a30e5b7e6", "flow_name": "FLOW_NAME", "flow_version_id": "FLOW_VERSION_ID", "placement_audience_version_id": "a9eb3ab8-3178-477d-84d4-ef9d3978e48b", "audience_name": "All Users", "ab_test_name": "", "cross_placement_info": null, "weight": 100, "variations": [ { "variation_id": "cb1c0ef8-aecd-4a53-a6f3-b98266e66884", "paywall_id": "PAYWALL_ID", "paywall_name": "PAYWALL_NAME", "ab_test_name": "", "products": [], "revision": 1, "custom_payload": null, "weight": 100 } ], "remote_configs": [] } ], "meta": { "placement": { "developer_id": "PLACEMENT_ID", "is_tracking_purchases": true, "audience_name": "All Users", "placement_audience_version_id": "a9eb3ab8-3178-477d-84d4-ef9d3978e48b", "revision": 0, "ab_test_name": "" } } } ``` SDKのバージョンによって正確な形式は異なる場合があります。手動で作成するのではなく、常に使用しているSDKバージョン向けにAdaptyが生成したファイルを使用してください。 </details> ## ダウンロード後の作業 \{#after-the-download\} ファイルをアプリのコードに追加したら、各プラットフォームのセットアップガイドに従ってください。ペイウォールのフォールバックを読み込む API は、アプリがフロー対応の SDK バージョンに移行した後、フローのフォールバックも同様に読み込みます。 - [iOS](ios-use-fallback-paywalls) - [Android](android-use-fallback-paywalls) - [React Native](react-native-use-fallback-paywalls) - [Capacitor](capacitor-use-fallback-paywalls) ## 制限事項 \{#limitations\} フォールバックフローはハードコードされてローカルに保存されるため、ライブフローの完全な動的機能は利用できません。 - **プレースメントごとに1つのバリアント。** プレースメントに複数のフロー(異なるオーディエンス、A/B テストのバリアント)がある場合、フォールバックファイルはウェイトが最も高いバリアント、または最も広いオーディエンスのバリアントを使用します。 - **A/B テストなし。** ライブフローの A/B テストはサーバー側で解決されます。フォールバックは常に1つの選択されたバリアントを提供します。 - **リモート更新なし。** フォールバックの更新には新しいアプリリリースが必要です。リモートコンフィグで行うような実行時の更新は、代わりにライブフロー経由で行ってください。 - **デフォルトロケールのみ。** フォールバックは `en` ロケールを使用します。ローカライズされたバリアントはバンドルされません。 --- # File: create-product --- --- title: "プロダクトを作成する" description: "Adapty で新しいサブスクリプションプロダクトを作成するためのステップバイステップガイド。収益管理を効率化できます。" --- Adapty でのプロダクト作成方法は、ストアにすでにプロダクトが存在するかどうかによって異なります。 - **[App Store や Google Play にプロダクトがまだない場合は、Adapty でプロダクトを作成してストアに直接プッシュする](#create-product-and-push-to-store)** - **[App Store や Google Play にすでにプロダクトがある場合は、Adapty でプロダクトを作成して既存のストアプロダクトに接続する](#create-product-and-connect-existing-store-products)** :::tip [Developer CLI](developer-cli-reference#adapty-products-create) を使ってプログラムでプロダクトを作成することもできます。 ::: ## プロダクトを作成してストアにプッシュする \{#create-product-and-push-to-store\} :::warning 始める前に、必要なストアとのインテグレーションが設定済みであることを確認してください。 - [App Store](initial_ios) - [Google Play](initial-android) App Store のインテグレーションを以前に設定した場合は、[App Store Connect API キーの追加](app-store-connection-configuration#step-6-add-app-store-connect-api-key)も完了しているかご確認ください。 ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/qUpC2XG-r5E?si=7Komyv4_PUQ4FaEH" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> アプリに新しいプロダクトを追加するには: 1. Adapty のメインメニューから **[Products](https://app.adapty.io/products)** に移動します。 <img src="/assets/shared/img/products-tab.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 右上の **Create product** をクリックします。Adapty はサブスクリプション、非消耗型(永続アクセスを含む)、消耗型アイテムなど、すべてのプロダクトタイプに対応しています。 3. **Create a new product and push to stores** を選択します。 <img src="/assets/shared/img/push-to-stores.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 以下の情報を入力します。 - **Product name**: Adapty ダッシュボードで使用するプロダクト名を入力します。この名前は主に管理用ですので、Adapty ダッシュボード全体で使いやすい名前を自由に選んでください。 - **Access Level**: プロダクトが属する[アクセスレベル](access-level)を選択します。アクセスレベルは、プロダクトを購入した後に解放される機能を決定します。このリストには、事前に作成されたアクセスレベルのみ表示されます。`premium` アクセスレベルは Adapty でデフォルトで作成されていますが、[アクセスレベルを追加する](access-level)こともできます。 - **Subscription duration**: リストからサブスクリプションの期間を選択します。 - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**: サブスクリプションの期間。 - **Lifetime**: アプリのプレミアム機能を永続的に解放するプロダクトには、永続期間を使用します。 - **Non-Subscriptions**: サブスクリプションではなく、期間のないプロダクトには Non-Subscriptions を使用します。追加機能や消耗型プロダクトなどに利用できます。 - **Consumables**: 消耗型アイテムは複数回購入できます。アプリのライフサイクル中に使い切るものです。ゲーム内通貨や追加アイテムが例として挙げられます。消耗型プロダクトはアクセスレベルに影響しないことに注意してください。買い切り購入でアクセスレベルを付与するには、**Non-Subscriptions** を使用してください。 - **Price (USD)**: プロダクトの USD 価格です。この価格を基準に、全国の価格が自動的に計算・設定されます。後から[国や地域ごとに価格をカスタマイズ](edit-product#set-country-specific-prices)することもできます。 <img src="/assets/shared/img/create-product-push.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Save & Continue** をクリックします。 6. App Store に公開する予定がある場合は、App Store 向けのプロダクト情報を設定します。 - **Product ID**: プロダクトの恒久的なユニーク ID を作成します。 - **Product group**: App Store Connect で作成した既存のプロダクトグループを選択するか、**Create new Product Group** をクリックしてグループ名を設定します。Adapty がグループを作成した後、ドロップダウンから選択できます。 - **Screenshot**: 提供するアイテムやサービスが明確に表示されているアプリ内課金のスクリーンショットをアップロードします。このスクリーンショットは App Store の審査にのみ使用され、App Store 上には表示されません。スクリーンショットのサイズとフォーマットの要件は[こちら](https://developer.apple.com/help/app-store-connect/reference/app-information/screenshot-specifications/)をご確認ください。 <img src="/assets/shared/img/push-app-store.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. **Push data to App Store** をクリックします。 :::warning このアプリで初めてのプロダクトの場合は、App Store Connect で手動で審査に提出する必要があります。これは初回のみ必要です。審査が完了すると、Adapty 上のプロダクトのステータスは自動的に更新されます。 ::: 8. Google Play に公開する予定がある場合は、Google Play 向けのプロダクト情報を設定します。 - **Base Product ID**: プロダクトの恒久的なユニーク ID を作成します。 - **Subscription**: Google Play Console で作成した既存のサブスクリプショングループを選択するか、**Create new Product Group** をクリックしてグループ名と ID を設定します。Adapty がグループを作成した後、ドロップダウンから選択できます。 :::note グレース期間とアカウント保留期間は、Play Store のルールに従ってデフォルト値が自動設定されます。後から Google Play Console で変更できます。 ::: <img src="/assets/shared/img/push-google-play.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. **Push data to Play Store** をクリックします。 10. iOS の場合は、ドロップダウンから **Free duration** を選択して初回オファー(無料トライアル)を設定します。この初期設定では無料トライアルの初回オファーを追加できます。メインプロダクトがストアの審査に通過したら、ストアコンソールの既存 ID を紐付けることで[さらにオファーを追加](offers)(プロモーションオファーやウィンバックオファーなど)できます。 <img src="/assets/shared/img/intro.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important 初回オファーは Google Play と自動的に同期されません。App Store とは異なり、Google Play には「初回オファー」という独立したタイプがありません。無料トライアルや割引オファーはすべて、ベースプランの**オファー**として設定します。[Google Play Console でオファーを作成し、Adapty プロダクトに紐付けてください](google-play-offers)。 ::: 11. 最後に **Save** をクリックしてプロダクトの作成を確定します。 ## プロダクトを作成して既存のストアプロダクトに接続する \{#create-product-and-connect-existing-store-products\} :::warning 始める前に、以下を確認してください。 - 必要なストアとのインテグレーションが設定済みであること: - [App Store](initial_ios) - [Google Play](initial-android) - 必要なストアでプロダクトが作成済みであること: - [App Store](app-store-products) - [Google Play](android-products) **プロダクトをまだ作成していない場合**は、[ストアへのプッシュ](#create-product-and-push-to-store)ガイドに従って、Adapty とストアの両方に同時に作成することをおすすめします。 ::: <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/nlkdKCF0SwY?si=VVigzHcpv3waKJmI" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> アプリに新しいプロダクトを追加するには: 1. Adapty のメインメニューから **[Products](https://app.adapty.io/products)** に移動します。 <img src="/assets/shared/img/products-tab.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 右上の **Create product** をクリックします。Adapty はサブスクリプション、非消耗型(永続アクセスを含む)、消耗型アイテムなど、すべてのプロダクトタイプに対応しています。 3. **Connect an existing store product** を選択します。 <img src="/assets/shared/img/existing-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 以下の情報を入力します。 - **Product name**: Adapty ダッシュボードで使用するプロダクト名を入力します。この名前は主に管理用ですので、Adapty ダッシュボード全体で使いやすい名前を自由に選んでください。 - **Access Level ID**: プロダクトが属する[アクセスレベル](access-level)を選択します。アクセスレベルは、プロダクトを購入した後に解放される機能を決定します。このリストには、事前に作成されたアクセスレベルのみ表示されます。`premium` アクセスレベルは Adapty でデフォルトで作成されていますが、[アクセスレベルを追加する](access-level)こともできます。 - **Subscription duration**: リストからサブスクリプションの期間を選択します。 - **Weekly/Monthly/2 Months/3 Months/6 Months/Annual**: サブスクリプションの期間。 - **Lifetime**: アプリのプレミアム機能を永続的に解放するプロダクトには、永続期間を使用します。 - **Non-Subscriptions**: サブスクリプションではなく、期間のないプロダクトには Non-Subscriptions を使用します。追加機能や消耗型プロダクトなどに利用できます。 - **Consumables**: 消耗型アイテムは複数回購入できます。アプリのライフサイクル中に使い切るものです。ゲーム内通貨や追加アイテムが例として挙げられます。消耗型プロダクトはアクセスレベルに影響しないことに注意してください。買い切り購入でアクセスレベルを付与するには、**Non-Subscriptions** を使用してください。 - **Price (USD)**: プロダクトの USD 価格です。プロダクトがすでにストアにある場合、この値はストアの実際の価格には影響しません。リストから任意の値を選択できます。後から Adapty ダッシュボード上で[地域ごとの価格をカスタマイズ](edit-product#set-country-specific-prices)することもできます。 <img src="/assets/shared/img/product-info.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Continue** をクリックします。 6. 各ストアのプロダクト情報を設定します。 - **App Store:** - **App Store Product ID:** デバイス上でプロダクトにアクセスするために使用する一意の識別子です。リストから選択してください。リストに表示されない場合は、App Store Connect での設定を確認し、正しくこのアプリに紐付けられているかご確認ください。 - **Play Store:** - **Google Play Product ID:** Play Store でのプロダクト識別子です。リストから選択してください。リストに表示されない場合は、Google Play Console での設定を確認し、正しくこのアプリに紐付けられているかご確認ください。 - **Base Plan ID:** Play Store でプロダクトのベースプランを定義するために使用する ID です。Play Store でサブスクリプションのプロダクト ID を追加する際は、ベースプラン ID の指定が必要です。ベースプランは、請求期間、更新タイプ(自動更新またはプリペイド)、および関連する価格を含むサブスクリプションの基本情報を定義します。Adapty では、同じサブスクリプションでも異なるベースプランの組み合わせはそれぞれ別のプロダクトとして扱われます。 - **Legacy fallback product**: フォールバックプロダクトは、古いバージョンの Adapty SDK(バージョン 2.5 以前)を使用するアプリ専用です。Google Play Console でプロダクトを後方互換としてマークすることで、Adapty は古い SDK バージョンで購入可能かどうかを識別できます。このフィールドには `<subscription_id>:<base_plan_id>` の形式で値を指定してください。 - **Stripe**: - **Stripe Product ID**: Stripe でのプロダクトの一意の識別子です。 - **Stripe Price ID**: Stripe の価格オブジェクトには価格金額だけでなく、税の扱い、ボリュームティア、サブスクリプション間隔なども含まれます。1 つのプロダクトに複数の価格を設定できるため、Adapty でプロダクトを作成する際は正しい価格 ID を指定してください。 - **Paddle**: - **Paddle Product ID**: Paddle でのプロダクトの一意の識別子です。 - **Paddle Price ID**: Paddle の価格オブジェクトには価格金額だけでなく、税の扱い、ボリュームティア、サブスクリプション間隔なども含まれます。1 つのプロダクトに複数の価格を設定できるため、Adapty でプロダクトを作成する際は正しい価格 ID を指定してください。 7. **オプション:** **Add custom store** をクリックすることで、任意のカスタムストアのプロダクトを追加できます。**Manage custom store info** ウィンドウでは、既存のカスタムストアを選択するか、新しいストアを追加してプロダクトと紐付けることができます。Adapty は App Store、Google Play、Stripe からのトランザクションのみを追跡することにご注意ください。カスタムストアの場合は、Adapty サーバーサイド API の Set transaction メソッドを使ってトランザクションを送信する必要があります。 8. **Save product** をクリックしてプロダクトの作成を完了します。プロダクトのステータス同期には最大 5 分かかる場合がありますので、テーブルに反映されるまでお待ちください。 9. 必要に応じて、プロダクトに[オファーを作成](create-offer)できます。オファーを追加するには **Yes, add offers** をクリックし、不要な場合は **No, thanks** をクリックします。 :::note 初回オファーは、プロダクトをストアにプッシュする際にのみ Adapty 上で作成されます。インポート時や既存のプロダクトの場合、初回オファーは同期されず Adapty には表示されませんが、アプリ内では正しく機能します。 ::: ## 次のステップ \{#next-steps\} おめでとうございます!Adapty にプロダクトを追加できました。次は何をしますか? - 初回オファーやプロモーションオファーをまだ設定していない場合は、今すぐ[設定](offers)できます。 - 設定済みの場合や後回しにする場合は、[ペイウォールの設定](quickstart-paywalls)に進んでアプリ内課金を有効にしましょう。 - ストアプロダクトの調整(地域別価格の設定やグレース期間の設定など)が必要な場合は、App Store Connect または Google Play Console で行ってください。 - 後から[プロダクトを編集する](edit-product)方法もご確認ください。 --- # File: edit-product --- --- title: "プロダクトの編集" description: "Adapty のサブスクリプションプロダクトを編集・管理して、収益トラッキングを改善しましょう。" --- Adapty では、プロダクトの名前、アクセスレベル、地域別価格、接続されているストア ID を編集したり、価格変更の履歴を追跡する監査ログを確認したりできます。サブスクリプションの期間はプロダクト作成後に変更できないため、変更が必要な場合は新しいプロダクトを作成してください。 :::warning プロダクトはどれでも編集できますが、すでに公開中のペイウォールで使用しているプロダクトを変更すると、アナリティクスに不整合が生じる可能性があります。 **アクセスレベル、App Store プロダクト ID、Play Store プロダクト ID の編集は推奨しません**。アナリティクスの精度に影響を与える恐れがあります。プロダクト ID のタイポなど、間違いを修正する場合に限り編集してください。 そのプロダクトをこれ以上使用しない場合は、新しいプロダクトを作成し、ペイウォールと A/B テストを更新することを強くお勧めします。 ::: ## プロダクトを編集する \{#edit-product\} プロダクトを編集するには: 1. Adapty のメインメニューから **[Products](https://app.adapty.io/products)** に移動します。 2. テーブル内のプロダクト行をクリックするか、プロダクトの横にある三点メニューをクリックして **Edit** を選択します。 3. 表示された **Edit** ウィンドウで必要な変更を加えます。このウィンドウのオプションについては、[プロダクトの作成](create-product)セクションをご覧ください。 4. **Save** をクリックします。 :::warning App Store Connect や Google Play Console で行った変更は Adapty に同期されません。Adapty に表示される価格はプロダクト作成時に設定されたものであり、ストアで価格を変更しても自動的に更新されません。 これは収益アナリティクスには影響しません。Adapty は収益データをストアから直接取得します。ダッシュボードの価格フィールドはあくまで参照用です。 ::: :::note アクセスレベルを変更した場合、その変更は新規サブスクリプションにのみ適用されます。既存のサブスクライバーは現在のアクセスレベルが維持され、次のサブスクリプション更新時に自動的に更新されます。 ::: <img src={require('./img/edit-product.png').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 国別価格を設定する \{#set-country-specific-prices\} Adapty ダッシュボード上で地域ごとに異なる価格を設定でき、その国別価格は App Store Connect や Google Play Console のプロダクトに自動的に反映されます。 国別価格を設定するには: 1. [編集用にプロダクトを開きます](#edit-product)。 2. **Download** をクリックして、ストアから正しい形式で現在の価格をエクスポートするか、新しい CSV ファイルを作成します。 <img src={require('./img/download-prices.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. CSV ファイルで価格を更新します。[フォーマット](#csv-file-format)に従ってください。ある国の価格を変更しないまま残したり、ファイルに含めなかったりした場合、何も変更されません。CSV をアップロードすると、Adapty は価格を比較して異なるものだけを更新します。 4. **Edit** ウィンドウで **Upload** をクリックし、CSV ファイルを選択します。 <img src={require('./img/upload-prices.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 既存のサブスクライバーにも変更を適用したい場合は、**Apply to existing subscribers** を選択します。 6. 適用される変更内容を確認して、**Save changes** をクリックします。 <img src={require('./img/country-level-price.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### CSV ファイルのフォーマット \{#csv-file-format\} :::tip 同じアプリに類似したプロダクトがある場合や、異なるアプリで同じ価格を設定したい場合は、同じ CSV ファイルを再利用できます。 ::: CSV で価格を編集する最も簡単な方法は、[現在の価格が含まれたファイルをダウンロードして直接編集する](#set-country-specific-prices)ことです。 ご自身で作成する場合は、ファイルに以下のカラムが必要です: - `region_name` - `region_code` - `app_store_currency` - `app_store_requested_price` - `play_store_currency` - `play_store_requested_price` 例: ``` region_name,region_code,app_store_currency,app_store_requested_price,play_store_currency,play_store_requested_price United States,US,,8.99,,8.99 United Arab Emirates,AE,USD,8.99,AED,39.99 Germany,DE,USD,8.99,USD,8.99 ``` ## 監査ログを確認する \{#view-audit-log\} Adapty は各プロダクトのすべての価格変更を記録しているため、誰がいつ変更を行ったかを追跡できます。監査ログを確認するには: 1. Adapty のメインメニューから **[Products](https://app.adapty.io/products)** に移動します。 2. プロダクトの横にある三点メニューをクリックして **Audit log** を選択します。 監査ログテーブルには、各価格変更の日付、チームメンバーの名前と役割、変更件数が表示されます。 イベントの詳細な CSV を取得するには、そのイベントの行にあるダウンロードアイコンをクリックします。 <img src={require('./img/audit-log.webp').default} style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: delete-product --- --- title: "プロダクトを削除する" description: "アプリの収益フローを妨げることなく、Adapty でサブスクリプションプロダクトを削除する方法をご確認ください。" --- 削除できるのは、ペイウォールで使用されていないプロダクトのみです。 プロダクトを削除するには: 1. Adapty メインメニューから **[Products](https://app.adapty.io/products)** に移動します。 2. プロダクトの横にある **3-dot** ボタンをクリックし、**Delete** を選択します。 <img src="/assets/shared/img/delete-product.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 削除しようとしているプロダクトの名前を入力します。 <img src="/assets/shared/img/b945add-delete_product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Delete forever** をクリックします。 --- # File: add-product-to-paywall --- --- title: "ペイウォールにプロダクトを追加する" description: "Adaptyのペイウォールにプロダクトを追加・管理する方法を説明します。" --- アプリのユーザーが[ペイウォール](paywalls)でプロダクトを表示・選択できるようにするには、以下の手順に従ってください。 1. [ペイウォールの設定](create-paywall)中に、**Products** タイトルの下にある **Add product** をクリックします。 2. 表示されるドロップダウンリストから、顧客に表示するプロダクトを選択します。リストには事前に作成済みのプロダクトのみ表示されます。プロダクトの順序はSDK側でそのまま反映されるため、ペイウォールを設定する際は表示順序を考慮することが重要です。また、必要に応じてプロダクトにオファーを指定することもできます。 <img src="/assets/shared/img/0479b51-ad_product_to_paywall.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ペイウォールのステータスに応じて、**Create as draft** または **Save and publish** をクリックします。 なお、ペイウォールを作成した後は、ペイウォールの指標に影響を与える可能性があるため、プロダクトの編集・追加・削除は推奨されません。 --- # File: virtual-currencies --- --- title: "仮想通貨" description: "Adaptyでアプリ内通貨を定義し、プロダクトにリンクして自動的にクレジットを付与し、すべてのユーザーの残高を追跡します。" --- <CustomDocCardList ids={['virtual-currency-quickstart', 'create-virtual-currency', 'virtual-currency-balance']} /> ユーザーがプロダクトを購入したりサブスクリプションを更新したりしたときに、AIトークン、クレジット、コインなどのバーチャル通貨を付与できます。通貨を一度定義してプロダクトに紐付けると、Adaptyが自動的に各ユーザーへ付与し、残高を管理します。アプリは[サーバーサイドAPI](getting-started-with-server-side-api)を通じてその残高を読み取ったり消費したりできます(たとえば、生成ごとにトークンを消費するといった用途に活用できます)。 ## 仕組み \{#how-it-works\} 1. [仮想通貨を作成する](create-virtual-currency): **Products** を開き、**Virtual currency** タブをクリックします。**New virtual currency** をクリックし、コード、名前、および任意の説明を入力して通貨を定義します。 2. **通貨をプロダクトに紐付ける**: 通貨を買い切りまたはサブスクリプションのプロダクトにマッピングし、各購入で付与されるクレジット数を設定します。 3. **クレジットは自動的に付与される**: ユーザーが紐付けられた買い切りプロダクトを購入するか、紐付けられたサブスクリプションが更新されると、Adapty は設定されたクレジットを残高に追加します。 4. **残高を読み取り、消費する**: アプリは各ユーザーの残高を読み取り、サーバーサイド API を通じてクレジットを付与または消費します。 5. **すべての変更を追跡する**: 残高の変更はすべて[ユーザーのプロファイル](virtual-currency-balance)に一覧表示されます。 通貨の設定からAPIを使ったクレジット消費まで、すべての手順を確認するには、[バーチャル通貨クイックスタート](virtual-currency-quickstart)を参照してください。 ## ユースケース \{#use-cases\} | アプリの種類 | バーチャル通貨の活用方法 | |----------|-------------------------------| | **AI アプリ**(画像・動画・テキスト生成) | 生成ごとにクレジットを消費。サブスクリプションに毎月のクレジット付与を含め、クレジットパックを買い切り商品として販売する。 | | **ショートドラマ・動画アプリ** | エピソードのアンロックにコインを消費。サブスクライバーには定期的なコイン付与を行い、コインパックを買い切り商品として販売する。 | | **語学学習・教育** | サーバーサイド API を通じて無料ユーザーにハートやライフの限定付与を行う。有料プランではより多く付与するか、残高チェック自体をスキップする。 | | **モバイルゲーム** | ソフト通貨とハード通貨を併用:サーバーサイド API でゲームプレイ報酬としてゴールドを付与し、ジェムは課金販売し、単一のアトミックトランザクションで相互交換できるようにする。 | | **生産性アプリ** | OCR やエクスポートなどコストの高い操作をクレジットで計量。無料ユーザーには少量を付与し、サブスクリプションではより多く付与し、まとめ作業向けにクレジットパックを販売する。 | :::tip サブスクリプションの利用枠には、[クレジットの有効期限](create-virtual-currency#link-products)を有効にしてください。未使用のクレジットが更新のたびにリセットされることで、利用枠がサブスクリプションを継続する動機になり、ヘビーユーザーはストックを使い切るのではなく、クレジットパックを購入するようになります。 ::: ## 制限事項 \{#limitations\} - **クロスデバイスのアクセスには識別が必要**: 残高は1つのプロファイルに紐づいています。匿名ユーザーは残高を獲得したデバイスにのみ残高が保持されるため、すべてのデバイスで残高を利用できるようにするにはユーザーを識別してください。詳しくは[残高、プロファイル、デバイス](virtual-currency-balance#balances-profiles-and-devices)を参照してください。 - **サーバーサイド専用**: 残高の読み取りや消費を行うSDKメソッドはまだ存在しないため、アプリにはバックエンドが必要です。バックエンドはサーバーサイドAPIを通じて残高の読み取りやクレジットの付与・消費を行います。 - **アプリごとに最大20通貨**: 1つのアプリに最大20種類のバーチャル通貨を作成できます。 --- # File: virtual-currency-quickstart --- --- title: "仮想通貨クイックスタート" description: "仮想通貨をエンドツーエンドでセットアップする:トークン通貨の作成、サブスクリプションによるトークン付与、サーバーサイドAPIを通じた消費。" --- :::link メイン記事: [仮想通貨](virtual-currencies) ::: このクイックスタートでは、トークン通貨をエンドツーエンドでセットアップします。サブスクリプションによってユーザーに毎月1000トークンが付与され、アプリ内の有料アクションでトークンを消費します。Adaptyがすべての残高を管理するため、バックエンドは残高の読み取りと消費のみを行います。 1. [仮想通貨を作成する](create-virtual-currency)ガイドに従って、`TOKENS`通貨を作成します。Proサブスクリプションにリンクし、**Credit per cycle**を1000に設定します。追加トークンを販売するには、買い切り型のトークンパックプロダクトもリンクします。 2. [仮想通貨残高の一覧を取得する](api-adapty/operations/listVirtualCurrencyBalances)を呼び出して、たとえばコンテンツ生成を開始する前にユーザーの残高を確認します。 ```bash title="Read balances" curl https://api.adapty.io/api/v2/server-side-api/vc/balances/ \ -H "Authorization: Api-Key {your secret key}" \ -H "adapty-customer-user-id: user-42" ``` レスポンスには、ユーザーが保有するすべての通貨が表示されます。たとえば `TOKENS` が 1000 の場合: ```json title="Response" { "data": [ { "code": "TOKENS", "name": "Tokens", "balance": 1000, "held": 0, "available": 1000 } ] } ``` 3. ユーザーが生成を実行したら、負の `amount` を指定して [仮想通貨トランザクションの作成](api-adapty/operations/createVirtualCurrencyTransaction) を呼び出してトークンを消費します。この例では、画像1枚の生成に100トークンかかります: ```bash title="Spend tokens" curl -X POST https://api.adapty.io/api/v2/server-side-api/vc/transactions/ \ -H "Authorization: Api-Key {your secret key}" \ -H "adapty-customer-user-id: user-42" \ -H "Content-Type: application/json" \ -d '{"items": [{"currency_code": "TOKENS", "amount": -100}]}' ``` トランザクションはアトミックで、更新後の残高を返します。ユーザーがコストを賄えない場合、リクエストは `insufficient_balance` を返し、何も変更されません。リクエストを安全に再試行するには、`Idempotency-Key` ヘッダーを含めてください。 4. ウィンバックプロモを実施するには、同じエンドポイントで正の `amount` を指定してトークンを付与します。この方法で付与したクレジットは有効期限がありません。 5. ユーザーの[プロファイル](virtual-currency-balance)や[トランザクション履歴](api-adapty/operations/listVirtualCurrencyTransactions)のすべての変更を確認することで、いつでもエコノミーを監査できます。 --- # File: create-virtual-currency --- --- title: "バーチャル通貨の作成" description: "Adaptyでバーチャル通貨を作成し、プロダクトにリンクして購入時にクレジットが付与されるよう設定します。また、クレジットの有効期限も設定できます。" --- :::link メイン記事:[バーチャル通貨](virtual-currencies) ::: バーチャル通貨のクレジットを販売するには、まずバーチャル通貨を一度定義し、プロダクトにリンクします。 この記事で説明する2つのステップで設定します。プロダクトをリンクすると、購入または更新のたびに自動的にクレジットが付与されます。 ## バーチャル通貨を作成する \{#create-a-virtual-currency\} Adapty ダッシュボードで **Products** > [**Virtual currency**](https://app.adapty.io/virtual-currency) を開きます。 バーチャル通貨を作成するには: 1. **New virtual currency** をクリックします。ドロワーが **General** ステップで開きます。 2. 通貨の詳細を入力します: - **Code**:アプリ内で使用する、`COINS` のような一意の**固定**識別子です。サーバーサイド API で通貨を識別し、各ユーザーの残高を追跡します。 ラテン文字、数字、アンダースコアを使用し、最大32文字。小文字は自動的に大文字に変換されます。 - **Name**: `Gold` など、表示名を設定します。後から変更可能です。 - **Description**: 通貨に関する任意のメモです。 3. **Continue** をクリックして **Link Products** ステップに進みます。 :::important 通貨の **Code** は作成後に変更できません。**Name** は後から編集できます。 ::: 新しい通貨を追加すると、すべてのユーザープロファイルの初期残高は0になります。 ## プロダクトをリンクする \{#link-products\} バーチャル通貨にプロダクトをリンクすると、購入またはサブスクリプションの更新時にその通貨のクレジットが付与されます。1つのプロダクトを複数の通貨にリンクしたり、1つの通貨を複数のプロダクトにリンクしたりすることができます。プロダクトは **Link Products** ステップで今すぐリンクするか、後から通貨を編集する際に追加することもできます。 **Link Products** ステップでは、**Associated products** セクションにその通貨を付与するプロダクトの一覧が表示されます。プロダクトを追加するには、**Add associated products** をクリックしてプロダクトを選択してください。 各付与は残高を置き換えるのではなく加算されるため、異なるプロダクトからのクレジットが累積されます。クレジットの設定はプロダクトタイプによって異なります: - **サブスクリプションプロダクト**には、3つのクレジット設定があります: - **Credit per cycle**(必須):トライアルから有料への切り替え時を含む、各更新時に付与されるクレジット数。 - **Credit on trial start**(任意):無料トライアル開始時に一度だけ付与される別枠のクレジット数。 - **Credits expire at the end of each billing cycle**(トグル):オンにすると、各更新時に未使用クレジットが0にリセットされてから、新しいサイクルのクレジットが付与されます。オフにすると、クレジットはサイクルをまたいで積み上がり、有効期限はありません。 - **買い切り購入プロダクト**:**Credit amount**(購入ごとに付与されるクレジット数)を設定します。買い切り購入のクレジットに有効期限はありません。 **Save** をクリックして、プロダクトリンクとともに通貨を作成します。 プロダクトリンクは今後の購入にのみ適用されます。新たにリンクされたプロダクトは、次回の購入または更新時からクレジットが付与されます。Adapty は現在のサブスクリプション登録者に対して自動的に通貨を付与しません。登録者はサブスクリプションを更新する必要があります。リンクを削除すると、以降の付与は停止しますが、すでに付与済みのクレジットはそのまま残ります。 有効期限トグルがオンの場合、期限付きクレジットはサブスクリプションのライフサイクルに従います: - 請求の再試行中やグレース期間中、Adaptyは新しいクレジットを付与しません。 - キャンセル後も、有料期間の終了まではクレジットが維持されます。 - サブスクリプションが期限切れになると、Adaptyは残りのクレジットを0にリセットします。 ## 次のステップ \{#next-steps\} 通貨を作成してプロダクトを紐付けると、購入時に自動でクレジットが付与されます。ここからできること: - 各ユーザーの残高は[バーチャル通貨残高](virtual-currency-balance)ページで確認できます。 - 残高の付与・消費・読み取りは、サーバーサイド API を通じてランタイムで行えます:[バーチャル通貨トランザクションの作成](api-adapty/operations/createVirtualCurrencyTransaction)と[バーチャル通貨残高の一覧取得](api-adapty/operations/listVirtualCurrencyBalances)。実際の使用例については、[バーチャル通貨クイックスタート](virtual-currency-quickstart)を参照してください。 --- # File: virtual-currency-balance --- --- title: "バーチャル通貨残高" description: "ユーザープロファイルでバーチャル通貨の残高を確認し、残高変更の履歴をイベント履歴で確認できます。" --- :::link メイン記事:[バーチャル通貨](virtual-currencies) ::: [Profiles/CRM](profiles-crm) のすべてのユーザープロファイルには、そのユーザーのバーチャル通貨残高と、すべての変更履歴が表示されます。 ## ユーザープロファイルで残高を確認する \{#view-balances-in-a-user-profile\} ユーザーの[プロファイル](https://app.adapty.io/profiles/users)を開きます。**Virtual currency** カードには、そのユーザーが保有しているすべての通貨が一覧表示されます。 各行には以下の情報が表示されます: - 通貨の**コード**(例:`COINS`) - 整数で表示される現在の**残高** 残高は、ユーザーがクレジットを獲得・消費・受取するたびに更新されます。残高が0を下回ることはありません。保有量を超えて消費しようとするトランザクションは`insufficient_balance`で失敗し、何も変更されません。残高が存在しないプロファイルには空のカードが表示されます。 独自のコードから残高を読み取るには、サーバーサイドAPIの[仮想通貨残高の一覧取得](api-adapty/operations/listVirtualCurrencyBalances)を呼び出してください。 ## 残高変更をイベント履歴で確認する \{#review-balance-changes-in-the-event-history\} すべての残高変更はプロファイルのイベント履歴に表示され、新しい順に並んでいます。各エントリには変更内容と影響を受けた通貨が記載されています。 履歴には3種類のバーチャル通貨イベントが表示されます: - **Virtual currency credited**:購入、更新、またはトライアル開始によってクレジットが付与された。 - **Virtual currency transaction**:サーバーサイドのAPI呼び出しによって残高へのクレジット付与または引き落としが行われた。 - **Virtual currency expired**:有効期限付きのクレジットが請求サイクルの終了時、またはサブスクリプション終了時にリセットされた。 各エントリには、変更があったすべての通貨について以下の情報が記載されています: - **Virtual currency**: 通貨名とコード(例:`Gold Coins (COINS)`)。 - **Amount**: 変動量(正の値は加算、負の値は減算)。 - **Balance after**: 変動適用後の通貨残高。 1つのイベントで複数の通貨を同時に変動させることも可能です。たとえば、1つの[トランザクション](api-adapty/operations/createVirtualCurrencyTransaction)で通貨を換算するために、ある通貨を減算し別の通貨を加算するケースなどがあります。 ## 残高、プロファイル、デバイス \{#balances-profiles-and-devices\} 残高は常に1つの[プロファイル](profiles-crm)にのみ属し、別のプロファイルに移動することはありません。Adapty は[ユーザーアカウント間でアクセスレベルを共有する](profiles-crm#sharing-paid-access-between-user-accounts)ような方法でプロファイル間の残高を共有・移転することはできません。 実際には、これは次のことを意味します: - **識別済みユーザー**: カスタマーユーザーIDは常に同じプロファイルに紐づくため、ログインしたすべてのデバイスで同じ残高が表示されます。 - **匿名ユーザー**: 匿名プロファイルもクレジットの獲得・消費は可能ですが、1台のデバイスにのみ存在します。同じユーザーがログインせずに別のデバイスでアプリを開いた場合、Adaptyは残高ゼロの新しい匿名プロファイルを作成します。 デバイスをまたいでバーチャルカレンシーのエコノミーを運用するには、ユーザーを識別する必要があります。識別はアプリのコード内でSDKを使って行う(クイックスタートの[ユーザーの識別](ios-quickstart-identify)を参照)か、バックエンドから[サーバーサイドAPI](getting-started-with-server-side-api)を使って行うことができます。 ユーザーの識別が遅れると、別の問題が生じます。ユーザーが匿名のままクレジットを獲得し、その後すでに別のプロファイルに紐付いているカスタマーユーザーIDでログインした場合、デバイスはそのプロファイルとその残高に切り替わります。匿名で獲得したクレジットは古いプロファイルに残ったままアクセスできなくなります。カスタマーユーザーIDが新規のものであれば、現在のプロファイルに紐付けられ、ユーザーは残高を引き継げます。安全のため、ユーザーがクレジットを獲得または購入できるようになる前に識別しておいてください。 [サーバーサイドAPI](getting-started-with-server-side-api)の呼び出しでは、`adapty-profile-id` または `adapty-customer-user-id` ヘッダーでプロファイルを識別します。どちらも同一のプロファイルに解決されます。匿名プロファイルの場合は `adapty-profile-id` を使用してください。 --- # File: app-store-offers --- --- title: "App Store のオファー" description: "App Store のオファーを設定・管理してユーザーの継続率を高めましょう。" --- :::info このガイドを進める前に、[ストアのプロダクト](quickstart-products)を設定してください。 ::: App Store のオファーとは、自動更新サブスクリプション向けの特別割引・トライアル・値引きのことです。新規ユーザーの獲得やコンバージョン向上に役立つ割引やバンドルオファーが含まれます。 App Store には 4 種類のオファーがあり、Adapty はすべてに対応しています。 - **新規ユーザー向け[初回オファー](#introductory-offers)**: - 無料または割引サブスクリプション期間 - 対象は新規ユーザーのみ(初回オファーを使用したことがない、またはサブスクリプションを持ったことがないユーザー) - Adapty のプロダクトにリンクする必要はありません。Adapty は対象ユーザーがプロダクトを購入する際にオファーを自動的に適用します。 - **[プロモーションオファー](#promotional-offers)および[ウィンバックオファー](#win-back-offers)**: - Adapty は購入時にこれらのオファーを自動的に適用しますが、先にプロダクトとペイウォールにオファーを設定する必要があります。 - プロモーションオファーには、無料サブスクリプション期間・割合割引・固定価格割引が含まれます。すべてのユーザーが対象になれます。 - ウィンバックオファーには、無料サブスクリプション期間またはパーセント割引が含まれます。対象は解約済みユーザーのみです。 - **オファーコード**:詳細は [iOS でオファーコードを使う](making-purchases#redeem-offer-codes-in-ios)をご覧ください。 :::important App Store のオファーを使用するには、[サブスクリプションキー](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers)を Adapty ダッシュボードにアップロードしてください。 ::: ## 初回オファー \{#introductory-offers\} Adapty は、ユーザーが対象の場合、iOS で初回オファーを自動的に適用します。 販売するプロダクトで初回オファーを有効にするには、App Store Connect で作成するだけで済みます。 1. App Store Connect でアプリを開き、**Monetization > Subscriptions** に切り替えます。 2. サブスクリプショングループを選択し、対象のサブスクリプションに移動します。サブスクリプションには期間が設定されている必要があります。 3. **View all Subscription Pricing** をクリックし、**Introductory offers** タブに切り替えます。**Set up introductory offer** をクリックします。 4. 初回オファーを利用可能にする国と地域を選択します。 5. 初回オファーの開始日と終了日を選択します。終了日を設けない場合は **No end date** を選択してください。**Next** をクリックします。 6. 初回オファーの種類を選択します。選択内容に応じて、オファーの期間と価格も設定する必要があります。詳細は [Apple のドキュメント](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-introductory-offers-for-auto-renewable-subscriptions)をご覧ください。 7. 内容を確認して **Confirm** をクリックします。 この設定が完了したら、Adapty での追加作業は不要です。対象ユーザーがプロダクトを購入する際にオファーが自動的に有効になります。オファーの対象ユーザーにのみ、このプロダクトを含むペイウォールが表示されるようにしてください。 ## プロモーションオファー \{#promotional-offers\} Adapty は、ユーザーが対象の場合、プロモーションオファーを自動的に適用します。まず App Store Connect でオファーを設定してから、Adapty のプロダクトとペイウォールに追加してください。 1. App Store Connect でアプリを開き、左メニューから **Monetization > Subscriptions** に切り替えます。 2. サブスクリプショングループを選択し、対象のサブスクリプションに移動します。サブスクリプションには期間が設定されている必要があります。 3. **View all Subscription Pricing** をクリックし、**Promotional offers** タブに切り替えます。**Set up promotional offer** をクリックします。 4. プロモーションオファーの詳細を設定します。これらの値は作成後に変更できず、再利用されるため、慎重に選択してください。 - **Promotional offer reference name**:プロモーションオファーの名前。ユーザーには表示されません。 - **Promotional offer identifier**:プロモーションオファーの識別コード。Adapty にオファーを追加する際に使用します。 5. プロモーションオファーの種類を選択します。種類によって、ユーザーが割引価格で支払うか無料期間を得るかが決まります。割引の場合は **Pay as you go** または **Pay up front** を選択し、無料サブスクリプション期間の場合は **Free** を選択してください。その後、オファーの期間と価格を設定します。詳細は [Apple のドキュメント](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-promotional-offers-for-auto-renewable-subscriptions)をご覧ください。 6. 必要に応じて国や地域ごとに異なる価格を設定し、**Next** をクリックします。 7. 内容を確認して **Confirm** をクリックします。 8. Adapty に[プロモーションオファーを追加](create-offer)します。 ## ウィンバックオファー \{#win-back-offers\} :::important ウィンバックオファーを作成する前に、サブスクリプションが App Review によって承認されている必要があります。 ::: Adapty は、ユーザーが対象の場合、ウィンバックオファーを自動的に適用します。まず App Store Connect でオファーを設定してから、Adapty のプロダクトとペイウォールに追加してください。 1. App Store Connect でアプリを開き、左メニューから **Monetization > Subscriptions** に切り替えます。 2. サブスクリプショングループを選択し、対象のサブスクリプションに移動します。サブスクリプションには期間が設定されている必要があります。 3. **View all Subscription Pricing** をクリックし、**Win-back offers** タブに切り替えます。**Create offer** をクリックします。 4. ウィンバックオファーの詳細を設定します。これらの値は作成後に変更できません。 - **Reference name**:オファーの名前。ユーザーには表示されません。 - **Offer identifier**:オファーの識別コード。Adapty にオファーを追加する際に使用します。 5. オファーの種類・期間・価格を設定します。詳細は [Apple のドキュメント](https://developer.apple.com/help/app-store-connect/manage-subscriptions/set-up-win-back-offers)をご覧ください。 6. 内容を確認して **Confirm** をクリックします。 7. Adapty に[オファーを追加](create-offer)します。 ## 次のステップ \{#next-steps\} オファーを追加したら、続けて以下の設定を行ってください。 - **Google Play アプリ**もお持ちの場合は、[Google Play のオファー](google-play-offers)を設定してください。 - **プロモーションオファーまたはウィンバックオファー**がある場合は、[Adapty に追加](create-offer)してください。 - **初回オファーのみ**でプロモーションオファーやウィンバックオファーがない場合は、これで完了です。[Adapty のオファー処理の仕組み](create-offer#how-adapty-works-with-offers)のセクションも参考になるかもしれません。 --- # File: google-play-offers --- --- title: "Google PlayのオファーGoogle Play" description: "Google Playのオファーを設定してアプリの収益化とリテンションを向上させましょう。" --- Google Playでは、あらゆる種類のオファー(無料トライアルや割引支払いなど)は**オファー**として追加されます。オファーを作成するには、まずサブスクリプションを作成し、自動更新ベースプランを追加する必要があります。 オファーは常にサブスクリプションのベースプランに対して作成されます。下のスクリーンショットでは、`premium_access`(1)というサブスクリプションに、`1-month`(2)と`1-year`(3)という2つのベースプランが含まれているのを確認できます。 <img src="/assets/shared/img/c0b1dfa-001930-November-03-XYnbieeu.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Google Play Consoleでオファーを作成するには: 1. **Add offer**をクリックし、リストからベースプランを選択します。 <img src="/assets/shared/img/75a5d69-eb0bc9a-001931-November-03-eQdthUMx.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. オファーIDを入力します。後で分析やAdaptyダッシュボードで使用されるため、わかりやすい名前をつけてください。 <img src="/assets/shared/img/ff282c2-c0b1dfa-001930-November-03-XYnbieeu.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 利用資格の条件を選択します: 1. **New customer acquisition**:過去にこのオファーを利用したことのない新規サブスクライバーのみが対象になります。最も一般的なオプションで、デフォルトとして使用することを推奨します。 2. **Upgrade**:他のサブスクリプションからアップグレードするユーザーが対象になります。たとえば、ブロンズからゴールドプランへのアップグレードなど、既存のサブスクライバーにより高額なプランを訴求したい場合に使用します。 3. **Developer determined**:アプリのコードからオファーの利用対象を制御できます。無料または割引サブスクリプションを繰り返し有効化される可能性があるため、本番環境での使用には注意が必要です。解約済みサブスクライバーのウィンバックに適したオファータイプです。 <img src="/assets/shared/img/ee302dc-a506e5a-001934-November-03-TVBLOz2L.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. オファーに最大2つの料金フェーズを追加します。利用可能なフェーズタイプは3種類あります: 1. **Free trial**:設定した期間(最短3日)、サブスクリプションを無料で使用できます。最も一般的なオファーです。 2. **Single payment**:最初にまとめて支払うことでサブスクリプションが割引になります。例えば、通常は月額$9.99のプランが、このオファータイプでは最初の3ヶ月で$19.99(30%割引)になります。 3. **Discounted recurring payment**:最初の`n`期間、サブスクリプションが割引になります。例えば、通常は月額$9.99のプランが、このオファータイプでは最初の3ヶ月間、毎月$4.99(50%割引)になります。 オファーには2つのフェーズを設定できます。この場合、最初のフェーズはFree trialとし、2番目はSingle paymentまたはDiscounted recurring paymentにする必要があります。この順番で適用されます。 <img src="/assets/shared/img/d6267f3-a48f79e-001936-November-03-A13wutRh.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important ペイウォールビルダーで作成したペイウォールは、複数フェーズのGoogle Playサブスクリプションオファーのうち、最初のフェーズのみを表示します。ただし、ユーザーがプロダクトを購入した際には、Google Playで設定したとおりすべてのオファーフェーズが適用されますのでご安心ください。 ::: 5. アプリで使用するためにオファーをアクティベートします。 <img src="/assets/shared/img/d3fc09b-f149ba6-001937-November-03-MO9Gz3ap.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. [AdaptyへのオファーAdaptyへのオファーの追加](create-offer)に進みます。 :::note オファーIDは、異なるベースプラン間で同じものを使用できます。 ::: ## 次のステップ \{#next-steps\} オファーを追加したら、次のセットアップに進みます: - **App Storeにもアプリがある**場合は、[App Storeガイド](app-store-offers)をご覧ください。 - **Google Playのみにアプリがある**場合は、[このガイド](create-offer)に従ってAdaptyにオファーを追加してください。 --- # File: create-offer --- --- title: "Adaptyへのオファーの追加" description: "Adaptyのツールを使って特別なサブスクリプションオファーを作成・管理しましょう。" --- Adaptyでは、新規・既存・解約済みのサブスクライバーに対してトライアルや割引を提供できます。 App Store ConnectやGoogle Play Consoleで設定した後、Adaptyに追加するには2つのステップが必要です: 1. [ストアのオファーIDを使ってAdaptyのプロダクトにオファーを追加する。](#1-create-offer) 2. [フローまたはペイウォールでオファーを表示する。](#2-display-offer) :::warning 初回オファー(App Store)は、ユーザーが対象である場合に自動的に適用されます。Adaptyのプロダクトに追加する必要はありません。 このガイドでは、プロモーションオファー(App Store)、ウィンバックオファー(App Store)、およびすべてのGoogle Playオファーの設定方法を説明します。 ::: ## 0. 開始前の確認事項 \{#0-before-you-start\} Adaptyでオファーの設定を始める前に、以下を確認してください: 1. 必要なオファーをストアで作成済みであること: - [App Store](app-store-offers) - [Google Play](google-play-offers) 2. Adaptyで[プロダクト](create-product)を作成し、IDを追加済みであること。 3. App Storeの場合:[プロモーションオファー用のアプリ内購入キー](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers)をアップロード済みであること。 ## 1. Adaptyのプロダクトにオファーを追加する \{#1-add-offer-to-product-in-adapty\} Play StoreおよびApp Storeのプロモーションオファー、またはApp StoreのWin-backオファーをアプリストアで設定したら、Adaptyへの追加はシンプルです: 1. Adaptyのメインメニューから[**Products**](https://app.adapty.io/products)を開き、オファーを追加したいプロダクトを探します。 2. オファーを追加したいプロダクトを見つけ、**Actions**列のプロダクト横にある**3-dot**ボタンをクリックして**Edit**を選択します。 3. **Edit product**ウィンドウで、**+**をクリックして**Add offers**を選択します。 4. **Add offer**をクリックします。 5. プロダクトのオファー詳細を入力します。 オファーのフィールドは以下のとおりです: - **Offer name**:Adaptyで識別しやすいようにオファー名を入力します。任意の名前を使用できます。 - **App Store Offer type**:追加するApp Storeオファーのタイプ(PromotionalまたはWin-back)を選択します。(初回オファーは追加不要です—対象の場合は自動的に適用されます。) - **App Store Offer ID**:[App Storeで設定した](app-store-products)オファーの固有IDです。 - **Play Store Offer ID**:同様に、[Play Storeで設定した](android-products)オファーの固有IDです。 :::tip **App Store Offer ID**または**Play Store Offer ID**フィールドが非アクティブの場合は、**Products**タブに切り替えてプロダクトIDを選択してください。 ::: 6. (任意)**Add offer**をクリックして、必要に応じてオファーを追加します。 7. **Save**をクリックしてオファーをプロダクトに追加します。 ## 2. オファーを表示する \{#2-display-offer\} オファーをプロダクトに紐付けたら、ユーザーがそのプロダクトを見る場所—フローまたはペイウォール—に表示します。 ### フローにオファーを追加する \{#add-offer-to-flow\} [フロービルダー](adapty-flow-builder)では、オファーはProductsエレメントのプロダクトに紐付けられます。まずプロダクトエレメントを追加してプロダクトを割り当ててください—[購入の設定](paywall-product-block)を参照してください。 オファーを紐付けるには: 1. キャンバス上で、オファーを表示するプロダクトカードを選択します。 2. 右側のパネルの**Product**で、プロダクトを選択し、**Select offer (optional)**ドロップダウンからオファーを選びます。 ### ペイウォールにオファーを追加する \{#add-offer-to-paywall\} :::info **live**ステータスのペイウォールにオファーを追加することはできません。既存のペイウォールにオファーを追加したい場合は、[複製](duplicate-paywalls)して新しいペイウォールでプロダクトを設定してください。 ::: アプリのユーザーが[ペイウォール](paywalls)内でオファーを確認・選択できるようにするには、次の手順に従ってください: 1. ペイウォールの作成または編集時に、**General**タブでオファーを追加したプロダクトを追加します。 2. このプロダクトに作成したオファーを**Offer**リストから選択します。リストはオファーが設定されているプロダクトにのみ表示されます。 3. 必要に応じてプロダクトとオファーを追加できますが、各プロダクトにつき1つのオファーのみ追加できます。 ## Adaptyでのオファーの動作について \{#how-adapty-works-with-offers\} オファーの動作について以下の点にご注意ください: - ユーザーがオファーの対象である場合、Adaptyは購入時に設定したオファーを自動的に適用します。 - App StoreでプロダクトにIntroductory offerとPromotional offerの両方が設定されている場合、対象ユーザーはまずIntroductory offerを受け取ります。その期間が終了した後、ユーザーがまだPromotional offerの対象であり、Adaptyでそのオファーを設定している場合、再度プロダクトを購入しようとしたときに適用されます。 - オファーの適用方法をより細かく制御したい場合や、特定のケースでオファーなしにプロダクトを販売したい場合は、いくつかの選択肢があります: - App StoreまたはGoogle Play Consoleで対象条件を設定する - App StoreまたはGoogle Play Consoleでオファーなしの別プロダクトを作成する - Adaptyでオファーなしの別プロダクトを作成し、両方のプロダクトバリアントを含むペイウォールを[プレースメント](placements)に追加して、オーディエンス[セグメント](segments)を使ってどのペイウォールをどのユーザーに表示するかを制御する。たとえば、**Subscription product**や**Paid access level**に基づいたセグメントを作成したり、[カスタム属性](profiles-crm)を使って独自のロジックを実装したりすることができます。 --- # File: create-access-level --- --- title: "アクセスレベルの作成" description: "ユーザーセグメンテーションを改善するために、Adaptyでアクセスレベルを作成・割り当てる方法を説明します。" --- アクセスレベルを使うと、プロダクトIDをハードコードすることなく、アプリ内でユーザーに許可する操作を制御できます。各プロダクトは、ユーザーが特定のアクセスレベルを得られる期間を定義します。ユーザーが購入を行うと、Adaptyはサブスクリプションの場合は一定期間、永続購入の場合は永続的にアプリへのアクセスを付与します。 Adapty ダッシュボードでアプリを作成すると、`premium` アクセスレベルが自動的に生成されます。これはデフォルトのアクセスレベルとして機能し、削除することはできません。 :::tip [Developer CLI](developer-cli-reference#adapty-access-levels-create) を使用してアクセスレベルをプログラムで作成することもできます。 ::: 新しいアクセスレベルを作成するには: 1. Adaptyのメインメニューから **[Products](https://app.adapty.io/access-levels)** に移動し、**Access levels** タブを選択します。 <img src="/assets/shared/img/access-level-list.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Create access level** をクリックします。 <img src="/assets/shared/img/b8646ca-image.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Create access level** ウィンドウで、IDを設定します。このIDはモバイルアプリ内での識別子として機能し、ユーザーが購入した際に追加機能へのアクセスを有効にします。また、この識別子はアプリ内で他のアクセスレベルと区別するためにも役立ちます。わかりやすく、理解しやすいIDを設定してください。 4. **Create access level** をクリックして、アクセスレベルの作成を確定します。 --- # File: assigning-access-level-to-a-product --- --- title: "プロダクトにアクセスレベルを割り当てる" description: "サブスクリプション管理を最適化するために、プロダクトにアクセスレベルを割り当てます。" --- すべての[プロダクト](product)には、購入時にユーザーが対応するコンテンツにアクセスできるよう、アクセスレベルを関連付ける必要があります。Adapty はサブスクリプションの期間を自動的に判別し、それをアクセスレベルの有効期限として設定します。永続アクセスのプロダクトを購入した場合、アクセスレベルは有効期限なしで永続的に有効になります。 プロダクトにアクセスレベルを紐付けるには: 1. [プロダクトの設定](create-product)中に、**Access Level ID** リストからアクセスレベルを選択します。 <img src="/assets/shared/img/access-level-product.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Save** をクリックします。 --- # File: give-access-level-to-specific-customer --- --- title: "特定の顧客にアクセスレベルを付与する" description: "Adaptyの高度なツールを使用して、顧客に特定のアクセスレベルを割り当てます。" --- Adapty ダッシュボードから、特定の顧客のアクセスレベルを手動で調整できます。これはサポート対応などの場面で特に便利です。たとえば、素晴らしいレビューを投稿してくれたお礼として、ユーザーのプレミアム利用期間を1週間延長したい場合などに活用できます。 ## Adapty ダッシュボードで特定の顧客にアクセスレベルを付与する \{#give-access-level-to-a-specific-customer-in-the-adapty-dashboard\} 1. Adapty のメインメニューから **[Profiles and Segments](https://app.adapty.io/placements)** に移動します。 <img src="/assets/shared/img/profiles-list.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. アクセスを付与したい顧客をクリックします。 3. **Add access level** をクリックします。 <img src="/assets/shared/img/add-access-level.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 付与するアクセスレベルと、その顧客に対する有効期限を選択します。 5. **Apply** をクリックします。 ## API で特定の顧客にアクセスレベルを付与する \{#give-access-level-to-a-specific-customer-via-api\} Adapty API を使用して、サーバーから顧客にアクセスレベルを付与することもできます。紹介報酬やプロダクトに関連するその他のイベントに対してボーナスを提供する場合に便利です。詳しくは [サーバーサイド API でアクセスレベルを付与する](api-adapty/operations/grantAccessLevel) のページをご覧ください。 --- # File: local-access-levels --- --- title: "ローカルアクセスレベル" description: "一時的な障害発生時にアクセスレベルを管理します。" --- :::important 以下の点に注意してください: - ローカルアクセスレベルは、Adapty SDK バージョン 3.12 以降でサポートされています。 - セキュリティ上の理由から、Android ではデフォルトでローカルアクセスレベルが無効になっています。必要な場合は、SDK のアクティベーション時に有効にしてください: [Android](sdk-installation-android#enable-local-access-levels)、[React Native](sdk-installation-reactnative)、[Flutter](sdk-installation-flutter#enable-local-access-levels-android)。 ::: 設定した各プロダクトには [**アクセスレベル**](access-level) が紐付けられています。ユーザーが購入を行うと、Adapty SDK はそのアクセスレベルをユーザーの[プロファイル](profiles-crm)に付与します。アプリ内の有料コンテンツへのアクセス可否の判定には、このアクセスレベルを使用する必要があります。 Adapty SDK は非常に信頼性が高く、サーバーが利用できなくなるケースはほとんどありません。しかし、万が一そのような状況が発生しても、ユーザーが気づくことはありません。 ユーザーが購入を行ったとき、Adapty がレスポンスを受信できない場合、SDK はストアで直接購入を検証する処理に切り替わります。これによりアクセスレベルはアプリ内でローカルに付与され、有効にするための追加設定は不要です。SDK がバックグラウンドで自動的に処理するため、ユーザーは通常どおり購入したコンテンツにアクセスできます。 ローカルアクセスレベルの動作について、以下の点に注意してください: - ユーザーがオンラインに戻ると、トランザクション情報が自動的に Adapty サーバーへ送信され、サーバーはそのトランザクションをユーザープロファイルに適用して、更新されたプロファイルを SDK に返します。 - データが送信されるまで、更新された情報は Adapty アナリティクスに反映されません。 - ローカルアクセスレベルは、Adapty サーバーがダウンしている場合にのみ機能します。それ以外の場合、SDK はキャッシュされたデータを使用します。 - ローカルアクセスレベルは消耗型アイテムには機能しません。ただし、Adapty ダッシュボードで消耗型アイテムにサブスクリプションタイプ(月次、年次、週次など)が設定されている場合は除きます。 --- # File: choose-meaningful-placements --- --- title: "意味のあるプレースメントの選び方" description: "Adaptyを使ってフローとペイウォールのプレースメントを最適化し、ユーザーエンゲージメントと収益を向上させましょう。" --- [プレースメントを作成する](create-placement)際は、アプリの論理的なフローと、ユーザーに提供したいエクスペリエンスを考慮することが重要です。ほとんどのアプリでは、実験を実施できる能力を損なわずに済む[プレースメント](placements)の数は5つ以下が目安です。以下はプレースメントの構成例です。 <img src="/assets/shared/img/placement-flows.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. **オンボーディングフロー:** このステージは、ユーザーがアプリと最初に接触する場面です。フロー、オンボーディング、ペイウォールのプレースメントを組み合わせて、アプリの価値提案をユーザーに紹介する絶好の機会です。サブスクリプションの80%以上はオンボーディング中に有効化されるため、ここで最も収益性の高いサブスクリプションを訴求することが重要です。Adaptyを使えば、オーディエンスに応じて異なる[フロー](adapty-flow-builder)、[オンボーディング](onboardings)、[ペイウォール](paywalls)を簡単に設定でき、A/B テストで最適な選択肢を見つけることができます。たとえば、米国のユーザーに対してより高額なサブスクリプションを50%の確率で表示するA/B テストを実施できます。 2. **アプリ設定:** オンボーディング中にサブスクリプションしなかったユーザーに対して、アプリ内にフローまたはペイウォールのプレースメントを設置できます。これはアプリ設定内や、ユーザーが特定のターゲットアクションを完了した後などに配置できます。アプリ内のユーザーはサブスクリプションをより慎重に検討する傾向があるため、ここで提供するプロダクトはオンボーディング段階のものよりやや安価に設定するとよいでしょう。 3. **プロモ:** フローやペイウォールを複数回見てもサブスクリプションしなかったユーザーには、価格が高すぎるか、サブスクリプション自体に躊躇している可能性があります。この場合、最も手頃なサブスクリプションや永続アクセスプロダクトを含む特別オファーを表示できます。これにより、価格を重視するユーザーやサブスクリプションに懐疑的なユーザーの購買意欲を高めることができます。 ほとんどのアプリはこれと同様のロジックとプレースメント構成を持ち、ユーザージャーニーとフロー・ペイウォール・オンボーディング・A/B テストを表示してコンバージョンと収益を促進できる重要なポイントに沿って設計されます。各プレースメントで設定を行い、マネタイズ戦略を実験・最適化しましょう。 --- # File: create-placement --- --- title: "プレースメントを作成する" description: "Adapty でプレースメントを作成・管理して、フローとペイウォールのパフォーマンスを向上させましょう。" --- [プレースメント](placements)とは、モバイルアプリ内でフロー、ペイウォール、オンボーディング、または A/B テストを表示できる特定の場所のことです。たとえば、サブスクリプションの選択画面をスタートアップフローに表示したり、ゲームでコインが不足したときに消耗型アイテム(ゴールドコインなど)を表示したりできます。 同じフロー、ペイウォール、オンボーディング、または A/B テストを複数のプレースメントで表示したり、異なるユーザーセグメント(Adapty では「オーディエンス」と呼びます)に対して異なるコンテンツを表示したりすることも可能です。 適切なプレースメントの選び方については、[意味のあるプレースメントを選ぶ](choose-meaningful-placements)セクションをご参照ください。 :::tip [Developer CLI](developer-cli-reference#adapty-placements-create) を使ってプレースメントをプログラムで作成することもできます。 ::: :::info プレースメントの作成プロセスはフロー、ペイウォール、オンボーディングで似ていますが、1 つのプレースメントで複数のタイプを兼用することはできません。プレースメントの種類ごとに処理される指標が異なるためです。 ::: ## プレースメントを作成・設定する \{#create-and-configure-a-placement\} 1. Adapty のメインメニューから **[Placements](https://app.adapty.io/placements)** に移動します。作成したいプレースメントの種類に応じて、**Flows**、**Paywalls**、または **Onboardings** タブに切り替えます。 2. **Create placement** をクリックします。 <img src="/assets/shared/img/create-placement-2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Placement name** を入力します。これは Adapty ダッシュボード内の内部識別子です。後から編集することもできます。 4. **Placement ID** を入力します。この ID は、Adapty SDK でプレースメントの[フロー](adapty-flow-builder)、[ペイウォール](paywalls)、[オンボーディング](onboardings)、[A/B テスト](ab-tests)を呼び出す際に使用します。各プレースメントで一意のため、後から編集することはできません。 次に、プレースメントにフロー、ペイウォール、オンボーディング、または A/B テストを割り当てます。Adapty は[セグメント](segments)に基づくユーザーセグメントである[オーディエンス](audience)をサポートしており、異なるユーザーグループに異なるコンテンツを表示できます。ターゲティングが不要な場合は、デフォルトの *All users* オーディエンスがすべてのユーザーをカバーします。 :::note 続行する前に、実行したいフロー、ペイウォール、オンボーディング、またはA/B テストと、指定したいオーディエンスを作成済みであることを確認してください。 ::: 1. **Placements/ Your placement** ウィンドウで、デフォルトの *All users* オーディエンスに表示するフロー、ペイウォール、オンボーディング、またはA/B テストを追加します。これを行うには、**Run flow**、**Run paywall**、または **Run A/B test** ボタン(ラベルはプレースメントの種類によって異なります)をクリックし、ドロップダウンリストから目的のフロー、ペイウォール、オンボーディング、またはA/B テストを選択します。 2. プレースメントで複数のオーディエンスを使用して、異なるユーザーグループ向けにパーソナライズされたコンテンツを作成したい場合は、**Add audience** ボタンをクリックして、リストから目的のユーザーセグメントを選択します。 <Zoom> <img src="/docs/img/placement-add-audience.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. このオーディエンスに表示するフロー、ペイウォール、オンボーディング、またはA/B テストを追加します。 4. 必要な数のオーディエンスを追加します。 5. 複数のオーディエンスがある場合は、オーディエンスの優先順位が正しく設定されているか確認してください。 6. **Save and publish** ボタンをクリックします。 プレースメントを保存して公開したら、準備完了です。アプリのコードで **Placement ID** を使用してコンテンツを取得・表示してください。 ## 次のステップ \{#next-steps\} アプリにペイウォールを表示する: [iOS](ios-present-paywalls) | [Android](android-present-paywalls) | [React Native](react-native-present-paywalls) | [Flutter](flutter-present-paywalls) | [Unity](unity-present-paywalls) | [Kotlin Multiplatform](kmp-present-paywalls) | [Capacitor](capacitor-present-paywalls) アプリにオンボーディングを表示する: [iOS](ios-present-onboardings) | [Android](android-present-onboardings) | [React Native](react-native-present-onboardings) | [Flutter](flutter-present-onboardings) | [Unity](unity-present-onboardings) | [Kotlin Multiplatform](kmp-present-onboardings) | [Capacitor](capacitor-present-onboardings) --- # File: edit-placement --- --- title: "プレースメントを編集する" description: "Adaptyでプレースメントを編集して、フローとペイウォールの表示およびユーザーエンゲージメントを最適化する方法を説明します。" --- [プレースメント](placements)は、フロー、ペイウォール、オンボーディング、またはA/B テストを表示できるモバイルアプリ内の特定の場所を指します。たとえば、サブスクリプションの選択画面をスタートアップフローに表示したり、ゲームでコインが不足したときに消耗型アイテム(ゴールデンコインなど)を提示したりすることができます。 同じまたは異なるフロー、ペイウォール、オンボーディング、またはA/B テストを、複数のプレースメントやユーザーセグメント(Adaptyではオーディエンスと呼びます)に表示する柔軟性があります。 既存のプレースメントを編集するには: 1. Adaptyのメインメニューから **[Placements](https://app.adapty.io/placements)** に移動します。編集したいプレースメントの種類に応じて、**Flows**、**Paywalls**、または **Onboardings** タブに切り替えます。 2. 編集したいプレースメントをクリックします。 3. 右上の **Edit placement** をクリックします。 4. 必要な変更を加えます。このウィンドウのオプションについて詳しくは、[プレースメントを作成する](create-placement)セクションをご覧ください。 5. **Save and publish** ボタンをクリックして変更を確定します。 --- # File: export-placements --- --- title: "プレースメントのエクスポート" description: "Adaptyでプレースメントをエクスポートして、フローとペイウォールの表示状況やユーザーエンゲージメントを最適化する方法を学びましょう。" --- 複数のフロー、ペイウォール、オンボーディングを扱う場合、どのユーザーにどれが表示されているかを把握することが重要です。[プレースメント](placements)の設定をCSVファイルにエクスポートすると、各オーディエンスに対してどのフロー/ペイウォール/オンボーディングが表示されるかを確認でき、変更後や実験中のセットアップをレビューするのに役立ちます。 :::tip サーバーサイドAPIを利用したほうが便利な場合は、[APIでプレースメントをエクスポート](api-export-analytics/operations/retrievePlacementInfo)することもできます。 ::: フロー、ペイウォール、またはオンボーディングのプレースメントをエクスポートするには: 1. メインメニューの **[Placements](https://app.adapty.io/placements)** に移動します。**Flows**、**Paywalls**、または **Onboardings** タブに切り替えてください。各タイプのプレースメントは個別にエクスポートされます。 2. **Export to CSV** をクリックします。 <img src="/assets/shared/img/export-placement.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> エクスポートされたCSVファイルには、プレースメントに関する以下の情報が含まれます: - プレースメントID - プレースメント名 - オーディエンス名 - セグメント名 - クロスプレースメント A/B テスト名 - A/B テスト名 - フロー名、ペイウォール名、またはオンボーディング名(エクスポートしたタブによって異なります) :::note クロスプレースメント A/B テストはフローのプレースメントには対応していないため、フローのエクスポートではその列は空になります。 ::: --- # File: delete-placement --- --- title: "プレースメントの削除" description: "フローやペイウォールのパフォーマンスに影響を与えずに、Adapty でプレースメントを削除する方法をご確認ください。" --- [プレースメント](placements)は、モバイルアプリ内でフロー、ペイウォール、オンボーディング、または A/B テストを表示する特定の場所を指定するものです。 :::danger 任意のプレースメントを削除することは可能ですが、モバイルアプリで現在使用中のプレースメントを削除しないよう十分に注意してください。アクティブなフローやペイウォールのプレースメントを削除すると、[フォールバックペイウォールを設定している場合](fallback-paywalls)はそれが永続的に表示され続け、リリース済みのアプリバージョンでは動的なフローやペイウォールに切り替えることが一切できなくなります。 ::: 既存のプレースメントを削除するには、次の手順に従ってください。 1. Adapty のメインメニューから **[Placements](https://app.adapty.io/placements)** に移動します。削除したいプレースメントの種類に応じて、**Flows**、**Paywalls**、または **Onboardings** タブに切り替えます。 2. プレースメントの横にある **3-dot** ボタンをクリックし、**Delete** オプションを選択します。 <img src="/assets/shared/img/delete-placement.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 表示された **Delete placement** ウィンドウで、削除しようとしているプロダクト名を入力します。 <img src="/assets/shared/img/8177c51-delete_placement.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Delete forever** ボタンをクリックして削除を確定します。 --- # File: add-audience-paywall-ab-test --- --- title: "オーディエンスとフロー、ペイウォール、またはA/Bテストをプレースメントに追加する" description: "Adaptyで異なるオーディエンスセグメントに対してフローとペイウォールのA/Bテストを実施します。" --- Adaptyの**オーディエンス**は、[セグメント](segments)で定義されたユーザーのグループです。オーディエンスを使うことで、フロー、ペイウォール、オンボーディング、A/Bテストを適切なユーザーに表示できます。各グループに最適なコンテンツが届くよう、フィルターを使ってセグメントを作成しましょう。 [プレースメント](placements)にオーディエンスを追加すると、特定のユーザーグループに対してフロー、ペイウォール、オンボーディング、またはA/Bテストをターゲティングできます。オーディエンスをプレースメントに紐付けることで、適切なユーザーが、アプリの利用フローの適切なタイミングで、適切なコンテンツを目にできるようになります。 フロー、ペイウォール、オンボーディング、またはA/Bテストを追加したいプレースメントを開くか、[Placements](https://app.adapty.io/placements) メニューから新しく作成してください。 :::note 続行する前に、実行したいフロー、ペイウォール、オンボーディング、またはA/B テストと、指定したいオーディエンスを作成済みであることを確認してください。 ::: 1. **Placements/ Your placement** ウィンドウで、デフォルトの *All users* オーディエンスに表示するフロー、ペイウォール、オンボーディング、またはA/B テストを追加します。これを行うには、**Run flow**、**Run paywall**、または **Run A/B test** ボタン(ラベルはプレースメントの種類によって異なります)をクリックし、ドロップダウンリストから目的のフロー、ペイウォール、オンボーディング、またはA/B テストを選択します。 2. プレースメントで複数のオーディエンスを使用して、異なるユーザーグループ向けにパーソナライズされたコンテンツを作成したい場合は、**Add audience** ボタンをクリックして、リストから目的のユーザーセグメントを選択します。 <Zoom> <img src="/docs/img/placement-add-audience.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. このオーディエンスに表示するフロー、ペイウォール、オンボーディング、またはA/B テストを追加します。 4. 必要な数のオーディエンスを追加します。 5. 複数のオーディエンスがある場合は、オーディエンスの優先順位が正しく設定されているか確認してください。 6. **Save and publish** ボタンをクリックします。 --- # File: change-audience-priority --- --- title: "プレースメントのオーディエンス優先度を変更する" description: "Adaptyでオーディエンスの優先度を調整して、ユーザーにパーソナライズされたオファーをターゲティングする方法。" --- 1つの[プレースメント](placements)に複数のオーディエンスを設定している場合、ユーザーが複数のオーディエンスに属することがあります。たとえば、「初心者」「ランナー」といったオーディエンスと「全ユーザー」のような汎用オーディエンスを定義している場合、ユーザーが複数のカテゴリに当てはまるとき、どのオーディエンスを優先して適用するかを決めることが重要です。 <img src="/assets/shared/img/afee54f-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このような場合、オーディエンス優先度が重要になります。オーディエンス優先度は数値による順序で、#1 が最も高い優先度を持ちます。これにより、オーディエンスをチェックする順番が決まります。簡単に言うと、オーディエンス優先度はペイウォール、オンボーディング、またはA/Bテストを表示する際にどのオーディエンスを最初に適用するかを Adapty が判断するための指針です。優先度が低いオーディエンスは、条件に合うユーザーが他のより高い優先度のオーディエンスに割り振られてしまい、スキップされる可能性があります。 クロスプレースメントオーディエンス([クロスプレースメントA/Bテスト](ab-tests#ab-test-types)向けに作成されたもの)は、常に通常のオーディエンスより優先されます。 「全ユーザー」オーディエンスは、他のどのオーディエンスにも一致しないすべてのユーザーを含むフォールバックであるため、常に最低優先度となります。 プレースメントのオーディエンス優先度を調整するには: 1. 新しいプレースメントの作成中または既存のプレースメントの編集中に、**Edit priority** をクリックします。このボタンは、プレースメントに少なくとも3つのオーディエンス(「全ユーザー」とその他2つ)が追加されている場合にのみ表示されます。それ未満の場合は順序が自明のため(「全ユーザー」が最後)、ボタンは表示されません。 <img src="/assets/shared/img/edit-priority.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 表示された **Edit audience priorities** ウィンドウで、オーディエンスをドラッグ&ドロップして正しい順序に並べ替えます。 <img src="/assets/shared/img/reorder_audiences.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Save** ボタンをクリックします。 --- # File: placement-metrics --- --- title: "プレースメント指標" description: "Adaptyのプレースメント指標を分析して、ペイウォールのパフォーマンスを改善しましょう。" --- Adaptyでは、アプリ内に複数のプレースメントを作成・管理でき、それぞれに異なるペイウォールやA/B テストを紐付けることができます。この柔軟性により、特定のユーザーセグメントをターゲットにしたり、異なるオファーや価格モデルを試したり、アプリの収益化戦略を最適化したりすることが可能です。 プレースメントのパフォーマンスやオファーに対するユーザーエンゲージメントに関する有益なインサイトを収集するため、Adaptyは表示されたペイウォールに関連するさまざまなユーザーインタラクションとトランザクションを追跡します。この強力な分析システムは、ビュー数、ユニークビュー数、購入数、トライアル数、返金数、コンバージョン率、収益などの指標を収集します。 収集された指標はリアルタイムで継続的に更新され、Adaptyの使いやすいダッシュボードから簡単にアクセスして分析できます。分析する時間範囲を自由にカスタマイズし、さまざまなパラメーターに基づいてフィルターを適用し、複数のプレースメント、ユーザーセグメント、プロダクト間で指標を比較することができます。 プレースメント指標はプレースメント一覧で確認でき、すべてのプレースメントのパフォーマンス概要を把握できます。この高レベルのビューでは、各プレースメントの集計指標が表示され、パフォーマンスの比較やトレンドの特定が可能です。 各プレースメントをより詳しく分析するには、プレースメントの詳細指標ページに移動します。このページでは、選択したプレースメントに特化した包括的な指標が表示されます。これらの指標により、特定のプレースメントのパフォーマンスをより深く把握し、有効性を評価してデータに基づいた意思決定を行うことができます。 <img src="/assets/shared/img/3e711fc-CleanShot_2023-07-26_at_14.55.042x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### インストール日による指標のフィルタリング \{#filter-metrics-by-install-date\} ペイウォール、トライアル、購入の指標は、2つの異なる日付でグループ化できます: - **イベント日** — ペイウォールが表示された日、トライアルが開始された日、または購入が行われた日。 - **インストール日** — ユーザーが初めてアプリを開いた日。 同じ日付範囲でも、この2つのビューは大きく異なる数値を示すことがあります。**Filter metrics by install date** チェックボックスで、ダッシュボードがどちらを使用するかを制御します: - **チェックなし(デフォルト)**:指標はイベント日でグループ化されます。 - **チェックあり**:指標はインストール日でグループ化されます。 **例。** 日付範囲を4月1日〜30日に設定し、トライアルを確認します。 - **チェックなし**:それらのユーザーがいつインストールしたかに関わらず、4月に*開始*されたトライアルを表示します。 - **チェックあり**:トライアルがいつ開始されたかに関わらず、4月に*インストール*したユーザーのトライアルを表示します。 特定のコホートのユーザー獲得パフォーマンスを測定するにはインストール日ビューを使用し、特定の期間のペイウォールやオンボーディングのアクティビティを測定するにはイベント日ビューを使用してください。 ### 指標のコントロール \{#metrics-controls\} システムは選択した時間帯に基づいて指標を表示し、4段階のインデントを持つ左側の列パラメーターに従って整理されます。 #### 指標データの表示オプション \{#view-options-for-metrics-data\} プレースメント指標ページでは、ペイウォールベースとオーディエンスベースの2つの表示オプションが用意されています。 <img src="/assets/shared/img/9d26b32-Export-1690376094858.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ペイウォールベースのビューでは、指標はペイウォールに紐付いたプレースメントごとにグループ化されます。これにより、異なるプレースメント別に指標を分析できます。 オーディエンスベースのビューでは、指標はペイウォールのターゲットオーディエンスごとにグループ化されます。ユーザーは異なるオーディエンスセグメントに特有の指標を確認できます。 #### 時間範囲 \{#time-ranges\} 指標データを分析する時間範囲を選択でき、日、週、月、カスタム日付範囲など特定の期間に絞り込むことができます。 <img src="/assets/shared/img/15d2c3e-CleanShot_2023-07-26_at_16.49.272x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[分析コントロール](controls-filters-grouping-compare-proceeds) ::: Adaptyは、ニーズに合わせて指標分析をフィルタリングおよびカスタマイズするための強力なツールを提供しています。Adaptyの指標ページでは、さまざまな時間範囲、グループ化オプション、フィルタリング機能が利用できます。 - ✅ フィルター対象:オーディエンス、ペイウォール、ペイウォールグループ、プレースメント、国、ストア - ✅ グループ化対象:セグメント、ストア、プロダクト #### 単一指標チャート \{#single-metrics-chart\} プレースメント指標ページの主要コンポーネントの1つがチャートセクションで、選択した指標を視覚的に表示して分析を容易にします。 プレースメント指標ページのチャートセクションには、選択した指標の値を視覚的に表す水平棒グラフが含まれています。グラフの各バーは指標の値に対応しており、サイズが比例しているため一目でデータを理解できます。水平線は分析対象の期間を示し、垂直列には指標の数値が表示されます。すべての指標値の合計はグラフの隣に表示されます。 <img src="/assets/shared/img/4623c5b-Export-1690375597411.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> また、チャートセクションの右上にある矢印アイコンをクリックすると、ビューが拡張され、選択した指標がチャートの全幅で表示されます。 #### 合計指標サマリー \{#total-metrics-summary\} 単一指標チャートの隣には合計指標サマリーセクションが表示されます。ここでは特定の時点における選択した指標の累積値が確認でき、ドロップダウンメニューで表示する指標を変更することもできます。 <img src="/assets/shared/img/0f647cf-CleanShot_2023-07-26_at_14.55.492x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 指標の定義 \{#metrics-definitions\} プレースメント指標の包括的な定義で、その可能性を最大限に活用しましょう。収益からコンバージョン率まで、アプリのマネタイズ戦略を強化し、成功へ導く貴重なインサイトを得られます。 <img src="/assets/shared/img/771a0f0-Export-1690375049771.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: #### 収益 \{#revenue\} この指標は、特定のプレースメント内での購入および更新によって生成された収益の合計額(USD)を表します。収益の計算にはApple App StoreまたはGoogle Play Storeの手数料は含まれず、手数料控除前の金額として計算されます。 #### 手取り収益(Proceeds) \{#proceeds\} この指標は、特定のプレースメント内での購入および更新から、Apple App StoreまたはGoogle Play Storeの適用手数料を差し引いた後にアプリオーナーが実際に受け取る金額(USD)を表します。アプリの収益に直接貢献する純収益を反映しています。手取り収益の計算方法の詳細については、Adaptyの[ドキュメント](analytics-cohorts#revenue-vs-proceeds)を参照してください。 #### ARPPU \{#arppu\} ARPPUは「Average revenue per paying user(課金ユーザー1人あたりの平均収益)」の略で、特定のプレースメント内での課金ユーザー1人あたりの平均収益を測定します。総収益をユニーク課金ユーザー数で割って計算されます。例えば、総収益が15,000ドルで課金ユーザーが1,000人の場合、ARPPUは15ドルになります。 #### ARPAS \{#arpas\} ARPASは「Average revenue per active subscriber(アクティブサブスクライバー1人あたりの平均収益)」の略で、特定のプレースメント内でのアクティブサブスクライバー1人あたりの平均収益を測定します。総収益をトライアルまたはサブスクリプションを有効化したサブスクライバー数で割って計算されます。例えば、総収益が5,000ドルでサブスクライバーが1,000人の場合、ARPASは5ドルになります。この指標はサブスクライバー1人あたりの平均収益化ポテンシャルを評価するのに役立ちます。 #### ARPU \{#arpu\} オンボーディングプレースメント専用。ARPUはオンボーディングを閲覧したユーザー1人あたりの平均収益です。ユニーク閲覧者数で総収益を割って計算されます。 #### ユニーク購入コンバージョン率(Unique CR to purchases) \{#unique-cr-to-purchases\} 購入へのユニークコンバージョン率は、特定のプレースメント内での購入数をユニークビュー数で割って計算されます。購入数とユニークビュー数の比率に注目することで、特定のプレースメント内でユニーク訪問者を課金顧客に転換する効果についてのインサイトが得られます。 #### 購入コンバージョン率(CR to purchases) \{#cr-to-purchases\} 購入へのコンバージョン率は、特定のプレースメント内での購入数をペイウォールの総ビュー数で割って計算されます。特定のプレースメント内でのビューのうち購入に至った割合を示し、ペイウォールがユーザーを課金顧客に転換する効果についてのインサイトが得られます。 #### ユニークトライアルコンバージョン率(Unique CR to trials) \{#unique-cr-to-trials\} トライアルへのユニークコンバージョン率は、特定のプレースメント内で開始されたトライアル数をユニークビュー数で割って計算されます。特定のプレースメント内でのユニークビューのうちトライアル有効化に至った割合を測定し、ペイウォールがユニーク訪問者をトライアルユーザーに転換する効果についてのインサイトが得られます。 #### 購入数(Purchases) \{#purchases\} 購入数は、特定のプレースメント内でのペイウォール上のさまざまなトランザクションの累計合計を表します。この指標には以下のトランザクションが含まれます(更新は含まれません): - 特定のプレースメント内で直接行われた新規購入 - 特定のプレースメント内で最初に有効化されたトライアルのトライアル転換 - 特定のプレースメント内で行われたサブスクリプションのダウングレード、アップグレード、クロスグレード - 特定のプレースメント内でのサブスクリプション復元(自動更新なしで期限切れになったサブスクリプションが再有効化された場合など) これらのさまざまな種類のトランザクションを考慮することで、購入数指標は特定のプレースメント内での全体的な獲得および収益化活動の包括的なビューを提供します。 #### トライアル数(Trials) \{#trials\} トライアル数指標は、特定のプレースメント内で有効化されたトライアルの総数を表します。これらのプレースメント内でペイウォールを通じてトライアル期間を開始したユーザーの数を反映します。この指標はトライアル提供の効果を追跡し、トライアルから有料サブスクリプションへのユーザーエンゲージメントとコンバージョンに関するインサイトを得るのに役立ちます。 #### トライアルキャンセル数(Trials canceled) \{#trials-canceled\} トライアルキャンセル数指標は、特定のプレースメント内で自動更新機能がオフにされたトライアルの数を表します。これはユーザーが手動でトライアルを解約した場合に発生し、トライアル期間終了後にサブスクリプションを継続しないという意思を示しています。トライアルキャンセル数の追跡は、ユーザー行動に関する貴重な情報を提供し、特定のプレースメント内でユーザーがトライアルを離脱する割合を把握するのに役立ちます。 #### 返金数(Refunds) \{#refunds\} 返金数指標は、特定のプレースメント内での返金された購入およびサブスクリプションの数を表します。これには、顧客のリクエスト、支払いの問題、その他の返金ポリシーなど、さまざまな理由で取り消しまたは返金されたトランザクションが含まれます。 #### 返金率(Refund rate) \{#refund-rate\} 返金率は、特定のプレースメント内での返金数を初回購入数(更新は含まれません)で割って計算されます。例えば、返金が5件で初回購入が1,000件の場合、返金率は0.5%になります。 #### ビュー数(Views) \{#views\} ビュー数指標は、特定のプレースメント内のペイウォールがユーザーに閲覧された総回数を表します。ユーザーがそのプレースメント内のペイウォールを訪れるたびに、個別のビューとしてカウントされます。ビュー数の追跡により、ペイウォールに対するエンゲージメントとユーザーインタラクションのレベルを把握でき、アプリの特定エリア内でのユーザー行動やペイウォールの配置およびデザインの有効性についてのインサイトが得られます。 #### ユニークビュー数(Unique views) \{#unique-views\} ユニークビュー数指標は、特定のプレースメント内のペイウォールがユーザーに閲覧されたユニークなインスタンスの数を表します。各訪問を個別のビューとしてカウントする総ビュー数とは異なり、ユニークビュー数は、ユーザーがそのプレースメント内のペイウォールに何度アクセスしても、各ユーザーの訪問を1回としてカウントします。ユニークビュー数の追跡は、特定のプレースメント内でのユーザーエンゲージメントとペイウォールのリーチをより正確に測定するのに役立ちます。総訪問数ではなく個々のユーザーに注目しているためです。 #### 完了数とユニーク完了数(Completions & unique completions) \{#completions--unique-completions\} オンボーディングプレースメント専用。完了数はユーザーがオンボーディングプレースメントを完了した(最初から最後のスクリーンまで進んだ)回数をカウントします。同じユーザーが2回完了した場合、**完了数**は2ですが**ユニーク完了数**は1になります。 #### ユニーク完了率(Unique completions rate) \{#unique-completions-rate\} オンボーディングプレースメント専用。ユニーク完了数をユニークビュー数で割った値です。この指標は、オンボーディングプレースメントに対するユーザーのエンゲージメントを把握し、無視されていることに気づいた場合に改善を加えるのに役立ちます。 --- # File: create-paywall --- --- title: "ペイウォールを作成する" description: "Adaptyのペイウォールビルダーを使って、コンバージョン率の高いペイウォールを作成する方法を学びましょう。" --- [ペイウォール](paywalls)とは、提供するプロダクトを定義するAdaptyの設定です。Adaptyでは、アプリ内でプロダクトを取得する唯一の方法がペイウォールです。 表示方法に関わらず、ペイウォールは必ず必要です: - [**ペイウォールビルダー**](adapty-paywall-builder):ノーコードエディタで画面をデザインします。Adaptyがレンダリングと購入処理を行います。 - **カスタムペイウォール**:独自のUIを実装し、ペイウォールの設定を使ってプロダクトを取得します。 作成後は、ペイウォールを[プレースメント](placements)に割り当てます。プレースメントによって、ユーザーに表示されるペイウォールが決まります。公開中のペイウォールのプロダクトは固定されているため、指標は常に同じ組み合わせを反映し、異なるプロダクトや価格設定のパフォーマンスを比較できます。 :::tip [Developer CLI](developer-cli-reference#adapty-paywalls-create)を使ってプログラムでペイウォールを作成することもできます。 ::: <details> <summary>ペイウォール作成を始める前に(クリックして展開)</summary> 1. [プロダクトを少なくとも1つ作成する](create-product)。 2. (任意)[オファーを作成する](create-offer)。 </details> ## ペイウォールを作成する \{#create-paywall\} Adaptyダッシュボードで新しいペイウォールを作成するには: 1. Adaptyのメインメニューから[**Paywalls**](https://app.adapty.io/paywalls)に移動します。このページには、すべてのペイウォールとその指標の概要が表示されます。 2. **Create paywall** をクリックします。 3. **Paywalls / New paywall** ページで、Adaptyダッシュボード全体でこのペイウォールを識別するための **Paywall name** を入力します。 4. **Add product** をクリックします。 5. ユーザーに表示するプロダクトを選択します。 :::note - このリストのプロダクトの順序はSDKでも維持されるので、希望する順序に並べてください。 - ペイウォールが本番環境で表示された後は、ペイウォールの指標に影響する可能性があるため、プロダクトを変更することはできません。 ::: 6. プロダクトに無料トライアルやその他のオファーを提供する場合は、ここで追加してください。追加しないと利用できません。**Offer** リストから、このプロダクト用に[事前に作成した](create-offer)オファーを選択します。このリストはオファーが設定されているプロダクトにのみ表示されます。 7. **Create as a draft** をクリックしてペイウォールの作成を確定します。 ペイウォールが作成されました! <img src="/assets/shared/img/create-paywall.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '900px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 次のステップ \{#next-steps\} 最初のペイウォールを作成したら: 1. [プレースメント](placements)に追加します。プレースメントIDがハードコードされる唯一の要素になります。販売するプロダクトの取得にこれを使用します。 2. 次のペイウォールの作業方法は実装方法によって異なります: - [Adaptyペイウォールビルダー](adapty-paywall-builder)を使用する場合は、ノーコードエディタでペイウォールをデザインします。Adaptyがペイウォールのレンダリングと購入ロジックを処理するため、アプリのコードではペイウォールを表示するだけで済みます。 - カスタムペイウォールを使用する場合は、各プラットフォームでAdaptyを使ったアプリ内課金を実装するためのガイドを参照してください: - [iOS](ios-implement-paywalls-manually) - [Android](android-implement-paywalls-manually) - [React Native](react-native-implement-paywalls-manually) - [Flutter](flutter-implement-paywalls-manually) - [Unity](unity-implement-paywalls-manually) - [Kotlin Multiplatform](kmp-implement-paywalls-manually) --- # File: customize-paywall-with-remote-config --- --- title: "リモートコンフィグでペイウォールをデザインする" description: "Adapty のリモートコンフィグを使用してペイウォールをカスタマイズし、より精度の高いターゲティングを実現しましょう。" --- :::important このガイドはクラシックペイウォールのリモートコンフィグについて説明しています。フロービルダーについては、[フローのリモートコンフィグカスタマイズ](customize-flow-with-remote-config)をご参照ください。 ::: ペイウォールのリモートコンフィグは、柔軟な設定オプションを提供する強力なツールです。カスタム JSON ペイロードを使用して、ペイウォールを細かく調整できます。タイトル、画像、フォント、カラーなど、さまざまなパラメーターを定義することが可能です。 <details> <summary>ペイウォールのカスタマイズを始める前に(クリックして展開)</summary> 1. [プロダクトを作成する](create-product)。 2. [ペイウォールを作成してプロダクトを追加する](create-paywall)。 </details> リモートコンフィグを使ってペイウォールをカスタマイズするには: 1. Adapty メインメニューの [**Paywalls**](https://app.adapty.io/paywalls) セクションを開きます。 2. ペイウォールをクリックして開きます。 <img src="/assets/shared/img/remote-config.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Remote config** タブに切り替えます。 <img src="/assets/shared/img/remote-config-3.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> リモートコンフィグには 2 つの表示形式があります: - [テーブル](customize-paywall-with-remote-config#table-view-of-the-remote-config) - [JSON](customize-paywall-with-remote-config#json-view-of-the-remote-config) **Table** と **JSON** の両方のビューには同じ設定要素が含まれています。違いは好みの問題ですが、唯一の相違点はテーブルビューにコンテキストメニューが用意されている点で、ローカライズのエラー修正に役立ちます。 **Table** または **JSON** タブをクリックすることで、いつでも表示を切り替えられます。 どちらのビューでペイウォールをカスタマイズした場合でも、SDK から `AdaptyPaywall` の `remoteConfig` または `remoteConfigString` プロパティを使用してこのデータにアクセスし、ペイウォールを調整できます。また、[サーバーサイド API](api-adapty/operations/updatePaywall) を使用してリモートコンフィグの値をプログラム的に更新することで、ダッシュボードを手動で更新することなくペイウォールの設定を動的に変更することも可能です。リモートコンフィグの活用例をいくつか紹介します。 <Tabs groupId="current-os" queryString> <TabItem value="Titles" label="タイトル" default> ```json showLineNumbers { "screen_title": "Today only: Subscribe, and get 7 days for free!" } # Test titles or others texts ``` </TabItem> <TabItem value="Images" label="画像" default> ```json showLineNumbers { "background_image": "https://adapty.io/media/paywalls/bg1.webp" } # Test images on your paywall ``` </TabItem> <TabItem value="Fonts" label="フォント" default> ```json showLineNumbers { "font_family": "San Francisco", "font_size": 16 } # Test fonts ``` </TabItem> <TabItem value="Color" label="カラー" default> ```json showLineNumbers { "subscribe_button_color": "purple" } # Test colors of buttons, texts etc. ``` </TabItem> <TabItem value="HTML" label="HTML" default> ```json showLineNumbers { "photo_gallery": "https://adapty.io/media/paywalls/link-to-html-snippet.html" } # Any HTML code that can be displayed on the paywall ``` </TabItem> <TabItem value="Soft/Hard Paywall" label="ソフト/ハードペイウォール" default> ```json showLineNumbers { "hard_paywall": true } # By setting it to true, you disalow skipping paywall without subscribing # You have to handle this logic in your app ``` </TabItem> <TabItem value="Translations" label="翻訳" default> ```json showLineNumbers { "title": { "en": "Try for free!", "es": "¡Prueba gratis!", "ru": "Попробуй бесплатно!" } } ``` </TabItem> </Tabs> さまざまなオプションを組み合わせて独自の設定を作ることができます。これにより、タイトル、テキスト、画像、フォント、カラーなどをテストできます。 ### リモートコンフィグの JSON ビュー \{#json-view-of-the-remote-config\} リモートコンフィグの **JSON** ビューでは、任意の JSON 形式のデータを入力できます: <img src="/assets/shared/img/3356ff5-remote_config_JSON.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### リモートコンフィグのテーブルビュー \{#table-view-of-the-remote-config\} コードに慣れていない場合や JSON の値を修正したい場合は、Adapty の **Table** ビューが便利です。 <img src="/assets/shared/img/4c27b2f-remote_config_table.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> JSON をテーブル形式で表示するため、読みやすく理解しやすくなっています。カラーコーディングによって異なるデータ型を識別できます。 キーを追加するには、**Add row** ボタンをクリックします。値と型のマッピングを自動でチェックし、修正内容が無効な JSON につながる可能性がある場合はアラートを表示します。 <img src="/assets/shared/img/ef682d8-add_raw.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 追加の行オプションは、主に[ペイウォールのローカライズ](add-remote-config-locale)で役立ちます: <img src="/assets/shared/img/17bcf80-remote_config_table_options.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 次は[プレースメントを作成](create-placement)してペイウォールを追加しましょう。その後、モバイルアプリでリモートコンフィグのペイウォールを <InlineTooltip tooltip="リモートコンフィグペイウォールを表示する">[iOS](present-remote-config-paywalls)、[Android](present-remote-config-paywalls-android)、[React Native](present-remote-config-paywalls-react-native)、[Flutter](present-remote-config-paywalls-flutter)、[Unity](present-remote-config-paywalls-unity)</InlineTooltip> で表示できます。 --- # File: add-paywall-locale-in-adapty-paywall-builder --- --- title: "フローの言語設定を追加する(フローBuilder)" description: "Adaptyのフローbuilderでローカライズされたコンテンツを追加し、ユーザーの言語で世界中にリーチしましょう。" --- フローをローカライズすると、複数の言語で利用できるようになります。フロービルダーでは、ローカライズは画面ごとに管理され、各画面には翻訳の進捗を確認できる完了率が表示されます。 :::tip 他の言語を追加する前に、デフォルトのロケールでフローの設定を完成させておきましょう。 ::: ## ローカライズの追加と設定 \{#add-and-set-up-localization\} 1. 左パネルで Localizations をクリックし、次に **Add locale** をクリックします。追加する言語を選択してください。 2. 追加した各ロケールは、ローカライズテーブルの列として表示され、デフォルト言語の値があらかじめ入力されています。 3. 未翻訳の項目だけに絞り込みたい場合は、左パネルの **Missing only** トグルをオンにします。テーブルが未翻訳の行だけを表示するようにフィルタリングされます。 ## 外部翻訳のためのエクスポートとインポート \{#export-and-import-for-external-translation\} ローカライズファイルをエクスポートして翻訳者と共有し、翻訳済みの結果をインポートできます。 上部のツールバーで **Import / Export** をクリックします。 ### エクスポートファイルの形式 \{#export-file-format\} エクスポートすると、翻訳可能な要素ごとに1行ずつ記録された `.tsv`(タブ区切り)ファイルが生成されます。列の内容は以下のとおりです: | 列 | 説明 | |--------|-------------| | `Screen` | その要素が属する画面(例:`Welcome`、`Quiz`) | | `Element` | 画面内の要素を示す自動生成の識別子。**Interactions** > **Element ID** で変更できます。 | | `Property` | プロパティの種類(例:`content`) | | `[default_locale]` | デフォルト言語コード(例:`en`) | | `[locale]` | 追加したロケールごとの列(例:`fr`、`es`) | 例: ``` Screen Element Property en fr es Welcome title content Turn words into art Transformez les mots en art Welcome subtitle content Create stunning images in seconds with AI Créez des images en quelques secondes Quiz quiz-title content What will you create? ``` :::note 未翻訳の行はロケール列を空白のままにしておいてください — Adapty は未翻訳として扱います。 ::: ### インポートファイルの要件 \{#import-file-requirements\} - **形式**:`.tsv`(タブ区切り値) - **ヘッダー**:`Screen`、`Element`、`Property`、および少なくとも1つのロケール列が必要です - **ロケール列名**:フローにすでに追加されているロケールコードと一致している必要があります。フローに存在しないロケールコードが含まれるファイルをインポートするとエラーになります。 - **部分インポート**:行の一部だけを含めることもできます。ファイルに含まれていない行は現在の値が保持されます。 ## 手動で翻訳する \{#translate-manually\} ローカライズテーブルの任意のセルに直接翻訳を入力することもできます。 特定の行を操作するには、コンテキストメニュー(**⋮**)を開いてください: - **Reset to default**:その行の翻訳をデフォルト言語の値に戻します。 ## ローカライズをプレビューする \{#preview-the-localization\} 翻訳を確認するには、フロービルダーでアクティブなロケールを切り替え、各画面を確認します。 --- # File: add-remote-config-locale --- --- title: "リモートコンフィグを使ったペイウォールのローカライズ" description: "リモートコンフィグのロケールを追加して、Adapty のペイウォールをパーソナライズしましょう。" --- 多様な文化が共存する現代において、ペイウォールをさまざまな言語に対応させることは欠かせません。ローカライズによって、特定の地域のユーザーに合わせた体験を提供できます。各ペイウォールに複数言語のバージョンを追加することで、プロダクトが現地のオーディエンスに響くようになります。 Adapty のペイウォールビルダーを使わずにペイウォールをデザインしている場合でも、カスタムペイウォールをローカライズしたり、アプリを再デプロイせずにローカライズを管理したりすることができます。 1. Adapty ダッシュボードで変数を含むリモートコンフィグを作成します。変数はテキスト・メディア・その他のコンテンツタイプを表すことができます。 2. 各ロケールに変数の値を設定します。 3. アプリのコードで変数を処理します。 4. プロダクトを含むペイウォールを取得してロケールを送信すると、適切な変数の値が返されます。 こうすることで、ローカライズはアプリのコードにハードコードされず、いつでも調整できます。 テーブルビューでも JSON 形式でも、各言語の設定を簡単に調整できます。たとえば、文字列キーを翻訳したり、Boolean 値を切り替えたり(例:英語は `TRUE`、イタリア語は `FALSE`)、背景画像を差し替えたりすることも可能です。 ## リモートコンフィグで設定したペイウォールのローカライズを設定する \{#set-up-localization-for-remote-configured-paywalls\} 1. Adapty の [**Paywalls**](https://app.adapty.io/paywalls) セクションに移動します。 2. ペイウォールをクリックして開きます。 3. **Remote config** タブに移動します。 <img src="/assets/shared/img/switch_to_remote_config.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Locales** をクリックして対応させたい言語を選択します。変更を保存すると、これらのロケールがペイウォールに追加されます。 <img src="/assets/shared/img/add_locale.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これで、コンテンツを手動で翻訳したり、AI を使ったり、外部の翻訳者向けにローカライズファイルをエクスポートしたりできます。 ## AI を使ったペイウォールの翻訳 \{#translate-paywalls-with-ai\} AI による翻訳は、ペイウォールをローカライズするための迅速かつ効率的な方法です。 **String** と **List** の両方の値を翻訳できます。デフォルトではすべての行が選択されています(紫色でハイライト表示)。すでに翻訳済みの行は緑色でマークされ、新しい翻訳にはデフォルトで含まれません。選択されていない行や未翻訳の行はグレーで表示されます。 <img src="/assets/shared/img/localization-table.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/localization-json.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. 翻訳する行を選択します。ID・URL・変数が含まれる行はチェックを外しておくと、AI による誤訳を防げます。 2. 翻訳する言語を選択します。 <img src="/assets/shared/img/localization-table-language.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **AI Translate** をクリックして翻訳を適用します。選択した行が翻訳されてペイウォールに追加され、翻訳済みの行は緑色でマークされます。 ## 外部翻訳向けのローカライズファイルのエクスポート \{#exporting-localization-files-for-external-translation\} AI によるローカライズが普及しつつある一方、プロの人間翻訳者や実績のある翻訳会社を使うといった、より確実な方法を好む場合もあるでしょう。そのような場合は、ローカライズファイルをエクスポートして翻訳者に共有し、翻訳結果を Adapty にインポートし直すことができます。 **Export** ボタンでエクスポートすると、各言語の `.json` ファイルが個別に作成され、1 つのアーカイブにまとめられます。1 つのファイルだけが必要な場合は、言語ごとのメニューから直接エクスポートできます。 <img src="/assets/shared/img/localization-single-export.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 翻訳済みのファイルを受け取ったら、**Import** ボタンを使って一括またはファイルごとにアップロードします。Adapty は自動的にファイルを検証して、正しい形式かどうかを確認します。 ### インポートファイルの形式 \{#import-file-format\} インポートを成功させるには、インポートファイルが以下の要件を満たす必要があります。 - **ファイル名と拡張子:** ファイル名は表すロケールと一致し、拡張子は `.json` である必要があります。Adapty ダッシュボードでロケール名を確認してコピーできます。名前が認識されない場合、インポートは失敗します。 <img src="/assets/shared/img/locale-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **有効な JSON:** ファイルは有効な JSON である必要があります。そうでない場合、インポートは失敗します。 ## 手動ローカライズ \{#manual-localization\} 翻訳を微調整したり、特定のロケール向けに異なる画像を追加したり、リモートコンフィグを直接調整したりしたい場合もあるでしょう。 1. 翻訳したい要素を選んで新しい値を入力します。**String** と **List** の両方の値を更新したり、ロケールに適した画像に差し替えたりできます。 <img src="/assets/shared/img/032b429-remote_config_localization.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 英語ロケールのコンテキストメニューを活用して、ローカライズの問題を効率的に解決できます。 - **Copy this value to all locales**:選択した行について、英語ロケールの値で他のすべてのロケールの変更を上書きします。 - **Revert all row changes to original values**:現在のセッション中に行った変更をすべて破棄し、最後に保存した状態に戻します。 <img src="/assets/shared/img/d7e70f1-remote_confi_loc_table_options.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ペイウォールにロケールを追加したら、アプリのコードにロケールコードを正しく実装してください。<InlineTooltip tooltip="アプリでのローカライズとロケールコードの使い方に関するガイド">[iOS](localizations-and-locale-codes), [Android](android-localizations-and-locale-codes)</InlineTooltip> を参照してください。 --- # File: web-paywall-configuration --- --- title: "Webペイウォールの設定" --- **Web paywall** ページで **Create web paywall** をクリックすると、Webペイウォールのデザインと支払い方法を設定する専用ページに移動します。 ## 支払い方法の設定 \{#set-up-a-payment-method\} まず、購入を処理する決済プロバイダーを連携する必要があります。利用可能なオプションは以下のとおりです: - Stripe - Paddle - Paypal - Solidgate :::important AdaptyでWebペイウォールのアナリティクストラッキングを正確に行うには、[プロダクトを追加](product)する際に、対応するStripe/Paddle/その他の決済プロバイダーのプロダクトIDも一緒に登録する必要があります。 ::: 決済プロバイダーを設定するには: 1. Webペイウォールの一覧ページで **Settings** をクリックし、**Integrations** タブに切り替えます。 2. 決済プロバイダーを選択し、画面上の連携手順に従います。 <img src="/assets/shared/img/web-paywall-configuration-1.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ⚠️ Stripeを選択する場合、インターフェースに **Sandbox** と表示されていても、**Test Mode** 環境のキーを使用してください。そうしないとWebペイウォールが動作しません。Stripeの **Sandboxes** はまだサポートされていません。 <img src="/assets/shared/img/web-paywall-configuration-stripe.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Apple Payドメイン認証の設定 \{#set-up-apple-pay-domain-verification\} **Settings > Domains** で、ドメイン認証に使用するメインの決済プロバイダーを選択します。次に、それぞれのプロバイダーでペイウォールのドメインを認証してください: **Stripe**: 1. [Payment method domain settings](https://dashboard.stripe.com/settings/payment_method_domains) にアクセスし、**Add a new domain** をクリックします。 2. `app.funnelfox.com` と個人用のペイウォールサブドメイン(`paywalls-....fnlfx.com` のような形式)を追加します。サブドメインを確認するには、**Settings > Domains** に移動して **Hosted subdomain** の値をコピーしてください。 **Paddle**: 1. Paddleコンソールで **Checkout > Website approval** に移動し、**Add a new domain** をクリックします。 2. `app.funnelfox.com` と個人用のペイウォールサブドメイン(`paywalls-....fnlfx.com` のような形式)を追加します。サブドメインを確認するには、**Settings > Domains** に移動して **Hosted subdomain** の値をコピーしてください。 Paddleの承認プロセスは手動なので、ドメインが `Pending` から `Approved` に変わるまで待つ必要があります。 **FunnelFox Billing**: [FunnelFox Billingの連携手順](https://funnelfox.com/docs/billing/integration-billing-funnelfox)に従ってください。 **SolidGate**: 1. SolidgateダッシュボードでDevelopers > Apple Pay Domains** に移動します。 2. **+ Add new domain** をクリックし、プロジェクトドメイン(FunnelFoxの **Settings > Domains** から確認)を貼り付けます。カスタムドメインがある場合はそちらも追加してください。 3. プレビューモードでApple Payを使用するには、`http://app.funnelfox.com/` も追加してください。 ## Webペイウォールの作成と設定 \{#create-and-configure-a-web-paywall\} 1. Webペイウォールの一覧ページで **Create a paywall** をクリックします。 2. ペイウォール名を入力し、**Create** をクリックします。 <img src="/assets/shared/img/web-paywall-configuration-2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 2つのサブスクリプションオプションとApple Pay購入ボタンを含む基本テンプレートに移動します。 最初の画面にはサブスクリプションプランの一覧が表示されます。2番目と3番目の画面はチェックアウト画面で、それぞれが提供するプランに対応しています。プランが1つだけの場合は、余分な画面を削除してください。プランが複数ある場合は、チェックアウト画面を複製する必要があります。 購入完了後にユーザーが最後に見る画面では、アプリに戻れることを明確に示す必要があります。 <img src="/assets/shared/img/web-paywall-configuration-10.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. プラン一覧を設定します:プランと価格を追加または削除してください。画面に表示される価格やプランは動的に追加されないため、手動で設定する必要があります。 <img src="/assets/shared/img/web-paywall-configuration-8.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. プランごとにチェックアウト画面を追加または設定します。ユーザーが購入ボタンをクリックする前に支払金額を確認できるよう、各チェックアウト画面に合計金額を表示することをお勧めします。 6. チェックアウト画面にはすでにApple Payボタンがあります。機能させるには、各画面で以下を設定してください: 1. **Product type**:トライアル期間または割引を追加するかどうかを選択します。 2. **Trial period**:トライアル期間の長さを入力します。 3. **Product**:決済プロバイダーからプロダクトを選択します。 :::important プロダクトがAdaptyに追加されていることを確認してください。そうでない場合、購入結果はデフォルト値になります。 ::: 4. **Subscription discount**:オプションで、決済プロバイダーからクーポンを選択します。 <img src="/assets/shared/img/web-paywall-configuration-6.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. 次に、プランとチェックアウト画面を紐付ける必要があります。プラン選択画面で **Continue** ボタンをクリックし、各プランの遷移先画面を選択します。 <img src="/assets/shared/img/web-paywall-configuration-9.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ペイウォールの準備が完了したら、Adaptyでこのペイウォールを有効化するためのリンクを取得する必要があります。取得方法は、テスト中か本番環境での公開かによって異なります: 1. **サンドボックステスト用**:右上の **Preview** をクリックしてリンクをコピーします。 2. **本番環境用**:右上の **Publish** をクリックします。**Home** をクリックし、**URL** 列からリンクをコピーします。 <img src="/assets/shared/img/web-paywall-configuration-11.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 以上です!このリンクを使用して[設定を続けてください](web-paywall#step-2-trigger-the-paywall)。 --- # File: fallback-paywalls --- --- title: "フォールバックペイウォール" description: "Adaptyでシームレスなユーザーエクスペリエンスを確保するためにフォールバックペイウォールを使用します。" --- スムーズなユーザー体験を維持するために、[ペイウォール](paywalls)と[オンボーディング](onboardings)の**フォールバックバージョン**を設定することが重要です。 アプリがペイウォールを読み込む際、Adapty SDKはサーバーにペイウォールの設定データをリクエストします。しかし、ネットワークの問題やサーバー障害によりデバイスがAdaptyに接続できない場合はどうなるでしょうか? * ユーザーが以前にペイウォールにアクセスしており、デバイスにデータがキャッシュされている場合、アプリは**キャッシュから**ペイウォールデータを読み込みます。 * デバイスにペイウォールがキャッシュされていない場合、アプリはローカルに保存された設定ファイルを探します。これにより、エラーなしにペイウォールを表示できます。 Adaptyはフォールバック設定ファイルを自動的に生成するので、ダウンロードしてすぐに使えます。各ファイルには、*すべての*プレースメントに対するプラットフォーム固有の設定が含まれています。 ## はじめに \{#get-started\} 1. Adaptyから[フォールバック設定ファイルをダウンロード](/local-fallback-paywalls)します。 2. Adapty SDKを使用してフォールバックペイウォールを設定します: * [iOS](ios-use-fallback-paywalls) * [Android](android-use-fallback-paywalls) * [React Native](react-native-use-fallback-paywalls) * [Flutter](flutter-use-fallback-paywalls) * [Unity](unity-use-fallback-paywalls) * [Kotlin Multiplatform](kmp-use-fallback-paywalls) * [Capacitor](capacitor-use-fallback-paywalls) ## 制限事項 \{#limitations\} フォールバックペイウォールはハードコードされてローカルに保存されるため、通常のAdaptyペイウォールのような動的な機能はありません。 * フォールバックペイウォールは[国際化](paywall-localization)をサポートしていません。Adaptyが設定ファイルを生成する際、デフォルトの`en`ロケールが使用されます。 * 各プレースメントに設定できるフォールバックペイウォールは1つだけです。設定に異なる[オーディエンス](audience)向けの複数のペイウォール設定が含まれている場合、Adaptyは「すべてのユーザー」向けの設定を使用します。 * フォールバックペイウォールは[A/B テスト](ab-tests)をサポートしていません。ペイウォールがA/B テストに参加している場合、フォールバック設定ファイルには最も重みの高いバリアントが含まれます。 * フォールバックペイウォールは[リモートで管理](customize-paywall-with-remote-config)できません。設定ファイルを更新する場合は、App Store / Google Playでアプリの新しいバージョンをリリースする必要があります。 --- # File: local-fallback-paywalls --- --- title: "フォールバックペイウォールをダウンロードする" description: "Adapty のローカルフォールバックペイウォールを使用して、シームレスなサブスクリプションフローを確保しましょう。" --- Adapty はプラットフォームごとに[フォールバックペイウォール](/fallback-paywalls)用の JSON 設定ファイルを自動生成します。これらのファイルにはオンボーディングのフォールバックデータも含まれています。 1 つのプレースメントに複数のペイウォールまたはオンボーディングがある場合、フォールバックバージョンには最も高いウェイトまたは最も広いオーディエンスを持つバリアントが含まれます。Adapty はペイウォールやオンボーディングを変更するたびにこれらのファイルを更新します。 フォールバック設定をダウンロードするには、以下の手順に従ってください。 1. **[Placements](https://app.adapty.io/placements)** ページを開きます。 2. **Fallbacks** ボタンをクリックします。 3. ドロップダウンからターゲットプラットフォーム(*iOS* または *Android*)を選択します。 4. SDK バージョンを選択してダウンロードを開始します。 <img src="/assets/shared/img/9c63367-placements.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ダウンロード後の手順 \{#after-the-download\} 各プラットフォームのセットアップガイドに従ってください。 * [iOS](ios-use-fallback-paywalls) * [Android](android-use-fallback-paywalls) * [React Native](react-native-use-fallback-paywalls) * [Flutter](flutter-use-fallback-paywalls) * [Unity](unity-use-fallback-paywalls) * [Kotlin Multiplatform](kmp-use-fallback-paywalls) * [Capacitor](capacitor-use-fallback-paywalls) --- # File: paywall-metrics --- --- title: "ペイウォール指標" description: "ペイウォールのパフォーマンス指標を追跡・分析して、サブスクリプション収益を改善しましょう。" --- Adapty はペイウォールのパフォーマンスをより正確に計測するための一連の指標を収集しています。ビューを除くすべての指標はリアルタイムで更新され、ビューは数分おきに更新されます。ビューを除くすべての指標は、ペイウォール内のプロダクトに紐付けられます。このドキュメントでは、利用可能な指標の定義と計算方法を説明します。 ペイウォール指標はペイウォール一覧ページで確認でき、すべてのペイウォールのパフォーマンスを一覧で把握できます。この統合ビューでは各ペイウォールの指標が集計表示され、効果の評価や改善点の特定に役立ちます。 各ペイウォールの詳細な分析には、ペイウォール詳細指標ページに移動します。ここでは選択したペイウォールに特化した詳細な指標を確認でき、パフォーマンスへの深い洞察が得られます。 ### インストール日でフィルタリング \{#filter-metrics-by-install-date\} ペイウォール、トライアル、購入の指標は、2つの異なる日付でグループ化できます: - **イベント日** — ペイウォールが表示された日、トライアルが開始された日、または購入が行われた日。 - **インストール日** — ユーザーが初めてアプリを開いた日。 同じ日付範囲でも、この2つのビューは大きく異なる数値を示すことがあります。**Filter metrics by install date** チェックボックスで、ダッシュボードがどちらを使用するかを制御します: - **チェックなし(デフォルト)**:指標はイベント日でグループ化されます。 - **チェックあり**:指標はインストール日でグループ化されます。 **例。** 日付範囲を4月1日〜30日に設定し、トライアルを確認します。 - **チェックなし**:それらのユーザーがいつインストールしたかに関わらず、4月に*開始*されたトライアルを表示します。 - **チェックあり**:トライアルがいつ開始されたかに関わらず、4月に*インストール*したユーザーのトライアルを表示します。 特定のコホートのユーザー獲得パフォーマンスを測定するにはインストール日ビューを使用し、特定の期間のペイウォールやオンボーディングのアクティビティを測定するにはイベント日ビューを使用してください。 ### 指標コントロール \{#metrics-controls\} システムは選択した期間に基づいて指標を表示し、左側の列パラメータに3段階のインデントで整理します。 ライブのペイウォールの指標は、ペイウォールの開始日から現在までの期間を対象とします。非アクティブなペイウォールの指標は、開始日から選択した期間の終了日までの全期間を対象とします。下書きおよびアーカイブ済みのペイウォールも指標テーブルに含まれますが、データがない場合は指標なしで一覧表示されます。 #### 指標データの表示オプション \{#view-options-for-metrics-data\} ペイウォールページでは、プレースメントベースとオーディエンスベースの2つの表示オプションを利用できます。 プレースメントベースのビューでは、指標がペイウォールに関連付けられたプレースメント別にグループ化されます。これにより、プレースメントごとに指標を分析できます。 オーディエンスベースのビューでは、指標がペイウォールのターゲットオーディエンス別にグループ化されます。異なるオーディエンスセグメントごとの指標を評価できます。ペイウォール詳細ページ上部のドロップダウンから表示方法を選択できます。 #### 期間の選択 \{#time-ranges\} 日、週、月、カスタム期間など、さまざまな時間範囲を選択して指標データを分析できます。 #### 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link 関連記事: [アナリティクスコントロール](controls-filters-grouping-compare-proceeds) ::: Adapty はニーズに合わせた指標分析のフィルタリングとカスタマイズのための強力なツールを提供しています。Adapty の指標ページでは、さまざまな期間、グループ化オプション、フィルタリング機能を利用できます。 - フィルター対象: オーディエンス、国、ペイウォール、ペイウォールの状態、ペイウォールグループ、プレースメント、国、ストア、プロダクト、プロダクトストア - グループ化: プロダクトとストア #### 単一指標チャート \{#single-metrics-chart\} ペイウォール指標ページの主要なコンポーネントの一つがチャートセクションで、選択した指標を視覚的に表示して分析を容易にします。 ペイウォール指標ページのチャートセクションには横棒グラフが含まれており、選択した指標の値を視覚的に表示します。チャートの各バーは指標の値に対応しており、サイズが比例しているため、一目でデータを把握できます。横の線は分析している期間を示し、縦の列は指標の数値を表示します。すべての指標値の合計はチャートの横に表示されます。 また、チャートセクション右上の矢印アイコンをクリックするとビューが展開され、選択した指標がチャートの全幅で表示されます。 #### 指標合計サマリー \{#total-metrics-summary\} 単一指標チャートの横には指標合計サマリーセクションが表示されます。特定の時点における選択した指標の累積値が表示され、ドロップダウンメニューから表示する指標を切り替えられます。 ### 指標の定義 \{#metrics-definitions\} :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: #### 収益 \{#revenue\} この指標は、購入および更新によって USD で生成された総収入を表します。収益の計算には App Store / Google Play のコミッションは含まれておらず、各種手数料を差し引く前の金額で計算されることにご注意ください。 #### 受取額 \{#proceeds\} この指標は、App Store / Google Play の適用コミッションを差し引いた後に、アプリオーナーが購入および更新から USD で実際に受け取る金額を表します。 :::important アプリが手数料減額プログラムに登録している場合は、Adaptyにお知らせください。正確な計算のために、[アプリ設定](general)で[Small Business Program](app-store-small-business-program)および[Reduced Service Fee program](google-reduced-service-fee)の状態を指定してください。 ::: この指標はアプリの収益に直接貢献するネット収益を反映します。Proceedsの計算方法については、Adaptyの[ドキュメント](analytics-cohorts#revenue-vs-proceeds)を参照してください。 #### ARPPU \{#arppu\} ARPPUは課金ユーザー1人あたりの平均収益です。総収益を課金ユーザー数で割って計算します。例: $15,000の収益 ÷ 1,000人の課金ユーザー = $15のARPPU。 #### ARPAS \{#arpas\} ARPASはアクティブサブスクライバー1人あたりの平均収益で、トライアルまたはサブスクリプションを開始したサブスクライバー数で総収益を割って計算します。例えば、総収益が$5,000でサブスクライバーが1,000人の場合、ARPASは$5になります。この指標はサブスクライバー1人あたりの平均収益化ポテンシャルを評価するのに役立ちます。 #### 購入へのユニークコンバージョン率(CR) \{#unique-conversion-rate-cr-to-purchases\} 購入へのユニークコンバージョン率は、購入数をユニークビュー数で割って計算します。例えば、購入が10件でユニークビューが100件の場合、購入へのユニークコンバージョン率は10%になります。この指標はユニーク訪問者を有料顧客に転換する効果を把握するための比率です。 #### 購入へのCR \{#cr-to-purchases\} 購入へのコンバージョン率は、購入数を総ビュー数で割って計算します。例えば、購入が10件でビューが100件の場合、購入へのコンバージョン率は10%になります。この指標はビューが購入に結びつく割合を示し、ペイウォールのユーザー転換効果を把握するのに役立ちます。 #### トライアルへのユニークCR \{#unique-cr-to-trials\} トライアルへのユニークコンバージョン率は、開始されたトライアル数をユニークビュー数で割って計算します。例えば、トライアルが30件開始されてユニークビューが100件の場合、トライアルへのユニークコンバージョン率は30%になります。この指標はユニーク訪問者をトライアルユーザーに転換するペイウォールの効果を測定します。 #### 購入数(Purchases) \{#purchases\} 購入数はペイウォールで行われたさまざまなトランザクションの累計合計です。この指標には以下のトランザクションが含まれます(更新は含まれません): - ペイウォールで直接行われた新規購入 - ペイウォールで最初に開始されたトライアルのトライアル転換 - ペイウォールで行われたサブスクリプションのダウングレード、アップグレード、クロスグレード - ペイウォールでのサブスクリプション復元(自動更新なしで有効期限切れ後に再開された場合など) これらのさまざまなトランザクションを考慮することで、購入数指標はペイウォール全体の獲得・収益化アクティビティを包括的に把握できます。 #### トライアル数(Trials) \{#trials\} トライアル数は開始されたトライアルの総数を表します。ペイウォールを通じてトライアル期間を開始したユーザー数を反映します。この指標はトライアル提供の効果を追跡し、ユーザーエンゲージメントや有料サブスクリプションへの転換に関する洞察を提供します。 #### キャンセルされたトライアル数(Trials canceled) \{#trials-canceled\} キャンセルされたトライアル数は、自動更新機能がオフにされたトライアルの数を表します。これはユーザーが手動でトライアルを解約した場合に発生し、トライアル期間終了後にサブスクリプションを継続しないという意思決定を示します。キャンセルされたトライアルを追跡することで、ユーザー行動に関する貴重な情報が得られ、トライアルからの離脱率を把握できます。 #### 返金数(Refunds) \{#refunds\} 返金数は返金された購入およびサブスクリプションの件数を表します。これには、顧客からのリクエスト、支払いの問題、その他の返金ポリシーに基づいて取り消しまたは返金されたトランザクションが含まれます。 #### 返金率(Refund rate) \{#refund-rate\} 返金率は、返金数を初回購入数(更新は含まれません)で割って計算します。例えば、返金が5件で初回購入が1,000件の場合、返金率は0.5%になります。 #### ビュー数(Views) \{#views\} ビュー数はユーザーがペイウォールを閲覧した総回数を表します。ユーザーがペイウォールを訪れるたびに1ビューとしてカウントされます。例えば、ユーザーがペイウォールを2回訪れた場合、2ビューとして記録されます。ビュー数を追跡することで、ペイウォールへのエンゲージメントとユーザーインタラクションのレベルを把握し、ユーザー行動やペイウォールの配置・デザインの効果についての洞察が得られます。 #### ユニークビュー数(Unique views) \{#unique-views\} ユニークビュー数は、ユーザーがペイウォールを閲覧したユニークな回数を表します。総ビュー数が各訪問を別々にカウントするのとは異なり、ユニークビュー数は各ユーザーのペイウォールへのアクセス回数に関わらず1回としてカウントします。例えば、ユーザーがペイウォールを2回訪れた場合、1ユニークビューとして記録されます。ユニークビュー数を追跡することで、訪問総数ではなく個々のユーザーに着目したユーザーエンゲージメントとペイウォールのリーチのより正確な計測が可能になります。 :::warning `.logShowFlow()` (iOS SDK v4+) / `.logShowPaywall()` メソッドを使用して、ペイウォールのビューをAdaptyに必ず送信してください。送信しない場合、ペイウォールのビューが指標に反映されず、コンバージョン率が正確に計算されません。 ::: --- # File: migrate-paywalls --- --- title: "アプリ間でペイウォールを移行する" description: "AdaptyでペイウォールをAdapter他のアプリから移行する方法を学びます。" --- Adaptyを使えば、アプリごとにペイウォールを一から作り直す必要はありません。複数のアプリを管理している場合、ペイウォールビルダーで作成したペイウォールのビルダー設定を、別のアプリにそのまま移行できます。 移行でコピーされる視覚的な設定は次のとおりです: - ペイウォールおよびすべてのペイウォール要素のレイアウト設定 - メディア - ローカライズ 移行はビルダー設定のみが対象で、プロダクトやリモートコンフィグはコピーされません。 :::note カスタムフォントを使用したペイウォールビルダー設定を移行する場合は、表示が崩れる可能性があるため、実機でテストしてください。 ::: ## ペイウォールの移行 \{#migrate-paywall\} :::important 移行できるのは、**新しい** Adapty ペイウォールビルダーで作成されたペイウォールのみです。**レガシー**ペイウォールビルダーのペイウォールを移行するには、先に新しいペイウォールビルダーへ移行する必要があります。 ::: ペイウォールビルダーの設定を移行するには: 1. **新しいペイウォールの場合**:[ペイウォールの作成](create-paywall)を開始し、プロダクトを追加します。次に、**Build no-code paywall** をクリックしてテンプレートライブラリを開きます。 **既存のペイウォールの場合**:**Builder & Generator** タブの **Layout settings** セクションに移動し、**Change template** をクリックします。 2. ペイウォールテンプレートを編集中に、**Copy a design from your apps** ボックス内の **Choose paywall** をクリックします。 <img src="/assets/shared/img/migrate-paywall-builder.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 設定のコピー元となるアプリとペイウォールを選択します。 <img src="/assets/shared/img/migrate-app.png" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Copy Selected Paywall** をクリックします。 移行後は必要に応じて編集でき、元のペイウォールには影響しません。 --- # File: duplicate-paywalls --- --- title: "ペイウォールを複製する" description: "Adaptyでのペイウォールの複製と管理方法について学びましょう。" --- 既存のペイウォールに少し変更を加えたい場合、特にすでにモバイルアプリで使用中でアナリティクスへの影響を避けたい場合は、単純に複製するだけで大丈夫です。作成した複製は、必要に応じて一部またはすべてのプレースメントで元のペイウォールと置き換えて使用できます。 複製を作成すると、ペイウォールの名前・プロダクト・プロモーションなど、すべての設定がコピーされます。新しいペイウォールには元の名前に「Copy」が付加されるため、元のペイウォールと区別しやすくなります。 Adapty ダッシュボードでペイウォールを複製する手順は次のとおりです。 1. Adaptyのメインメニューから [**Paywalls**](https://app.adapty.io/paywalls) セクションを開きます。Adapty ダッシュボードのペイウォール一覧ページには、アカウント内のすべてのペイウォールが表示されます。 2. 複製したいペイウォールの隣にある **3-dot** ボタンをクリックし、**Duplicate** を選択します。 <img src="/assets/shared/img/duplicate.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 新しいペイウォールを編集し、**Save** ボタンをクリックします。 4. 元のペイウォールがいずれかのプレースメントで使用中の場合、Adaptyは元のペイウォールを複製に置き換えるかどうかを確認するプロンプトを表示します。**Create and replace original** を選択すると、新しいペイウォールはすぐに **Live** 状態になります。または、**Draft** 状態の新しいペイウォールとして作成し、後でプレースメントに追加することもできます。 --- # File: archive-paywalls --- --- title: "ペイウォールのアーカイブ" description: "データを失わずにAdaptyで古いペイウォールをアーカイブする方法を説明します。" --- Adaptyを使い込んでペイウォールの設定を細かく調整していくうちに、現在の戦略やキャンペーンに合わなくなったペイウォールが増えていくことがあります。こうした未使用のペイウォールが `Inactive` のまま残っていると、ワークスペースが散らかり、必要なものを見つけにくくなります。この問題を解決するために、Adaptyでは不要なペイウォールをアーカイブする機能を提供しています。 アーカイブすることで、ペイウォールを完全に削除せず安全に保存でき、必要になったときにいつでも参照できます。また、アーカイブしたペイウォールはデフォルトの表示から除外できるため、ワークスペースがすっきりし、インターフェースも見やすくなります。このガイドでは、Adaptyでペイウォールを効率的にアーカイブする方法を説明し、ペイウォール管理をより細かくコントロールできるようにします。 ご注意:少なくとも1つのプレースメントで現在アクティブなライブのペイウォールはアーカイブできません。そのようなペイウォールをアーカイブしたい場合は、事前にすべてのプレースメントから削除してください。 :::note 非アーカイブのA/B テストで使用中のペイウォールはアーカイブできません。これにより、完了したA/B テストの詳細な指標を確認でき、紐付けられたペイウォールもそのデータの一部として保持されます。 ::: **ペイウォールをアーカイブするには:** 1. Adaptyのメインメニューで [**Paywalls**](https://app.adapty.io/paywalls) セクションを開きます。 2. アーカイブしたいペイウォールの横にある **3-dot** ボタンをクリックし、**Archive** オプションを選択します。 <img src="/assets/shared/img/archive-paywall.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Archive paywall** ウィンドウが表示されたら、アーカイブしたいペイウォールの名前を入力し、**Archive** ボタンをクリックします。 --- # File: restore-paywall --- --- title: "ペイウォールをアーカイブから戻す" description: "Adapty でペイウォールを復元して、ユーザーへのサブスクリプションサービスを途切れなく提供しましょう。" --- ペイウォールをアーカイブできる機能は、ペイウォール管理プロセスを効率化するうえで非常に役立ちます。不要になったペイウォールを非表示にしてワークスペースをすっきりさせたり、必要になった際にアーカイブ済みのペイウォールを復元して再活用したりと、柔軟な運用が可能です。 アーカイブ済みのペイウォールはデフォルトビューではフィルタリングされて表示されない場合があります。表示するには、**State** フィルターで **Archived** を選択してください。 **ペイウォールをアーカイブから元に戻すには** 1. Adapty メインメニューの [**Paywalls**](https://app.adapty.io/paywalls) セクションを開きます。 2. アーカイブ済みのペイウォールがリストに表示されていることを確認します。表示されていない場合は、右側のフィルターを更新してください。 <img src="/assets/shared/img/paywall-filter.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. アーカイブ済みペイウォールの横にある **3点ドット** ボタンをクリックし、**Back to active** を選択します。 <img src="/assets/shared/img/restore-paywall.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: profiles-crm --- --- title: "プロファイル/CRM" description: "Adaptyでユーザープロファイルとデータを管理し、オーディエンスのセグメンテーションを強化します。" --- プロファイルはユーザー向けのCRMです。プロファイルを使うと、次のことができます: 1. プロファイル ID、カスタマーユーザー ID、メールアドレス、またはトランザクション ID で特定のユーザーを検索する。 2. 請求の問題、グレース期間、その他の[イベント](events)を含む、ユーザーのイベントタイムラインを確認する。 3. サブスクリプションの状態、総収益・手取り額など、ユーザーのプロパティを分析する。 4. ユーザーにサブスクリプションを付与する。 :::note イベントフィードのイベントはダッシュボードに届くまでに遅延が発生します。新しいプロファイルや属性の変更はすぐに反映されない場合があります。 ::: <img src="/assets/shared/img/profiles.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::link Adapty がどのようにユーザープロファイルを作成・紐付けするかについては、[プロファイルの仕組み](how-profiles-work)をご覧ください。 ::: ## ユーザーの検索 \{#finding-users\} プロファイル一覧では、次の方法で特定のユーザーを検索できます。 - **Profile ID**: Adapty がユーザーに付与する内部識別子(Adapty ID とも呼ばれます)。 - **Customer user ID**: アプリ側で設定したユーザーの識別子(設定している場合)。 - **Email**: カスタム属性として送信したユーザーのメールアドレス(送信している場合)。 - **Transaction ID**: 購入時のストアトランザクション ID。 任意の行をクリックすると、そのユーザーの詳細プロファイルが開きます。 ## サブスクリプション状態 \{#subscription-state\} プロファイル一覧では、サブスクリプション状態でユーザーをフィルタリングおよび並べ替えることができます。状態の値は以下のとおりです: | ユーザーの**状態** | 説明 | | :--------------------- | :----------------------------------------------------------- | | Subscribed | ユーザーは自動更新が有効なアクティブなサブスクリプションを持っています。 | | Auto-renew off | ユーザーは自動更新をオフにしましたが、サブスクリプション期間の終了までプレミアム機能にアクセスできます。 | | Subscription cancelled | ユーザーはサブスクリプションをキャンセルし、完全に終了しました。 | | Billing issue | サブスクリプションまたはトライアル終了後に請求の問題が発生し、ユーザーに課金できませんでした。 | | Grace period | サブスクリプションまたはトライアル終了後の課金試行時に請求の問題が発生したため、ユーザーは現在グレース期間中です。 | | Active trial | ユーザーはトライアル期間中のアクティブなサブスクリプションを持っています。 | | Trial cancelled | ユーザーはトライアルをキャンセルし、アクティブなサブスクリプションはありません。 | | Never subscribed | ユーザーはサブスクリプションを開始したことがなく、トライアルも利用したことがない無料ユーザーです。 | ## ユーザー属性 \{#user-attributes\} <img src="/assets/shared/img/ce8df4d-CleanShot_2023-06-26_at_20.32.232x.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> SDKを使って、追加のユーザープロパティをAdaptyに送信できます。 デフォルトでは、Adaptyが設定する項目: | プロパティ | 説明 | | ---------------- | ------------------------------------------------------------ | | Customer user ID | あなたのシステム上のエンドユーザーの識別子。 | | Adapty ID | エンドユーザーの Adapty 内部識別子。プロファイル ID とも呼ばれます。 | | IDFA | Apple がユーザーのデバイスに割り当てる広告識別子。iOS 14 以降では App Tracking Transparency (ATT) の許可が必要です。Android では利用できません。 | | Country | エンドユーザーの国。 | | OS | エンドユーザーが使用しているオペレーティングシステム。 | | Device | エンドユーザーに表示されるデバイスのモデル名。 | | Install date | ユーザーが Adapty に初めて記録された日付:<ul><li>ユーザーが作成された日付。</li><li>Adapty を導入する前にアプリをインストールしていたユーザーの場合、インストール日は最初のトランザクションの日付になります。</li><li>該当する場合、過去データのインポート時に提供された日付。</li></ul> | | Created at | ユーザーが作成された日付。 | SDKをインストールした後、Adaptyは支払いキューからユーザーイベントを自動的に収集し、ユーザープロファイルに表示します。上記の表の属性は自動的に収集されるため、送信する必要はありません。 ### カスタム属性 \{#custom-attributes\} プロファイルの **Attributes** セクションでは、SDK または API を通じて設定されたカスタム属性を確認できます。**Add attribute** ボタンを使って手動で属性を追加することもできます。 <img src="/assets/shared/img/378c1fb-add_attribute.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> ## サブスクリプションの付与 \{#granting-a-subscription\} プロファイルでは、実際に購入しなくても、有効なサブスクリプションを延長したり、アクセスレベルへの永続アクセスをユーザーに付与したりすることができます。 <img src="/assets/shared/img/b1d74fd-edit_paid_access_level.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 主な用途は以下のとおりです: - 請求やサポートに関する問題が発生したユーザーへの補償。 - 手動プロモーションやベータプログラムの実施。 - 実際に購入せずにサブスクリプションのフローをテストする。 アクセスを付与するには、ユーザーのプロファイルを開き、**Access levels** セクションに移動して **Edit** をクリックします。有効期限を設定して保存してください。有効期限は未来の日時である必要があり、一度設定したら短縮することはできません。有効なサブスクリプションに対して調整しても、継続中の支払いには影響しません。 :::note アクセスの付与は、App Store や Google Play の購入イベントを作成しません。ユーザーのイベントフィードやアナリティクスは、実際の購入フローとは異なります。 ::: プログラムからアクセスを付与する場合は、[Grant access level](api-adapty/operations/grantAccessLevel) API メソッドを使用してください。 ## ユーザーアカウント間での有料アクセスの共有 \{#sharing-paid-access-between-user-accounts\} :::link メイン記事: [ユーザーアカウント間での有料アクセスの共有](sharing-paid-access-between-user-accounts) ::: ### アクセス共有の履歴 \{#access-sharing-history\} アクセスレベルが共有または転送されると、ユーザーのプロファイルに接続されたプロファイルへのリンクが表示されます。このリンクは、アクセスを共有したプロファイル、またはアクセスを受け取ったプロファイルを示しています。接続されたプロファイルを表示するには、ユーザーの **Profile** でアクセスレベルの横にあるリンクをクリックしてください。 <img src="/assets/shared/img/profile-access-level-origin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note バーチャル通貨の残高は、アクセスレベルのようにプロファイル間で共有・転送されません。各残高は単一のプロファイルに紐づきます — 詳細は[残高、プロファイル、デバイス](virtual-currency-balance#balances-profiles-and-devices)をご覧ください。 ::: ## 次のステップ \{#next-steps\} - Adapty がプロファイルを作成・リンクする仕組みについては、[プロファイルの仕組み](how-profiles-work)を参照してください。 - アクセス共有ポリシーの設定については、[ユーザーアカウント間での有料アクセスの共有](sharing-paid-access-between-user-accounts)を参照してください。 - プログラムからアクセスを付与するには、[アクセスレベルの付与](api-adapty/operations/grantAccessLevel) API メソッドを参照してください。 --- # File: how-profiles-work --- --- title: "プロファイルの仕組み" description: "Adaptyがユーザープロファイルをどのように作成・追跡・紐付けするかを理解しましょう — 匿名プロファイル、識別済みユーザー、親/継承プロファイルの関係を含みます。" --- アプリのすべてのユーザーには、購入履歴・イベント・サブスクリプションの状態を追跡するAdaptyプロファイルが割り当てられます。プロファイルがどのように作成・紐付けされるかを理解することで、インテグレーションのバグを防ぎ、データの断片化を避け、[プロファイル](profiles-crm)セクションのデータを正しく解釈できます。 ## プロファイルの作成 \{#profile-creation\} Adaptyはユーザーがアプリを初めて起動したタイミングで、自動的にプロファイルを作成します。 **Customer User IDがない場合**、プロファイルは匿名になります。以下のタイミングで毎回新しい匿名プロファイルが作成されます: - ユーザーがアプリを再インストールしたとき - ユーザーがアプリからログアウトしたとき(アプリが`Adapty.logout()`を呼び出したとき) 購入はアプリのインストールに紐付けられ、永続的なユーザー識別情報には紐付けられません。 **Customer User IDがある場合**、プロファイルは再インストールやデバイスをまたいで維持されます。Customer User IDを使うことで、次のことが可能になります: 1. 再インストールや複数デバイスにまたがってユーザーを追跡できます。 2. [**Profiles**](profiles-crm)セクションでCustomer User IDからユーザーを検索できます。 3. [サーバーサイドAPI](getting-started-with-server-side-api)でCustomer User IDを使用できます。 4. AdaptyはCustomer User IDをすべてのインテグレーションに送信します。 Customer User IDを使用する場合のプロファイルの動作は、いつ設定するかによって異なります: - **SDKの初期化時**:そのCustomer User IDを持つ既存のプロファイルを使用します(再訪ユーザーの場合)、または新しいプロファイルを作成します(初回ユーザーの場合)。 - **SDK初期化後**:初期化時に匿名プロファイルが作成されます。その後ユーザーを識別すると、AdaptyはCustomer User IDを匿名プロファイルに紐付けます(初回ユーザーの場合)、または既存のプロファイルに切り替えます(再訪ユーザーの場合)。 **どちらのアプローチを使うか:** - **アプリ起動時にCustomer User IDが利用可能な場合**(例:前回のセッションから保存されている)— SDKの初期化時に`activate()`へ渡します。 - **ユーザーがアプリ起動後にサインインする場合**— 認証後に`identify()`を呼び出します。AdaptyはそのIDを現在のプロファイルに紐付けます(IDが新規の場合)、または既存のプロファイルに切り替えます(IDが既に存在する場合)。 - **ログイン前に購入できる場合**— ログイン後に`identify()`を呼び出します。Customer User IDがAdaptyに既に存在する場合は、その後プロファイルを取得して現在のアクセスレベルを同期してください。 実装の詳細については、[ユーザーの識別](identifying-users)SDKガイドを参照してください。 :::note 以前にCustomer User IDなしでアプリを使用したことがある再訪ユーザーの場合、SDK初期化時に識別を開始しても、それらの匿名プロファイルは自動的にマージされません。そのようなユーザーの完全な履歴を維持するには、ログイン後に`identify()`を使用してください。 ::: ## 親プロファイルと継承プロファイル \{#parent-and-inheritor-profiles\} 同じストア側のサブスクリプションが複数のAdaptyプロファイルに関連付けられている場合、Adaptyはそれらのプロファイルをチェーンとして扱います:1つの**親**プロファイルと、同じ購入からアクセスを共有する1つ以上の**継承**プロファイルです。 これは以下の場合に発生します: - [ユーザーアカウント間での有料アクセスの共有](sharing-paid-access-between-user-accounts)が有効で、別のプロファイルが購入したデバイスにユーザーがサインインしたとき。 - ユーザーが`customer_user_id`なしでアプリを再インストールし、新しいプロファイルが前のインストールの購入を引き継いだとき。 - 異なる識別済みユーザーが同じデバイスで購入を復元したとき。 - アプリがApple Team IDを変更し、新しいアプリが旧Team IDで行われた購入を引き継いだとき。 **親の決定方法。** 親は**最初に購入を記録したプロファイル**です — プロファイルの作成順ではなく、Adaptyでの購入レシートの順序によって決定されます。例:アプリをインストールして購入せず、再インストールしてサブスクリプションを購入した場合、2番目のプロファイルが親になります(購入を行ったため)。最初のプロファイルは継承プロファイルとなり、共有によってアクセスを得ます。 **イベントの分配方法:** - **トランザクションイベント**(購入、更新、キャンセル、請求の問題、グレース期間、返金):購入を行った**親プロファイル**にのみ表示されます。サブスクリプションの更新・変更はすべてこのプロファイルに表示され続けます。 - **`access_level_updated`イベント**:アクセスレベルの状態が変化するたびに、**親プロファイルと継承プロファイルの両方**に表示されます。これにより、紐付けられたすべてのプロファイルが現在のアクセス状態を把握できます。 親プロファイルには完全なトランザクション履歴が表示されます。継承プロファイルには、アクセスレベルの更新のみが表示され、**Access level**セクションに親プロファイルへのリンクが表示されます。 <img src="/assets/shared/img/98d0dad-non-original_profile.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> **複数のプロファイルにまたがる同一サブスクリプションの追跡。** 各継承プロファイルは独自の`profile_id`を持つため、`profile_id`はチェーン全体で一定ではありません。複数のプロファイルにまたがって同じサブスクリプションを特定するには(例:Webhookイベントの照合や、ダッシュボードのプロファイルと1人のユーザーの対応付け)、ストア側の識別子を使用してください。 | フィールド | 用途 | | --- | --- | | `store_original_transaction_id` | プロファイルをまたいだサブスクリプションチェーンの識別。Appleのサブスクリプションごとに一意。 | | `profiles_sharing_access_level`(Webhookフィールド) | 共有が有効な場合に、そのサブスクリプションによって権限を付与されているすべてのプロファイル。 | | `profile_id` | クロスプロファイル追跡には**不適切** — 各継承プロファイルが独自のIDを持つため。 | ## プロファイルなしのトランザクション \{#transactions-without-profiles\} Adaptyの一部のトランザクションはプロファイルに紐付けられていません — アナリティクスとエクスポートには表示されますが、プロファイルリストには表示されません。これは、Adapty SDKを通じてアプリに接続したことがないユーザーへの**サーバー間(S2S)ストア通知**が届いた場合に発生します。既知の発生源は以下の通りです: - App Store S2S通知(返金イベントを含む) - Google Play S2S通知 - StripeおよびPaddleのWebhookイベント これらのトランザクションは: - **アナリティクスチャートに表示されます**(全体の指標にカウントされます) - **エクスポートに表示されます**(S3、GCS、BigQuery)— `profile_id`は`null`に設定されます - **プロファイルリストには表示されません** — 紐付けるプロファイルが存在しないため アナリティクスやエクスポートで、プロファイルUIで見つけられるより多くのイベントが表示される場合、その差はおそらくこれらのプロファイルなしトランザクションによるものです。エクスポートで見つけるには、`profile_id IS NULL`の行でフィルタリングしてください。 ## ユーザーアカウント間での有料アクセスの共有 \{#sharing-paid-access-between-user-accounts\} :::link メイン記事: [ユーザーアカウント間での有料アクセスの共有](sharing-paid-access-between-user-accounts) ::: アクセスレベルの共有ポリシーを設定するには、[**General**](general)設定ページで共有オプションを選択します。[サンドボックス環境](test-purchases-in-sandbox)に対して別のポリシーを設定することもできます。 **有効(デフォルト)** 識別済みユーザー([Customer User ID](identifying-users#set-customer-user-id-on-configuration)が設定されているユーザー)は、同じApple/Google IDでサインインしているデバイスであれば、Adaptyが提供する同じ[アクセスレベル](access-level)を共有できます。これは、ユーザーがアプリを再インストールして別のメールアドレスでログインした場合でも、以前の購入へのアクセスを維持できるため便利です。このオプションでは、複数の識別済みユーザーが同じアクセスレベルを共有できます。 アクセスレベルは共有されますが、過去および将来のすべてのトランザクションは、一貫したアナリティクスを維持し完全なトランザクション履歴(トライアル期間、サブスクリプション購入、更新など)を同じプロファイルに紐付けるため、元のCustomer User IDのイベントとして記録されます。 **新しいユーザーへアクセスを移譲** 識別済みユーザーは、デバイスが同じApple/Google IDでサインインしている限り、別の[Customer User ID](identifying-users#set-customer-user-id-on-configuration)でログインしたりアプリを再インストールしたりしても、Adaptyが提供する[アクセスレベル](access-level)を引き続き利用できます。 前のオプションとは異なり、Adaptyは識別済みユーザー間で購入を移譲します。これにより購入済みコンテンツへのアクセスが保証されますが、一度にアクセスできるのは1人のユーザーのみです。たとえば、UserAがサブスクリプションを購入し、同じデバイスでUserBがログインしてトランザクションをリストアした場合、UserBがサブスクリプションへのアクセスを取得し、UserAからはアクセスが取り消されます。 いずれかのユーザー(新しいユーザーまたは古いユーザー)が識別されていない場合でも、Adapty内でそれらのプロファイル間でアクセスレベルは共有されます。 アクセスレベルは移譲されますが、過去および将来のすべてのトランザクションは、一貫したアナリティクスを維持し完全なトランザクション履歴(トライアル期間、サブスクリプション購入、更新など)を同じプロファイルに紐付けるため、元のCustomer User IDのイベントとして記録されます。 **新しいユーザーへアクセスを移譲**に切り替えた後、アクセスレベルはすぐにはプロファイル間で移譲されません。特定のアクセスレベルの移譲プロセスは、サブスクリプションの更新、リストア、またはトランザクションの検証など、ストアからのイベントをAdaptyが受信したときにのみトリガーされます。 **無効** 最初にアクセスレベルを取得した識別済みユーザープロファイルが、それを永続的に保持します。これは、ビジネスロジック上、購入を単一のCustomer User IDに紐付ける必要がある場合に最適なオプションです。 なお、匿名ユーザー間ではアクセスレベルは引き続き共有されます。 [オーナーのユーザープロファイルを削除する](https://adapty.io/docs/ja/api-adapty/operations/deleteProfile)ことで、購入の紐付けを解除できます。削除後、アクセスレベルは最初にそれを要求したユーザープロファイル(匿名または識別済みを問わず)に付与されます。 共有の無効化は新しいユーザーにのみ影響します。すでにユーザー間で共有されているサブスクリプションは、このオプションを無効にした後も共有され続けます。 :::warning AppleとGoogleは、購入をApple/Google IDに紐付けているため、ユーザー間でアプリ内課金を共有または移譲することを求めています。共有がなければ、その後の再インストール時に購入のリストアが機能しない可能性があります。 共有を無効にすると、ログイン後にユーザーがアクセスを取り戻せなくなる場合があります。 共有の無効化は、ユーザーが購入前に**ログインを必須とする**場合にのみ推奨します。そうでない場合、識別済みユーザーがサブスクリプションを購入した後に別のアカウントにログインすると、アクセスを永続的に失う可能性があります。 ::: ### どの設定を選べばよいですか? \{#which-setting-should-i-choose\} | アプリの条件 | 選択するオプション | | ------------------------------------------------------------ | ------------------------------------------------------------ | | ログインシステムがなく、AdaptyのみMatch anonymous profile IDを使用している。 | デフォルトオプションを使用してください。3つのオプションすべてで、匿名プロファイルID間ではアクセスレベルが常に共有されます。 | | オプションのログインシステムがあり、アカウント作成前に購入できる。 | **新しいユーザーへアクセスを移譲**を選択してください。アカウントなしで購入したユーザーが後でトランザクションをリストアできるようになります。 | | 購入前にアカウント作成を必須とするが、購入を複数のCustomer User IDに紐付けることを許可している。 | **新しいユーザーへアクセスを移譲**を選択してください。一度にアクセスできるCustomer User IDは1つに限られますが、別のCustomer User IDでログインしても有料アクセスを失わずに済みます。 | | 購入前にアカウント作成を必須とし、購入を単一のCustomer User IDに厳密に紐付けるルールがある。 | **無効**を選択してください。アカウント間でトランザクションが移譲されないことが保証されます。 | ## 未来の日付のイベントタイムスタンプ(Apple/iOS) \{#event-timestamps-with-future-dates-appleios\} この動作はApple App Storeに特有のものです。Google Playの通知システムはイベントを事前に送信しません。 プロファイルやインテグレーションのイベントタイムスタンプが未来の日付を示すことがあります。これはAppleが更新イベントを事前に送信するためです。 - **発生理由**:Appleはサブスクリプションが期限切れになる前に自動更新されるようにしており、ユーザーのサービス中断を防ぐためです。詳細はAppleのデベロッパーフォーラムをご覧ください:[Server Notifications for Subscriptions](https://developer.apple.com/forums/tags/app-store-server-notifications)。 - **影響するイベントの種類**:通常、サブスクリプションの更新とトライアルから有料への転換に適用されます。これらのイベントはAppleが事前に通知するため、未来のタイムスタンプを持つ場合があります。 - **その他のイベントの種類**:追加のアプリ内課金とサブスクリプションプランの変更は、事前に予測できないため、実際のタイムスタンプで記録されます。 - **アナリティクスとイベントフィードへの影響**:これらのイベントは、タイムスタンプが過ぎた後にのみ**Analytics**と**Event Feed**に表示されます。未来のタイムスタンプを持つイベントはどちらのセクションにも表示されません。 - **インテグレーションへの影響**:Adaptyはイベントを受信したらすぐにインテグレーションへ送信します。イベントが未来のタイムスタンプを持つ場合、Adaptyはその未来のタイムスタンプをそのままインテグレーションに送信します。 ## 次のステップ \{#next-steps\} - プロファイルダッシュボードを使用してユーザーを検索・管理するには、[プロファイル](profiles-crm)を参照してください。 - アプリでのユーザー識別を設定するには、[ユーザーの識別](identifying-users)SDKガイドを参照してください。 - アクセス共有ポリシーを設定するには、[ユーザーアカウント間での有料アクセスの共有](sharing-paid-access-between-user-accounts)を参照してください。 --- # File: sharing-paid-access-between-user-accounts --- --- title: "ユーザーアカウント間での有料アクセスの共有" description: "複数のデバイスや複数のアプリプロファイルを持つユーザーに対応するため、異なるユーザーアカウント間で有料アクセスを共有する方法" --- ユーザーが購入を行うと、Adapty はアクティブな[プロファイル](identifying-users)に新しい[アクセスレベル](access-level)を割り当てます。このアクセスレベルにより、購入者は有料コンテンツにアクセスできるようになります。 購入者のプロファイルは、アプリの再インストールや新しいアプリ内アカウントへのログインによって意図せず変わることがあります。アクセスが途切れないよう、Adapty は元のプロファイルとその後のプロファイルの間でユーザーのアクセスレベルを自動的に共有します。 このアプローチはほとんどのアプリケーションに最適です。ただし、ビジネスロジックの要件によっては、より制限的な有料アクセス共有ポリシーを選択することもできます。 [General Settings](https://app.adapty.io/settings/general) ページを開いて、アクセスレベルの共有ポリシーを設定してください。テストを容易にするため、[サンドボックス環境のみ](#sharing-paid-access-on-sandbox)でこの設定を変更することもできます。 <Details> :::important アプリケーションがユーザー認証を行っていない場合、この設定は無視してかまいません。同じストアアカウントに関連付けられた匿名プロファイルは、*常に*アクセスレベルを共有します。 ::: <summary>どのアクセス共有ポリシーを選べばよいですか?(クリックして展開)</summary> | 私のアプリは… | おすすめの設定 | | ------------------------------------------------------------ | ------------------------------------------------------------ | | 認証機能を持たず、Adapty の匿名プロファイル ID のみを使用している。 | **Enabled (default)** 設定を使用してください。 | | ユーザー認証が可能だが、アカウントなしで購入できる。 | **Transfer access to new user** 設定を有効にしてください。ユーザーがサインアップして匿名購入を引き継げるようになります。 | | 購入前にアカウント作成が必須だが、1 つのプロダクトを複数の Customer User ID にリンクできる。 | **Transfer access to new user** 設定を有効にしてください。複数のアカウントがプロダクトにアクセスできますが、順番にのみアクセス可能です。 | | 購入前にアカウント作成が必須で、購入を単一の Customer User ID に紐付ける厳格なルールがある。 | アクセスレベルの共有を**無効**にしてください。 | </Details> <img src="/assets/shared/img/sharing-paid-access.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Enabled(デフォルト) \{#enabled-default\} この設定は、**組み込み認証を持たない**アプリケーションに最適です。購入後、同じストアアカウントに関連付けられたすべてのプロファイルがアクセスレベルを自動的に*継承*します。 * ユーザーが新しい認証情報でアプリにログインしても、有料コンテンツへのアクセスは維持されます。 * ユーザーが工場出荷時リセット後にアプリを再インストールしても、有料コンテンツへのアクセスは維持されます。 * ユーザーが同じストアアカウントで他のデバイスにアプリをインストールしても、購入はすべてのデバイスで利用可能になります。アプリの各インスタンスが独自のカスタマープロファイルを持っている場合でも同様です。 ## Transfer access to new user \{#transfer-access-to-new-user\} この設定は、**認証の有無にかかわらず購入を許可する**アプリケーション、または**1 デバイスにつき 1 ユーザー**のポリシーを適用したいアプリケーションに最適です。 Adapty は購入へのアクセスを一度に 1 つの Customer ID に制限します。デバイス所有者はアプリを再インストールしたり、ログインとログアウトを繰り返すことができますが、複数の Customer ID から同時に同じプロダクトにアクセスすることはできません。 この設定を有効にすると、匿名プロファイル(たとえばユーザーがログアウトした後にアクティブになるプロファイル)は常に最後にアクティブだった Customer ID のアクセスレベルを継承します。これは後でアクセスを失わないようにするために必要です。 :::warning デフォルト設定を無効にして **Transfer access to new user** を有効にしても、Adapty は既存のカスタマープロファイルのアクセスレベルをすぐには更新しません。 切り替えは、ユーザーが新しいストアイベント(サブスクリプションの更新や購入の復元など)をトリガーしたときに行われます。 ::: :::important Adapty が古いプロファイルを失効させるのは、SDK がトランザクションを伝播する時点で新しいプロファイルに [Customer User ID](identifying-users#set-customer-user-id-on-configuration) が設定されている場合のみです。`restorePurchases` が匿名プロファイルで実行された場合、古い Customer User ID と新しい匿名プロファイルの両方がアクセスレベルを持つことになります。古いプロファイルは、匿名プロファイルを識別した後に失効します。 これを避けるには、SDK メソッドをこの順番で呼び出してください:`activate` → `identify` → `restorePurchases`。 ::: ## 有料アクセス共有の無効化 \{#disable-paid-access-sharing\} この設定は、**必須認証**を持つアプリケーション、または独自のアクセス管理を実装しているアプリケーションに**のみ適切**です。それ以外の場合、ユーザーが購入にアクセスできなくなり、アプリが**必須のストアレビューに失敗するリスク**があります。 有料アクセス共有を無効にすると、Adapty は購入時にアクティブな [Customer ID](identifying-users#set-customer-user-id-on-configuration) にプロダクトを紐付け、他のカスタマープロファイルとアクセスレベルを共有しません。このポリシーにより、厳格な 1 対 1 のプロダクト配布が可能になります。 :::warning 有料アクセス共有を無効にすると、Customer ID が有料アクセスを継承できなくなります。過去に有料アクセスを継承した Customer ID がある場合、自動的に取り消すことはできません。 ::: :::important 緊急時には、次に利用可能なプロファイル(識別済みまたは匿名)がアクセスレベルを引き継げるよう、[ユーザープロファイルを削除する](api-adapty/operations/deleteProfile)必要がある場合があります。 ::: ## 実践的なリファレンス \{#practical-reference\} モードを選択したら、以下の一覧で期待される動作を確認してください:どのプロファイルがアクセスを受け取るか、古いプロファイルがいつアクセスを失うか、どのウェブフックイベントが発火するか。 | モード | 複数のプロファイルが 1 つの購入を共有するか | 転送時に古いプロファイルが失効するか | 古いプロファイルが失効するタイミング | 2 番目のプロファイルがサブスクリプションを引き継ぐ際のウェブフックイベント | | --- | --- | --- | --- | --- | | **Enabled (default)** | はい — 復元またはサインインしたすべてのプロファイルがアクセスを継承 | しない | N/A | 継承する各新規プロファイルに `access_level_updated`(`is_active=true`) | | **Transfer access to new user** | いいえ — 排他的だが、プロファイル間で移動可能 | はい | 新しい識別済みデバイスがトランザクションを伝播したとき(`restorePurchases`、identify、または次のストア側イベント)に即時 | 新しいプロファイル:`access_level_updated`(`is_active=true`)。古いプロファイル:`access_level_updated`(`is_active=false`) | | **Disabled** | いいえ — 購入ごとに 1 つの Customer User ID、永続的 | N/A — アクセスは転送されない | N/A | 2 番目のプロファイルには何もなし。SDK はそのプロファイルのアクセスを表示しない | ## サンドボックスでの有料アクセス共有 \{#sharing-paid-access-on-sandbox\} サンドボックス環境専用の有料アクセス共有ポリシーを設定できます。サンドボックス環境で購入をテストする際は、以下の動作が予想されます: * Apple はアカウントの購入履歴に過去の購入情報を保存します。Adapty SDK もこれにアクセスできます。 * アプリを再インストールした際、Adapty がプロダクトがすでに購入済みであることを検出した場合、アクティブなプロファイルがアクセスレベルを継承します。 * Apple がプロダクトの既存の購入を検出した場合、アクティブなプロファイルに必要なアクセスレベルがなくても、同じ購入を 2 回行うことはできません。 この動作は**有料アクセス共有の設定に関係なく**発生します。アプリにペイウォールが表示されず、プロダクトを購入できません。唯一の解決策は、**アカウントの購入履歴をクリアすること**です。詳細な手順は[サンドボックステストガイド](test-purchases-in-sandbox)を参照してください。 :::warning Apple のサンドボックスサブスクリプションは数分ごとに自動更新されます。この急速な更新により、Adapty が[親プロファイル](how-profiles-work#parent-and-inheritor-profiles)として扱うプロファイルが入れ替わることがあります。これは本番環境ではほとんど再現されないパターンです。本番環境で使用するモードをテストし、サンドボックスでの結論を出す前に実際の Apple ID で動作を確認してください。 ::: ## アナリティクスにおける有料アクセス共有 \{#paid-access-sharing-in-analytics\} * Adapty はトランザクションが発生した時点でそれを記録します。1 つのトランザクションが複数のプロファイルに関連付けられることがありますが、複数回カウントされることはありません。 * 2 つ以上のプロファイルが同じアクセスレベルを共有している場合、購入は[親プロファイル](how-profiles-work#parent-and-inheritor-profiles)に帰属されます。 * アクセスレベルの継承はインストール統計には影響しません。Adapty がインストールをカウントする方法を決定するには、設定ページで利用可能な 2 つの[インストール定義](installs#counting-modes)のいずれかを選択できます。 --- # File: segments --- --- title: "セグメント" description: "Adapty でユーザーセグメントを作成・管理して、より精度の高いターゲティングを実現しましょう。" --- **セグメント**は、共通の属性を持つユーザーをグループ化するフィルターの集合です。セグメントを使うと、ペイウォールや A/B テストのターゲティングをより効果的に行えます。 :::note イベントフィードのイベントはダッシュボードに届くまでに遅延が発生します。新しいプロファイルや属性の変更はすぐに反映されない場合があります。 ::: セグメントを作成したら、[プレースメントや A/B テストで**オーディエンス**として使用](audience)し、ユーザーに表示するペイウォール(単数または複数)を制御できます。使用例: - 非サブスクリプションユーザーには標準のペイウォールを表示し、以前サブスクリプションやトライアルをキャンセルしたユーザーには割引を提示する。 - 国ごとに異なるペイウォールを表示する。 - Apple Search Ads のアトリビューションデータに基づいてユーザーをターゲティングする。 - 古いバージョンのアプリを使用しているユーザーには既存のペイウォールを表示し続け、新しいバージョンのユーザーには更新されたペイウォールを表示する。 - [アナリティクス](controls-filters-grouping-compare-proceeds#filter-and-group-data)では、セグメントでフィルタリングして特定のユーザーグループのパフォーマンスを確認する。セグメントでグループ化すると、**全ユーザー**内でのパフォーマンスや貢献度を比較できる。 <img src="/assets/shared/img/3244407-Segments.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 作成 \{#creation\} セグメントを作成するには、名前を入力し、フィルターを定義する属性を選択します。複数の属性を選択した場合、ユーザーはすべての条件を満たす必要があります。Adapty は属性間に AND 論理を適用します。 <img src="/assets/shared/img/1af9744-new_cohort.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 利用可能な属性 \{#available-attributes\} :::note **Country**(国)や **Calculated total revenue USD**(計算済み合計収益 USD)など多くのユーザー属性は自動的に設定されますが、**Age**(年齢)、**App user ID**(アプリユーザー ID)、**Attribution**(アトリビューション)データ、**Gender**(性別)、**Custom attributes**(カスタム属性)は自動的には設定されません。セグメント化に利用する場合は、[ユーザー属性を設定](setting-user-attributes)するか、[アトリビューションデータを渡す](attribution-integration)必要があります。 ::: :::tip 日付ベースの属性には、以下の方法でフィルタリングできます: - **固定日付**: カレンダーから特定の日付を選択(例:ブラックフライデーからサイバーマンデーの間にインストールしたユーザーに特別オファーを表示) - **相対範囲**: 「過去 7 日間」や「過去 3 ヶ月」などの動的な期間を設定(例:30 日以上前に最後に見られたユーザーを再エンゲージしたり、最近のインストールをターゲティングしたりする) 相対範囲は自動的に更新されるため、継続的なキャンペーンに最適です。固定日付は期間限定のプロモーションに最も適しています。 ::: | 属性 | フィルター対象 | |---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Age** | ユーザーの年齢。年齢は Adapty が最初に受け取った時点で計算され、その後は更新されません。 | | **App User ID** | アプリ内のユーザー識別子([customer_user_id](profiles-crm#user-attributes))。存在するかどうかでフィルタリングできます。例えば、ログインしていないユーザーにのみペイウォールを表示する場合などに使います。 | | **App version (current)** | Adapty が最後にイベントデータを受け取ったユーザーデバイスにインストールされているアプリの現在のバージョン。ユーザーがアップグレードすると**更新され**、常に現在実行中のバージョンを反映します。特定のバージョンを実行しているすべてのユーザー(以前のバージョンからアップグレードしたユーザーを含む)にロールアウトする場合に使用します。セグメント作成時に、**App version** の横にある鉛筆アイコンを選択して新しいバージョンを追加すると、すぐに使用できます。<br/> **version > X.X** 条件を使うと、各バージョンを個別にリストアップすることなく、特定のバージョンより古いまたは新しいすべてのアプリバージョンのコンバージョンへの影響を計測できます。<br/><br/> **フォーマット:** バージョン文字列は [SemVer](https://semver.org/) 形式に従う必要があります。各部分の先頭ゼロは無効です。`26.03.4` はマッチしませんが、`26.3.4` はマッチします。無効なバージョンはセグメントから黙って除外されます。 | | **App version (on install)** | Adapty が初めてイベントデータを受け取ったときにユーザーデバイスにインストールされていたアプリのバージョン。インストール時の値に**固定され、ユーザーがアップグレードしても更新されません**。現在のバージョンではなく、最初にインストールしたバージョンでユーザーをターゲティングする場合に使用します。`App version (on install) = 1.5.7` は、初回インストールが 1.5.7 だったユーザーのみにマッチし、以前のバージョンから 1.5.7 にアップグレードしたユーザーは黙って除外されます。アップグレードユーザーも対象にするには、**App version (current)** を使用してください。<br/><br/> **フォーマット:** バージョン文字列は [SemVer](https://semver.org/) 形式に従う必要があります。各部分の先頭ゼロは無効です。`26.3.04` はマッチしませんが、`26.3.4` はマッチします。無効なバージョンはセグメントから黙って除外されます。 | | **Attribution: Ad Group** | アトリビューションの広告グループ。 | | **Attribution: Ad Set** | アトリビューションの広告セット。 | | **Attribution: Campaign** | マーケティングキャンペーン名。 | | **Attribution: Creative** | アトリビューションのクリエイティブキーワード。 | | **Attribution: Channel** | マーケティングチャネル名。 | | **Attribution: Source** | アトリビューションの発生元。 | | **Attribution: Status** | アトリビューションのステータス。設定可能な値:<ul><li>**Organic** – 有料マーケティングの影響を受けずにアプリをインストールしたユーザー(App Store/Google Play での直接検索、口コミ、オーガニックソーシャルメディアなど)。</li><li>**Non-organic** – 有料マーケティングチャネル経由で獲得したユーザー(広告、インフルエンサーキャンペーン、リファラルプログラムなど)。</li><li>**Unknown** – このユーザーのアトリビューションデータが利用できない。</li></ul> | | **Calculated subscription state** | ユーザーの[現在のサブスクリプション状態](profiles-crm#subscription-state)。サブスクリプションがアクティブか、キャンセル済みか、または未解決の請求問題があるかを示します。 | | **Calculated total revenue USD** | このユーザーが生み出した合計収益。 | | **Country** | 直近の IP アドレスから判定された顧客の国。Adapty は IP シグナルを最大週 1 回更新するため、ユーザーが場所を変えたり VPN を使用したりすると値がずれる場合があります。ユーザーの App Store / Play Store アカウントの国でターゲティングする場合は、**Country from store account** を使用してください。 | | **Country from store account** | ユーザーの iOS または Android ストアアカウントに関連付けられた国。Adapty がストアの国を収集するのは、バージョン 13 以降の iOS デバイスのみです。 | | **Creation date** | プロファイルが作成された日付(ユーザーのデバイスにアプリが初めてインストールされた日時)。 | | **Device** | メタデータに基づくデバイスタイプ。例:「Samsung Galaxy」や「iPhone 13」 | | **Gender** | ユーザーの性別。この値は自分で設定します。 | | **Installation date** | ユーザーがアプリをインストールした日付。 | | **Language** | ユーザーのデバイスの言語。<Callout type="warning">Adapty は言語を 2 文字の `ISO 639-1` コードで保存します。`zh-Hant-TW` や `pt-BR` のような拡張ロケールは使用しないでください。ドロップダウンに表示される場合がありますが、どのユーザーにもマッチしません。</Callout> <Callout type="tip">言語ターゲティングをさらに絞り込むには、**Language** と **Country** を組み合わせてください。例えば、**簡体字中国語(`zh`)** + **Country = TW, HK, MO** とすると、繁体字スクリプトのユーザーをターゲットにできます。</Callout> | | **Last seen** | ユーザーが最後にアプリを開いた日付。 | | **OS** | ユーザーデバイスのオペレーティングシステムのバージョン。 | | **Paid access level** | ユーザーに付与されているアクセスレベル。 | | **Platform** | ユーザーのデバイスプラットフォーム。設定可能な値:`iOS`、`macOS`、`iPadOS`、`visionOS`、`Android`。<br/> ユーザーが複数のプラットフォーム(iOS と Android など)からアプリにアクセスする場合、セグメントへの所属はそれぞれのデバイスの最新データを使って各プラットフォームで個別に評価されます。これにより、同じユーザープロファイルでもプラットフォームごとにターゲティングが可能です。 | | **Subscription expiration date** | サブスクリプションの有効期限、またはその有無。永続アクセス購入の場合は `none` と表示され、ユーザーがプロファイルを持っているがトライアル、サブスクリプション、永続アクセス購入のいずれも行っていない場合は空のままです。 | | **Subscription product** | 顧客のアクティブなサブスクリプションの最新プロダクト ID。 | | **[Custom attributes](profiles-crm#custom-attributes)** | アプリやビジネスに固有のプロパティに基づいて、高度にターゲティングされたセグメントを作成するための独自属性を定義します。 | ## カスタム属性 \{#custom-attributes\} カスタム属性を定義して、アプリやビジネスに固有のプロパティに基づいたより精度の高いセグメントを構築できます。 :::note - カスタム属性は SDK または Adapty ダッシュボードで設定できます。SDK での設定手順は[こちら](setting-user-attributes#custom-user-attributes)をご覧ください。 - セグメントで使用後にカスタム属性を変更すると、[アナリティクス](controls-filters-grouping-compare-proceeds#filter-and-group-data)でそのセグメントとユーザーの同期が外れる場合があります。データは以前の値を反映します。 ::: ### カスタム属性の設定方法 \{#how-to-configure-a-custom-attribute\} Adapty ダッシュボードで、属性のドロップダウンメニューから **Create custom attributes** を選択します。 <img src="/assets/shared/img/883d3b2-CleanShot_2023-03-16_at_17.20.452x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> | フィールド | 説明 | | ------ |--------------------------------------------------------------------------------------------------------------------------------------| | **Name** | カスタム属性のラベル。Adapty ダッシュボード内でのみ使用されます。 | | **Key** | 属性の一意の識別子。SDK で使用されるキーと一致している必要があります。 | | **Type** | 以下から選択します:<ul><li>String:あらかじめ定義した値のリストが必要です。</li><li>Number:数値のみ受け付けます。</li></ul> | | **Values** | `String` を選択した場合は、使用可能な値のリストを入力します。`Number` を選択した場合、属性は数値入力のみ受け付けます。数値属性は小数値をサポートし、比較演算子と組み合わせて使用できます。 | 必須フィールドを入力したら、セグメント、[A/B テスト](ab-tests)などでカスタム属性を使用できます。 各プロファイルには最大 30 個のカスタム属性を設定できます。 ## 総数とランダムサンプル \{#total-number-and-random-sample\} セグメントを作成すると、Adapty はセグメント条件に一致するユーザーの総数を表示します。 また、条件に合致する 40 人のランダムサンプルも表示されます。これを使ってセグメントをテストし、正しく設定されているか確認できます。 <img src="/assets/shared/img/segment-random-set.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## セグメントの複製 \{#duplicate-segments\} 既存のセグメントに似たものが必要な場合は、最初から作り直す代わりに複製しましょう。ユーザーグループが重複する複数のキャンペーンや A/B テストを運用しているチームの作業時間を節約できます。 セグメントを複製すると、すべてのフィルターと説明を含むコピーが作成されます。新しいセグメントの名前には「(copy)」が追加されるので、元のものと区別できます。新しいセグメントは元のセグメントから独立しており、一方への変更は他方に影響しません。 Adapty ダッシュボードでセグメントを複製するには: 1. Adapty メインメニューの **Profiles & Segments** セクションを開き、[**Segments**](https://app.adapty.io/segments) タブに切り替えます。 2. セグメントの横にある **3-dot** ボタンをクリックし、**Duplicate** を選択します。 <img src="/assets/shared/img/duplicate-segment.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 新しいセグメントを開き、必要に応じてフィルターを調整します。 ## セグメントの削除 \{#delete-segments\} セグメントが不要になったら、完全に削除できます。 以下のいずれかでセグメントが現在オーディエンスとして使用されている場合、Adapty は削除をブロックします: - **プレースメント**:削除されていないプレースメントの少なくとも 1 つがそのセグメントをオーディエンスとして使用している。 - **A/B テスト(ライブまたは完了済み)**:削除されていない A/B テストの少なくとも 1 つがそのセグメントをオーディエンスとして使用している。 セグメントの削除において、Adapty は**ライブ**と**完了済み**の A/B テストをどちらもアクティブとして扱います。完了済みのテストは、テスト後のペイウォールまたはオンボーディングを一致するユーザーに表示するために引き続きオーディエンスを使用しており、テストの過去の指標はそのセグメントにスコープされています。セグメントは A/B テスト自体が削除されて初めて解放されます。 :::warning セグメントの削除は永続的です。削除されたセグメントは復元できません。 ::: Adapty ダッシュボードでセグメントを削除するには: 1. Adapty メインメニューの **Profiles & Segments** に移動し、[**Segments**](https://app.adapty.io/segments) タブに切り替えます。 2. セグメントの横にある **3-dot** ボタンをクリックし、**Delete** を選択します。 3. 確認フィールドにセグメント名を入力し、**Delete forever** をクリックします。 :::info セグメントが使用中の場合、ダイアログにはそれを参照しているプレースメントと A/B テストの一覧が表示されます。 削除のブロックを解除するには、リストの各プレースメントまたは A/B テストを開き、オーディエンスからセグメントを削除するか、プレースメントまたは A/B テスト自体を削除してください。何もセグメントを参照していない状態になれば、削除できます。 ::: --- # File: event-feed --- --- title: "イベントフィード" description: "Adaptyのイベントフィードでユーザーアクティビティを監視・分析します。" --- イベントフィードを使うと、Adaptyが生成した[イベント](events)を視覚的に追跡し、Webhookを含むサードパーティ連携へのエクスポート状況を確認できます。 :::warning イベントフィードには以下は表示されません: - **サーバーサイドAPI v1のトランザクション**:[サーバーサイドAPI(バージョン1)](server-side-api-specs-legacy#requests)を使って作成されたもの。表示させるには[サーバーサイドAPI(バージョン2)](api-adapty/operations/setTransaction)を使用してください。 - **プロファイルのないイベント**:SDKがユーザーを識別する前に届いたトランザクション(例:ストアのサーバー通知)。これらをエクスポートに含めるには、[S3](s3-exports)または[Google Cloud Storage](google-cloud-storage)連携で **Include events without profile** を有効にしてください。 ::: <img src="/assets/shared/img/event-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note AppsFlyer、Facebook Ads、Branchの送信ステータスは、エラーが発生しても常に返されるとは限らないため、正確でない場合があります。 ::: トランザクションを開始したユーザーのプロファイルを確認するには、イベント詳細の **View Profile** ボタンをクリックしてください。 --- # File: ab-tests --- --- title: "A/B テスト" description: "Adapty の A/B テストでサブスクリプション価格を最適化し、コンバージョン率を向上させましょう。" --- :::tip リサーチなしでも実践的な A/B テスト計画を立てられます。[AI Growth Advisor](autopilot) がペイウォールを分析し、競合他社のベンチマークを行い、Adapty が追跡する 20,000 以上のサブスクリプションアプリの匿名データからご提案を生成します。 ::: Adapty で A/B テストを実行して、アプリの収益を向上させましょう。コードを変更することなく、さまざまなフロー、ペイウォール、オンボーディングを比較して、最もコンバージョン率の高いものを見つけられます。たとえば、以下のようなテストが可能です。 - サブスクリプション価格 - ペイウォールのデザイン、コピー、レイアウト - トライアル期間とサブスクリプション期間 - オンボーディングのデザイン ## 前提条件 \{#prerequisites\} A/B テストを設定する前に、以下が必要です: - **プレースメント**: フロー、ペイウォール、またはオンボーディングが表示される1つ以上の[プレースメント](placements)。 - **フローの場合**: 少なくとも2つの[フロー](adapty-flow-builder)。 - **ペイウォールの場合**: 少なくとも2つの[ペイウォール](paywalls)。 - **オンボーディングの場合**: 少なくとも2つの[オンボーディング](onboardings)。 :::warning [Adapty フロービルダー](adapty-flow-builder)または[Adapty ペイウォールビルダー](adapty-paywall-builder)を使用していない場合は、`.logShowFlow()`(iOS SDK v4+)/ `.logShowPaywall()` を使って[ペイウォールビューを Adapty に送信](present-remote-config-paywalls#track-paywall-view-events)してください。このメソッドを使用しないと、Adapty はテスト内のペイウォールビュー数を計算できず、コンバージョン統計が不正確になります。 ::: ## A/B テストの種類 \{#ab-test-types\} Adapty は 2 つの主要な A/B テストタイプをサポートしています: - **通常**:単一のフロー/ペイウォール/オンボーディングのプレースメントで実行されます。 - **クロスプレースメント**:複数のペイウォールプレースメントにまたがって実行され、同じバリアントをユーザーに一貫して表示します。現在はペイウォールのみで利用可能です。 タイプの詳細な比較、ユースケース、優先順位のルールについては、[A/B テストの種類](ab-test-types)を参照してください。 ## 次のステップ \{#next-steps\} - [Growth Autopilot](autopilot) — ペイウォールを分析し、市場インサイトを取得して、A/B テスト計画を生成する - [A/B テストの種類](ab-test-types) — テストの種類とそれぞれの使いどころを学ぶ - [A/B テストの作成・実行・停止](run_stop_ab_tests) — はじめてのテストをセットアップして実行する - [A/B テストの結果と指標](results-and-metrics) — A/B テストのデータを理解して勝者を選ぶ --- # File: ab-test-types --- --- title: "A/B テストタイプ" description: "Adapty の A/B テストタイプについて説明します。" --- Adapty では、テストシナリオに応じた 2 種類の A/B テストタイプを用意しています。 - **通常の A/B テスト:** 単一の[フロー](adapty-flow-builder)/[ペイウォール](paywalls)/[オンボーディング](onboardings)プレースメントに対して作成する A/B テストです。 - **クロスプレースメント A/B テスト:** アプリ内の複数のペイウォールプレースメントに対して作成する A/B テストです。A/B テストが<InlineTooltip tooltip="バリアント">A/B テストのバリアントとは、テスト対象のフロー、ペイウォール、またはオンボーディングの代替バージョンです。</InlineTooltip>を割り当てると、選択したアプリのすべてのセクションにわたって同じバリアントを一貫して表示します。 :::warning クロスプレースメント A/B テストは、Adapty SDK v3.5.0 以降でのみ利用可能です。クロスプレースメント A/B テストはペイウォールのみで動作します。 フロー A/B テストには Adapty SDK v4.0.0 以降が必要です。 オンボーディング A/B テストには、Adapty SDK v3.8.0 以降(iOS、Android、React Native、Flutter)、v3.14.0 以降(Unity)、または v3.15.0 以降(Kotlin Multiplatform、Capacitor)が必要です。 旧バージョンのユーザーはスキップされます。 ::: 各フロー/ペイウォール/オンボーディングにはウェイトが設定され、テスト中のトラフィックを分割します。 たとえば、ウェイトが 70% と 30% の場合、1,000 人のユーザーのうち最初のペイウォールは約 700 人に、2 番目のペイウォールは約 300 人に表示されます。クロスプレースメントテストでは、ウェイトはペイウォールごとではなくバリアントごとに設定されます。 この設定により、異なるフローやペイウォールを比較し、アプリのマネタイズ戦略についてデータに基づいた意思決定ができます。 ## どちらのタイプを使うべきか \{#when-to-use-each-type\} 各 A/B テストタイプが有効な場面は以下のとおりです。 - **通常の A/B テスト**: - アプリにプレースメントが 1 つしかない場合。 - アプリに複数のプレースメントがある場合でも、1 つのプレースメントのみで A/B テストを実行し、そのプレースメントの経済効果の変化だけを追跡したい場合。 - 過去のユーザー(少なくとも 1 つの Adapty ペイウォールを見たことがあるユーザー)に対して A/B テストを実行したい場合。 - **クロスプレースメント A/B テスト**: - 複数のプレースメントにわたってバリアントを同期させたい場合。たとえば、オンボーディングフローとアプリ設定の両方で同時に価格を変更したい場合。 - アプリ全体の経済効果を評価したい場合。すべてのプレースメントにわたってテストを実行することで、個別のプレースメントをテストするよりも A/B テストの統計が分析しやすくなります。 - 新規ユーザーのみ(Adapty のペイウォールを一度も見たことがないユーザー)に対して A/B テストを実行したい場合。 - 1 つのバリアント内で複数のペイウォールを使用したい場合: <img src="/assets/shared/img/ab-test-variants.png" alt="1 つのクロスプレースメント A/B テストバリアント内に複数のペイウォールがある例" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 主な違い \{#key-differences\} | 機能 | 通常の A/B テスト | クロスプレースメント A/B テスト | | ------------------------------- |--------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------| | **テスト対象** | 1 つのフロー/ペイウォール/オンボーディング | 1 つのバリアントに属するペイウォールのセット | | **バリアントの一貫性** | バリアントはプレースメントごとに個別に決定される | すべてのペイウォールプレースメントで同じバリアントが使用される | | **オーディエンスのターゲティング** | フロー/ペイウォール/オンボーディングのプレースメントごとに定義される | すべてのペイウォールプレースメントで共有される | | **アナリティクス** | 1 つのフロー/ペイウォール/オンボーディングのプレースメントを分析する | テストの一部であるプレースメントに対してアプリ全体を分析する | | **バリアントのウェイト分布** | フロー/ペイウォール/オンボーディングごと | ペイウォールのセットごと | | **ユーザー** | すべてのユーザー | 新規ユーザーのみ(Adapty ペイウォールを見たことがないユーザー) | | **Adapty SDK バージョン** | フローの場合: v4.0.0 以降。ペイウォールの場合: 任意。オンボーディングの場合: v3.8.0 以降(iOS、Android、React Native、Flutter)、v3.14.0 以降(Unity)、v3.15.0 以降(KMP、Capacitor) | 3.5.0 以降 | | **最適な用途** | アプリ全体の経済効果を考慮せずに、単一のフロー/ペイウォール/オンボーディングプレースメントの独立した変更をテストする場合 | アプリ全体のマネタイズ戦略を評価する場合 | ## A/B テストの選択ロジック \{#ab-test-selection-logic\} **クロスプレースメント A/B テストは通常の A/B テストよりも優先されます。** ただし、クロスプレースメントテストは**新規ユーザー**(まだ Adapty のペイウォールを一度も見ていないユーザー、つまり `getPaywall` SDK メソッドが一度も呼び出されていないユーザー)にのみ表示されます。これにより、プレースメント間での結果の一貫性が確保されます。 以下のダイアグラムは、Adapty がプレースメントに対して A/B テストを選択するためのロジックを示しています。 <img src="/assets/shared/img/ab-tests-scheme.webp" alt="ペイウォールプレースメントの A/B テスト選択ロジックを示すダイアグラム" style={{ border: '1px solid #727272', /* border width and color */ width: '350px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **A/B Tests** ページでは、ペイウォール、オンボーディング、フロー、クロスプレースメントのテストが別々のタブに表示されます。 <img src="ab-tests-tabs.webp" alt="通常、オンボーディング、クロスプレースメントのテストタイプごとにタブが設けられた A/B テスト一覧ページ" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## クロスプレースメント A/B テストの制限事項 \{#crossplacement-ab-test-limitations\} :::warning クロスプレースメント A/B テストには、フローまたはオンボーディングのプレースメントを含めることができません。 ::: クロスプレースメント A/B テストは、テスト内のすべてのプレースメントで各ユーザーが同じバリアントを見ることを保証します。これにより、以下の制限が生じます。 * 参加できるのは新規ユーザーのみです。新規ユーザーとは、Adapty のペイウォールを見たことがなく、アプリが `getPaywall` を一度も呼び出していないユーザーです。それ以外のユーザーに対して一貫したペイウォールのチェーンを保証することはできません。 * ユーザーが最初に訪れたプレースメントで、Adapty が表示するペイウォールが決まります。ユーザーの割り当てを変更したり、同じユーザーを複数のクロスプレースメント A/B テストに登録したりすることはできません。 :::warning ユーザーがクロスプレースメントのペイウォールを受け取ると、テストを停止した後も 90 日間はそれが表示され続けます。この期間を変更するには、**General** 設定の **[Cross-placement variation stickiness](general#9-cross-placement-variation-stickiness)** を調整してください。 ::: ## クロスプレースメント A/B テストの優先順位 \{#crossplacement-ab-test-priority\} * クロスプレースメント A/B テストは、常に通常の A/B テストおよびオンボーディング A/B テストよりも優先されます。新規ユーザーが同じプレースメントでクロスプレースメントテストと通常のテストの両方の対象となる場合は、クロスプレースメントテストが表示されます。 * 同じオーディエンスを持つ複数のクロスプレースメント A/B テストが同じプレースメントを共有している場合、Adapty は追加された順序に基づいてテストの優先順位を自動的に割り当てます。最初のテストが最高優先度を持ちます。手動で変更することはできません。 * オーディエンスの小さいセグメントをターゲットとするテストは、「すべてのユーザー」セグメントをターゲットとするテストよりも自動的に優先されます。 :::note アナリティクスでは、クロスプレースメント A/B テストはプレースメントごとに 1 つずつ、複数の子テストとして表示されます。子テストの命名パターンは `<test-name> child-0`、`<test-name> child-1` のようになります。番号は A/B テスト詳細ページのプレースメントの順序と対応しています。特定のプレースメントの結果を確認するには、**Placement** でフィルタリングしてください。 ::: ## 次のステップ \{#next-steps\} - [A/B テストの作成・実行・停止](run_stop_ab_tests) — 最初のテストをセットアップして開始する - [A/B テストの結果と指標](results-and-metrics) — パフォーマンスを分析して勝者を選ぶ --- # File: run_stop_ab_tests --- --- title: "A/B テストの作成・実行・停止" description: "Adapty で A/B テストを作成・実行・停止するためのステップバイステップガイド。" --- この記事では、Adapty における A/B テストのライフサイクル全体(テストの作成・実行・停止)について説明します。 ## 前提条件 \{#prerequisites\} A/B テストを設定する前に、以下が必要です。 - [フロー](adapty-flow-builder)/[ペイウォール](paywalls)/[オンボーディング](onboardings)が少なくとも 2 つ作成されていること - アプリに[プレースメント](placements)が設定されていること :::warning [Adapty フロービルダー](adapty-flow-builder)や [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用していない場合は、`.logShowPaywall()` を使って[ペイウォールのビュー情報を Adapty に送信](present-remote-config-paywalls#track-paywall-view-events)してください。このメソッドを使用しないと、Adapty はテスト内のペイウォールビュー数を計算できず、コンバージョン統計が不正確になります。 ::: :::info Adapty の A/B テストは 2 ステップで進みます。まずテストを作成して下書きとして保存します。この時点ではすぐには公開されません。準備ができたら、別途実行します。これにより、ユーザーに表示される前に設定内容を確認できます。 ::: ## A/B テストを作成する \{#create-an-ab-test\} 新しい A/B テストを作成する際は、[フロー](adapty-flow-builder)/[ペイウォール](paywalls)/[オンボーディング](onboardings)を少なくとも 2 つ含める必要があります。 新しい A/B テストを作成するには: 1. Adapty のメインメニューから [**A/B tests**](ab-tests) に移動します。 <img src="/assets/shared/img/go-to-abtests.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 右上の **Create A/B test** をクリックします。 <img src="/assets/shared/img/create-abtest.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Create the A/B test** ウィンドウで **Test name** を入力します。これは必須項目です。結果を確認する際に識別しやすいよう、テストの内容を明確に表す名前を選んでください。 4. **Test goal** に達成したい目標(例:サブスクリプションの増加やチャーンの削減)を記入します。 5. **Select placement** をクリックして、フロー・ペイウォール・オンボーディングのプレースメントを選択します。 6. **Variants** テーブルでテストの内容を設定します。各行がバリアント、各列がプレースメントになります。各交点にペイウォールを追加します。 デフォルトでは、テーブルに 2 つのバリアントと 1 つのプレースメントがあります。バリアントは最大 20 個まで追加できます。2 つ目のプレースメントを追加すると、テストはクロスプレースメント A/B テストになります。なお、クロスプレースメント A/B テストはペイウォールのみ対応しています。 <img src="/assets/shared/img/abtest-variants.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 7. テストを保存します。2 つの選択肢があります: 1. **Save as draft**:テストはすぐに公開されません。後でプレースメントまたは A/B テストリストから起動できます。公開前に設定を確認したい場合に使用してください。 2. **Run A/B test**:テストをすぐに起動します。このボタンをクリックした瞬間にテストが公開されます。 下書きとして保存した後は、[A/B テストを実行する](#run-an-ab-test)に進んでください。 ## A/B テストを編集する \{#edit-an-ab-test\} A/B テストは下書きとして保存されている場合にのみ編集できます。テストが公開された後は変更できません。公開中のテストを更新するには、**Modify** オプションを使用します。これにより同じ名前の複製が作成され、そこで変更を加えることができます。Adapty は元のテストを停止し、元のバージョンと修正バージョンがどちらも分析画面に別々に表示されます。 ## A/B テストを実行する \{#run-an-ab-test\} Adapty で A/B テストを実行するとは、プレースメントに割り当ててユーザーへのペイウォールやオンボーディングの表示を開始することを意味します。 1. Adapty のメインメニューから [**A/B tests**](ab-tests) セクションに移動します。 2. 正しいリストを表示していることを確認してください。**Paywall**・**Flow**・**Onboardings**・**Crossplacement** の A/B テストは、切り替え可能な別々のタブに表示されます。 <img src="/assets/shared/img/ab-tests-tabs.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Drafts** タブに切り替えます。起動できるのは下書きのテストのみです。 4. 起動したいテストの横にある **Run A/B test** をクリックします。 <img src="/assets/shared/img/run-ab-test-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Edit A/B test** ウィンドウが開きます。設定を確認し、必要な最終変更を行います。プレースメントやオーディエンスが未設定の場合は、ここで追加してください。 6. 設定を確認したら、**Run A/B test** をクリックして開始します。 テストを起動した後は、[A/B テストの結果と指標](results-and-metrics)ページで進捗を追跡し、パフォーマンスデータを確認できます。 ## A/B テストを停止する \{#stop-an-ab-test\} A/B テストを停止すると、テストが終了し結果を確認できます。また、テスト終了後に対象プレースメントでユーザーに何を表示するかを決定します。 <img src="/assets/shared/img/stop-ab-test.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. [**A/B tests**](https://app.adapty.io/ab-tests) セクションを開き、**Live** タブに移動します。 2. 停止したいテストの横にある 3 点メニューをクリックし、**Stop A/B test** を選択します。 3. **Stop the A/B test** ウィンドウで、テスト終了後の動作を決定します。3 つの選択肢があります: | オプション | 説明 | |----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | テスト済みのペイウォール/オンボーディングのいずれかを表示する | 収益・最良確率(**P2BB**)・1,000 ユーザーあたりの収益などのテスト結果をもとに、勝者のペイウォールまたはオンボーディングを選択します。選択したプレースメントとオーディエンスに対して、そのペイウォールまたはオンボーディングが表示されます。 | | A/B テストに参加していないペイウォール/オンボーディングを選択する | 現在の A/B テストに含まれていないペイウォールまたはオンボーディングを選択します。テストしたバリアントがどれも目標を達成しなかった場合に使用します。 | | 特定のペイウォール/オンボーディングを表示しない | 選択したプレースメントとオーディエンスに対して、A/B テスト終了後に特定のペイウォールまたはオンボーディングは選択されません。代わりに、オーディエンスの優先度に基づいて次に利用可能なペイウォールまたはオンボーディングが表示されます。手動で選択せずに既存の設定でペイウォールまたはオンボーディングを決定したい場合に適しています。 | :::note A/B テストの停止は取り消しできません。テストを再起動することはできないため、停止を決定する前に十分なデータが集まっていることを確認してください。 ::: 4. **Stop and complete this A/B test** ボタンをクリックします。 A/B テストが終了すると、テストはアクティブでなくなり、テスト内のペイウォールまたはオンボーディングは新しいユーザーに表示されなくなります。 テスト実行中に参加したユーザーのパフォーマンスを確認するために、[A/B テストの指標ページ](results-and-metrics#metrics-controls)で引き続き A/B テストの結果と指標にアクセスできます。それらのユーザーに新たな購入や収益イベントが紐付けられると、指標は引き続き更新される場合があります。 --- # File: ab-test-no-paywall-variants --- --- title: "フローまたはペイウォールなしでA/Bテストのバリアントを追加する" description: "リモートコンフィグのフラグを使って表示を制御し、フローまたはペイウォールをスキップするバリアントでA/Bテストを実行する方法。" --- フローまたはペイウォールの効果を、空のバリアントとのA/Bテストで測定できます。一方のバリアントはフロー/ペイウォールを表示し、もう一方は何も表示しません。アプリはリモートコンフィグのフラグを読み取って、レンダリングするかどうかを判断します。 ## 仕組み \{#how-it-works\} 同じプレースメントに2つのフロー/ペイウォールを設定します。 - **フロー/ペイウォール A**: テストしたいフローまたはペイウォール。リモートコンフィグで `show_paywall` を `true` に設定します。 - **フロー/ペイウォール B**: 空のフローまたはペイウォール。リモートコンフィグで `show_paywall` を `false` に設定します。 SDKがフローまたはペイウォールを返すと、アプリは `show_paywall` フラグを読み取ります。フラグが `true` の場合はレンダリングし、`false` の場合はレンダリングをスキップして、ユーザーは何も見ずに続行します。 ## 1. リモートコンフィグにshow_paywallフラグを追加する \{#1-add-the-show_paywall-flag-in-remote-config\} 同じプレースメントに2つのフローまたはペイウォールが必要です。フロー/ペイウォール A(テストしたいもの)とフロー/ペイウォール B(空のもの)です。両方のバリアントで同じキーを使って分岐できるよう、それぞれに `show_paywall` フィールドを追加します。 フロー/ペイウォール A にフラグを追加するには: 1. Adapty のメインメニューで [**Flows**](https://app.adapty.io/flows)/[**Paywalls**](https://app.adapty.io/paywalls) セクションを開き、フロー/ペイウォール A を選択します。 2. **Remote config** セクションを開きます。 3. 名前 `show_paywall`、値 `true` のフィールドを作成します。**JSON** ビューでは次のようになります: ```json showLineNumbers { "show_paywall": true } ``` 4. 変更を保存します。 フロー/ペイウォール B にも同じ手順を繰り返しますが、`show_paywall` を `false` に設定します。 リモートコンフィグの詳細については、[リモートコンフィグでフローをカスタマイズする](customize-flow-with-remote-config)または[リモートコンフィグでペイウォールをデザインする](customize-paywall-with-remote-config)を参照してください。 :::tip 両方のバリアントに `show_paywall` を設定することで、両グループのコードパスが同一になり、後からバリアントを追加するときも簡単に拡張できます。 ::: ## 2. A/Bテストを設定する \{#2-set-up-the-ab-test\} 1. プレースメントに[A/Bテストを作成](run_stop_ab_tests)し、両方のフロー/ペイウォールをバリアントとして追加します。 2. バリアントのウェイトを設定して、フロー/ペイウォールを見るユーザーと見ないユーザーにトラフィックを分配します。 ## 3. アプリでフラグを確認する \{#3-check-the-flag-in-your-app\} SDKから返されるリモートコンフィグの `show_paywall` を読み取ります。フラグが `false` の場合、レンダリングをスキップしてユーザーを続行させます。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> ```swift showLineNumbers do { let flow = try await Adapty.getFlow(placementId: "YOUR_PLACEMENT_ID") let config = flow.remoteConfigs.first(where: { $0.locale == "en" }) ?? flow.remoteConfigs.first let showPaywall = config?.dictionary?["show_paywall"] as? Bool ?? true if showPaywall { // render the flow or paywall } } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android"> ```kotlin showLineNumbers Adapty.getPaywall("YOUR_PLACEMENT_ID") { result -> when (result) { is AdaptyResult.Success -> { val paywall = result.value val showPaywall = paywall.remoteConfig?.dataMap?.get("show_paywall") as? Boolean ?: true if (showPaywall) { // Render the paywall } } is AdaptyResult.Error -> { // handle the error } } } ``` </TabItem> <TabItem value="react-native" label="React Native"> ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: "YOUR_PLACEMENT_ID" }); const showPaywall = paywall.remoteConfig?.data?.["show_paywall"] ?? true; if (showPaywall) { // Render the paywall } } catch (error) { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter"> ```dart showLineNumbers try { final paywall = await Adapty().getPaywall(id: "YOUR_PLACEMENT_ID"); final bool showPaywall = paywall.remoteConfig?.dictionary?['show_paywall'] as bool? ?? true; if (showPaywall) { // Render the paywall } } on AdaptyError catch (adaptyError) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity"> ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // handle the error return; } var showPaywall = paywall.RemoteConfig?.Dictionary?["show_paywall"] as bool? ?? true; if (showPaywall) { // Render the paywall } }); ``` </TabItem> <TabItem value="kmp" label="Kotlin Multiplatform"> ```kotlin showLineNumbers Adapty.getPaywall( placementId = "YOUR_PLACEMENT_ID" ).onSuccess { paywall -> val showPaywall = paywall.remoteConfig?.dataMap?.get("show_paywall") as? Boolean ?: true if (showPaywall) { // Render the paywall } }.onError { error -> // handle the error } ``` </TabItem> <TabItem value="capacitor" label="Capacitor"> ```typescript showLineNumbers try { const paywall = await adapty.getPaywall({ placementId: 'YOUR_PLACEMENT_ID' }); const showPaywall = paywall.remoteConfig?.data?.['show_paywall'] ?? true; if (showPaywall) { // Render the paywall } } catch (error) { // handle the error } ``` </TabItem> </Tabs> フォールバック値を `true` にしておくことで、フラグがない場合もフロー/ペイウォールは表示されたままになり、フラグを持たない既存のフロー/ペイウォールに影響しません。 :::important ペイウォールを自分でレンダリングする場合([フロービルダー](adapty-flow-builder)や[ペイウォールビルダー](adapty-paywall-builder)を使わない場合)、フロー/ペイウォール A を表示する際に [`logShowFlow`(iOS SDK v4+)/ `logShowPaywall`](present-remote-config-paywalls#track-paywall-view-events) を呼び出してください。これをしないと、Adapty はテストのビュー数を計測できません。フロー/ペイウォール B は表示されないため、ビューをログに記録しないでください。 ::: ## 次のステップ \{#next-steps\} - [A/Bテストの作成・実行・停止](run_stop_ab_tests) — 両方のバリアントを含むテストを設定する - [A/Bテストの結果と指標](results-and-metrics) — 空のバリアントとフロー/ペイウォールを比較する --- # File: results-and-metrics --- --- title: "A/B テストの結果と指標" description: "Adaptyの結果と主要指標を分析して、アプリのサブスクリプションパフォーマンスとユーザーエンゲージメントを向上させましょう。" --- [A/B テスト](ab-tests)では、さまざまなペイウォールやオンボーディングを比較し、ユーザーの行動・エンゲージメント・コンバージョン率にどう影響するかを確認できます。ここで紹介する指標や結果を活用すれば、より賢い判断を下してアプリのパフォーマンスを向上させることができます。データを深掘りして、実践的なインサイトを見つけましょう。 ## A/B テスト結果 \{#ab-test-results\} Adapty が A/B テスト結果として提供する指標は次の3つです: <img src="/assets/shared/img/ab-test-results.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: **Revenue(収益)**: この指標は、購入とリニューアルから発生した USD 総収益から、ユーザーへの返金を差し引いた金額を示します。初回購入だけでなく、その後のサブスクリプション更新も含まれます。収益を見ることで、各 A/B テストバリアントの財務パフォーマンスを把握し、どのバリアントが最も多くの収益をもたらしているかを判断できます。 [ペイウォール](paywall-metrics)の指標についてはこちらをご覧ください。 **Probability to be best(最良の確率)**: Adapty は強固な数学的分析フレームワークを用いて A/B テストの結果を分析し、「最良の確率(Probability to be best)」という指標を提供します。この指標は、特定のバリアントがテストされたすべてのバリアントの中で最も優れたパフォーマンス(長期的な収益の観点から)である可能性を評価します。1% ~ 100% のパーセンテージで表されます。Adapty がこの指標を計算する方法については、[ドキュメント](maths-behind-it)をご参照ください。1K ユーザーあたりの収益で最も優れたオプションは緑色でハイライトされ、デフォルトとして自動的に選択されます。 **Revenue per 1K users(1K ユーザーあたりの収益)**: この指標は、各 A/B テストバリアントにおける 1,000 ユーザーあたりの平均収益を計算します。ユーザー総数に関わらず、バリアントの収益効率を把握するのに役立ちます。標準化されたスケールで異なるバリアントのパフォーマンスを比較し、収益創出効率に基づいて情報に基づいた意思決定を行えます。 **Prediction intervals for revenue 1K users(1K ユーザー収益の予測区間)**: 1K ユーザーあたりの収益指標には予測区間も含まれています。この予測区間は、利用可能なデータと統計分析に基づいて、特定のバリアントの 1,000 ユーザーあたりの真の収益が収まると予測される範囲を表します。 A/B テストにおいて、異なるバリアントが生み出す収益を分析する際、各バリアントの 1,000 ユーザーあたりの平均収益を計算します。収益はユーザーごとに異なるため、予測区間は予測プロセスに伴う変動性と不確実性を考慮しつつ、1,000 ユーザーあたりの収益の妥当な値の範囲を明確に示します。 1K ユーザーあたりの収益指標に予測区間を組み込むことで、Adapty は A/B テストバリアントの収益効率を評価しながら、潜在的な収益結果の幅も考慮できるようにしています。この情報は、予測プロセスの不確実性と 1,000 ユーザーあたりの収益の妥当な値を踏まえた、データに基づく意思決定とサブスクリプション戦略の最適化に役立ちます。 これらの指標を分析することで、A/B テストバリアントの財務パフォーマンス・統計的有意性・収益効率についてのインサイトを得られ、データに基づいた意思決定とサブスクリプション戦略の効果的な最適化が可能になります。 ## A/B テストの指標 \{#ab-test-metrics\} Adapty は、ペイウォールやオンボーディングのバリエーションに対して実施された A/B テストのパフォーマンスを効果的に測定するための包括的な指標セットを提供します。これらの指標はリアルタイムで継続的に更新されますが、ビュー数は定期的に更新されます。これらの指標を理解することで、さまざまなバリエーションの効果を評価し、ペイウォールやオンボーディング戦略を最適化するためのデータドリブンな意思決定が可能になります。 A/B テストの指標は A/B テストリストで確認でき、すべての A/B テストのパフォーマンス概要を把握できます。この包括的なビューでは各テストバリエーションの集計指標が表示され、パフォーマンスの比較や有意な差異の特定が可能です。各 A/B テストのより詳細な分析には、A/B テスト詳細指標にアクセスできます。このセクションでは選択した A/B テストに固有の詳細な指標が提供され、個々のバリエーションのパフォーマンスを深く掘り下げることができます。 ビュー数を除くすべての指標は、ペイウォールやオンボーディング内のプロダクトに紐付けられます。 ## インストール日で指標をフィルタリング \{#filter-metrics-by-install-date\} ペイウォール、トライアル、購入の指標は、2つの異なる日付でグループ化できます: - **イベント日** — ペイウォールが表示された日、トライアルが開始された日、または購入が行われた日。 - **インストール日** — ユーザーが初めてアプリを開いた日。 同じ日付範囲でも、この2つのビューは大きく異なる数値を示すことがあります。**Filter metrics by install date** チェックボックスで、ダッシュボードがどちらを使用するかを制御します: - **チェックなし(デフォルト)**:指標はイベント日でグループ化されます。 - **チェックあり**:指標はインストール日でグループ化されます。 **例。** 日付範囲を4月1日〜30日に設定し、トライアルを確認します。 - **チェックなし**:それらのユーザーがいつインストールしたかに関わらず、4月に*開始*されたトライアルを表示します。 - **チェックあり**:トライアルがいつ開始されたかに関わらず、4月に*インストール*したユーザーのトライアルを表示します。 特定のコホートのユーザー獲得パフォーマンスを測定するにはインストール日ビューを使用し、特定の期間のペイウォールやオンボーディングのアクティビティを測定するにはイベント日ビューを使用してください。 ## 指標のコントロール \{#metrics-controls\} システムは選択した期間に基づいて指標を表示し、3 段階のインデントを持つ左側カラムのパラメータに従って整理します。 ### 期間の選択 \{#time-ranges\} 分析する期間を日・週・月やカスタム日付範囲など、さまざまな時間軸から選択できます。 <img src="/assets/shared/img/ab-test-time-ranges.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: Adapty は、ニーズに合わせた指標分析のフィルタリングとカスタマイズのための強力なツールを提供しています。Adapty の指標ページでは、さまざまな期間・グループ化オプション・フィルタリング機能を利用できます。 - ✅ フィルター対象:オーディエンス、アトリビューション、国、ペイウォール、ペイウォールの状態、ペイウォールグループ、オンボーディング、プレースメント、国、ストア、プロダクト、プロダクトストア - ✅ グループ化対象:プロダクトおよびストア :::note A/B テストでフィルタリングすると、クロスプレースメント A/B テストはプレースメントごとに個別の子テスト(例:`My test child-0`、`My test child-1`)として表示されます。詳細は [クロスプレースメント A/B テストの制限事項](ab-test-types#crossplacement-ab-test-limitations)をご覧ください。 ::: ## 単一指標チャート \{#single-metrics-chart\} ペイウォールやオンボーディングの指標ページの主要コンポーネントの一つが、選択した指標を視覚的に表示して分析を容易にするチャートセクションです。 <img src="/assets/shared/img/e6b0674-Area.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> A/B テスト指標ページのチャートセクションには、選択した指標の値を視覚的に表す横棒グラフが含まれています。グラフの各バーは指標値に対応し、サイズが比例しているためデータをひと目で把握できます。横軸は分析対象の期間を示し、縦軸には指標の数値が表示されます。すべての指標値の合計はグラフの横に表示されます。 また、チャートセクション右上の矢印アイコンをクリックすると、ビューが拡大され、選択した指標がチャートの全体ラインに表示されます。 ## A/B テストのサマリー \{#ab-test-summary\} 単一指標チャートの隣には A/B テスト詳細サマリーセクションが表示されており、A/B テストの状態・期間・プレースメント・その他の関連詳細情報が含まれています。 <img src="/assets/shared/img/90fa3f5-Area.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 指標の定義 \{#metrics-definitions\} A/B テストで利用可能な主要指標は以下のとおりです。 <img src="/assets/shared/img/30c7b68-Area.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Revenue(収益) \{#revenue\} Revenue は、A/B テストによる購入とリニューアルから発生した USD 総収益を表します。初回購入とその後のサブスクリプション更新が含まれます。収益指標は App Store または Play Store の手数料を差し引く前の金額で計算されます。 [ペイウォール](paywall-metrics#revenue)の収益指標についてはこちらをご覧ください。 ### CR to purchases(購入へのコンバージョン率) \{#cr-to-purchases\} 購入へのコンバージョン率は、A/B テストがビューを実際の購入に転換する効果を測定します。購入数をビュー数で割ることで計算されます。例えば、購入数が 10、ビュー数が 100 の場合、購入へのコンバージョン率は 10% になります。 ### CR trials(トライアルへのコンバージョン率) \{#cr-trials\} トライアルへのコンバージョン率(CR)は、A/B テストから開始されたトライアル数をビュー数で割った値です。A/B テストがビューをトライアル有効化に転換する効果を測定します。開始されたトライアル数をビュー数で割ることで計算されます。 ### Purchases(購入数) \{#purchases\} 購入数指標は、A/B テストによってペイウォールやオンボーディング内で行われたトランザクションの総数を表します。以下の種類の購入が含まれます。 - 新規購入 - 有効化されたトライアルのトライアル転換 - サブスクリプションのダウングレード、アップグレード、クロスグレード - サブスクリプションの復元(自動更新なしで期限切れになったサブスクリプションが後に復元された場合など) なお、更新(リニューアル)は購入数指標には含まれません。 ### Trials(トライアル数) \{#trials\} トライアル数指標は、A/B テストによって有効化されたトライアルの総数を示します。 ### Trials cancelled(キャンセルされたトライアル) \{#trials-cancelled\} キャンセルされたトライアル指標は、自動更新がオフになったトライアルの数を表します。これはユーザーがトライアルを手動で解除した場合に発生します。 ### Refunds(返金) \{#refunds\} A/B テストの返金は、テストされたバリエーションに関連する返金された購入とサブスクリプションの件数を表します。 ### Views(ビュー数) \{#views\} ビュー数は、A/B テストを構成するペイウォールやオンボーディングが閲覧された回数です。同じユーザーが 2 回訪問した場合、2 回としてカウントされます。 ### Unique views(ユニークビュー数) \{#unique-views\} ユニークビュー数は、ペイウォールやオンボーディングのユニーク閲覧数です。同じユーザーが 2 回訪問した場合、1 回としてカウントされます。 ### Probability to be the best(最良の確率) \{#probability-to-be-the-best\} 「最良の確率」指標は、A/B テスト内の特定のバリアントが、テストされたすべてのペイウォールやオンボーディングの中で最もパフォーマンスの高いオプションである可能性を数値化したものです。各ペイウォールやオンボーディングの相対的なパフォーマンスを示す数値確率を提供します。1% ~ 100% のパーセンテージで表されます。 ### ARPU(ユーザーあたりの平均収益) \{#arpu-average-revenue-per-user\} オンボーディング A/B テストのみ対象。特定期間における各ユーザーから生み出された平均収益を測定します。総収益をユニークユーザー数で割ることで計算されます。 ### ARPPU(有料ユーザーあたりの平均収益) \{#arppu-average-revenue-per-paying-user\} ARPPU は A/B テストによる有料ユーザーあたりの平均収益(Average Revenue Per Paying User)です。総収益をユニーク有料ユーザー数で割ることで計算されます。例えば、1,000 人の有料ユーザーから $15,000 の収益が発生した場合、ARPPU は $15 となります。 ### ARPAS(アクティブサブスクライバーあたりの平均収益) \{#arpas-average-revenue-per-active-subscriber\} ARPAS は、A/B テストの実施によるアクティブサブスクライバーあたりの平均収益を測定する指標です。総収益をトライアルまたはサブスクリプションを有効化したサブスクライバー数で割ることで計算されます。例えば、総収益が $5,000 でサブスクライバーが 1,000 人の場合、ARPAS は $5 となります。この指標はサブスクライバーあたりの平均収益化ポテンシャルを評価するのに役立ちます。 ### Proceeds(手取り収益) \{#proceeds\} A/B テストの手取り収益指標は、App Store / Play Store の手数料を差し引いた後にアプリオーナーが受け取る実際の USD 金額を、購入とリニューアルから表したものです。A/B テストでテストされたバリエーションに関連する純収益を反映し、アプリの収益に直接貢献します。手取り収益の計算方法については、Adapty の[ドキュメント](analytics-cohorts#revenue-vs-proceeds)をご参照ください。 ### Unique subscribers(ユニークサブスクライバー数) \{#unique-subscribers\} ユニークサブスクライバー数指標は、A/B テストのバリエーションを通じてサブスクリプションを登録またはトライアルを有効化した個別ユーザーの数を表します。サブスクリプションやトライアルの開始回数に関わらず、各サブスクライバーを 1 回のみカウントします。 ### Unique paid subscribers(ユニーク有料サブスクライバー数) \{#unique-paid-subscribers\} ユニーク有料サブスクライバー数指標は、A/B テストのバリエーションを通じて購入を完了し、有料サブスクライバーになったユニークユーザーの数を表します。 ### Refund rate(返金率) \{#refund-rate\} A/B テストの返金率は、テストのバリエーションに関連する返金数を初回購入数(更新は除く)で割ることで計算されます。例えば、返金が 5 件、初回購入が 1,000 件の場合、返金率は 0.5% となります。 ### Unique CR purchases(ユニーク購入コンバージョン率) \{#unique-cr-purchases\} A/B テストのユニーク購入コンバージョン率は、テストのバリエーションに関連する購入数をユニークビュー数で割ることで計算されます。例えば、購入数が 10、ユニークビュー数が 100 の場合、ユニーク購入コンバージョン率は 10% となります。 ### Unique CR trials(ユニークトライアルコンバージョン率) \{#unique-cr-trials\} A/B テストのユニークトライアルコンバージョン率は、テストのバリエーションに関連する開始されたトライアル数をユニークビュー数で割ることで計算されます。例えば、開始されたトライアルが 30、ユニークビュー数が 100 の場合、ユニークトライアルコンバージョン率は 30% となります。 ### Completions & unique completions(完了数とユニーク完了数) \{#completions--unique-completions\} オンボーディング A/B テストのみ対象。完了数は、A/B テストのバリエーションを通じてユーザーがオンボーディングを完了した(最初から最後のスクリーンまで進んだ)回数をカウントします。2 回完了した場合は、**completions(完了数)** が 2 カウントされますが、**unique completion(ユニーク完了数)** は 1 になります。 ### Unique completions rate(ユニーク完了率) \{#unique-completions-rate\} オンボーディング A/B テストのみ対象。ユニーク完了数をユニークビュー数で割った値です。この指標は、A/B テストのバリエーションを通じてユーザーがオンボーディングにどう関わっているかを把握し、無視されていると気づいた場合に改善を行うのに役立ちます。 --- # File: maths-behind-it --- --- title: "A/B テストの背後にある数学" description: "サブスクリプション分析の背後にある数学を理解して、収益インサイトを向上させましょう。" --- A/B テストは、フロー、ペイウォール、またはオンボーディングの2つの異なるバージョンのパフォーマンスを比較するための強力な手法です。最終的な目標は、12か月間のユーザーあたりの平均収益に基づいて、どちらのバージョンがより効果的かを判断することです。しかし、データを収集して意思決定を行うために丸1年待つのは現実的ではありません。そのため、目標指標の代替として2週間のユーザーあたりの収益が使用されており、これは過去のデータ分析に基づいて選択されています。正確で信頼性の高い結果を得るためには、多様なデータタイプを扱える堅牢な統計手法を使用することが重要です。現代のデータ分析で人気のアプローチであるベイズ統計は、A/B テストに柔軟で直感的なフレームワークを提供します。事前知識を取り込み、新しいデータで更新することで、ベイズ手法は不確実性の下でより良い意思決定を可能にします。このドキュメントでは、A/B テスト結果の評価とデータ駆動型の意思決定に向けた貴重なインサイトの提供において、Adapty が採用している数学的分析の包括的なガイドを提供します。 ## 統計分析に対する Adapty のアプローチ \{#adaptys-approach-to-statistical-analysis\} Adapty は、A/B テストのパフォーマンスを評価し、正確で信頼性の高いインサイトを提供するために、包括的な統計分析アプローチを採用しています。私たちの方法論は以下の主要なステップで構成されています: 1. **指標の定義:** A/B テストを成功させるには、分析の具体的な目標や目的に合致する主要指標を特定・定義する必要があります。Adapty は大量のサブスクリプションアプリの過去データを活用し、1年後の平均収益という長期目標に対するプロキシ指標として最適なものを特定しました。それは14日後の ARPU です。 2. **仮説の設定:** A/B テストのために2つの仮説を作成します。帰無仮説(H0)は、コントロールグループ(A)とテストグループ(B)の間に有意な差がないと仮定します。対立仮説(H1)は、2つ以上のグループの間に有意な差があることを示唆します。 3. **分布の選択:** データの特性と観察している指標に基づいて、最適な分布ファミリーを選択します。ここで最も頻繁に選択されるのは対数正規分布(ゼロ値を考慮したもの)です。 4. **ベストである確率の計算:** A/B テストへのベイズアプローチを活用して、テストに参加しているすべてのペイウォールまたはオンボーディングのバリアントに対して、ベストである確率を計算します。この値は以前使用していた p 値と確かに関連していますが、本質的には異なるアプローチであり、より堅牢で理解しやすいものです。 5. **結果の解釈:** 「ベストである確率」は文字通りその意味です。確率が高いほど、特定のオプションがタスクに対して最良の選択である可能性が高くなります。意思決定のしきい値は自分自身で決定する必要があり、具体的な状況の多くの要因に依存すべきですが、一般的な確率の基準は 95% です。 6. **予測区間:** Adapty は各グループのパフォーマンス指標に対する予測区間を計算し、真の母集団パラメータが収まる可能性のある値の範囲を提供します。これにより、推定されたパフォーマンス指標に関連する不確実性を定量化できます。 ## サンプルサイズの決定 \{#sample-size-determination\} 適切なサンプルサイズを決定することは、信頼性が高く決定的な A/B テスト結果を得るために重要です。Adapty は、現在採用しているベイズアプローチにおいても依然として重要となる統計的検出力や期待効果量などの要因を考慮し、適切なサンプルサイズを確保します。現在採用しているベイズアプローチに特有の、必要なサンプルサイズを推定するための手法が、分析の信頼性を担保します。 A/B テストの機能について詳しくは、[A/B テストの作成](ab-tests)と[A/B テストの実行](run_stop_ab_tests)に関するドキュメント、および[A/B テストの指標と結果](results-and-metrics)の理解をご参照ください。 Adapty の A/B テスト向け分析フレームワークはベイズアプローチを採用するようになりましたが、指標の定義、仮説の設定、分布の選択に焦点を当てるという点は変わりません。ただし、p 値を決定する代わりに、事後分布を計算し、各バリアントがベストである確率を算出するようになりました。また、予測区間も算出しています。この改訂されたアプローチは、依然として包括的でさらに堅牢でありながら、より直感的で解釈しやすいインサイトを提供するように設計されています。目標は、A/B テストの堅牢な統計分析に基づいて、企業が戦略を最適化し、パフォーマンスを向上させ、成長を促進できるよう支援することです。 --- # File: autopilot-how-it-works --- --- title: "AI Growth Advisor: 仕組み" description: "AI Growth Advisorの仕組みを理解し、収益アップをお任せください。" --- [AI Growth Advisor](autopilot)は、実際のパフォーマンスデータと同じ市場における類似アプリの動向をもとに、どのような実験を実施すべきかを提案します。何が効果的かを推測するのではなく、結果を改善できる可能性の高いテストについて、具体的な提案を受け取ることができます。 この記事では、AI Growth Advisorの思考プロセスを透明性をもって解説します。どのようなデータを使用しているか、どのように機会を評価しているか、そしてなぜ特定の提案が表示されるのか、といった点について説明します。成長のワークフローにAI Growth Advisorを取り入れて自信を持って活用していただくことが、この記事の目的です。 ## AI Growth Advisorが実際に行うこと \{#what-ai-growth-advisor-actually-does\} AI Growth Advisorは、アプリとペイウォールの指標を分析し、収益向上につながる可能性が最も高い実験を見つけます。具体的には以下を確認します: - **現在の設定**: 価格、トライアル、プロダクト、コンバージョン率 - **市場のパターン**: 類似アプリのオファー構成と価格帯 - **テスト履歴**: すでに実施した実験とその結果 - **成長ポテンシャル**: 最も効果が見込める変更内容 Growth Advisor はAIを使ってこれらの要因を総合的に評価し、すぐに開始できるA/B テストに変換します。競合他社を調査したり、次に何をテストすべきか悩んだりする必要はなく、すぐに使える計画が手に入ります。 ## AI Growth Advisorを支えるデータ \{#the-data-behind-ai-growth-advisor\} 各レコメンデーションは、連携する3つの主要なデータソースをもとに構築されています。 #### アプリ自身のデータ \{#your-apps-own-data\} AI Growth Advisorは、あなたのアプリの現在のパフォーマンスを分析します: - ペイウォール全体のコンバージョン指標 - 価格設定とプロダクト構成 これにより、AI Growth Advisorは変更を提案する前に、ベースラインを把握します。 :::note あなたのアプリのパフォーマンスデータを、他のアプリへのレコメンデーション学習に使用することはありません。データはプライベートに保たれます。 ::: #### ペイウォール分析 \{#paywall-analysis\} AI Growth Advisorは、ペイウォールのスクリーンショットを分析し、そのデザインをあなたのカテゴリーのトップアプリが採用している実績あるパターンと比較します。レイアウトの選択、コピー、サブスクリプションの内訳、節約バッジやレビューセクションなどのコンバージョン重視の要素を評価します。 この分析により、2種類の推奨事項が生成されます。 - **ベンチマークに基づく推奨事項**:トップパフォーマンスのアプリが何を違いとして実践しているかをもとにした推奨事項で、それぞれ具体的な統計データに裏付けられています(例:「教育カテゴリのトップアプリの72%が使用」)。 - **ビジュアル分析の推奨事項**:スクリーンショットをAIが分析して生成する推奨事項で、コピーの改善、レイアウトの変更、その他のデザイン調整を含みます。 これらの推奨事項は、[グロースプラン](autopilot-growth-plan#view-the-growth-plan)に仮説として直接フィードされ、[A/B テストとして実行](autopilot-execute-plan)することができます。 #### 競合データ \{#competitor-data\} AI Growth Advisorは、価格設定やサブスクリプション構造、カテゴリ内の一般的なパターンなど、公開情報を使って同じ市場の類似アプリとあなたのセットアップを比較します。競合他社の価格設定や構造は市場によって異なるため、この比較は国ごとに行われます。競合他社の価格情報は、App Storeなどのサードパーティおよび公開ソースから取得されており、指標分析で使用される匿名化されたAdatyネットワークデータとは別のものです。 このようにして、ランダムなアイデアではなく、あなたのアプリと似たアプリで実績のある戦略をテストできます。分析結果を見れば、自分のベンチマークと競合他社の価格を並べて比較できます。同じようなアプリが異なる価格設定や構造でより良い成果を上げているなら、同じアプローチが自分にも有効だというサインです。 :::tip AI Growth Advisorは、実際に競合できるアプリを基準に、関連する競合他社を自動的に選択します。一般的には、差が大きすぎるアプリを追加するよりも、この提案に従うことをおすすめします。アプリが複数のカテゴリにまたがる場合は、最も関連性の高い市場セグメントに絞り込むようリストを調整するとよいでしょう。 ::: #### 業界ベンチマーク \{#industry-benchmarks\} AI Growth Advisorは、Adaptyが追跡する20,000件のサブスクリプションアプリから収集した匿名化データを活用し、特定の国におけるカテゴリ平均との比較を提供します。データはネットワーク全体で集計されており、特定のアプリに紐づくことはありません。 たとえば、コンバージョンファネルやインストールあたりの収益を、同じカテゴリ・国のアプリの平均値と比較できます。これにより、自分のアプリが平均を下回っているのか、平均並みなのか、あるいはすでに上回っているのかを把握できます。 #### 地域市場データ \{#geographic-market-data\} AI Growth Advisorは、Adaptyネットワーク全体の20,000以上のアプリから得られたパターンをもとに、個別の地域市場を分析し、地域別の価格調整によって収益を伸ばせる可能性のある市場を特定します。各国について、以下の項目を評価します: - **コンバージョン率**:インストールから有料への転換率がグローバル平均と比べてどうか。高い場合は値上げの余地があることを示し、低い場合は価格への感度が高いことを示す可能性があります。 - **価格指数**:[Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf) における各国の位置づけ。その国の住民の購買力を示します。 [ジオプライシングの提案](autopilot-growth-plan#geo-pricing-hypotheses)から A/B テストを作成することで、これらの推奨事項に基づいて行動できます。 ## AI Growth Advisorが推奨事項を決定する仕組み \{#how-ai-growth-advisor-decides-what-to-recommend\} AI Growth Advisorはペイウォールのコンバージョンを改善するための提案を生成します。これらの提案は、各変更の効果を確実に測定できるよう、1つずつ順番にテストできるよう設計されています。 AI Growth Advisorが提案を生成する仕組みは次のとおりです。 1. **最も大きな改善機会を見つける** AI Growth Advisorは、あなたの価格設定・プロダクト・ファネルのパフォーマンスを分析し、業界のパターンや類似アプリと比較します。分析はメイン市場の通貨で行われるため(USDのみではなく)、価格の提案がサブスクライバーの実際の支払い通貨に合ったものになります。改善の余地が最も大きい部分——価格の調整、トライアルの追加、オファー構成の変更など——を特定します。 2. **次の実験を選択する** 各仮説は、既存のテスト履歴をもとに生成されます。AI Growth Advisorは、すでに実施した実験、勝者となった実験、まだ探索する価値がある方向性を把握しています。次の提案は、固定されたシーケンスに従うのではなく、前回の実験で明らかになった内容をもとに構築されます。 3. **勝者 vs. チャレンジャーのテストを実施する** 各実験の後、勝者が新しいベースラインになります。その結果が成長プランの次の推奨事項を形成します。AI Growth Advisorは効果のあったものを維持し、効果のなかったものを除外して、そこから次のテストを選択します。 4. **実用的に活用する** AI Growth Advisorは、既存のプロダクトや設定、または新しいプロダクトの作成や価格調整といった小さな変更で実施できるテストのみを提案します。テストを素早く、管理しやすい状態に保つことが目的です。 5. **根拠を示す** AI Growth Advisorは各レコメンデーションに対して、なぜそのテストを実施する価値があるのかを明確に説明する仮説を提示します。現在の指標が競合他社や業界平均と比較してどうか、どんな機会があるか、どの主要指標の改善が見込まれるかを確認できます。 これにより、実験が繰り返し可能なプロセスになり、各テストから得た知見をもとに、より効果的なペイウォールへと着実に近づいていけます。 ## 各実験の後に起こること \{#what-happens-after-each-experiment\} おすすめの実験が尽きることはありません。完了した各テストは、次の実験の土台となります。テストを続ける限り、AI Growth Advisor は次に試すべき施策を提案し続けます。 基礎となる市場データを更新するには、同じプレースメントで分析を再実行してください。再実行のたびに、競合他社の最新の価格情報、コンバージョンのベンチマーク、カテゴリのトレンドが取り込まれ、新たに特定された仮説がグロースプランに追加されます(既存のデータには影響しません)。既存のAI生成の仮説、カスタム仮説、進行中のA/B テストは、再実行後も保持されます。 ベースラインを最適化したら、さらに高度な競合との戦いに挑むこともできます。このような反復的なアプローチにより、アプリの成長や市場の変化に合わせて収益を最大化し続けることができます。 :::tip 試してみませんか?[AI Growth Advisor](autopilot-analysis) を使ってペイウォールを分析し、A/B テストを含む成長計画を作成しましょう。[内蔵ウィザード](autopilot-execute-plan) を使えば、複雑なテストをスムーズに開始できます。プロダクトの作成、ペイウォールの複製、セグメントの設定まで、ステップごとにガイドしてくれます。 ::: --- # File: autopilot-analysis --- --- title: "ペイウォール・市場分析" description: "アプリに合わせたデータドリブンな成長プランを生成します。" --- この記事の手順に従って、AI グロースアドバイザーの分析を実行し、成長プランを生成してください。 対象のプレースメントに対してすでに成長プランを生成済みの場合、この分析では新しい仮説が生成され、そこから選択できます。 :::tip 分析を開始する前に、[分析の要件](autopilot#prerequisites)を満たしていることを確認してください。 ::: ## ペイウォール分析 \{#paywall-analysis\} ### 分析するペイウォールを選択する \{#select-a-paywall-for-analysis\} 1. **AI Growth Advisor** ページを開き、[Get Growth plan](https://app.adapty.io/ab-tests/analysis/start) ボタンをクリックします。 2. **Paywall Diagnostic** ページで、ドロップダウンから **Placement** と **Paywall** を選択します。Adapty は収益の高いプレースメントとそのトップペイウォールをあらかじめ選択しています。別のペイウォールを分析する場合は、先にプレースメントを変更してください。 3. スクリーンショットをアップロードします。AI Growth Advisor がペイウォールのデザインとコンテンツを分析するために、スクリーンショットが必要です。 4. ペイウォールのアクティブなプロダクトを確認します。右側のプロダクトカードには、各プロダクトのサブスクリプション期間、価格、トライアル期間が表示されます。 5. **Confirm & Analyze** をクリックして進みます。Adapty がペイウォールを分析し、診断レポートを表示します。 ### ペイウォール分析レポート \{#paywall-analysis-report\} ペイウォールを選択してスクリーンショットをアップロードすると、Adapty はペイウォールの確立されたデザインパターンを分析し、優れた点と改善の余地がある点を明示します。 #### うまくいっている点 \{#whats-working-well\} このセクションでは、コンバージョンを最大化する確立されたパターンのうち、あなたのペイウォールで活用できているものをハイライトします。例:目立つ割引バッジ、目を引くユーザーレビューセクション、わかりやすいサブスクリプションの内訳など。 #### ペイウォールの改善点 \{#what-to-fix-on-your-paywall\} Adapty は推奨事項を次の 2 つのカテゴリに分類します。 - **ベンチマークに基づく推奨事項**: あなたのカテゴリでトップパフォーマンスを誇るアプリのデータに基づく提案です。各推奨事項にはベンチマーク統計(例:「上位の教育アプリの72%で使用されている」)と、変更内容の説明が含まれます。 - **ビジュアル分析の推奨事項**: ペイウォールのスクリーンショットをもとにAIが生成する提案です。コピーの改善、レイアウトの変更などが含まれます。 :::tip [成長プラン](autopilot-growth-plan#view-the-growth-plan)には、ベンチマークの推奨事項に基づいた仮説が含まれます。視覚的な分析の提案は、手動でプランに追加できます。 ::: **Get Market Insights** をクリックして次に進みます。 ## マーケットと競合分析 \{#market-and-competitor-analysis\} :::note マーケットと競合分析を行うには、先に[ペイウォール分析](#paywall-analysis)を完了する必要があります。 ::: Market Insights 分析では、アプリの価格設定とコンバージョン指標を競合他社や業界平均と比較します。比較は国ごとに行われます。ベンチマークとして、Adapty は同サブカテゴリー・同国の App Store アプリのデータを集計・分析します。このデータは他では公開されていません。 ### 競合他社を選択する \{#select-competitors\} 比較対象として最大 5 社の競合他社を選択します。 Adapty が自動的に 5 社を選び、さらに 5 社を提案します。App Store のリンクを使って手動でアプリを追加することもできます。より精度の高い結果を得るには、自社より MRR が高いアプリを選択してください。 **Generate report** をクリックしてリストを確定し、分析が完了するまで待ちます。 ### 国を選択する \{#select-a-country\} Country ドロップダウンを使って、詳細分析の対象となるトップ国を 1 つ選択します。 ### 収益の地域分布 \{#revenue-distribution\} この収益分布チャートは、パーセンテージの内訳とともに、収益がどの国から得られているかを示します。上位 5 か国がハイライトされ、以降の分析はそれらを中心に行われます。 ### 競合他社の価格設定 \{#competitor-pricing\} 競合他社の価格比較テーブルでは、[選択した国](#select-a-country)における競合他社のサブスクリプション価格とペイウォールの価格を比較します。サブスクリプション期間ごとに列が分かれています。 ### コンバージョンファネル \{#conversion-funnel\} このチャートは、Views-to-Trial、Trial-to-Paid、Views-to-Paid のコンバージョン率を、類似アプリの平均値と並べて表示します。 ### 期間別収益分布 \{#revenue-distribution-by-duration\} このチャートは、業界平均と比較して、どのサブスクリプション期間が収益に最も貢献しているかを示します。特定の期間に収益が偏っている場合、価格戦略の最適化の機会がある可能性があります。 ### アクティベーション ARPU \{#activation-arpu\} **Activation ARPU: your app vs. category** チャートは、新規インストールあたりの平均収益をカテゴリ平均と比較します。 [コンバージョンファネル](#conversion-funnel)と組み合わせて活用してください。 - コンバージョンは、課金ユーザーの割合を示します。 - アクティベーション ARPU は、ユーザーあたりの平均収益を示します。 コンバージョン率が高いのにアクティベーション ARPU が低い場合は、価格設定が低すぎる可能性があります。 この指標は**コホートベース**です。Adapty は過去 90 日間にインストールしたユーザーを対象に、そのユーザーが生んだ収益をユーザー数で割って算出します。 #### 他の指標との比較 \{#comparison-to-other-metrics\} Activation ARPU は、ダッシュボードの他の箇所に表示される ARPU 値とは一致しません。各指標が測定する内容が異なるためです。 - **[ARPU アナリティクスチャート](arpu)**:古いコホートからの更新も含まれるため、Activation ARPU より数倍高い値になります。 - **[収益チャート](revenue)(Period フィルターを「Activation」に設定)**:各ユーザーの初回支払いのみをカウントします。90 日間のウィンドウ内でコホートが行った更新はカウントされません。 - **[コホート収益](analytics-cohorts)(90 日間)**:最も近い比較対象です。この指標を参考値として使用してください。 ## 次のステップ \{#next-steps\} [成長プランの実行](autopilot-execute-plan)を読んで、分析結果に基づいた A/B テストの実施方法を確認してください。 分析レポートはいつでも成長プランから確認できます。**Analysis Results** タブに切り替えてください。 --- # File: autopilot-growth-plan --- --- title: "成長計画の管理" description: "カスタム仮説の追加、アーカイブ、成長計画の更新を行います。" --- [分析](autopilot-analysis)が完了すると、Adapty は成長計画(**実行可能な改善仮説**のリスト)を提示します。各項目には、新しい価格設定やデザイン改善の提案が含まれています。 仮説を[A/B テストで試してみる](autopilot-execute-plan)ために開きましょう。 各プレースメントにはそれぞれの成長計画があります。市場環境が変化したときは、分析を再実行して提案を更新できます。過去の実行結果はバージョン履歴に保存されます。 ## 仮説 \{#hypotheses\} 成長プランの上部にあるタブを切り替えると、仮説をタイプ別にフィルタリングできます: - **最優先** には、最も重要な仮説が含まれており、優先的に確認することをお勧めします。該当する仮説がない場合、このタブは非表示になります。 - **すべて** では、アクティブなプランのすべての仮説を表示します。 - **価格設定** 仮説では、新しい価格帯やトライアル設定を検討します。それぞれはペイウォール診断または市場インサイトレポートからの特定の推奨に基づいています。 - **ビジュアル** 仮説は、デザイン改善の提案です。コピー、レイアウト、その他のビジュアル要素の変更が含まれる場合があります。 - [**地域別価格設定**](#geo-pricing-hypotheses) 仮説では、国ごとの価格調整をテストします。 - [**アーカイブ済み**](#archive-a-hypothesis) 仮説は、アクティブなプランから削除した提案です。いつでも復元できます。 独自の仮説を[追加](#add-your-own-hypothesis)したり、テストしたくない仮説を[アーカイブ](#archive-a-hypothesis)したりすることができます。 これらの仮説は、任意の順序で1つずつテストしてください。地域別価格設定のテストは例外です。オーディエンスが重複しないため、並行して実行できます。 ### 地域別価格設定の仮説 \{#geo-pricing-hypotheses\} :::important 買い切り購入は地域別価格最適化の対象外です。 ::: **Geo-pricing** タブを開くと、地域別価格設定のレコメンデーション一覧が表示されます。各レコメンデーションは1つの国を対象とし、1つの価格変更として個別の A/B テストで実行されます。 Adapty は価格調整が必要な国を検出し、[Adapty Pricing Index](https://uploads.adapty.io/adapty_pricing_index.pdf) によって検証されたデータドリブンなレコメンデーションを提供します。 <br /> #### Adaptyが地域価格の提案を行う仕組み \{#how-adapty-makes-geo-pricing-suggestions\} - 価格の推奨はApp Storeのデータに基づいています。作成されたA/B テストはApp StoreとGoogle Playの両方で実行できます。 - 価格変更の割合は、すべてのサブスクリプション期間で同一です。 - すべての価格は、最も近いApp Storeの価格帯に丸められます。 - Adaptyがその国のトランザクションデータを持っている場合、価格はローカル通貨(EURやGBPなど)で表示されます。ローカルデータがない場合は、USDで表示されます。 ### 仮説のステータスバッジ \{#hypothesis-status-badges\} 1. **稲妻マーク** — 優先度の高い提案を示します。 2. **プロダクトの同期ステータス** — A/B テストを開始するためにプロダクトの対応が必要な場合に表示されます。 - **Draft** — プロダクトの設定が未完了です(Adapty 側) - **Action required** — プロダクトの設定が未完了です(ストア側) - **Pending...** — Adapty がストアによる審査または初回同期の完了を待っています。 - **Approved** — プロダクトがストアに承認され、テスト可能な状態です。 - **Rejected** — ストアがプロダクトを却下しました。 - **Not connected** — プロダクトがまだストアに連携されていません。 3. **A/B テストのステータス** — A/B テストを開始すると表示されます。 - **Draft test** — テストは下書き状態で、まだ実行されていません。 - **Running** — テストは稼働中です。 - **Completed** — テストが完了しました。 - **Archived test** — テストは結論を出さずにアーカイブされました。 ## 新しいAI生成の仮説を取得する \{#get-new-ai-generated-hypotheses\} 各テストの後、Adaptyはテスト結果に基づいて自動的に仮説を更新します。 最新の競合他社の価格情報、コンバージョンのベンチマーク、カテゴリーのトレンドを取り込むには、グロースプランのヘッダーにある **Update** Refresh をクリックするか、AI Growth Advisorのホームページで **Update Analysis** をクリックします。プロンプトが表示されたら **Get New Ideas** をクリックします。 Adapty は、あなたのプレースメントが事前に選択された状態で分析ウィザードを開きます。ペイウォール分析と競合リサーチが再実行され、Adapty はその結果から新しい仮説を特定します。 追加したいものを選択するか、**Add All To Plan** Plus をクリックしてすべてを承認します。新たに追加された仮説はリストの先頭に表示されます。既存の AI 生成仮説、カスタム仮説、進行中の A/B テストには影響しません。 更新を途中で終了した場合、**再開**して続きから行うか、**破棄**して最初からやり直すかを選べます。 ## 独自の仮説を追加する \{#add-your-own-hypothesis\} **Add Hypothesis** Plus をクリックして、独自の価格設定またはビジュアルの提案を作成します。 フォームに入力します:タイトル、説明、仮説タイプ(**Monetization** または **Visual**)。 - ドロップダウンメニューから改善したい指標を選択します。 - Monetization 仮説は、テスト用プロダクトの選択も必要です。 ## 仮説をアーカイブする \{#archive-a-hypothesis\} 仮説をアーカイブするには、Close ボタンをクリックし、**Skip** をクリックして確認します。理由を入力することもできます — Adapty が将来の提案を改善するのに役立ちます。 仮説は **Archived** タブに移動します。 アーカイブされた仮説をアクティブなプランに戻すには、カード上の **Restore** をクリックします。 ## 過去の仮説を見直して再利用する \{#revisit-and-reuse-old-hypotheses\} 過去の分析で生成された提案を確認するには、グロースプランのヘッダーにある **Clock** Clock をクリックしてください。**Version history** モーダルには、そのプレースメントにおけるすべての過去の実行履歴(日付、ペイウォール、当時承認した仮説の数)が一覧表示されます。 過去の実行結果をクリックすると、そのときに生成された仮説が表示されます。**Add to Plan** Plus を使って、任意の仮説をアクティブなプランに追加できます。以前見送った提案を後から取り込みたいときに便利です。 --- # File: autopilot-execute-plan --- --- title: "グロースプランを実行する" description: "グロースプランの仮説からA/Bテストを起動する。" --- テストはどんな順序でも実行できますが、**一度に1つずつ**実行する必要があります。ただし、地域別価格テストのオーディエンスは重複しないため、それらは並行して実行できます。テストが終わったら、勝利した戦略を次のラウンドに進めてください。各ラウンドを経るごとに、アプリにとってより効率的な設定に絞り込まれていきます。 私たちの試算では、推奨テストのフルセットを実施することで、収益が**最大80%増加**する可能性があります。 :::important 各提案には、A/B テストの最小実施期間が含まれています。次のステージに進む前に、最も正確なデータを得るためにこれらの推奨事項に従ってください。A/B テストは手動で停止する必要があります。 ::: 仮説を開いて **Set Up & Run Test** をクリックすると、A/B テスト作成ウィザードが起動します。 ## ステップ1:仮説を確認する \{#step-1-view-the-hypothesis\} 最初のステップでは、仮説の概要が表示されます。提案された変更内容とその根拠が説明されています。「Set up & Run Test」をクリックして次のステップに進んでください。 {/* TODO: REPLACE SCREENSHOT */} ## ステップ2:新しいプロダクトを作成する \{#step-2-create-new-products\} テストに価格変更が含まれる場合、2番目のステップでテストバリアント用の新しいプロダクトを作成できます。ビジュアル仮説の場合、このステップはスキップされます。 * **Create a new product and push to stores** をクリックすると、新しいプロダクトをゼロから作成できます。 * **Connect an existing product** をクリックすると、アプリストアに既に存在するプロダクトを接続できます。 ## ステップ3:セグメントとペイウォールを設定する \{#step-3-set-up-segment-and-paywall\} 3番目のステップでは、ペイウォールのテストバリアントを設定できます。Adaptyはペイウォールを複製して、提案された変更を適用するよう促します。 **ジオプライシング仮説**の場合、ウィザードは既存のジオフェンスセグメントを選択するか、新しいセグメントを作成するよう促します。 新しいペイウォールの準備が整い、セグメントの設定が完了したら **Next** をクリックしてください。 ## ステップ4:確認して起動する \{#step-4-review--launch\} 最後のステップでは、これから実施するテストのサマリーが表示されます。以下の内容が含まれます: - **バリアントA vs バリアントB** の主要指標 — ペイウォール名、プロダクトの選択、トライアル期間、価格。 - テストの **Duration**(期間)、**Traffic**(分割)、**Subscribers**(最小サンプルサイズ)。 - テストの成否を示すシグナルを説明する **How to interpret results** セクション。 設定内容を確認し、**Launch Test** をクリックしてA/Bテストを開始します。 --- # File: how-adapty-analytics-works --- --- title: "Adapty アナリティクスの仕組み" description: "Adapty アナリティクスがサブスクリプションのパフォーマンスを効率的に追跡する仕組みについて説明します。" --- この記事では、Adapty アナリティクスの仕組みについて説明します。表示されるデータの種類、データの取得元、およびデータの処理方法を紹介します。また、Adapty アナリティクスを他と差別化する設計上の判断と、それがどのようにあなたのメリットになるかについても解説します。 ## Adapty アナリティクス vs ストアアナリティクス \{#adapty-analytics-vs-store-analytics\} - **データの多様性**: ストアは自社のデータのみ表示でき、アプリ内のユーザー行動にはアクセスできません。 Adapty は複数のストアのデータを統合できるほか、マーケティングプラットフォームや広告ネットワークなどの追加ソースとも連携できます。Adapty SDK はペイウォールやオンボーディングに対するユーザーの操作を追跡します。 - **更新頻度**: アプリストアは通常、データを1日1回更新するため、リアルタイムな意思決定が難しくなることがあります。 Adapty は[ほぼリアルタイム](#data-processing)のアナリティクスを提供します。 - **高度な指標**: アプリストアは、ダウンロード数、収益、リテンション率などの基本的な指標を表示します。 Adapty はさらに、経常収益やユーザーあたりの平均収益といった高度な指標も算出します。専用のセクションでは、ユーザーのチャーンや課金の失敗など、サブスクリプションに関する問題を分析できます。全一覧は[指標比較表](metric-comparison-table)をご覧ください。 - **予測**: Adapty は高度な機械学習アルゴリズムを使用して、[将来の LTV と収益を予測](predicted-ltv-and-revenue)します。 ## データとその入手元 \{#data-and-its-sources\} Adapty Analytics は以下のデータを処理して[チャートやグラフ](analytics)を生成します。 - [サブスクリプションイベント](events):トライアル開始、購入、更新、キャンセル、請求失敗、返金など、ユーザーのライフサイクル全体で生成されます。Adaptyはこれらを[アナリティクスチャート](analytics)に集約し、リアルタイムで[ウェブフック](webhook)、[イベントフィード](event-feed)、[イベントベースの連携](analytics-integration)に転送します。 - [トランザクションデータ](revenue):収益、返金、購入者の国など。 - **アプリケーションデータ**:インストール数や[ペイウォールのインタラクション](paywalls)など。 - [トランザクションのアトリビューションデータ](attribution-integration):トラフィックソースや広告キャンペーン。 (No translatable prose was provided in the input fragment.) - <InlineTooltip tooltip="Adapty SDK">[iOS](ios-sdk-overview)、[Android](android-sdk-overview)、[React Native](react-native-sdk-overview)、[Flutter](flutter-sdk-overview)、[Unity](unity-sdk-overview)、[Kotlin Multiplatform](kmp-sdk-overview)、[Capacitor](capacitor-sdk-overview) </InlineTooltip> はアプリ内のユーザー行動データを収集します。Adapty が購入フローを管理している場合、SDK は購入イベントに関する一次情報を共有します。[オブザーバーモード](observer-vs-full-mode)を使用している場合、SDK は手動で設定した[イベントレポート](report-transactions-observer-mode)を受け取ります。 - ストアはサーバー間通信を使用して、トランザクション(トライアル、サブスクリプションの更新、キャンセルなど)を Adapty に通知します。 - サードパーティの[アトリビューションサービス](attribution-integration)(Appsflyer、Adjust、Branch など)は、トラフィックソースや広告キャンペーンに関するデータを共有します。[Adapty Attribution](adapty-user-acquisition) を設定すると、このステップを省略して Adapty が広告キャンペーンデータを直接処理できます。 - ユーザーは[過去のトランザクションデータを手動でインポート](importing-historical-data-to-adapty)して、Adapty で分析・表示させることができます。 ソースの1つに問題が発生すると、アナリティクスデータ全体の品質に影響する場合があります。詳細については、[トラブルシューティング](#troubleshooting)セクションをご覧ください。 ## サードパーティ連携 \{#third-party-integrations\} [Adapty User Acquisition](adapty-user-acquisition) を有効にすると、広告キャンペーンデータで Adapty のアナリティクス機能を拡張できます。広告キャンペーンの費用とユーザー行動の相関関係を発見するのに役立ちます。 同様に、アナリティクスデータをサードパーティプラットフォームや[プライベートサーバー](webhook)に[エクスポート](analytics-integration)して、別のプラットフォームで Adapty のデータを分析することもできます。 ## データ処理 \{#data-processing\} Adapty はほぼリアルタイムの分析を提供しており、主要な指標の変化に素早く対応できます。 - **アナリティクスチャート**: トランザクション発生後、データが反映されるまで **15〜30分の遅延** があります。Adapty はこの時間を使って、トランザクションの検証、手数料・税金の適用、データの集計を行います。 - **[イベントフィード](event-feed)**: ストアからイベントが届き次第、リアルタイムで更新されます。 - **[ウェブフック](webhook)およびイベントベースの連携**(AppsFlyer、Branch など): Adapty はイベント発生時に即座に転送します。15〜30分のアナリティクス遅延は適用されません。受信側のサービスで独自の処理時間が発生する場合があります。 各サーフェスにはそれぞれ固有のタイミングがあります。同じイベントがチャート、イベントフィード、インテグレーションでわずかに異なるタイミングで表示されることがあります。これらの間の小さなずれは想定内の動作です。 ## 手数料と税金 \{#commissions-and-taxes\} 収益関連のチャートを表示する際、**Gross revenue(総収益)**、**Revenue after commissions(手数料控除後の収益)**、**Revenue after commissions and taxes(手数料・税金控除後の収益)**から選択できます。 ### コミッション \{#commissions\} ストアは各トランザクションからコミッションを差し引きます。所属する組織が手数料減額プログラムに参加している場合は、Adapty の設定を変更してコミッション率の計算を調整してください: * [App Store Small Business Program](app-store-small-business-program) * Google の[手数料減額プログラム](google-reduced-service-fee) その他の要因によりトランザクションのコミッションが減額される場合、ストアは自動的にそれを報告します: * [1年以上のApp Storeサブスクリプションの更新](https://developer.apple.com/app-store/subscriptions/) — 手数料15% * 国別レート(例:[日本で配布されるApp Storeアプリは21%](https://developer.apple.com/support/app-distribution-in-japan/#business-terms)) ### 税金 \{#taxes\} **Adapty は税金を計算しません。** Apple と Google が各トランザクションに適用される税率を決定し、Adapty にそのまま報告します。Adapty はその値をそのまま表示します。 特定のトランザクションに表示される税率は、以下によって異なります: - **購入者の請求先国**とその国で適用される現地の税率。 - **ストアの税処理ルール**。管轄によっては、ストアが開発者に代わって税金を徴収・納付する場合があり、開発者が自ら対応する必要がある場合もあります。 - App Store の取引では、アプリやアプリ内課金に割り当てられた**税カテゴリ**(書籍、ニュース、動画など)— カテゴリによって、現地のルールに応じて異なる税率が適用されることがあります。 税率は、購入者の国、ストアの処理ルール、(App Store の場合)割り当てられた税カテゴリーの組み合わせにより、アプリ間はもちろん、同一アプリ内のトランザクション間でも大きく異なる場合があります。 公式ルールについては、各ストアの公式ドキュメントを参照してください: - [App Store: 税金について](https://developer.apple.com/help/app-store-connect/making-payments-to-apple/understanding-taxes/) - [Google Play: 税率と VAT](https://support.google.com/googleplay/android-developer/answer/138000) ## トラブルシューティング \{#troubleshooting\} :::link メイン記事:[データの相違とトラブルシューティング](discrepancies-and-troubleshooting) ::: * データソースの設定が間違っていたり、見つからない場合、アナリティクス全体に悪影響を及ぼす可能性があります。データに問題が生じた場合は、ストアおよびサードパーティプラットフォームとのインテグレーションが正しく設定され、有効になっているか確認してください。 * Adapty のチャートを他の分析プラットフォームと比較すると、数値に差異が生じる場合があります。これはデータ処理の違いによるもので、想定内の動作です。よくある差異の原因については、[差異に関するガイド](discrepancies-and-troubleshooting)をご覧ください。 --- # File: metric-comparison-table --- --- title: "さまざまな指標を比較する" description: "Adapty アナリティクスの指標リファレンステーブル(カテゴリ別)。" --- これは Adapty Analytics で利用できる指標の概要です。各指標が何を測定するのか、また関連する指標との違いを理解するためにご活用ください。 Adapty がアナリティクスデータをどのように処理するかについての詳しい説明は、[Adapty アナリティクスの仕組み](how-adapty-analytics-works)をご覧ください。 :::note この記事では[Adapty アトリビューション](adapty-user-acquisition)の指標については説明していません。広告キャンペーンの指標(費用、CPI、ROAS、CTRなど)について詳しくは、[Adapty アトリビューション アナリティクス](ua-analytics)をご覧ください。 ::: ## グローバル指標 \{#global-metrics\} グローバル指標は、すべてのプレースメントとペイウォールにわたるアプリ全体のパフォーマンスを追跡します。 ### 収益 \{#revenue\} これらの指標は、アプリがどれだけの収益を生み出しているか、またその収益源を測定します。 | 指標 | 説明 | 主な違い | |--------|-------------|----------------| | [Revenue](revenue) | サブスクリプションおよび買い切り購入からの総収益(返金分を除く) | 実際に発生した収益。[チャートコントロール](controls-filters-grouping-compare-proceeds)の設定に応じて、グロス収益・手数料控除後の収益・税金と手数料の控除後の収益を表示できます | | [MRR](mrr) | アクティブなサブスクリプションからの月間経常収益 | アプリの安定した月間収益。買い切り購入および非継続型サブスクリプションは除外されます | | [ARR](arr) | アクティブなサブスクリプションからの年間経常収益 | MRRと同じ計算方法を年単位で適用したもの。年間収益の予測に役立ちます | | [ARPU](arpu) | ユーザー1人あたりの平均収益 | 収益を、課金・非課金を問わない全ユーザー数で割った値。各ユーザーが平均的にどれだけの収益をもたらしているかを示します | | [ARPPU](arppu) | 課金ユーザー1人あたりの平均収益 | 選択期間中に購入を行ったユーザー(返金済みのトランザクションを含む)のみをカウント。常にARPUより高くなります | | [LTV(ライフタイムバリュー)](ltv) | コホート内の課金顧客からの収益を課金顧客数で割った値 | 課金顧客1人あたりの実現済み価値を時系列で示します。ARPPU(単一期間)とは異なり、LTVは顧客との関係全体にわたる総収益を表します。更新回数別または暦日別で表示可能です | | [予測LTV](predicted-ltv-and-revenue) | コホートのユーザー1人あたりの推定ライフタイムバリュー | 将来予測の指標。実現済みLTVとは異なり、コホートの過去の継続率パターンから将来の価値を予測します。3・6・9・12・18・24ヶ月で表示可能です | | [予測収益](predicted-ltv-and-revenue) | コホートが生み出すと推定される総収益 | 将来予測の指標。実現済みRevenueとは異なり、選択した期間にコホートが生み出す総額を予測します。毎日更新されます | | [Non-subscriptions](non-subscriptions) | アプリ内課金(消耗型アイテム・非消耗型アイテム・非継続型サブスクリプション)の件数 | 自動更新型サブスクリプションは除外されます | | [Refund events](refund-events) | 返金された購入またはサブスクリプションの件数 | 元の購入日ではなく、返金日に帰属します | | [Refund money](refund-money) | 選択期間中の返金総額 | 返金による財務的な影響。ストア手数料控除前の金額で算出されます。Refund events(件数)とは異なり、金額を表示します | ### サブスクライバーとコンバージョン \{#subscribers-and-conversion\} これらの指標は、ユーザーがアプリに流入し、ファネルを通過していく過程を追跡します。 | 指標 | 説明 | 主な違い | |--------|-------------|----------------| | [インストール数](installs) | 期間中のアプリインストール数 | [インストールの定義](general#4-installs-definition-for-analytics)に応じて、以下のいずれかをカウント: <br /> • デバイスインストール数(アプリを再インストールしたユーザーは再カウント) <br /> • ユニークユーザー数(`customer_user_id` を設定したユーザーのみカウント。匿名ユーザーは完全に除外 — ユーザーが識別されていない場合、カウントは0) | | [新規トライアル](new-trials) | 期間中に開始されたトライアル | チャートを表示した時点でトライアルが既に期限切れまたは有料転換済みであっても、すべてのトライアル開始をカウント | | [アクティブトライアル](active-trials) | まだ期限切れになっていないトライアル数 | 期間終了時点でアクティブなトライアルのみカウント | | [新規サブスクリプション](reactivated-subscriptions) | 期間中に初めて有効化されたサブスクリプション(トライアルなしの初回購入とトライアルから有料への転換の両方を含む) | 更新や再アクティブ化は除外。トライアル転換は `trial_converted` を発火するため、トライアルなしの初回購入のみをカウントする `subscription_started` インテグレーションイベントとは異なる | | [アクティブサブスクリプション](active-subscriptions) | まだ期限切れになっていない有料サブスクリプション数 | トライアルと更新がキャンセルされたサブスクリプションは除外 | | [インストールからトライアルへ](analytics-conversion#install---trial) | トライアルを開始したインストール者の割合 | 分母にはペイウォール閲覧者だけでなくすべてのインストール者が含まれるため、ペイウォール閲覧からトライアルへの割合よりも低くなる場合がある。また、アプリがペイウォール表示をログに記録しない場合、両指標に乖離が生じることがある。これは、`logShowFlow`(iOS SDK v4+)/ `logShowPaywall` を呼び出さないカスタムペイウォールを使用している場合や、ユーザーが[プロモートされたアプリ内課金](https://developer.apple.com/documentation/storekit/supporting-promoted-in-app-purchases-in-your-app)からトライアルを開始した場合に発生する可能性がある。 | | [ペイウォール閲覧からトライアルへ](analytics-conversion#paywall-view---trial) | トライアルを開始したペイウォール閲覧者の割合 | ペイウォールを閲覧したユーザーのみカウントするため、インストールからトライアルへの割合より高くなる場合がある | | [トライアルから有料へ](analytics-conversion#trial---paid) | サブスクリプションを購入したトライアルユーザーの割合 | トライアルの質と転換効率を測定。インストールから有料へとは異なり、トライアルを完了したユーザーのみに注目 | | [インストールから有料へ](analytics-conversion#install---paid) | 最初のサブスクリプションを購入したインストール者の割合 | ペイウォール閲覧者だけでなくすべてのインストール者をカウント。ペイウォール閲覧から有料への割合よりも低くなる場合がある。直接購入とトライアルから有料への転換の両方を含む | | [ペイウォール閲覧から有料へ](analytics-conversion#paywall-view---paid) | 最終的にサブスクリプションを購入したペイウォール閲覧者の割合 | ペイウォールを閲覧したユーザーのみカウントするため、インストールから有料への割合より高くなる場合がある。トライアルを先に完了したユーザーも含む | ### 維持率とサブスクリプション更新 \{#retention-and-subscription-renewal\} これらの指標は、アプリが有料サブスクライバーをどの程度長く維持できているかを追跡します。 | 指標 | 説明 | 主な違い | |--------|-------------|----------------| | [リテンション](analytics-retention) | 各請求期間(1回目の更新、2回目の更新など)後に残っている元のサブスクライバーの割合 | 初回支払い以降のサブスクライバーを追跡します。以下の期間対期間の指標とは異なり、常に元のグループと比較するため、全体像を一目で把握できます | | [Paid to 2nd period](analytics-conversion#paid---2nd-period) | 初回サブスクライバーのうち、2回目の期間に更新した割合 | 隣接する2つの特定の期間間のトランジションを測定します。リテンションとは異なり、最も重要な最初の更新に焦点を当てています | | [2nd to 3rd period](analytics-conversion#2nd-period---3rd-period) | 2回目から3回目の期間に更新した割合 | 初回更新後の初期リテンションの安定性を示します | | [3rd to 4th period](analytics-conversion#3rd-period---4th-period) | 3回目から4回目の期間に更新した割合 | 中期リテンションの指標 | | [4th to 5th period](analytics-conversion#4th-period---5th-period) | 4回目から5回目の期間に更新した割合 | 長期ロイヤルティの指標 | | [6 Months+](analytics-conversion#6-months-) | 初回サブスクライバーのうち、6ヶ月以上サブスクリプションを継続している割合 | 更新回数ではなくカレンダー上の時間を測定します。年間サブスクライバーは、更新がなくても6ヶ月時点でリテンション済みとしてカウントされます | | [1 Year+](analytics-conversion#1-year-) | 初回サブスクライバーのうち、12ヶ月以上サブスクリプションを継続している割合 | 年間リテンションのマイルストーン | | [2 Years+](analytics-conversion#2-years-) | 初回サブスクライバーのうち、24ヶ月以上サブスクリプションを継続している割合 | 長期リテンションのマイルストーン | ### チャーン \{#churn\} これらの指標は、アプリが失ったサブスクリプションユーザーとトライアルユーザーの数を測定します。 | 指標 | 説明 | 主な違い | |--------|-------------|----------------| | [トライアル更新キャンセル](trials-renewal-cancelled) | 自動更新を無効にしたユーザーのトライアル | ユーザーはトライアル終了まで引き続きアクセスできるが、自動的に有料へは移行しない。サブスクリプション更新キャンセルとは異なり、まだ支払いをしていないトライアルユーザーに適用される | | [期限切れ(解約)トライアル](expired-churned-trials) | 期限が切れたトライアル — ユーザーがプレミアム機能へのアクセスを失った | ユーザーはすでにアクセスを失っている。前の期間に更新をキャンセルしていた場合でも、有効期限日に帰属される。理由別(自発的 vs. 請求上の問題)にグループ化可能 | | [サブスクリプション更新キャンセル](cancelled-subscriptions) | 自動更新を無効にしたユーザーのサブスクリプション | ユーザーは期間終了まで引き続きアクセスできる。実際の解約ではなく解約リスクのシグナル — 期間が終わる前に自動更新を再有効化する可能性がある | | [解約(期限切れ)サブスクリプション](churned-expired-subscriptions) | 期限が切れたサブスクリプション — ユーザーがプレミアム機能へのアクセスを失った | 実際の解約。ユーザーはすでにアクセスを失っている。前の期間に更新をキャンセルしていた場合でも、有効期限日に帰属される。理由別(自発的 vs. 請求上の問題)にグループ化可能 | ### 請求の問題と収益の回復 \{#billing-issues-and-revenue-recovery\} これらの指標は、請求の問題によって失われた収益をアプリがどれだけ効果的に回復しているかを追跡します。 | 指標 | 説明 | 主な違い | |--------|-------------|----------------| | [グレース期間](grace-period) | 請求失敗によりグレース期間に入ったサブスクリプション | グレース期間を超過してアクセスを失ったユーザーも含む | | [グレース期間から有料転換](analytics-conversion#grace-period---paid) | グレース期間終了前に更新したグレース期間ユーザーの割合 | 割合(%)。「グレース期間ユーザーのうち何割が回復したか」を示す | | [グレース期間転換数](grace-period-converted) | 正常に更新されたグレース期間サブスクリプションの絶対数 | グレース期間から有料転換と同じイベントだが、割合ではなく件数で表示 | | [グレース期間転換収益](grace-period-converted-revenue) | グレース期間回復による収益 | グレース期間機能の財務的インパクト | | [請求問題](billing-issue) | 請求問題の状態に入ったサブスクリプション | グレース期間終了後に開始。グレース期間とは異なり、すでにプレミアムアクセスを失ったユーザーのみをカウント | | [請求問題から有料転換](analytics-conversion#billing-issue---paid) | 請求サイクル終了前に更新した請求問題ユーザーの割合 | 割合(%)。「請求問題ユーザーのうち何割が回復したか」を示す | | [請求問題転換数](billing-issue-converted) | 正常に更新された請求問題サブスクリプションの絶対数 | 正常に更新された請求問題サブスクリプションの件数。請求問題から有料転換と同じイベントだが、割合ではなく件数で表示 | | [請求問題転換収益](billing-issue-converted-revenue) | 請求問題回復による収益 | 請求問題回復の財務的インパクト | ## ペイウォール、プレースメント、オンボーディングの指標 \{#paywall-placement-and-onboarding-metrics\} これらの指標は、個々の[ペイウォール](paywall-metrics)、[プレースメント](placement-metrics)、およびオンボーディングに対して計算されます。アプリ全体のパフォーマンスではなく、特定のペイウォールやプレースメントのパフォーマンスを測定するものです。**Associated global metric** 列は、グローバルアナリティクスセクションの対応する指標を示しています。 | 指標 | 説明 | 主な違い | 関連するグローバル指標 | |--------|-------------|----------------|---------------| | [収益(Proceeds)](paywall-metrics#proceeds) | 個別プレースメントの税・手数料控除後の収益 | 税・手数料控除後の[Revenue](revenue)に相当 | [Revenue](revenue) | | [ARPPU](paywall-metrics#arppu) | このペイウォールまたはプレースメントの課金ユーザー1人あたりの平均収益 | グローバルARPPUと同じ計算式だが、単一のペイウォールまたはプレースメントにスコープされる | [ARPPU](arppu) | | [ARPAS](paywall-metrics#arpas) | 収益をアクティブなサブスクライバー数(トライアルおよび有料)で割った値 | トライアルユーザーを含む。ARPPUと異なり、サブスクライバーベース全体の収益ポテンシャルを反映する | — | | [ビュー数(Views)](paywall-metrics#views) | ペイウォールまたはプレースメントが表示された合計回数 | 表示ごとにカウント。同じユーザーが同じペイウォールを2回見た場合は2ビューとしてカウントされる | — | | [ユニークビュー数(Unique views)](paywall-metrics#unique-views) | ペイウォールまたはプレースメントを閲覧したユニークユーザー数 | 何回見ても1ユーザーとして1回カウント。Viewsと異なり、エンゲージメント頻度ではなくリーチを測定する | — | | [購入へのCR(CR to purchases)](paywall-metrics#cr-to-purchases) | 購入数を総ビュー数で割った値 | 分母として総ビュー数(同じユーザーの繰り返し閲覧を含む)を使用 | [Paywall view to paid](analytics-conversion#paywall-view---paid) | | [購入へのユニークCR(Unique CR to purchases)](paywall-metrics#unique-conversion-rate-cr-to-purchases) | 購入数をユニークビュー数で割った値 | 分母としてユニークビュー数を使用。繰り返し閲覧ユーザーが1回としてカウントされるため、非ユニークCRより高い率になる | [Paywall view to paid](analytics-conversion#paywall-view---paid) | | [トライアルへのCR(CR to trials)](paywall-metrics#unique-cr-to-trials) | 開始されたトライアル数を総ビュー数で割った値 | ペイウォールがビューをトライアルにどれだけ効果的にコンバートするかを測定する | [Paywall view to trial](analytics-conversion#paywall-view---trial) | | [トライアルへのユニークCR(Unique CR to trials)](paywall-metrics#unique-cr-to-trials) | 開始されたトライアル数をユニークビュー数で割った値 | トライアルへのCRと同様の計算だが、分母にユニーク閲覧者数を使用 | [Paywall view to trial](analytics-conversion#paywall-view---trial) | | [購入数(Purchases)](paywall-metrics#purchases) | このペイウォールにおけるトランザクションの合計数:新規購入、トライアルコンバージョン、アップグレード、ダウングレード、および復帰サブスクリプション | 更新(リニューアル)を除く | [Revenue](revenue) | | [トライアル数(Trials)](paywall-metrics#trials) | このペイウォールを通じて有効化されたトライアルの合計 | このペイウォールのみにスコープされる | [New trials](new-trials) | | [トライアルキャンセル数(Trials canceled)](paywall-metrics#trials-canceled) | 自動更新を無効にしたトライアルの数 | このペイウォールのトライアルのみにスコープされる | [Trials renewal cancelled](trials-renewal-cancelled) | | [返金率(Refund rate)](paywall-metrics#refund-rate) | 返金数を初回購入数(更新を除く)で割った値 | 件数ではなく率(%)。返金数を購入数で正規化する | [Refund events](refund-events)(率ではなく件数) | | 完了数(Completions) | ユーザーがオンボーディングフローを最初から最後の画面まで完了した回数 | プレースメントおよびオンボーディングのみ。同じユーザーによる繰り返し完了を含む、すべての完了をカウントする | — | | ユニーク完了数(Unique completions) | オンボーディングフローを完了したユニークユーザー数 | プレースメントおよびオンボーディングのみ。各ユーザーは1回としてカウント。Completionsと異なり、フローを完了した個人の数を測定する | — | | ユニーク完了率(Unique completions rate) | ユニーク完了数をユニークビュー数で割った値 | プレースメントおよびオンボーディングのみ。オンボーディングの効果を測定:開始したユーザーのうち実際に完了した割合 | — | --- # File: overview --- --- title: "アナリティクス概要ページ" description: "複数の Adapty アナリティクスチャートを同じページで確認し、アプリのパフォーマンスを俯瞰できます" --- [概要ページ](https://app.adapty.io/overview)では、すべてのアプリの統合指標を一か所で確認できます。ダッシュボードのホームページとして機能し、左側のメニューからもアクセスできます。特定のアプリのデータを見たい場合は、個別の[チャート](charts)を開いてください。 ## チャート \{#charts\} 概要ページでは、Adapty の[アナリティクスチャート](charts)の中からカスタマイズして表示できます。利用可能なすべてのチャートの説明と比較については、[指標比較表](metric-comparison-table)を参照してください。 表示するチャートとその順序をカスタマイズするには、右上の **Edit** をクリックします。そこからチャートの削除、追加、並べ替えが行えます。 以下のチャートが利用できます: - [Revenue](revenue) - [MRR](mrr) - [ARR](arr) - [ARPU](arpu) - [ARPPU](arppu) - [ARPAS](placement-metrics#arpas) - [Installs](installs) - [New trials](new-trials) - [New subscriptions](reactivated-subscriptions) - [Active trials](active-trials) - [Active subscriptions](active-subscriptions) - [New non-subscriptions](non-subscriptions) - [Refund events](refund-events) - [Refund money](refund-money) - [Subscriptions renewal canceled](cancelled-subscriptions) - [インストールからトライアル、インストールから有料、トライアルから有料へのコンバージョン率](analytics-conversion) ## コントロール \{#controls\} 概要ページは、フィルタリング、グルーピング、期間比較など、[アナリティクスコントロール](controls-filters-grouping-compare-proceeds)のほとんどに対応しています。 概要ページ独自の機能として、アプリ別のグルーピングとフィルタリングがあります。このページはすべてのアプリのデータを統合しているため、アプリごとのビューでビジネス指標への各アプリの貢献度を確認できます。 ## インストール数とタイムゾーン \{#install-count-and-timezone\} 概要ページは**独自のタイムゾーンとインストール集計設定**を使用してすべてのアプリのデータを統合します。アプリごとの設定はここでは適用されません。 - **Installs**:インストールの集計方法を選択します。**By device installations** は、再インストールを含めデバイスへのインストールをそれぞれ個別にカウントします。**By unique users** は識別されたユーザーごとに初回インストールのみをカウントします。設定を変更するには、**Edit Metrics** をクリックし、ドロップダウンから[別のオプション](general#4-installs-definition-for-analytics)を選択してください。 - **Timezone**:概要ページのタイムゾーンを変更するには、**Edit Metrics** をクリックし、ドロップダウンからタイムゾーンを選択します。アカウント内の異なるアプリが異なるタイムゾーンを使用している場合に特に便利です。 --- # File: controls-filters-grouping-compare-proceeds --- --- title: "アナリティクスコントロール" description: "Adapty アナリティクスデータをフィルタリング、グループ化、比較する方法。" --- Adapty では、各アナリティクスタブのデータを絞り込むためのコントロールとして、時間範囲、期間比較、フィルタリング、グループ化、チャート表示を利用できます。利用可能なコントロールはタブによって異なります。 **アナリティクスタブ別の利用可能なコントロール:** | コントロール | チャート | コホート | ファネル | リテンション | コンバージョン | LTV | | :--- | :---: | :---: | :---: | :---: | :---: | :---: | | 日付範囲 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 期間比較 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | フィルター | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | グループ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | | チャート表示 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | | テーブル表示 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | CSV エクスポート | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | 手数料と税金 | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ### 日付範囲を設定する \{#set-the-date-range\} 各チャート上部の **Date range** カレンダーで期間を指定します。Adapty アナリティクスは **UTC タイムゾーン** を使用します。[概要ページ](overview) には独自の設定可能なタイムゾーンがあります。 #### プリセット範囲 \{#preset-ranges\} 任意の開始日・終了日を指定するには **Custom** オプションを使用します。プリセットの一覧は以下のとおりです: | プリセット | 開始 | 終了 | | --- | --- | --- | | Last 7 days | 6日前 | 今日 | | Last 28 days | 27日前 | 今日 | | Last month | 前月の同日 | 今日 | | Last 3 months | 3ヶ月前 | 今日 | | Last 6 months | 6ヶ月前 | 今日 | | Last year | 1年前 | 今日 | | Previous month | 前月の初日 | 前月の末日 | | This month | 当月1日 | 今日 | | This quarter | 当四半期の初日 | 今日 | | This year | 当年1月1日 | 今日 | :::tip 週次サブスクリプションプロダクトを追跡するには **Last 28 days** を使用してください。この範囲は4週間分をカバーするため、週の途中で期間が切れてしまうことがありません。 ::: #### タイムスケール \{#time-scale\} チャート上の各データポイントは一定の時間単位を表します。ドロップダウンから日、週、月、四半期、年を選択できます。日・週は短期的な増減を、月・四半期・年は長期的なトレンドを把握するのに適しています。 [コホート](analytics-cohorts)分析や [LTV](ltv) 分析では、同じ設定を **cohort length** と呼びます。詳細は各記事を参照してください。 ### 2つの期間を比較する \{#compare-two-time-periods\} カレンダーの隣にある比較オプションをクリックすると、現在の期間と直前の同じ長さの期間を重ねて表示できます。比較範囲を変更するには、オプションを再度クリックしてカスタム範囲を選択してください。 比較結果は以下の形式で表示されます: - **チャート上** — グループが0または1つの場合、折れ線・エリア・カラムが重ねて表示されます。 - **数値** — 2つの期間の差分が、上昇時は緑、下降時は赤で表示されます。 - **ツールチップ** — データポイントにカーソルを合わせると、そのポイントの数値差分が表示されます。 ### データをフィルタリング・グループ化する \{#filter-and-group-data\} **フィルター** を使うと、1つ以上の属性(例: 特定の国やプロダクト)に一致するデータのみをチャートに表示できます。**グループ化** を使うと、チャートの合計を属性値ごとに別々の系列に分割できます。たとえば、収益を国別にグループ化すると、合算した総計の代わりに国ごとの収益ラインが表示されます。 **利用可能なフィルター・グループ化属性:** | 属性 | フィルター | グループ | 説明 | | --- | :---: | :---: | --- | | アトリビューション | ✅ | ✅ | レポート元、ステータス、チャネル、キャンペーン、広告グループ、広告セット、クリエイティブ(キーワード)。[アトリビューション統合](attribution-integration)が必要です。 | | オーディエンス | ✅ | ✅ | ユーザーが属する[オーディエンス](audience)。 | | 更新ステータス | ❌ | ✅ | サブスクリプションが次の期間に更新されるかどうか。 | | 期間 | ✅ | ✅ | サブスクリプションのライフサイクルステージ: **Trial**、**Activation**(初回支払い)、**Renewal 1**〜**Renewal 5**、**Renewals 6+**(以降の更新)。 | | 国 | ✅ | ✅ | ユーザーのストア国。取得できない場合、Adapty は通貨コードまたはデバイスの IP から推定します。 | | オファータイプ | ✅ | ✅ | トランザクションに適用されたオファー: <ul><li>**Introductory** — サブスクリプション初回期間の初回オファー。有料の初回オファーと無料トライアルを区別するには **Offer Discount Type** を使用してください。</li><li>**Promotional** — App Store プロモーションオファーおよびそれに相当するもの。</li><li>**Offer Code** — ユーザーがストアで入力するプロモコード。</li><li>**No offer** — オファーなし。</li></ul> | | オファー ID | ✅ | ✅ | 特定のオファー ID。 | | オファー割引タイプ | ✅ | ✅ | 初回オファーまたはプロモーションオファーの価格モデル: **Free Trial**、**Pay As You Go**、または **Pay Up Front**。たとえば無料トライアルの初回オファーと有料の初回オファーを区別するには **Offer Type** と組み合わせて使用します。 | | ペイウォール | ✅ | ✅ | 購入に使用された[ペイウォール](paywalls)。 | | A/B テスト | ✅ | ❌ | 購入時に有効だった [A/B テスト](ab-tests)。 | | プレースメント | ✅ | ✅ | 購入が発生した[プレースメント](placements)。 | | ストア | ✅ | ✅ | トランザクションを処理したストア: App Store、Google Play、Stripe など。 | | プロダクト | ✅ | ✅ | [プロダクト](product) — サブスクリプションと買い切り購入。 | | 期間 | ✅ | ✅ | プロダクトの期間。 | | セグメント | ✅ | ✅ | ユーザー[セグメント](segments)。セグメントでグループ化すると、**All users** に対するセグメントのパフォーマンスを比較できます。<ul><li>ファネルはセグメントによるグループ化をサポートしていません。</li><li>セグメントが使用しているカスタム属性を後から変更した場合、Adapty はアナリティクスからそのユーザーをセグメントから除外することがあります。データには引き続き以前の値が表示されます。</li></ul> | | 払い戻し理由 | ✅ | ✅ | トランザクションが払い戻された理由(例: **Refund** または **Upgraded**)。払い戻しおよび請求問題解決チャートで利用可能。 | | 失効理由 | ❌ | ✅ | サブスクリプションまたはトライアルが失効した理由: **Cancelled by customer**、**Billing issue**、**Customer hasn't agreed to price increase**、**Unknown**、または **Refund**。失効(チャーン)したサブスクリプションおよびトライアルで利用可能。 | | コホート(LTV のみ) | ❌ | ✅ | LTV チャートでコホート期間(**Day**、**Week**、**Month**、**Year**)でグループ化します。このチャートではアトリビューションによるグループ化に代わります。 | 上記のすべてのフィルター・グループ化属性がすべてのアナリティクスビューで使用できるわけではありません。チャートタブの ARPU とインストール数は、アトリビューション、国、セグメント、ストア、および(フィルターのみ)A/B テストに限定されています。LTV、コホート、ファネル、リテンション、コンバージョンの各タブはそれぞれ異なるサブセットをサポートしています。詳細については、各チャートまたはタブの記事を参照してください。 ### 国の判定方法 \{#how-country-is-determined\} 各トランザクションには作成時に国が付与されます。国のソースは以下の優先順位で適用されます: 1. トランザクション時のユーザーの**デバイス IP の国**。 2. ユーザーの**ストア国** — App Store または Google Play のアカウント国。 3. 最後に確認されたユーザーの **IP の国**。 ウェブ決済(Stripe、Paddle)、手動で付与されたアクセス、またはストアが提供しなかったトランザクションではストア国を取得できません。その場合、Adapty は IP ベースの国にフォールバックします。 国はトランザクションごとに記録されるため、インストール後に App Store の国を変更したユーザーは、変更前後のトランザクションで異なる国の値を持ちます。過去のトランザクションは元の国を保持します。 **GB と United Kingdom について。** 国データは ISO 3166-1 alpha-2 コードで保存されます(「United Kingdom」ではなく「GB」)。ダッシュボードの表示レイヤーはコードをルックアップテーブルで正式名称にマッピングしており、レガシーの `'UK' → 'United Kingdom'` エイリアスが含まれています。そのため、セグメント作成時に両方が選択肢として表示されることがあります。 ### チャートの表示形式を変更する \{#change-the-chart-visualization\} 表示形式ドロップダウンからチャートの表示方法を選択します: - **Stacked column** — 各カラムに合計値をグループごとの色付きセグメントで表示します。 - **Stacked area** — 積み上げカラムと同様ですが、データポイントを結ぶ塗りつぶしエリアで表示します。 - **Line** — グループごとに1本の折れ線を表示し、塗りつぶしなし。 - **100% stacked column** — 各カラムがチャートの最大高さに達し、実際の値の代わりにグループごとの相対的な割合(パーセンテージ)を表示します。時系列での比率確認に便利です。 - **100% stacked area** — 100% 積み上げカラムと同様ですが、カラムの代わりに塗りつぶしエリアで表示します。 ### テーブルでデータを確認する \{#view-data-as-a-table\} 各チャートの下には同じデータが日付を列としたテーブルで表示されます。Total 行と列にはチャート上では確認できない集計値が表示されます。 ### データを CSV にエクスポートする \{#export-data-to-csv\} **Export** ボタンをクリックすると、チャートの基礎データを CSV ファイルとしてダウンロードできます。 :::tip プログラムによるアクセスや定期的なアクセスには、代わりに [Export API](export-analytics-api) を使用してください。CSV ダウンロードと同じデータを返します。 ::: ### 収益の表示形式(総収益 / 純収益) \{#display-gross-or-net-revenue\} 収益関連のチャート([Revenue](revenue)、[MRR](mrr)、[ARR](arr)、[ARPU](arpu)、[ARPPU](arppu))には、3つの表示モードを切り替えるドロップダウンがあります: - **Gross revenue** — 控除前の総収益。 - **Proceeds after store commission** — ストアの手数料を差し引いた収益(税金は含む)。 - **Proceeds after store commission and taxes** — 手数料と税金の両方を差し引いた収益。 手数料と税金の計算方法の詳細については、「*Adapty アナリティクスの仕組み*」の[手数料と税金](how-adapty-analytics-works#commissions-and-taxes)を参照してください。 --- # File: revenue --- --- title: "収益" description: "Adaptyのサブスクリプションインサイトを使用して、アプリの収益を追跡・分析します。" --- 収益チャートは、サブスクリプションと買い切り購入の両方から得た総収益から、後日返金された金額を差し引いた値を表示します。アプリの財務パフォーマンスを監視するための主要な指標です。 月次の解像度に切り替えると、過去12か月の全体的なトレンドを把握できます。プロダクト、ユーザーセグメント、またはアトリビューションソース別にチャートをグループ化して収益の発生源を確認し、新規対更新の比率を見てビジネスのどちらの側が成長を牽引しているかを把握しましょう。 ## 計算方法 \{#calculation\} :::warning 以下の計算機は[ストア手数料と税金](how-adapty-analytics-works#commissions-and-taxes)を**考慮していません**。結果をあなたの**グロス収益**の計算と比較してください。 ::: 収益は、期間内のすべての有料トランザクション(新規サブスクリプション、更新、トライアルからの転換、買い切り購入)の合計から、期間内に処理された返金を差し引いた値です:**収益 = 総トランザクション − 返金**。 各トランザクションの全額は、サブスクリプションの期間にわたって分散されるのではなく、購入日に計上されます。 チャートはデフォルトでグロス収益を表示します。[チャートコントロール](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)を使用して、グロス、手数料差引後、または手数料・税金差引後の表示に切り替えられます。 <CompoundCalculator client:load heading="Revenue" formuLatex="\sum P_i \times Q_i - D" variables={[ { nameInTheFormula: "P", variableName: "price", variableDescription: "Price per unit", variableValue: 10 }, { nameInTheFormula: "Q", variableName: "qty", variableDescription: "Quantity", variableValue: 1, isInteger: true }, { nameInTheFormula: "D", variableName: "refunds", variableDescription: "Amount refunded", variableValue: 35, global: true } ]} rowFormula="price * qty" resultFormula="_sum - refunds" defaultRows={[ { price: 10, qty: 5 }, { price: 50, qty: 10 }, { price: 100, qty: 1 } ]} /> ## 返金の処理 \{#refund-handling\} 収益は、各返金を元の購入日ではなく、返金が処理された日付に差し引きます。特定のグループや日にバケット内の返金が新規収益を上回った場合、チャートに負の値が表示されることがあります。 指標全体での比較については、[指標における返金の処理方法](refund-events#how-metrics-handle-refunds)をご覧ください。 ## 通貨 \{#currency\} Adaptyはすべてのマネーチャートを、元のトランザクション通貨に関係なく**米ドル**で表示します。これには、Revenue、MRR、ARR、ARPU、ARPPU、LTV、予測収益、返金額、コホートやA/Bテストレポート内の収益数値が含まれます。別の通貨で表示する設定はありません。 Adaptyは各トランザクションを、[currencylayer.com](https://currencylayer.com/)から8時間ごとに更新されるレートを使用してUSDに換算します。このレートは**トランザクション時点で固定**されます。為替が変動しても、過去のUSD換算値は再計算されません。 現地通貨の値は、以下の場所でトランザクションごとに確認できます。 - Webhookの`price_local`フィールドと`currency`フィールド - S3、GCS、BigQueryエクスポートの`_local`列(`revenue_local`、`proceeds_local`など)と`currency` - プロファイルページ(トランザクション別ビュー) 現地通貨で財務レポートを作成する場合は、エクスポートからトランザクションごとの現地通貨値を取得し、ご自身で集計してください。 ## 更新時の価格設定 \{#renewal-pricing\} Adaptyは、ユーザーが最初に購読したときの価格に関わらず、プロダクトの現在の価格で更新収益を計算します。App Store ConnectまたはGoogle Playで価格を変更した後、既存のサブスクリプションユーザーに対するダッシュボードのRevenue、MRR、ARRの数値は、実際に収集された収益と乖離する場合があります。ストアがそれらのユーザーを旧価格のまま維持していても、Adaptyは新しい価格を適用します。 確認するには、S3、GCS、またはBigQueryエクスポートのトランザクションごとの`price`フィールドと、同じトランザクションのダッシュボードの値を比較してください。エクスポートフィールドはストアが報告した値(顧客が実際に支払った価格)を反映し、ダッシュボードは現在のプロダクト価格を反映します。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間(デュレーション)。 - ✅ グループ化:期間、更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間(デュレーション)、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 類似指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#revenue)をご覧ください。 - [MRR](mrr) - [ARR](arr) - [ARPU](arpu) - [ARPPU](arppu) --- # File: mrr --- --- title: "MRR" description: "Adapty で月次経常収益(MRR)を理解し最適化する。" --- 月次経常収益(MRR)チャートは、アクティブな有料サブスクリプションからの収益を月次換算した値で表示します。サブスクリプションの期間に関わらず、サブスクリプションビジネスが生み出す安定した収益を示します。 各サブスクライバーのコホートが経常収益にどのように貢献しているかを時系列で確認するには、チャートを初回購入月でグループ化し、月次解像度に切り替えてください。積み上げエリア表示で、各コホートの月ごとの貢献を確認できます。 ## 計算方法 \{#calculation\} :::warning 以下の計算機は、[ストア手数料と税金](how-adapty-analytics-works#commissions-and-taxes)を**考慮していません**。結果は**グロス収益**の計算と比較してください。 ::: MRR は各サブスクリプションの収益を月次換算に正規化します。たとえば、年間 $240 のサブスクリプションは毎月 $20 として計上され、$240 が一括計上されるわけではありません。これにより、サブスクリプションの請求期間の分布に関わらず MRR が安定します。 MRR は、すべてのサブスクリプション種別に対して(価格 × アクティブなサブスクライバー数 ÷ 請求期間(月数))の合計です。週次サブスクリプションの請求期間は ≈0.23 ヶ月として計算されます。 <SimpleCalculator client:load heading="MRR" formuLatex="\sum_{subscriptions}^{}\frac{P_s\times N_s}{D_m}" variables={[ { nameInTheFormula: "P_s", variableName: "subscriptionPrice", variableDescription: "Price", variableValue: 10 }, { nameInTheFormula: "N_s", variableName: "activeSubs", variableDescription: "Subscribers", variableValue: 1, isInteger: true }, { nameInTheFormula: "D_m", variableName: "duration", variableDescription: "Subscription period", variableValue: 1, options: [ { label: "Weekly", value: 0.23 }, { label: "Monthly", value: 1 }, { label: "2 months", value: 2 }, { label: "3 months", value: 3 }, { label: "6 months", value: 6 }, { label: "Annual", value: 12 } ] } ]} formulaCalculation="(subscriptionPrice * activeSubs) / duration" isSum={true} defaultRows={[ { subscriptionPrice: 240, activeSubs: 2, duration: 12}, { subscriptionPrice: 30, activeSubs: 10, duration: 1}, { subscriptionPrice: 10, activeSubs: 20, duration: 0.23}, ]} /> MRR には、経常収益を生み出さないプロダクトは含まれません。 - 買い切り購入 - 消耗型アイテム - 非更新型サブスクリプション ユーザーベースが買い切り型プロダクトを通じて安定した収益を生み出している場合でも、購入自体が継続的なものではないため、その収益は MRR に計上されません。 ## 返金処理 \{#refund-handling\} サブスクリプションが返金されると、MRR はそれまでカウントされていたすべての日付からその貢献分を差し引きます。返金が発生すると、過去の MRR 値が下がる場合があります。 指標間の全体的な比較については、[指標の返金処理方法](refund-events#how-metrics-handle-refunds)を参照してください。 ## 通貨 \{#currency\} Adaptyはすべてのマネーチャートを、元のトランザクション通貨に関係なく**米ドル**で表示します。これには、Revenue、MRR、ARR、ARPU、ARPPU、LTV、予測収益、返金額、コホートやA/Bテストレポート内の収益数値が含まれます。別の通貨で表示する設定はありません。 Adaptyは各トランザクションを、[currencylayer.com](https://currencylayer.com/)から8時間ごとに更新されるレートを使用してUSDに換算します。このレートは**トランザクション時点で固定**されます。為替が変動しても、過去のUSD換算値は再計算されません。 現地通貨の値は、以下の場所でトランザクションごとに確認できます。 - Webhookの`price_local`フィールドと`currency`フィールド - S3、GCS、BigQueryエクスポートの`_local`列(`revenue_local`、`proceeds_local`など)と`currency` - プロファイルページ(トランザクション別ビュー) 現地通貨で財務レポートを作成する場合は、エクスポートからトランザクションごとの現地通貨値を取得し、ご自身で集計してください。 ## 更新時の価格設定 \{#renewal-pricing\} Adaptyは、ユーザーが最初に購読したときの価格に関わらず、プロダクトの現在の価格で更新収益を計算します。App Store ConnectまたはGoogle Playで価格を変更した後、既存のサブスクリプションユーザーに対するダッシュボードのRevenue、MRR、ARRの数値は、実際に収集された収益と乖離する場合があります。ストアがそれらのユーザーを旧価格のまま維持していても、Adaptyは新しい価格を適用します。 確認するには、S3、GCS、またはBigQueryエクスポートのトランザクションごとの`price`フィールドと、同じトランザクションのダッシュボードの値を比較してください。エクスポートフィールドはストアが報告した値(顧客が実際に支払った価格)を反映し、ダッシュボードは現在のプロダクト価格を反映します。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、国、オファータイプ、オファー ID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間長。 - ✅ グループ化対象:期間、更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間長、オファータイプ、オファー割引タイプ、オファー ID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#revenue)を参照してください。 - [Revenue(収益)](revenue) - [ARR](arr) - [ARPU](arpu) - [ARPPU](arppu) --- # File: arr --- --- title: "ARR" description: "年間定期収益(ARR)を追跡し、サブスクリプション戦略を最適化しましょう。" --- 年間定期収益チャートは、有効なすべての自動更新サブスクリプションの収益を1年間に換算して表示します。有料かつ未失効のサブスクリプションはすべてアクティブとみなされます。ARRは、サブスクリプションビジネスの成長を追跡し、将来の収益を予測するための重要な指標です。 ## 計算方法 \{#calculation\} :::warning 以下の計算機は、[ストア手数料と税金](how-adapty-analytics-works#commissions-and-taxes)を**考慮していません**。結果は**売上総額**の計算と比較してください。 ::: ARRは、定期的なサブスクリプション収益を年換算したものです。年間サブスクリプションがメインのプロダクトである場合に最も役立ちます。月次または週次のサブスクリプションが中心のビジネスには、[MRR](mrr)の方が参考になります。 ARRは、すべてのサブスクリプションタイプにわたる「価格 × アクティブな加入者数 ÷ 請求期間(年単位)」の合計です。月次は1/12、週次は1/52を使用します。 <SimpleCalculator client:load heading="ARR" formuLatex="\sum \frac{P_s \times U_s}{D_y}" variables={[ { nameInTheFormula: "P_s", variableName: "price", variableDescription: "Subscription price", variableValue: 240 }, { nameInTheFormula: "U_s", variableName: "subs", variableDescription: "Active paid subs", variableValue: 2, isInteger: true }, { nameInTheFormula: "D_y", variableName: "periods", variableDescription: "Subscription period", variableValue: 1, options: [ { label: "Weekly", value: "1/52" }, { label: "Monthly", value: "1/12" }, { label: "2 months", value: "2/12" }, { label: "3 months", value: "3/12" }, { label: "6 months", value: "6/12" }, { label: "Annual", value: 1 } ] } ]} formulaCalculation="(price * subs ) / periods" isSum={true} defaultRows={[ { price: 240, subs: 2, periods: "1" }, { price: 30, subs: 10, periods: "1/12" }, { price: 10, subs: 20, periods: "1/52" } ]} /> ## 返金の処理 \{#refund-handling\} サブスクリプションが返金された場合、それ以前にカウントされていたすべての日付について、ARRからその寄与分が差し引かれます。返金が発生すると、過去のARR値が減少することがあります。 各指標での返金の扱いを比較するには、[指標における返金の処理方法](refund-events#how-metrics-handle-refunds)を参照してください。 ## 通貨 \{#currency\} Adaptyはすべてのマネーチャートを、元のトランザクション通貨に関係なく**米ドル**で表示します。これには、Revenue、MRR、ARR、ARPU、ARPPU、LTV、予測収益、返金額、コホートやA/Bテストレポート内の収益数値が含まれます。別の通貨で表示する設定はありません。 Adaptyは各トランザクションを、[currencylayer.com](https://currencylayer.com/)から8時間ごとに更新されるレートを使用してUSDに換算します。このレートは**トランザクション時点で固定**されます。為替が変動しても、過去のUSD換算値は再計算されません。 現地通貨の値は、以下の場所でトランザクションごとに確認できます。 - Webhookの`price_local`フィールドと`currency`フィールド - S3、GCS、BigQueryエクスポートの`_local`列(`revenue_local`、`proceeds_local`など)と`currency` - プロファイルページ(トランザクション別ビュー) 現地通貨で財務レポートを作成する場合は、エクスポートからトランザクションごとの現地通貨値を取得し、ご自身で集計してください。 ## 更新時の価格 \{#renewal-pricing\} Adaptyは、ユーザーが最初に購読したときの価格に関わらず、プロダクトの現在の価格で更新収益を計算します。App Store ConnectまたはGoogle Playで価格を変更した後、既存のサブスクリプションユーザーに対するダッシュボードのRevenue、MRR、ARRの数値は、実際に収集された収益と乖離する場合があります。ストアがそれらのユーザーを旧価格のまま維持していても、Adaptyは新しい価格を適用します。 確認するには、S3、GCS、またはBigQueryエクスポートのトランザクションごとの`price`フィールドと、同じトランザクションのダッシュボードの値を比較してください。エクスポートフィールドはストアが報告した値(顧客が実際に支払った価格)を反映し、ダッシュボードは現在のプロダクト価格を反映します。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間長。 - ✅ グループ化対象:期間、更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間長、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#revenue)を参照してください。 - [収益](revenue) - [MRR](mrr) - [ARPU](arpu) - [ARPPU](arppu) --- # File: arpu --- --- title: "ARPU" description: "ユーザー一人当たりの平均収益(ARPU)を分析して、収益の最適化に役立てましょう。" --- ARPU(ユーザー一人当たりの平均収益)チャートは、特定の期間におけるユーザー一人当たりの平均収益を表示します。この指標は、コホートの総収益をそのコホートのユーザー数で割ることで算出されます。ARPUを使って、アトリビューションソース、国、プロダクトなどのユーザーセグメント間での収益パフォーマンスを比較できます。 ## 計算方法 \{#calculation\} :::warning 以下の計算機は[ストアの手数料と税金](how-adapty-analytics-works#commissions-and-taxes)を**考慮していません**。結果は**総収益**の計算と比較してください。 ::: ARPUは、アプリがユーザー一人当たりに生み出す平均収益を示す、マネタイズ効率の一般的な基準指標です。 ARPUは、その期間の収益(返金を差し引いた額)を同期間のアプリ総ユーザー数で割った値です。 <CompoundCalculator client:load heading="ARPU" formuLatex="\frac{\sum P_i \times Q_i - D}{U_p}" variables={[ { nameInTheFormula: "P", variableName: "price", variableDescription: "プロダクト価格", variableValue: 10 }, { nameInTheFormula: "Q", variableName: "qty", variableDescription: "購入されたプロダクト数", variableValue: 1, isInteger: true }, { nameInTheFormula: "D", variableName: "refunds", variableDescription: "返金額", variableValue: 35, global: true }, { nameInTheFormula: "Up", variableName: "users", variableDescription: "総ユーザー数", variableValue: 160, global: true, isInteger: true } ]} rowFormula="price * qty" resultFormula="(_sum - refunds) / users" defaultRows={[ { price: 10, qty: 5 }, { price: 50, qty: 10 }, { price: 100, qty: 1 } ]} /> ## 返金の処理 \{#refund-handling\} 返金は、処理された日付に収益の分子から差し引かれます。 各指標での返金の扱いの詳細な比較については、[各指標における返金の処理方法](refund-events#how-metrics-handle-refunds)を参照してください。 ## 通貨 \{#currency\} Adaptyはすべてのマネーチャートを、元のトランザクション通貨に関係なく**米ドル**で表示します。これには、Revenue、MRR、ARR、ARPU、ARPPU、LTV、予測収益、返金額、コホートやA/Bテストレポート内の収益数値が含まれます。別の通貨で表示する設定はありません。 Adaptyは各トランザクションを、[currencylayer.com](https://currencylayer.com/)から8時間ごとに更新されるレートを使用してUSDに換算します。このレートは**トランザクション時点で固定**されます。為替が変動しても、過去のUSD換算値は再計算されません。 現地通貨の値は、以下の場所でトランザクションごとに確認できます。 - Webhookの`price_local`フィールドと`currency`フィールド - S3、GCS、BigQueryエクスポートの`_local`列(`revenue_local`、`proceeds_local`など)と`currency` - プロファイルページ(トランザクション別ビュー) 現地通貨で財務レポートを作成する場合は、エクスポートからトランザクションごとの現地通貨値を取得し、ご自身で集計してください。 ## 利用可能なフィルターとグループ \{#available-filters-and-grouping\} :::link メイン記事:[分析のコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、国、A/B テスト、セグメント、ストア - ✅ グループ対象:国、ストア、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標の比較については、[指標比較表](metric-comparison-table#revenue)を参照してください。 - [収益(Revenue)](revenue) - [MRR](mrr) - [ARPPU](arppu) - [ARR](arr) --- # File: arppu --- --- title: "ARPPU" description: "ARPPU(有料ユーザー一人当たりの平均収益)がアプリのマネタイズに与える影響を理解しましょう。" --- ARPPU(有料ユーザー一人当たりの平均収益)チャートは、有料ユーザー一人当たりの平均収益を表示します。有料ユーザーが実際に生み出した収益を顧客数で割り、返金額を差し引いた値です。アトリビューション別にARPPUをグループ化すると、より高い価値の有料ユーザーをもたらしている獲得チャネルを確認できます。 ## 計算方法 \{#calculation\} :::warning 以下の計算ツールは[ストア手数料と税金](how-adapty-analytics-works#commissions-and-taxes)を**考慮していません**。結果は**グロス収益**の計算と比較してください。 ::: ARPPUは有料ユーザー一人当たりの平均収益を示します。分母に非有料ユーザーが含まれないため、通常は[ARPU](arpu)よりも大幅に高くなります。 ARPPUは、該当期間の収益(返金額を差し引いた値)をその期間の有料ユーザー数で割った値です。 <CompoundCalculator client:load heading="ARPPU" formuLatex="\frac{\sum P_i \times Q_i - D}{U_p}" variables={[ { nameInTheFormula: "P", variableName: "price", variableDescription: "Product price", variableValue: 10 }, { nameInTheFormula: "Q", variableName: "qty", variableDescription: "Products purchased", variableValue: 1, isInteger: true }, { nameInTheFormula: "D", variableName: "refunds", variableDescription: "Amount refunded", variableValue: 35, global: true }, { nameInTheFormula: "Up", variableName: "users", variableDescription: "Paying users", variableValue: 16, global: true, isInteger: true } ]} rowFormula="price * qty" resultFormula="(_sum - refunds) / users" defaultRows={[ { price: 10, qty: 5 }, { price: 50, qty: 10 }, { price: 100, qty: 1 } ]} /> ## 返金の処理方法 \{#refund-handling\} 返金は処理された日付に収益の分子から差し引かれます。購入後に返金を受けたユーザーも有料ユーザーの分母にはカウントされたままになるため、返金が多いほどARPPUは予想以上に急激に低下します。 指標全体にわたる比較については、[指標における返金の扱い方](refund-events#how-metrics-handle-refunds)をご覧ください。 ## 通貨 \{#currency\} Adaptyはすべてのマネーチャートを、元のトランザクション通貨に関係なく**米ドル**で表示します。これには、Revenue、MRR、ARR、ARPU、ARPPU、LTV、予測収益、返金額、コホートやA/Bテストレポート内の収益数値が含まれます。別の通貨で表示する設定はありません。 Adaptyは各トランザクションを、[currencylayer.com](https://currencylayer.com/)から8時間ごとに更新されるレートを使用してUSDに換算します。このレートは**トランザクション時点で固定**されます。為替が変動しても、過去のUSD換算値は再計算されません。 現地通貨の値は、以下の場所でトランザクションごとに確認できます。 - Webhookの`price_local`フィールドと`currency`フィールド - S3、GCS、BigQueryエクスポートの`_local`列(`revenue_local`、`proceeds_local`など)と`currency` - プロファイルページ(トランザクション別ビュー) 現地通貨で財務レポートを作成する場合は、エクスポートからトランザクションごとの現地通貨値を取得し、ご自身で集計してください。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[Analytics controls](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間。 - ✅ グループ化:期間、更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、セグメント、アトリビューション。 ## 類似指標 \{#similar-metrics\} これらの指標の並べて比較については、[指標比較表](metric-comparison-table#revenue)をご覧ください。 - [Revenue](revenue) - [MRR](mrr) - [ARPU](arpu) - [ARR](arr) --- # File: installs --- --- title: "インストール" description: "Adaptyを使ってアプリのインストール数を追跡し、サブスクリプションへの影響を把握しましょう。" --- インストールチャートは、選択した期間にアプリをインストールしたユーザー数を表示します。何がインストールとしてカウントされるか、またどのようにグループ化されるかは、インストールのカウント設定によって異なります。 この記事では、適切なカウントモードの選択方法と、さまざまなアナリティクスソース間で[生じる可能性のある差異のトラブルシューティング](#troubleshooting)について説明します。 ## インストールとしてカウントされるもの \{#what-counts-as-an-install\} Adapty SDKは、ユーザーがアプリを初めて起動したときに「インストール」として登録し、Adaptyに送信します。 これには2つの影響があります。 - Adaptyへのインストール記録は、ユーザーが初めてアプリを開いたタイミングで行われるため、ダウンロードから数時間〜数日後になることがあります。 - ユーザーがダウンロードしてもアプリを一度も開かない場合、Adaptyにはカウントされません。 **App Settings**のレポートタイムゾーンによって、各インストールがどの日付に反映されるかが決まります。たとえば、UTC 6月1日の23:30のインストールは、タイムゾーンが+02:00の場合は6月2日として記録されますが、App Store ConnectやGoogle Playでは6月1日として表示される場合があります。 ### カウントモード \{#counting-modes\} **Installs definition for analytics** 設定により、新規インストールとしてカウントされる条件が決まります。変更するには、[App Settings → General → Installs definition for analytics](general#4-installs-definition-for-analytics)を開いてください。 | モード | カウント対象 | 例 | サードパーティの指標 | 差異が生じる可能性 | | --- | --- | --- | --- | --- | | **New device_ids**(推奨) | 再インストールを含む**すべてのアプリインストール**。認証、プロファイル作成、バージョンアップグレードはカウントに含まれません。 | 1ユーザーが5台のデバイスを使用 = 5インストール。<br /> <br /> 同じデバイスで再インストール = 2インストール。 | App Store: <br /> **Total Active Devices** <br /> <br /> Google Play: **Devices** | 再インストールが多い場合、**アプリダウンロード数より多くなる**可能性があります。<br /> <br /> アプリを開かずにダウンロードするユーザーが多い場合、**アプリダウンロード数より少なくなる**可能性があります。 | | **New customer_user_ids** | [識別済みユーザー](identifying-users)ごとの**初回インストールのみ**。追加デバイスや匿名ユーザーはカウントされません。 | 1ユーザーが5台のデバイスを使用 = 1インストール。<br /> <br /> 再インストール後にログインし直しても新規インストールとしてカウントされません。<br /> <br /> アカウントなしでアプリを使用した場合もカウントされません。 | アプリの認証システムのサインアップ統計 | ユーザーをまったく識別しない場合、**データが空のまま**になります。 | | **New profiles in Adapty**(レガシー) | すべてのインストールと再インストール、さらに**ログアウト時に作成された匿名プロファイル**もカウントします。 | 1ユーザー・1デバイスで3回ログアウト = 4インストール。 | なし | **すべての外部指標より高くなります**。ログアウト時に作成される匿名プロファイルもインストールとしてカウントされます。 | 特別な理由がない限り、**New device_ids** を使用してください。 ## トラブルシューティング \{#troubleshooting\} ### AdaptyのカウントがApp Store ConnectやGoogle Playより多い \{#adaptys-count-is-higher-than-app-store-connect-or-google-play\} 主な原因は2つあります。 - **再インストール。** [カウントモード](#counting-modes)が **New device_ids** に設定されている場合、Adaptyは初回起動と再インストールの両方をカウントします。App Store Connectの「Total Downloads」は初回ダウンロードのみをカウントします。 - **初回起動日 ≠ ダウンロード日。** ストアはダウンロード日をもとに集計します。アプリを遅れて開いたユーザーは別の日付に記録されます。 より正確に比較するには、**App Store Connect → Total Active Devices** または **Google Play → Devices** を確認してください。これらの指標はデバイス単位で集計されており、Adaptyの **New device_ids** モードに近い数値になります。 ### Adaptyのカウントがゼロになる \{#adaptys-count-is-zero\} カウントモードが **New customer_user_ids** に設定されているにもかかわらず、<InlineTooltip tooltip="ユーザーを認証する">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)、[Kotlin Multiplatform](kmp-quickstart-identify)、[Capacitor](capacitor-quickstart-identify)</InlineTooltip>を実装していない場合、Adaptyはインストールを記録しません。このモードでは、匿名インストールは除外されます。**New device_ids** に切り替えるか、ユーザー識別を実装してください。 ### AdaptyのカウントがAppsFlyerやAdjustと異なる \{#adaptys-count-differs-from-appsflyer-or-adjust\} MMP(モバイル計測パートナー)は、独自のSDK初期化またはファーストタッチイベントを基準にインストールを計測します。これらのタイミングはAdaptyのSDK初回起動とは異なるため、ある程度の差異が生じるのは正常です。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター:アトリビューション、国、A/B テスト、セグメント、ストア - ✅ グループ化:国、ストア、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標の比較一覧については、[指標比較表](metric-comparison-table#subscribers-and-conversion)をご覧ください。 - [新規サブスクリプション](reactivated-subscriptions) - [アクティブサブスクリプション](active-subscriptions) - [新規トライアル](new-trials) --- # File: active-subscriptions --- --- title: "アクティブなサブスクリプション" description: "Adaptyの強力なアナリティクスでアクティブなサブスクリプションを監視・管理しましょう。" --- アクティブなサブスクリプションチャートは、選択した各期間の終了時点でまだ有効期限が切れていない一意の有料サブスクリプション数を表示します。開始済みで現在アクティブな通常の(有効期限内の)アプリ内サブスクリプションを含み、無料トライアルおよび更新がキャンセルされたサブスクリプションは除外されます。サブスクライバーベースの規模と成長を把握するための指標です。 ## 計算方法 \{#calculation\} アクティブなサブスクリプションの指標は、各期間終了時点における有料かつ有効期限内のサブスクリプション数をカウントします。グレース期間のないサブスクリプションの場合、次の更新日が到来しても正常に更新されなければ有効期限切れとなります。 例:先月末のアクティブなサブスクリプション500件+今月の新規50件-今月に有効期限が切れた25件=今月末のアクティブなサブスクリプション525件。 ## 返金の処理 \{#refund-handling\} サブスクリプションが返金された場合、Adaptyはそのサブスクリプションをアクティブ数から削除します。これは現在だけでなく、過去の日付に対しても遡って適用されます。 指標全体での返金の取り扱い比較については、[指標の返金処理方法](refund-events#how-metrics-handle-refunds)をご覧ください。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター:アトリビューション、オーディエンス、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間。 - ✅ グループ化:期間、更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標の横断比較については、[指標比較表](metric-comparison-table#subscribers-and-conversion)をご覧ください。 - [解約(期限切れ)サブスクリプション](churned-expired-subscriptions) - [キャンセルされたサブスクリプション](cancelled-subscriptions) - [買い切り購入](non-subscriptions) --- # File: reactivated-subscriptions --- --- title: "新規サブスクリプション" description: "Adaptyで新規サブスクリプションを追跡し、初回コンバージョンや無料トライアルから有料への転換を監視します。" --- 新規サブスクリプションチャートは、アプリ内で新たに(初めて)有効化されたサブスクリプションの数を表示します。この指標は、特定の期間に開始した新規サブスクリプションの数を示しており、ゼロから始まるサブスクリプションと、無料トライアルから有料サブスクリプションに転換したものの両方が含まれます。サブスクリプションの更新や再開されたサブスクリプションは含まれません。 ## 計算方法 \{#calculation\} 新規サブスクリプション指標は、期間中の初回サブスクリプション有効化数をカウントします。ゼロから始まるサブスクリプションと、無料トライアルから有料サブスクリプションに転換したものの両方が含まれます。 ## 返金の扱い \{#refund-handling\} 新規サブスクリプションは返金を**差し引きません**。後に返金されたサブスクリプションもカウントに含まれます。正味の影響を把握するには、[返金イベント](refund-events)と比較してください。 各指標における返金の扱いの全体比較については、[指標ごとの返金処理方法](refund-events#how-metrics-handle-refunds)をご覧ください。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター項目:アトリビューション、オーディエンス、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間長。 - ✅ グループ化項目:更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間長、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標の比較表については、[指標比較テーブル](metric-comparison-table#subscribers-and-conversion)をご覧ください。 - [アクティブサブスクリプション](active-subscriptions) - [解約済み(期限切れ)サブスクリプション](churned-expired-subscriptions) - [キャンセル済みサブスクリプション](cancelled-subscriptions) - [買い切り購入](non-subscriptions) --- # File: non-subscriptions --- --- title: "非サブスクリプション" description: "Adaptyで非サブスクリプションプロダクトを管理し、ユーザーの購入を効率的に追跡する方法を学びましょう。" --- 非サブスクリプションチャートは、自動更新サブスクリプション以外のアプリ内課金(消耗型アイテム、非消耗型アイテム、非更新型サブスクリプション)の件数を集計します。更新は対象外です。 :::note 「非サブスクリプション」は「買い切り購入」より広い概念です。消耗型アイテムと非更新型サブスクリプションはそれぞれ複数回購入できます。 ::: ## 計算方法 \{#calculation\} 非サブスクリプションのアプリ内課金は、次の3種類に分類されます。 - **消耗型アイテム**: 複数回購入できるアイテム。釣りアプリの魚のエサや追加のゲーム内通貨などが例として挙げられます。 - **非消耗型アイテム**: 1回購入すると永続的に使用できるアイテム。ゲームアプリのレーストラックや広告非表示版などが該当します。 - **非更新型サブスクリプション**: 一定期間後に期限切れとなり、自動更新されないサブスクリプション。コンテンツカタログへの1年間アクセスなどが例として挙げられます。コンテンツは静的なものでよく、期限が切れると更新されません。 :::note このチャートは購入イベントのみを集計し、返金された購入分は差し引きません。非サブスクリプションプロダクトで返金が多い場合、表示される件数は実際に収益を生んだ購入数より多くなります。 ::: ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター:アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト - ✅ グループ化:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標を横並びで比較するには、[指標比較表](metric-comparison-table#revenue)をご覧ください。 - [アクティブなサブスクリプション](active-subscriptions) - [新規サブスクリプション](reactivated-subscriptions) - [解約(期限切れ)サブスクリプション](churned-expired-subscriptions) - [キャンセルされたサブスクリプション](cancelled-subscriptions) --- # File: cancelled-subscriptions --- --- title: "サブスクリプションの自動更新キャンセル" description: "Adaptyの管理ツールを使って、キャンセルされたサブスクリプションを効率的に管理する方法を解説します。" --- 「サブスクリプションの自動更新キャンセル」チャートは、自動更新がオフに切り替えられた(ユーザーによってキャンセルされた)サブスクリプションの数を表示します。サブスクリプションの自動更新がオフになると、次の期間は自動的に更新されません。ただし、ユーザーは現在の期間が終了するまで、アプリのプレミアム機能へのアクセスを引き続き利用できます。 ## 計算方法 \{#calculation\} 「サブスクリプションの自動更新キャンセル」指標は、指定期間内に自動更新がオフに切り替えられたサブスクリプションをカウントします。ユーザーは現在の請求期間が終了するまでプレミアムアクセスを維持しますが、その後サブスクリプションは自動的に更新されません。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事: [アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター: アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、利用期間 - ✅ グループ化: プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、利用期間、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#churn)をご覧ください。 - [アクティブなサブスクリプション](active-subscriptions) - [チャーン(期限切れ)サブスクリプション](churned-expired-subscriptions) - [新規サブスクリプション](reactivated-subscriptions) - [買い切り購入](non-subscriptions) --- # File: churned-expired-subscriptions --- --- title: "解約済み(期限切れ)サブスクリプション" description: "解約済みおよび期限切れサブスクリプションを管理して、ユーザー維持率を改善しましょう。" --- 解約済み(期限切れ)サブスクリプションチャートは、期限切れになったサブスクリプションの件数、つまりユーザーがアプリのプレミアム機能へのアクセスを失った件数を表示します。これは通常、ユーザーがサブスクリプション期間終了時に更新をやめた場合や、支払いの問題が発生した場合に起こります。失効理由でグループ化することで、自発的な解約と課金起因の解約を区別できます。 ## 計算方法 \{#calculation\} 解約済み(期限切れ)サブスクリプション指標は、対象期間中に期限切れとなったサブスクリプション件数をカウントします。これには、更新しなかったユーザーと、支払い問題によってサブスクリプションを失ったユーザーの両方が含まれます。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事: [アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター条件: アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト、期間。 - ✅ グループ化: 失効理由、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較テーブル](metric-comparison-table#churn)をご覧ください。 - [有効なサブスクリプション](active-subscriptions) - [新規サブスクリプション](reactivated-subscriptions) - [キャンセル済みサブスクリプション](cancelled-subscriptions) - [非サブスクリプション](non-subscriptions) --- # File: active-trials --- --- title: "アクティブトライアル" description: "Adapty アナリティクスを使ってアクティブなサブスクリプショントライアルを追跡・管理しましょう。" --- Adapty のアクティブトライアルチャートは、指定期間の終了時点でまだ有効な無料トライアルの数を表示します。「アクティブ」とは、まだ期限切れになっていないサブスクリプションを指します。つまり、ユーザーはアプリの有料機能に引き続きアクセスできる状態です。 ## 計算方法 \{#calculation\} アクティブトライアルの指標は、各期間の終了時点で期限切れになっていない無料トライアルをカウントします。自動更新をキャンセルしてもカウントからは除外されません。除外されるのは期限切れになった場合のみです。 例: 昨日のアクティブトライアルが 100 件、本日新たに 10 件追加、本日 5 件が期限切れ = 本日のアクティブトライアルは 105 件。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事: [アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象: アトリビューション、オーディエンス、国、オファータイプ、オファー ID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト、期間。 - ✅ グループ化: 期間、更新ステータス、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、オファータイプ、オファー割引タイプ、オファー ID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#subscribers-and-conversion)を参照してください。 - [新規トライアル](new-trials) - [トライアル更新キャンセル](trials-renewal-cancelled) - [期限切れトライアル](expired-churned-trials) --- # File: new-trials --- --- title: "新規トライアル" description: "新規サブスクリプショントライアルを管理し、トライアルから有料への転換率を最適化します。" --- 新規トライアルチャートは、選択した期間中に開始されたトライアルの数を表示します。広告キャンペーンやその他の獲得施策からのトライアル数を追跡するために使用してください。 ## 計算方法 \{#calculation\} 新規トライアル指標は、その期間が終了した時点でまだアクティブかどうかに関わらず、期間中に開始されたトライアルをカウントします。 たとえば、5月に50人のユーザーがトライアルを開始した場合、5月のデータポイントは50と表示されます。チャートを確認する時点で一部がすでに期限切れになっていたり有料に転換していたりしても、この数値は変わりません。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト、期間。 - ✅ グループ化の基準:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#subscribers-and-conversion)をご覧ください。 - [アクティブトライアル](active-trials) - [トライアル更新のキャンセル](trials-renewal-cancelled) - [期限切れトライアル](expired-churned-trials) --- # File: trials-renewal-cancelled --- --- title: "トライアル更新キャンセル" description: "Adaptyのインサイトでトライアルの更新、キャンセル、サブスクリプションフローを理解しましょう。" --- トライアル更新キャンセルチャートは、更新がキャンセルされたトライアル(ユーザーによるキャンセル)の件数を表示します。トライアルの更新が無効になると、そのトライアルは有料サブスクリプションに自動的に移行しなくなります。ただし、ユーザーは現在の期間が終了するまでアプリのプレミアム機能を引き続き利用できます。 ## 計算方法 \{#calculation\} トライアル更新キャンセルの指標は、当該期間中にユーザーによって自動更新がオフにされたトライアルの件数をカウントします。ユーザーはトライアル期間が終了するまでアクセスを維持できますが、そのトライアルは有料サブスクリプションに自動的に移行しません。 ## 利用可能なフィルターとグルーピング \{#available-filters-and-grouping\} :::link 関連記事:[アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター項目:アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト、期間 - ✅ グループ項目:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較する場合は、[指標比較表](metric-comparison-table#churn)をご覧ください。 - [新規トライアル](new-trials) - [アクティブトライアル](active-trials) - [期限切れトライアル](expired-churned-trials) --- # File: expired-churned-trials --- --- title: "期限切れ(チャーン)トライアル" description: "Adapty アナリティクスで期限切れ・チャーンしたトライアルを効果的に管理しましょう。" --- 期限切れ(チャーン)トライアルチャートは、期限切れとなりユーザーがアプリのプレミアム機能にアクセスできなくなったトライアルの件数を表示します。多くの場合、これはユーザーがアプリへの課金をやめた場合や、請求の問題が発生した場合に起こります。 ## 計算方法 \{#calculation\} 期限切れトライアルの指標は、対象期間中に終了したトライアル(ユーザーがプレミアム機能へのアクセスを失ったもの)をカウントします。これには、自発的に継続しなかったユーザーと、請求の問題により継続に失敗したユーザーの両方が含まれます。 **Expiration reason** でグループ化すると、自発的なチャーンと請求起因のチャーンを分けて確認できます。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター:アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト、期間 - ✅ グループ化:有効期限の理由、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較テーブル](metric-comparison-table#churn)を参照してください。 - [新規トライアル](new-trials) - [アクティブトライアル](active-trials) - [トライアル更新キャンセル](trials-renewal-cancelled) --- # File: refund-events --- --- title: "返金イベント" description: "Adaptyで返金イベントを管理し、チャーンを抑制して収益を最適化しましょう。" --- 返金イベントチャートは、返金された購入件数とサブスクリプション件数を表示します。Adaptyは各返金イベントを、サブスクリプションの開始日ではなく、返金が発生した日付に紐づけます。 ## 計算方法 \{#calculation\} Adaptyは、選択した期間内に返金されたすべての購入またはサブスクリプションをカウントします。各返金は、サブスクリプションが開始された日ではなく、返金が発生した日付に紐づけられます。トライアルの返金は、トライアルが収益を生まないため、除外されます。 ## 指標ごとの返金処理方法 \{#how-metrics-handle-refunds\} 指標によって、返金の扱い方は異なります。同じ返金イベントでも、あるチャートではすぐに減少し、別のチャートでは遡及的に(過去の期間の値が変わる形で)減少し、さらに別のチャートにはまったく影響しない場合があります。以下のマトリックスに、各指標のルールをまとめています。 | 指標 | 返金は適用されるか? | アトリビューション日付 | マイナスになるか? | 備考 | | --- | --- | --- | --- | --- | | [収益](revenue) | はい | 返金日(元の購入日ではない) | はい — 返金が新規収益を上回る日はマイナスになる | 収益 = 総トランザクション − 返金 | | [MRR](mrr) | はい(遡及適用) | サブスクリプションがアクティブだったすべての期間から削除 | いいえ | 返金後は過去期間の値が減少する場合がある | | [ARR](arr) | はい(遡及適用) | MRR と同じ | いいえ | 返金後は過去期間の値が減少する場合がある | | [ARPU](arpu) | はい | 返金日 | はい(返金が多い期間) | 返金は収益の分子から差し引かれる | | [ARPPU](arppu) | はい(分子のみ) | 返金日 | はい(返金が多い期間) | 返金は収益の分子から差し引かれる。返金済みユーザーは支払いユーザーの分母に残るため、返金が多いと ARPPU は予想より速く低下する | | [アクティブサブスクリプション](active-subscriptions) | はい(遡及適用) | カウントからサブスクリプションが削除される | いいえ | | | [新規サブスクリプション](reactivated-subscriptions) | **いいえ** | — | いいえ | カウントには後から返金されたサブスクリプションも含まれる。正味の影響は [返金イベント](refund-events) と比較すること | | [返金金額](refund-money) / [返金イベント](refund-events) | 返金がデータそのもの | 返金日 | いいえ(常に ≥ 0) | | | [リテンション](analytics-retention) | **いいえ** | — | いいえ | 返金済みユーザーはリテンション曲線上にカウントされたまま残る。そのため同一コホートで比較すると、リテンションが [アクティブサブスクリプション](active-subscriptions) や [収益](revenue) より高く見えることがある | | [コホート収益](analytics-cohorts) | はい(累積) | 返金日 | いいえ(累積減算によってコホート収益がゼロを下回ることはない) | 返金は発生時点でコホート収益から差し引かれる。その他のコホート指標については [コホート > 返金の扱い](analytics-cohorts#refund-handling) を参照 | | [ペイウォール指標](paywall-metrics) / [A/B テスト指標](results-and-metrics)(カウント) | **いいえ** | — | いいえ | これらのページのサブスクライバー数・有料サブスクライバー数・ARPPU のカウントは返金を差し引かない | | GCS / S3 エクスポート | 返金は独自のイベント行として記録 | `event_datetime` = 返金タイムスタンプ | 集計時に純額列がマイナスになる場合がある | 返金行には `is_refund = true`(S3/GCS)またはイベントタイプ `subscription_refunded`(Webhook)が付与される | ### マイナス値 \{#negative-values\} 集計ビュー(収益チャート、エクスポートのカスタム分析)では、特定の期間やグループ内の返金が同じバケット内の新規収益を超えると、指標がマイナス値を示すことがあります。これはバグではなく、設計通りの計算結果です。 例:ある国で火曜日に新規購入がなかったものの、過去の購入に対する$100の返金がその日に処理された場合、その国の火曜日の収益は −$100 と表示されます。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター項目:アトリビューション、オーディエンス、返金理由、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間。 - ✅ グループ化項目:返金理由、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#revenue)をご覧ください。 - [返金金額](refund-money) - [請求問題](billing-issue) - [グレース期間](grace-period) --- # File: refund-money --- --- title: "返金" description: "Adapty で収益を失わずにサブスクリプションの返金を処理する方法を学びましょう。" --- 「返金金額」チャートは、選択した期間中に返金された金額を表示します。Adapty は各返金イベントを処理された日付に紐付けるため、その期間の収益がその分だけ減少します。 ## 計算方法 \{#calculation\} Adapty は収益を生成するトランザクション(新規有料サブスクリプション、更新、買い切り購入)のみをカウントします。収益が発生せず返金もできない無料トライアルは除外されます。各返金金額は処理された日付に紐付けられるため、収益の減少はその同じ期間に反映されます。 :::info 返金金額は、ストアの手数料が差し引かれる前の金額で計算されます。 ::: ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事: [アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象: アトリビューション、オーディエンス、返金理由、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間。 - ✅ グループ化: 返金理由、プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、オファータイプ、オファー割引タイプ、オファーID、セグメント、アトリビューション。 ## 返金リクエストの管理 \{#refund-request-management\} 返金セーバーは、Adapty ユーザーが Apple の App Store からの返金リクエストを自動化によってより効率的に処理するためのツールです。プロセスを効率化することで時間を節約し、収益の損失を減らします。リアルタイム通知と実用的なインサイトにより、Apple のガイドラインに準拠しながら返金リクエストに対応しやすくなります。 詳しくは [返金セーバー](refund-saver) をご覧ください。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#revenue) をご覧ください。 - [返金イベント](refund-events) - [請求の問題](billing-issue) - [グレース期間](grace-period) --- # File: grace-period --- --- title: "グレース期間" description: "サブスクリプションのグレース期間の仕組みを理解し、ユーザーリテンションを向上させましょう。" --- グレース期間チャートは、[請求の問題](billing-issue)によってグレース期間の状態に入ったサブスクリプションの数を表示します。この期間中、ストアがサブスクライバーへの支払い請求を試みる間もサブスクリプションはアクティブな状態を維持します。グレース期間が終了するまでに支払いが正常に受け取られなかった場合、サブスクリプションは請求の問題の状態に移行します。 ## 計算方法 \{#calculation\} グレース期間の指標は、選択した期間中にグレース期間に入ったサブスクリプションの数をカウントします。グレース期間は、サブスクリプションの更新支払いが失敗したときに開始され、週次サブスクリプションの場合は最大6日間、その他の請求期間の場合は最大16日間続きます。この期間内に支払いが完了した場合、サブスクリプションは通常通り継続されます。支払いが完了しなかった場合、サブスクリプションは[請求の問題](billing-issue)の状態に移行します。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、デュレーション - ✅ グループ化:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、デュレーション、セグメント、アトリビューション ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#billing-issues-and-revenue-recovery)をご覧ください。 - [返金金額](refund-money) - [返金イベント](refund-events) - [請求の問題](billing-issue) --- # File: grace-period-converted --- --- title: "グレース期間からの復旧件数" description: "グレース期間に入り、期間終了前に更新されたサブスクリプションの件数を追跡します。" --- **Grace period converted** チャートは、[グレース期間](grace-period)の状態に入り、期間終了前に正常に更新されたサブスクリプションの件数を表示します。 ### 計算方法 \{#calculation\} Grace period converted チャートは、グレース期間中のユーザーにおけるサブスクリプション更新の日次件数を表示します。 グレース期間は、支払い失敗により請求問題の状態に入ったときに始まり、一定の期間(週次サブスクリプションは6日間、その他のサブスクリプションはすべて16日間)が経過するか、支払いが正常に受領された時点で終了します。このチャートは、グレース期間機能の有効性を把握するためのインサイトを提供し、支払い処理やサブスクリプション管理における潜在的な問題の特定にも役立ちます。 ### 利用可能なフィルター \{#available-filters\} :::link 関連記事:[アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、返金理由、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間長。 - ✅ グループ化:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間長、セグメント、アトリビューション。 ### Grace period converted チャートの使い方 \{#grace-period-converted-chart-usage\} このチャートを使って、グレース期間機能が支払い問題のあるサブスクリプションをどれほど効果的に回復しているかを追跡しましょう。時系列での復旧トレンドをモニタリングすることで、支払い解決のパターンを把握し、グレース期間中の支払い更新フローやコミュニケーション施策の変更が与える影響を評価できます。 ### 関連指標 \{#similar-metrics\} - [請求問題](billing-issue) - [請求問題からの復旧件数](billing-issue-converted) - [請求問題からの復旧収益](billing-issue-converted-revenue) - [グレース期間](grace-period) - [グレース期間からの復旧収益](grace-period-converted-revenue) - [返金額](refund-money) - [返金イベント](refund-events) --- # File: grace-period-converted-revenue --- --- title: "グレース期間コンバージョン収益" description: "グレース期間コンバージョンの総収益を追跡します。" --- **Grace period converted revenue** チャートは、[グレース期間コンバージョン](grace-period-converted)から生み出された収益を表示します。これは、[グレース期間](grace-period)状態に入り、期間が終了する前に正常に更新されたサブスクリプションの収益です。 ### 計算方法 \{#calculation\} Grace period converted revenue チャートは、グレース期間中のユーザーのサブスクリプション更新によって生み出された日次収益を表示します。 グレース期間は、支払い失敗によるサブスクリプションの請求問題状態への移行時に開始し、指定された期間(週次サブスクリプションは6日間、その他すべてのサブスクリプションは16日間)が経過するか、支払いが正常に受領されると終了します。このチャートは、グレース期間機能の効果についての洞察を提供し、支払い処理またはサブスクリプション管理における潜在的な問題を特定するのに役立ちます。 ### 利用可能なフィルター \{#available-filters\} :::link メイン記事: [アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象: アトリビューション、オーディエンス、返金理由、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間。 - ✅ グループ化: プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、セグメント、アトリビューション。 ### Grace period converted revenue チャートの使い方 \{#grace-period-converted-revenue-chart-usage\} このチャートを使用して、支払い問題のあるサブスクリプションから回収した収益を追跡することで、グレース期間機能の財務的影響を測定します。これにより、グレース期間戦略の効果を定量化し、グレース期間関連の機能やコミュニケーションを実装した際の投資対効果を評価できます。 ### 関連指標 \{#similar-metrics\} - [請求問題](billing-issue) - [請求問題コンバージョン](billing-issue-converted) - [請求問題コンバージョン収益](billing-issue-converted-revenue) - [グレース期間](grace-period) - [グレース期間コンバージョン](grace-period-converted) - [返金額](refund-money) - [返金イベント](refund-events) --- # File: billing-issue --- --- title: "課金エラー" description: "Adaptyのサポートツールを使用してサブスクリプションの課金エラーを解決します。" --- 課金エラーチャートは、課金エラー状態に入ったサブスクリプションの数を表示します。この状態は通常、AppleやGoogleなどのストアが何らかの理由でサブスクライバーから支払いを受け取れない場合に発生します。クレジットカードの有効期限切れや残高不足などが原因として考えられます。 ## 計算方法 \{#calculation\} 課金エラー指標は、指定期間内に課金エラー状態に入ったサブスクリプションの数をカウントします。サブスクリプションがこの状態に入るのは、ストア(AppleまたはGoogle)が更新支払いを処理できない場合です。主な原因としては、クレジットカードの有効期限切れや残高不足が挙げられます。課金エラー状態の間、サブスクリプションはアクティブではありません。 [グレース期間](grace-period)機能が有効になっている場合、サブスクリプションはグレース期間が支払いなしで終了した後にのみ課金エラー状態に入ります。 ## 利用可能なフィルターとグループ化 \{#available-filters-and-grouping\} :::link メインの記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター: アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、デュレーション。 - ✅ グループ化: プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、デュレーション、セグメント、アトリビューション。 ## 関連指標 \{#similar-metrics\} これらの指標を並べて比較するには、[指標比較表](metric-comparison-table#billing-issues-and-revenue-recovery)をご参照ください。 - [課金エラーからの回復](billing-issue-converted) - [課金エラーからの回復による収益](billing-issue-converted-revenue) - [返金額](refund-money) - [返金イベント](refund-events) - [グレース期間](grace-period) - [グレース期間からの回復](grace-period-converted) - [グレース期間からの回復による収益](grace-period-converted-revenue) --- # File: billing-issue-converted --- --- title: "請求問題の解決" description: "請求サイクルが終了する前に解決された請求問題の件数を追跡します。" --- Billing issue converted チャートは、[Billing Issue(請求問題)](billing-issue)状態に入り、請求サイクルが終了する前に更新されたサブスクリプションの日次件数を表示します。 ### 計算方法 \{#calculation\} Billing issue converted チャートは、現在の請求サイクル内で[Billing Issue](billing-issue)状態に入り、当日に更新されたサブスクリプションの件数を表示します。 サブスクリプションは、クレジットカードの有効期限切れや残高不足など、何らかの理由でストア(Apple、Googleなど)がサブスクライバーへの請求処理に失敗した場合に、Billing Issue状態に入ります。Billing Issue状態中はサブスクリプションがアクティブとは見なされず、ストアの設定でグレース期間機能が有効になっている場合、グレース期間が終了した後にのみBilling Issue状態へ移行します。 ### 利用可能なフィルター \{#available-filters\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、返金理由、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、期間。 - ✅ グループ化:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、期間、セグメント、アトリビューション。 ### Billing issue converted チャートの活用方法 \{#billing-issue-converted-chart-usage\} グレース期間終了後の請求サイクル内で、請求問題がどの程度効果的に解決されているかを追跡するためにこのチャートを活用してください。時系列での解決傾向を監視することで、支払い回収のパターンを把握し、請求問題発生時の支払い再試行ロジックやコミュニケーション戦略の変更による効果を評価できます。 ### 関連指標 \{#similar-metrics\} - [Billing issue(請求問題)](billing-issue) - [Billing issue converted revenue(請求問題解決の収益)](billing-issue-converted-revenue) - [Refund money(返金額)](refund-money) - [Refund events(返金イベント)](refund-events) - [Grace period(グレース期間)](grace-period) - [Grace period converted(グレース期間の解決)](grace-period-converted) - [Grace period converted revenue(グレース期間解決の収益)](grace-period-converted-revenue) --- # File: billing-issue-converted-revenue --- --- title: "請求問題からの回収収益" description: "Adaptyのサポートツールを使用してサブスクリプションの請求問題を解決する方法。" --- **Billing issue converted revenue** チャートは、[請求問題からの回収](billing-issue-converted)による収益、つまり[請求問題(Billing Issue)](billing-issue)状態に入り、請求サイクルの終了前に更新されたサブスクリプションの収益を表示します。 ### 計算方法 \{#calculation\} **Billing issue converted revenue** チャートは、現在の請求サイクルで[請求問題(Billing Issue)](billing-issue)状態に入り、当日に更新されたサブスクリプションの日次収益を表示します。 サブスクリプションが請求問題状態になるのは、有効期限切れのクレジットカードや残高不足などの理由により、ストア(Apple、Googleなど)がユーザーへの支払い処理を完了できない場合です。請求問題状態の間、サブスクリプションはアクティブとはみなされません。ストアの設定でグレース期間機能が有効になっている場合、グレース期間が終了した後にのみ請求問題状態へ移行します。 ### 利用可能なフィルター \{#available-filters\} :::link メイン記事:[アナリティクスの操作](controls-filters-grouping-compare-proceeds) ::: - ✅ フィルター対象:アトリビューション、オーディエンス、返金理由、国、オファータイプ、オファーID、オファー割引タイプ、ペイウォール、A/B テスト、プレースメント、期間、セグメント、ストア、プロダクト、利用期間 - ✅ グループ化:プロダクト、国、ストア、ペイウォール、オーディエンス、プレースメント、利用期間、セグメント、アトリビューション ### 請求問題からの回収収益チャートの活用方法 \{#billing-issue-converted-revenue-chart-usage\} このチャートを使用して、グレース期間終了後にサブスクリプションから回収された収益を追跡し、解決済みの請求問題による財務的影響を測定しましょう。請求問題の回収戦略の効果を数値化し、請求リトライの仕組みやターゲットユーザーへのコミュニケーション施策の投資対効果を評価するのに役立ちます。 ### 関連指標 \{#similar-metrics\} - [請求問題(Billing issue)](billing-issue) - [請求問題からの回収(Billing issue converted)](billing-issue-converted) - [返金金額(Refund money)](refund-money) - [返金イベント(Refund events)](refund-events) - [グレース期間(Grace period)](grace-period) - [グレース期間からの回収(Grace period converted)](grace-period-converted) - [グレース期間からの回収収益(Grace period converted revenue)](grace-period-converted-revenue) --- # File: ltv --- --- title: "Lifetime Value (LTV)" description: "Adapty で Lifetime Value (LTV) を計算・最適化する方法を学びましょう。" --- Realized LTV(ライフタイムバリュー)は、課金ユーザーコホートが実際に生み出した収益から返金を差し引いた金額を、そのコホートの課金ユーザー数で割ったものです。つまり、このチャートを見ると、課金ユーザー1人あたりの平均収益がわかります。 Adapty の LTV チャートは、アプリの収益とユーザー行動に関する次のような重要な問いに答えるよう設計されています。 1. 各コホートはアプリの利用期間全体でどれだけの収益をもたらすか? 2. コホートが元を取るのはいつの時点か? 3. LTV の高い優良ユーザーを獲得するために、マーケティングや獲得コストをどう最適化できるか? 4. 新規ユーザーの獲得コストを回収するまでにどれくらいかかるか? LTV チャートは、SDK とアプリ内イベントを通じて収集したデータをもとに動作します。 この情報を活用すると、サブスクリプションのパフォーマンスや、特定期間に購読者から得られる収益を把握できます。また、サブスクリプションの提供内容・広告費・ユーザー獲得戦略に関してデータに基づいた意思決定が可能です。さらに、フィルター機能を使えば国・アトリビューション・その他の変数でデータをセグメント化できるため、ユーザーベースをより細かく理解できます。 ### 更新回数別 LTV \{#ltv-by-renewals\} **更新回数別 LTV** ビューは、サブスクリプション期間(P)に関するデータを表示し、特にユーザーが初めて支払いを行ったタイミングを捉えます。週次サブスクリプションの場合、これは次の週次サブスクリプション期間に該当します。 ### 日数別 LTV \{#ltv-by-days\} **日数別 LTV** ビューは、日次・週次・月次の間隔でデータを整理・フィルタリングします。特定の日・週・月にアプリをインストールしたすべてのユーザーが生み出した総収益を、同期間の課金ユーザー数で割った値を提供します。このビューは収益の追跡に役立ち、時間の経過によるユーザー行動を総合的に把握できます。 ### コホートの長さと期間 \{#cohort-length-and-time-frame\} テーブルの表示内容は、2つの時間設定で決まります。 - **Time frame** — 対象となる日付の範囲です。テーブル上部のカレンダーで設定します。 - **Cohort length** — 各行の粒度です。日・週・月・四半期・年から選べます。月単位にすると、各行がインストール1か月分に対応します。 この2つは独立して動作します。たとえば、Time frame を6か月、Cohort length を月単位にすると6行のテーブルになります。Time frame を1年、Cohort length を週単位にすると52行になります。 ### 計算方法 \{#calculation\} Realized LTV は、各ユーザーコホートから得られた総収益から返金を差し引いて計算されます。 _日次/週次/月次の LTV = 該当日/週/月にアプリをインストールしたすべての課金ユーザーから得た収益 ÷ 該当日/週/月にアプリをインストールした課金ユーザー数_ LTV の計算には、アップグレード・ダウングレード・再アクティベーション(ユーザーがサブスクリプションプランや価格を変更した場合など)が含まれます。初回サブスクリプションの収益と、更新後のプランに基づくその後の更新収益が考慮されます。 ### グルーピングとフィルタリング \{#available-grouping-and-filtering\} :::link メイン記事:[アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: フィルターとグルーピングはどちらも、LTV チャートの更新回数別ビューと日数別ビューの両方に適用でき、特定のコホートを詳しく調べ、時間の経過に伴う行動を把握できます。 - ✅ フィルター項目:アトリビューション、オーディエンス、国、ペイウォール、A/B テスト、プレースメント、セグメント、ストア、プロダクト、期間。 - ✅ グループ項目:プロダクト、国、ストア、期間、セグメント、コホート(日次、週次、月次、年次)。 Adapty の Realized LTV チャートは、ユーザー行動に関する有益なインサイトを得て、マーケティング戦略を最適化し、収益パフォーマンスを追跡し、顧客の長期的な価値を最大化するためのデータドリブンな意思決定を支援します。 --- # File: analytics-cohorts --- --- title: "コホート分析" description: "Adaptyのコホートを使って、ユーザーエンゲージメントとサブスクリプションの動向を追跡しましょう。" --- Adaptyのコホートは、次のような重要な疑問に答えるために設計されています。 1. コホートが黒字転換するのはいつか? 2. 特定のコホートのアプリ収益はいくらか? 3. 有料ユーザー獲得に使える広告費の上限はいくらか? 4. 広告費を回収するまでにどのくらいかかるか? コホートは、SDKとストア通知を通じて収集したアプリデータを使用して機能するため、追加の設定は不要です。 ## 更新回数または日数によるコホート \{#cohorts-by-renewals-or-by-days\} コホートは更新回数または日数で分析できます。このコントロールによってカラムの見出しが変わり、それに応じて分析のアプローチも変わります。 **日別**のトラッキングは、予算管理や支払いタイムラインの把握に役立ちます。特に、消耗型アイテムや買い切り購入など、サブスクリプション以外のプロダクトのトラッキングに有効です。このモードでは、2つの主な要因により、テーブルセルの青色が列の中央付近に集中する傾向があります。1つ目は、日別でコホートを表示することで、短期間プロダクトに関連する支払いを早期に確認できる点です(リニューアルビューでは、これらは月次・年次のリニューアルと一緒にグループ化されます)。2つ目は、遅延支払いが分布パターンに影響する点で、一部のユーザーが予定より遅れて支払いを行うことがあります。 **更新回数ベース**のトラッキングは、日付を考慮せずに1回の支払いから次の支払いへとコホートの継続率とチャーンを表示します。遅延して支払ったユーザー(数ヶ月遅れる場合もあります)は、該当するサブスクリプション期間の数に追加されます。このアプローチはカレンダー上の収益状況を反映するものではありませんが、コホートの継続率とチャーンを分析してユーザー行動からインサイトを得るには非常に便利です。 どちらか使いやすいモードを選ぶか、より多くの結論やアイデアを得るために両方を活用してください。 ## Adapty がコホートを構築する仕組み \{#how-adapty-builds-cohorts\} 更新回数によるコホートを例に、テーブルがどのように形成されるかを見ていきましょう。コホートの構築には、アプリのインストール数とトランザクション(購入)の 2 つの指標を使用します。コホートの各行は特定の時間間隔(1 日から 1 年)を表します。各行は、その期間中にアプリをインストールし、サブスクリプションを有効化または永続アクセス・買い切り購入を行ったユーザー数から始まります。 各列は、そのperiodにサブスクリプションを更新したユーザー数を示します。M3は「月3」を意味し、その時点までに3回連続で更新したサブスクライバーを表します。W7は「週7」、Y2は「年2」を意味します。コホートにはP2と表示される場合もあります。PはサブスクリプションのPeriod(期間)を表し、同一コホート内に更新期間が異なる複数のプロダクトが存在する場合に、W/M/Yの代わりに表示されます。 コホートの値の差を強調するために、グラデーションカラーを使用しています。数値が大きいほど、より濃い色で表示されます。 以下の画像は、典型的なコホートの例です。 1. このコホートは週次プロダクトのデータのみを表示しています(マーク #1)。 2. 手数料を除外せず、収益を絶対値で表示しています(マーク #2)。 3. 対象期間は過去6ヶ月で、コホートの長さは1ヶ月です(マーク #3)。 4. **Total** 行(マーク #4)は各期間の累積値を表示します。**Total** 行の最初のセルにある $442K は、タイムフレーム終了までのすべての月(11月、12月など)における第1期間(サブスクリプション開始)の収益を合計したものです。Total セルには、期間全体でアプリをインストールしたユーザー数が表示されます。 5. Nov 2023 行の最初の列(マーク #5)は、Nov 2023 にアプリをインストールしたユーザーによる第1期間(サブスクリプション開始)の収益 $37.7K を示しています。Nov 2023 にアプリをインストールしたユーザー数(95,129 人)はヘッダー列に表示されています。 Nov 2023 行の2列目は、Nov 2023 にアプリをインストールしたユーザーの第2週(2週目に更新されたサブスクリプション)の収益 $8,77K を示しています。 6. テーブルには、Total revenue、ARPU、ARPPU、ARPAS が表示されています(マーク #6)。これらの詳細については、この記事の少し後で説明します。 7. テーブル右側の **Columns** ドロップダウンフィールドで、表示する列を設定できます(マーク #7)。 8. テーブル右上(マーク #8)には、特定のコホート分析におけるストアの手数料および税計算を選択するドロップダウンフィールドもあります。Adapty がストアの手数料と税を計算する方法については、[この記事](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)で詳しく説明しています。ドロップダウンから対応するオプションを選択すると、収益データがそれに基づいて再計算されます。 9. テーブルの右側には、予測収益(Predicted Revenue)と予測 LTV(Predicted LTV)が表示されています(マーク #9)。**Predicted Revenue** フィールドは特定の期間内にサブスクライバーコホートが生み出す総収益の予測値を示し、**Predicted LTV** フィールドはコホート内の各ユーザーの期待価値を表します。 コホートの任意のセルにカーソルを合わせると、その期間の詳細な指標を確認できます。 背景に斜線が入っているセルはまだ完了していない期間を示しており、値が今後増加する可能性があります。 ## コホートの長さと期間 \{#cohort-length-and-time-frame\} テーブルの表示内容は、2つの時間設定で決まります。 - **Time frame** — 対象となる日付の範囲です。テーブル上部のカレンダーで設定します。 - **Cohort length** — 各行の粒度です。日・週・月・四半期・年から選べます。月単位にすると、各行がインストール1か月分に対応します。 この2つは独立して動作します。たとえば、Time frame を6か月、Cohort length を月単位にすると6行のテーブルになります。Time frame を1年、Cohort length を週単位にすると52行になります。 ## フィルター、指標、コホートセグメント、CSV エクスポート \{#filters-metrics-cohort-segments-and-export-in-csv\} :::link メイン記事: [アナリティクスのコントロール](controls-filters-grouping-compare-proceeds) ::: デフォルトでは、Adapty はすべての購入データを使用してコホートを構築します。プロダクトの期間、特定のプロダクト、国、ストア、ペイウォール、セグメント、アトリビューションデータでフィルタリングできます。 コントロールパネルの右側には、コホートデータを CSV にエクスポートするボタンがあります。エクスポートしたファイルは Excel や Google スプレッドシートで開いたり、独自の分析システムにインポートしたりできます。 コホートに表示できる指標は、Subscriptions、Payers、Revenue、ARPU、ARPPU、ARPASの6つです。絶対値として表示することも、コホート開始時点からの相対的な変化として表示することもできます。 ## サブスクリプション数、支払いユーザー数、総収益、ARPU、ARPPU、ARPAS \{#subscriptions-payers-total-revenue-arpu-arppu-and-arpas\} **サブスクリプション数**は、選択した期間内にコホートが行ったアクティブなサブスクリプション、永続アクセス購入、および非サブスクリプション購入の合計数です。この指標を追跡することで、ユーザーの行動や提供内容の効果を把握できます。得られたインサイトをもとに、プロダクト戦略の改善、マーケティング施策のターゲティング、収益源の最適化に役立てることができます。 **Payers**(支払者)とは、コホート内で購入を行ったユーザーの総数です。この指標を使うと、収益に貢献しているユニークユーザーの数を把握できます。アプリ内課金(非サブスクリプション)が多いアプリでは、プロダクト提供の真の広がりを示す指標として役立ちます。幅広いユーザー層が購入しているのか、それとも少数のリピーターが収益を支えているのかを確認できます。支払者数を把握することで、顧客エンゲージメントの評価、ターゲットマーケティングの計画、収益戦略の最適化に役立てることができます。 **Total revenue(総収益)** は、選択した期間(2022年11月25日〜2023年5月24日)内に特定のコホートから積み上げられた収益です。特定のコホートのユーザーからどれだけの収益を得たかを把握し、ROASを算出するのに役立ちます。たとえば、2022年9月の広告費が$10,000で、2022年9月コホートの総収益が$30,000であれば、ROAS=3:1となります。 **ARPU**(ユーザー1人あたりの平均収益)は、総収益をユニークユーザー数で割って算出します。例:収益60,000ドル ÷ 5,000ユーザー = ARPU 12ドル。インストール単価(CPI)と比較することで、マーケティングキャンペーンの効果を把握できます。 **ARPPU**(課金ユーザー1人あたりの平均収益)は、総収益をユニーク課金ユーザー数で割って算出します。例:収益60,000ドル ÷ 1,000課金ユーザー = ARPPU 60ドル。課金ユーザー1人が平均してどれだけの収益をもたらしているかを把握するのに役立ちます。 **ARPAS**(Average Revenue Per Active Subscriber)は、アクティブなサブスクリプション1人あたりの平均収益です。総収益 ÷ アクティブなサブスクライバー数で計算されます。ここでいうサブスクライバーとは、トライアル期間またはサブスクリプションを有効化したユーザーを指します。$60,000の収益 ÷ 1,500人のサブスクライバー = $40のARPAS。 ## 手数料と税金 \{#commission-fees-and-taxes\} コホート分析における収益計算の重要な側面として、ストアの手数料と税金(ユーザーのストアアカウントの国によって異なる場合があります)が挙げられます。Adapty は現在、コホート分析において App Store と Play Store の両方で手数料・税金の計算をサポートしています。 Adapty が分析内で税金と手数料をどのように計算するかについての詳細は、[ドキュメント](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)をご参照ください。 ## 収益と手取り額 \{#revenue-vs-proceeds\} 収益(Revenue)と手取り額(Proceeds)はどちらも金額に関する指標です。収益は売上総額、手取り額は売上純額と考えるとわかりやすいでしょう。収益は App Store / Google Play ストアの手数料を差し引く前の金額であり、手取り額は手数料を差し引いた後の金額です。そのため、手取り額は常に収益よりも少なくなります。 実際に差し引かれる手数料は、[Small Business Program](app-store-small-business-program)(15%)などのプログラムへの適用資格、長期サブスクリプションの優遇レート(1年以上の更新後は15%)、国別レート、標準レート(最大30%)など、複数の要因によって異なります。 Adaptyは、顧客が行うすべての取引に対して適用される手数料率を自動的に算出し、それに基づいて収益を計算します。手数料率の決定方法の詳細については、[ストア手数料と税金](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)のドキュメントをご覧ください。 ## 返金の処理 \{#refund-handling\} コホート指標に共通する2つのルールがあります。 - 返金は元の購入日ではなく、返金が発生した日に記録されます。返金がコホートに影響するのは、その返金日が選択した期間内に含まれる場合のみです。 - 返金によってユーザーがコホートから除外されることはなく、インストール数も変わりません。コホートへの所属はユーザーのインストール時点で確定します。 これらのルールに加え、返金の影響は指標と[ビューモード](#cohorts-by-renewals-or-by-days)によって異なります。使用するモードの列を下方向に読み進めてください。 | 指標 | 更新回数別 | 日数別 | | --- | --- | --- | | インストール数(コホートサイズ) | 影響なし。ユーザーは元のコホートに残る。 | 「更新回数別」と同じ。 | | サブスクリプション | 返金済みのサブスクリプションも引き続きカウントされる。 | 返金によりそのサブスクリプションがカウントから除外される。 | | 支払いユーザー数 | 返金済みの支払いユーザーも引き続きカウントされる。 | 他に成功した支払いがある場合でも、返金によりそのユーザーがカウントから除外される。 | | 収益 | 返金額は、元の支払いがカウントされていた更新期間の列から差し引かれる。 | 返金額は、返金日以降から差し引かれる。 | | ARPU | 収益 ÷ インストール数。返金により収益が下がるが、インストール数は変わらない。 | 「更新回数別」と同じ。 | | ARPPU | 収益 ÷ 支払いユーザー数。返金により収益と支払いユーザー数の両方が下がる可能性があるため、ARPPUは収益単独の場合よりも大きく変動することがある。 | 「更新回数別」と同じ。 | | ARPAS | 収益 ÷ アクティブサブスクライバー数。返金により収益が下がるが、サブスクライバー数は変わらない。 | 「更新回数別」と同じ。 | | リテンション | 影響なし。トライアルおよび購入イベントをカウントするものであり、返金はカウントしない。 | 「更新回数別」と同じ。 | 払い戻しは、有効な収益計算モードに関係なく、払い戻された金額を収益から差し引きます。 ### コンバージョン率とARPPU \{#conversion-rate-and-arppu\} 返金はインストール数ベースのコンバージョン率に影響しません。インストール数は変わらないためです。課金ユーザーベースのコンバージョン率は異なります。返金は **by days** ビューではコンバージョン率を下げますが、**by renewals** ビューでは影響しません。 **renewals ビュー**では、Revenue 列と Payers 列はそれぞれ1期間分のデータのみを表示します。一方、ARPPU 列は異なります。各 ARPPU セルは、コホートの最初の期間からその列の期間までのすべてを合算します。つまり、常に複数の期間をまとめて扱い、さらに返金済みユーザーを除外します。そのため、1期間の Revenue をその期間の支払いユーザー数で割っても、表示されている ARPPU を再現することはできません。 **例:** あるユーザーが2月にアプリをインストールしてサブスクリプションを購入し、その後4月に全額返金を受けた場合。2月コホートを **by days** で表示すると: - 時間軸:2月〜3月(返金がウィンドウに入る前):ユーザーは有料ユーザー1名としてカウントされ、収益は全額含まれます。 - 時間軸:2月〜6月(返金がウィンドウに入った後):ユーザーは有料ユーザー0名としてカウントされ、収益は0になります。 どちらの時間軸でも、2月のインストール数とリテンションは変わりません。 [指標が返金を処理する方法](refund-events#how-metrics-handle-refunds)では、MRR、収益チャート、データエクスポートにわたって同じルールを比較しています。 ## 予測:収益とLTV \{#prediction-revenue-and-ltv\} **予測収益**は、コホート作成後の選択した期間内に、課金ユーザーのコホートが生み出すと見込まれる収益の合計推定値です。コホートの予測LTVに、コホート内の課金ユーザーの予測数を掛け合わせて算出されます。たとえば、予測LTVが$50でコホート内の課金ユーザーが100人の場合、予測収益は$5,000となります。 **予測 LTV** とは、課金ユーザー 1 人あたりの推定ライフタイムバリューであり、コホート作成後の選択期間内に各課金ユーザーが生み出すと期待される平均収益を表します。 この予測は、過去のコホート継続率パターンに基づいており、十分な履歴データがある場合はアプリ固有のデータを使用し、そうでない場合はアプリをまたいだ平均値を使用します。Adapty の予測モデルの詳細については、[予測のドキュメント](predicted-ltv-and-revenue)をご参照ください。 Adapty のコホートは、アプリ内のユーザー行動と財務パフォーマンスについて詳細なインサイトを提供します。更新回数または日数に基づいてコホートを分析することで、コホートが収益化するタイミングの把握、収益のトラッキング、ユーザーあたりの平均収益の算出、広告費用の回収にかかる時間の把握が可能になります。カスタマイズ可能なフィルター、指標、エクスポートオプションにより、Adapty はデータに基づいた意思決定をサポートし、ユーザー獲得とマネタイズ戦略を最適化してアプリの成功を最大化します。 --- # File: analytics-funnels --- --- title: "ファネル分析" description: "Adaptyのアナリティクスファネルを理解して、ユーザー行動を把握しコンバージョンを改善する方法を学びましょう。" --- Adaptyのファネルは、次のような疑問に答えるために設計されています。 1. インストールのうち、何パーセントが有料ユーザーに転換するか? 2. プロダクトを試したユーザーのうち、何割がリピーターになるか? 3. どのステップで離脱が多く、改善が必要か? 4. なぜユーザーは課金をやめるのか? ファネルチャートでは、フィルターやグループを設定することで、ユーザー行動についてさらに深いインサイトを得ることができます。 ファネルはSDKおよびストア通知から収集したデータを使用するため、追加の設定は不要です。 :::note ファネルは、[App Settings](general#4-installs-definition-for-analytics) のインストール定義に従ってインストールデータを反映します。 ::: <img src="/assets/shared/img/funnels-tab.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ファネルチャートをステップごとに解説 \{#funnel-chart-step-by-step\} チャート上でユーザーの行動を正しく読み取るために、ファネルの各要素を順番に確認していきましょう。 <img src="/assets/shared/img/ed5bf5d-CleanShot_2022-06-23_at_09.36.49.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### インストール \{#installs\} 1列目(1)はインストール数を表します。インストールの総数(ユニークユーザーではなく)が絶対値(2)として表示され、以降のコンバージョン計算の基準となる100%として扱われます。ユーザーがアプリを削除して再インストールした場合は、2件のインストールとしてカウントされます。 隣のグレーのエリアはステップ間の遷移パラメーターを示します。次のステップ(ペイウォール表示)へのコンバージョン率がフラグ(3)に表示され、離脱率と絶対値のチャーン数がその下(4)に表示されます。 <img src="/assets/shared/img/00416f9-CleanShot_2022-06-23_at_14.02.06.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ペイウォール表示 \{#paywall-displayed\} 2列目(5)は、選択した期間内に少なくとも1回ペイウォールを閲覧したアプリユーザー数(6)を表します。この期間内にインストールしたユーザーのみが対象です。ペイウォールの閲覧が選択期間内であっても、インストール日が範囲外の場合はカウントされません。 また、1ステップ目からの割合(7)も表示されます。この割合は1ステップ目のグレーのフラグ(3)と同じ値になりますが、これは最初の2ステップ間だけに成立する関係です。 このステップのデータは、`logShowFlow()`(iOS SDK v4+)/ `logShowPaywall()` メソッドを使用しているすべてのペイウォールから収集されます。そのため、[ドキュメント](present-remote-config-paywalls#track-paywall-view-events)に記載されているように、このメソッドを使ってすべてのペイウォール表示をAdaptyに送信してください。 2列目の隣にあるグレーのエリアは遷移を表します。次のステップ(トライアル)へのコンバージョン率がフラグ(8)に表示され、ペイウォール後の離脱率と絶対値のチャーン数がその下(9)に表示されます。 <img src="/assets/shared/img/fb11650-CleanShot_2022-06-23_at_15.54.32.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### トライアル \{#trials\} 3列目(10)は、選択した期間内にインストールしたユーザーがペイウォールで有効化したトライアル数(11)を表します。フィルターがトライアルなしのプロダクトに設定されている場合、この値はゼロになり、列は空になります。 1ステップ目からのトライアル割合も表示され、インストールからトライアルへのコンバージョン率(12)を確認できます。 この割合は前のステップのグレーのフラグ(8)と一致しないことに気づくでしょう。これは、チャート上部では現在の値を1ステップ目と比較し、グレーのフラグでは直前のステップと比較しているためです。 3列目の隣のグレーエリアは、次のステップ(有料)へのコンバージョン率をフラグ(13)で表示します。トライアル期間中の離脱率と絶対値のチャーン数がその下(14)に表示されます。 <img src="/assets/shared/img/7b88909-CleanShot_2022-06-23_at_15.54.32_-_2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### サブスクリプションと更新 \{#subscriptions-and-renewals\} 4列目はアクティベートされたサブスクリプション数(15)を示します。トライアルなしのプロダクトはペイウォールからの直接サブスクリプションが含まれ、トライアルありのプロダクトはトライアルから有料サブスクリプションに転換した数が含まれます。両方のタイプがある場合は合算されます。 上部の割合はインストールからのコンバージョン(16)を示します。 グレーのフラグの割合は次のステップ(2期目への更新)へのコンバージョン(17)を示します。 2期目への更新前の離脱率と絶対値はコンバージョンの下(18)に表示されます。 <img src="/assets/shared/img/d13bf9b-CleanShot_2022-06-23_at_15.54.32-3.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このステップ以降は、同じ構造のステップが続きます。2回目の更新、3回目、4回目と続き、アプリの履歴データが十分あれば、水平スクロールで数十期分を確認できます。各ステップの見方は共通です。 - 上部にインストールからの割合、 - 下部に直前のステップからの割合、 - 上部に更新数の絶対値、 - 下部にチャーン数の絶対値、 - チャーン理由のポップアップ表示(ホバー時)。 ### チャーンの理由 \{#churn-reasons\} Adaptyはトライアルステージ以降の*チャーン*統計を詳細に表示します。あるステージに入ったが次のステージに進まなかったユーザーは、すべてチャーンとしてカウントされます。 * 特定のイベント(例:トライアルの期限切れや支払い問題)がコンバージョンの失敗を引き起こした場合、Adaptyはその理由を表示します。 * **unknown**ステータスは一時的な状態です。ユーザーが次のステージに進むために必要なイベントにまだ遭遇していないことを示します。 トライアルステージでは、通常はトライアルがまだ終了していないことを意味します。トライアルの解決には時間がかかるため、短い日付範囲や単日でファネルを確認する場合によく見られます。 ユーザーがコンバージョンするかトライアルをキャンセルした時点で、Adaptyが情報を更新します。 <img src="/assets/shared/img/churn-reasons.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### テーブルビュー、フィルター、CSVエクスポート \{#table-view-filters-and-csv-export\} ファネルチャートには数値データを扱いやすいテーブルが付属しています。 <img src="/assets/shared/img/4787aff-CleanShot_2022-06-23_at_21.01.44.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このテーブルはファネルと同じアプローチを踏まえつつ、一部変更が加えられています。 1回目の有料サブスクリプションのステップを除くすべてのステップのデータが列として表示されます。 その代わりに、「インストール → 有料」と「トライアル → 有料」の2つの列が用意されており、無料ユーザーが有料ユーザーになる核心的なコンバージョンポイントを示しています。 「インストール → 有料」列はトライアルなしのプロダクトのみ、「トライアル → 有料」列はトライアルありのプロダクトのみを示しているように見えるかもしれませんが、正確にはそうではありません。トライアルが期限切れになり、ユーザーがトライアルなしのように扱ってトライアルありのプロダクトを購入した場合も考慮されるためです。 <img src="/assets/shared/img/a9bcbc7-CleanShot_2022-06-23_at_21.29.12.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 数値をさらに深掘りしていくと、新たな仮説のための強力なフィルタリングツールが見つかります。 さまざまなディメンションで条件を自由に設定し、データに基づいた真のインサイトを得ましょう。 以下を組み合わせてみてください。 1. プロダクトタイプ(価格帯、期間など) 2. 期間。 3. 国別セグメンテーション。 4. トラフィックのアトリビューション。 5. ストア。 必要なデータだけを表示するために、絶対値 #、相対値 %、またはその両方を選択できます。 <img src="/assets/shared/img/1475e42-CleanShot_2022-06-23_at_21.50.33_-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> コントロールパネルの右側には、ファネルデータをCSVでエクスポートするボタンがあります。エクスポートしたファイルはExcelやGoogle スプレッドシートで開いたり、独自の分析システムにインポートしたりできます。 :::important アプリが手数料減額プログラムに登録されている場合は、Adaptyにお知らせください。正確な計算のために、[アプリ設定](general)で[Small Business Program](app-store-small-business-program)および[Reduced Service Fee program](google-reduced-service-fee)のステータスを設定してください。 ::: <img src="/assets/shared/img/ff23846-CleanShot_2022-06-23_at_22.15.49.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: analytics-retention --- --- title: "リテンション分析" description: "ユーザーリテンション分析を理解し、サブスクリプション戦略を最適化する方法を説明します。" --- リテンションチャートは、次のような疑問に答えるのに役立ちます。 1. アプリはユーザーを期間ごとにどのように維持しているか? 2. どのプロダクトがより魅力的で、継続率が高いか? 3. どのユーザーグループがより忠実か? 4. 成長のベンチマークとして使えるリテンションレベルはどのくらいか? 5. そして当然ながら、新規ユーザーの獲得ではなく、既存オーディエンスへの投資でコストを節約するにはどうすればよいか? フィルターやグループを設定することで、ユーザー行動に関する貴重なインサイトが得られます。 リテンションは、SDK とストア通知から収集したデータをもとに算出されるため、追加の設定は不要です。 ### リテンションの計算方法 \{#how-do-we-calculate-retention\} リテンションチャートでは、ユーザー数がステップ(トライアル(「トライアルを表示」チェックボックスが有効な場合)、1回目の支払い、2回目の支払いなど)に応じてどう変化するかを確認できます。日付範囲を選択した際にカウントされるユーザーについて説明します。 例えば、カレンダーで過去3か月を選択し、「トライアルを表示」チェックボックスがオフの場合、過去3か月以内に初回サブスクリプションを開始したユーザーのみがカウントされます。「トライアルを表示」がオンで過去3か月を選択した場合は、その期間中にトライアルを開始したすべてのユーザーがカウントされます。これらのサブスクライバーについて、N番目のステップの絶対リテンションはN回目の支払いをしたユーザー数として表示され、N番目のステップの相対リテンションは、選択した期間内のサブスクリプション(またはトライアル)総数に対するN回目の支払い件数の割合として算出されます。 :::info リテンションは遡って変化します チャートを確認するタイミングに関わらず、選択した期間のベースライン(100%)は変わりません。一方、次の期間へのリテンションは時間とともに増加することがあります。 例えば、月次サブスクリプションの場合、12月1日〜31日に20件の初回購入があったとすると、ユーザーが通常通り、あるいは何らかの理由(グレース期間など)でやや遅れて次のサブスクリプション期間に移行するにつれ、2回目の期間へのリテンションは1月を通じて(場合によってはそれ以降も)増加していくことが想定されます。 ::: ### 返金の取り扱い \{#refund-handling\} 返金はリテンションから**除外されません**。返金されたユーザーはリテンションカーブに残るため、同じコホートにおいて[アクティブサブスクリプション](active-subscriptions)や[収益](revenue)よりもリテンションが高く見える場合があります。 各指標での返金の扱いについては、[指標が返金イベントをどのように処理するか](refund-events#how-metrics-handle-refunds)を参照してください。 ### リテンション活用のヒント \{#retention-opportunities\} Adaptyのリテンション機能をより活用する方法を見ていきましょう。 数字への純粋な関心だけでなく、分析結果を実装したあとのビジネス価値を重視するなら、まず目的を明確にすることが大切です。チャート機能を深く理解することで、このデータが持つインパクトも見えてきます。 では、「なぜ」と「どのように」を一緒に整理していきましょう。 1 - オーディエンスへのアプローチ。 まず、リテンションはターゲットオーディエンス、その好み、そしてプロダクトが利用期間中に期待に応えているかどうかに関するものです。収益を生み出すビジネスの核心的な関係性を測る方法をお探しなら、リテンションがその答えです。 このような測定が有効なのは、一般的に既存顧客への販売は新規顧客への販売よりもコストが低いためです。その理由は2つあります。販売にかかる手間が少なく、平均単価が高いのです。そのため、リテンションが低下したときはサブスクライバーのロイヤルティに投資することが賢明な選択かもしれません。 2 - プロダクトへのアプローチ。 2つ目の理由として、リテンションチャートはプロダクトの実際の利用期間を示し、長期的な予測を可能にします。改善したい場合は、プロダクトを提供する施策を修正してその期間を延ばし、再度予測してビジネス目標に近づけましょう。こうした取り組みは、予測ルーティンと組み合わせた戦略的ビジョンの一部になり得ます。そして、絶えず変化する環境で同じ場所にとどまるために皆が全力で走り続けているように、このプロセスに終わりはありません。 3 - 市場へのアプローチ。 主要な競合他社より速く動くことは重要ですが、時には通常の競争から抜け出すことでより大きな成果が得られることもあります。異なる国やストアのユーザー行動を分析すると、地域特有の特性から優れたインサイトやビジネスの新たな機会が見えてくることがあります。文化的・市場的背景をリテンションの観点から分析し、セグメンテーションや今後の開発に活かすことができます。例えば、特定の地域でブルーオーシャンを見つけ、そこで急速に成長できるかもしれません。 リテンションデータの活用はもちろんこの基本的な解釈に限りませんが、素早く実際の価値を得たい場合の良いスタートになるでしょう。 ### カーブ、テーブルビュー、フィルター、CSVエクスポート \{#curves-table-view-filters-and-csv-export\} リテンションの目的と基本的な解釈について共通認識が持てたところで、これらを便利に使うためのツールを見ていきましょう。 Adaptyのリテンション機能の核となるのはチャートです。リテンションレベルが顧客のライフタイムのステップにどう依存するかを示します。 ステップは横軸に表示されます:トライアル、有料(1回目のサブスクリプション)、P2(2回目のサブスクリプション)、P3、P4など。 「トライアルを表示」チェックボックスが選択されている場合のみ、軸はトライアルステップから始まります。 データの計算において、このチェックボックスは次のように機能します。「トライアルを表示」が選択されていて軸がトライアルステップから始まる場合、トライアルを含むシナリオのみが表示され、インストールから直接行われたトランザクションは表示されません。また、「有料」ステップにはトライアルから移行したトランザクションのみが含まれます。「トライアルを表示」が選択されておらず軸が有料ステップから始まる場合、この最初のステップにはトライアルからのものとインストールから直接のものの両方を含む、すべての初回トランザクションが含まれます。 チャート上にマウスを乗せると、データのサマリーポップアップが表示されます。また、下のテーブルの列にマウスを乗せると、チャート上に関連データのサマリーポップアップが表示されます。 テーブルには、チャートで選択したグループとフィルターが同様に反映されます。 フィルターとグループを自由に組み合わせて高度な分析を行いましょう。データに基づいた真のインサイトを収集できます。 以下を組み合わせて活用してください: 1. プロダクトタイプ 2. 期間 3. 時間範囲 4. 国 5. トラフィックアトリビューション 6. ストア 「#絶対値」と「%相対値」コントロールを使って必要なデータを表示してください。 最後に、コントロールパネルの右側にはファネルデータをCSVにエクスポートするボタンがあります。ExcelやGoogleスプレッドシートで開いたり、独自の分析システムにインポートして、使いやすい環境で分析や予測を続けることができます。 :::warning [Adapty General Settings](https://app.adapty.io/settings/general) で、アプリがSmall Business Programに含まれていることを必ず設定してください。 ::: --- # File: analytics-conversion --- --- title: "コンバージョン分析" description: "Adaptyのアナリティクスツールを使ってサブスクリプションのコンバージョン率を測定しましょう。" --- ファネルが全体像を把握するためのもので、リテンションがユーザーロイヤルティに焦点を当てるものだとすれば、コンバージョン分析はユーザージャーニーの各重要ステップにおける効果を時系列で評価するためのものです。 コンバージョンは次のような疑問に答えます: 1. アプリのコンバージョンは時間とともにどのように変化しているか?季節的なトレンドはあるか? 2. マーケティング活動や新たな状況が発生した時点でコンバージョンはどう変化したか? 3. 異なる地域のユーザーはアプリのアップデートにどう反応しているか? 4. どのプロダクトタイプが時間とともによりコンバージョンしやすいか? コンバージョンはAdapty SDKとストア通知から収集したデータをもとに行われるため、追加の設定は必要ありません。 ## メインコントロールとチャート \{#main-controls-and-charts\} 収益は成功を測る定番の指標ですが、それは全体像の一部に過ぎません。異なるユーザー行動やライフサイクルステージ全体にわたって、ビジネスが時間とともにどのように推移しているかを把握することも同様に重要です。そこで役立つのがコンバージョン分析です。 フィルターやグループを設定することで、ユーザー行動についてより深いインサイトを得られます。トレンドを特定して分析するために、コンバージョンが日次・月次・年次でどのように推移しているかをモニタリングしましょう。 チャートの左側にはコンバージョンステップのコントロールがあります。ここで追跡したいコンバージョン(例:インストール → トライアル、トライアル → 有料、有料 → 更新)を選択できます。 各コンバージョン指標は次のロジックに従います: - **X** を選択した日に開始ステートに入ったユーザー数(例:インストール数)とします。 - **Y** をそのユーザーのうち最終的にターゲットステートに到達したユーザー数(例:トライアル開始数)とします。 - コンバージョン率の計算式:**コンバージョン = (Y / X) × 100%** :::note チャートに表示される日付は、ユーザーが初期ステート(X)に入った時点、つまりコンバージョン対象となった瞬間に対応しています。 ::: 各コンバージョンの説明と参考例を以下に示します。 ### インストール → 有料 \{#install---paid\} この指標は、特定の日にアプリをインストールしたユーザーのうち、最終的に初回サブスクリプションを購入した割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日のインストール数(インストール時点ではプロダクトが選択されていないため、全プロダクトで同じ値)。 - **Y** = そのユーザーのうち最終的に初回サブスクリプション(トライアルまたは非トライアル)を購入したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件のインストールがあった。 - 1月8日までに、そのうち20人がサブスクリプションを購入した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、1月1日のインストールグループからさらに30人がサブスクリプションを購入した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、1月1日にアプリをインストールしたユーザーの50%が、現時点までに有料サブスクリプションへコンバージョンしたことになります。 </details> ### インストール → トライアル \{#install---trial\} この指標は、特定の日にアプリをインストールしたユーザーのうち、最終的にトライアルを開始した割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日のインストール数(インストール時点ではプロダクトが選択されていないため、全プロダクトで同じ値)。 - **Y** = そのユーザーのうち、任意のタイミングでトライアルを有効化したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件のインストールがあった。 - 1月8日までに、そのうち20人がトライアルを開始した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、1月1日のインストールグループからさらに30人がトライアルを開始した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、1月1日にアプリをインストールしたユーザーの50%が、現時点までにトライアルを開始したことになります。 </details> ### ペイウォール表示 → トライアル \{#paywall-view---trial\} この指標は、ペイウォールを見たユーザーのうちトライアルを開始したユーザーの割合を追跡します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日にペイウォールを見たユーザー数。 - **Y** = その後任意のタイミングでトライアルを開始したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件のペイウォール表示があった。 - 1月8日までに、そのうち20人がトライアルを開始した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、さらに30人がトライアルを開始した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% これは、1月1日にペイウォールを見たユーザーの50%が、現時点までにトライアルを開始したことを示しています。 </details> ### ペイウォール表示 → 有料 \{#paywall-view---paid\} この指標は、ペイウォールを見たユーザーのうち購入したユーザーの割合を追跡します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日にペイウォールを見たユーザー数。 - **Y** = その後任意のタイミングで購入したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件のペイウォール表示があった。 - 1月8日までに、そのうち20人が購入した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、さらに30人が購入した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% これは、1月1日にペイウォールを見たユーザーの50%が、現時点までに購入したことを示しています。 </details> ### トライアル → 有料 \{#trial---paid\} この指標は、特定の日にトライアルを開始したユーザーのうち、その後初回サブスクリプションを購入した割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日に開始されたトライアル数。 - **Y** = そのユーザーのうち、トライアル後に最終的にサブスクリプションを購入したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件のトライアルが開始された。 - 1月8日までに、そのうち20人がサブスクリプションを購入した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、1月1日のトライアルグループからさらに30人がサブスクリプションを購入した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、1月1日にトライアルを開始したユーザーの50%が、現時点までに有料サブスクリプションへコンバージョンしたことになります。 </details> ### 有料 → 2期目 \{#paid---2nd-period\} この指標は、初回支払い後にサブスクリプションを更新したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日の初回サブスクリプション数。 - **Y** = 任意のタイミングで2期目に更新したユーザー数(通常1サブスクリプションサイクル後。グレース期間中の更新を含む)。 - **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件の初回サブスクリプションがあった。 - 1月8日までに、そのうち20件が更新された。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、そのグループからさらに30人が更新した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% これは、1月1日に初回サブスクリプション支払いをしたユーザーの50%が、現時点までに2期目へ更新したことを示しています。 </details> ### 2期目 → 3期目 \{#2nd-period---3rd-period\} この指標は、2期目のサブスクリプション後に再度更新したユーザーの割合を追跡します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日の2期目サブスクリプション数。 - **Y** = 任意のタイミングで3期目に更新したユーザー数(通常もう1回の請求サイクル後。グレース期間中の更新を含む)。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件の2期目サブスクリプションがあった。 - 1月8日までに、そのうち20人が更新した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、さらに30人が更新した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% これは、1月1日に2期目のサブスクリプションに入ったユーザーの50%が、現時点までに3期目へ更新したことを示しています。 </details> ### 3期目 → 4期目 \{#3rd-period---4th-period\} この指標は、3期目のサブスクリプション後に更新したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日の3期目サブスクリプション数。 - **Y** = 任意のタイミングで4期目に更新したユーザー数(通常1回の請求サイクル後。グレース期間中の更新を含む)。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件の3期目サブスクリプションがあった。 - 1月8日までに、20人が更新した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、さらに30人が更新した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、1月1日に3期目のサブスクリプションに入ったユーザーの50%が、現時点までに4期目へ更新したことになります。 </details> ### 4期目 → 5期目 \{#4th-period---5th-period\} この指標は、4期目のサブスクリプション後に更新したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日の4期目サブスクリプション数。 - **Y** = 任意のタイミングで5期目に更新したユーザー数(通常1回の請求サイクル後。グレース期間中の更新を含む)。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件の4期目サブスクリプションがあった。 - 1月8日までに、20人が更新した。 - 1月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 2月1日までに、さらに30人が更新した。 - 2月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、1月1日に4期目のサブスクリプションに入ったユーザーの50%が、現時点までに5期目へ更新したことになります。 </details> ### 6ヶ月以上 \{#6-months-\} この指標は、初回サブスクリプションから6ヶ月以上サブスクリプションを継続したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日の初回サブスクリプション数。 - **Y** = そのユーザーのうち、元のサブスクリプション日から6ヶ月以降に少なくとも1回更新したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に100件の初回サブスクリプションがあった。 - 7月第1週までに、そのうち20人が更新した(例:25回目の週次サブスクリプション)。 - 7月8日時点での1月1日のコンバージョン = (20 / 100) × 100% = 20% - 8月1日までに、さらに30人が6ヶ月以降に更新した。 - 8月1日時点での1月1日のコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、1月1日にサブスクリプションを開始したユーザーの50%が、8月1日時点で6ヶ月を超えてサブスクリプションを継続したことになります。 </details> ### 1年以上 \{#1-year-\} この指標は、初回サブスクリプションから12ヶ月以上サブスクリプションを継続したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - **X** = 選択した日の初回サブスクリプション数。 - **Y** = そのユーザーのうち、元のサブスクリプション日から12ヶ月以降に少なくとも1回更新したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 2021年1月1日に100件の初回サブスクリプションがあった。 - 2022年1月第1週までに、20人が更新した。 - 2022年1月8日時点でのコンバージョン = (20 / 100) × 100% = 20% - 2022年2月1日までに、さらに30人が12ヶ月以降に更新した。 - 2022年2月1日時点でのコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、2021年1月1日にサブスクリプションを開始したユーザーの50%が、1年以上アクティブを維持したことになります。 </details> ### 2年以上 \{#2-years-\} この指標は、初回支払い日から24ヶ月以上サブスクリプションを継続したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - X = 選択した日の初回サブスクリプション数。 - Y = そのユーザーのうち、元のサブスクリプション日から24ヶ月以降に少なくとも1回更新したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 2020年1月1日に100件の初回サブスクリプションがあった。 - 2022年1月第1週までに、そのうち20人が更新した。 - 2022年1月8日時点でのコンバージョン = (20 / 100) × 100% = 20% - 2022年2月1日までに、さらに30人が2年以降に更新した。 - 2022年2月1日時点でのコンバージョン = ((20 + 30) / 100) × 100% = 50% つまり、2020年1月1日にサブスクリプションを開始したユーザーの50%が、2022年2月1日時点で2年以上アクティブだったことになります。 </details> ### グレース期間 → 有料 \{#grace-period---paid\} この指標は、[サブスクリプショングレース期間](grace-period)に入ったユーザーのうち、グレース期間終了*前*に問題を解決したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - X = グレース期間に入ったサブスクライバー数。 - Y = そのユーザーのうち、グレース期間が終了する前にサブスクリプションを更新したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 2025年1月1日に、100人のサブスクリプションが自動更新できなくなった。彼らは1月17日までの16日間のグレース期間に入った。 - 1月1日から1月17日の間に50人が支払い情報を更新し、サブスクリプションが正常に更新された。 - 2025年1月17日時点でのコンバージョン = (50 / 100) × 100% = 50% </details> ### 請求問題 → 有料 \{#billing-issue---paid\} この指標は、[請求問題](/billing-issue)が発生したユーザーのうち、請求サイクル終了前に支払いを再開したユーザーの割合を示します。 <details> <summary>仕組み</summary> **定義**: - X = 請求問題が発生したサブスクライバー数。 - Y = そのユーザーのうち、請求問題発生から請求サイクル終了までの間にサブスクリプションを更新したユーザー数。 **計算式**:コンバージョン = (Y / X) × 100% **例**: - 1月1日に、100人のサブスクライバーのサブスクリプションが自動更新できず、請求問題が発生した。 - 注意:グレース期間が有効な場合、請求問題ステートはグレース期間終了後にのみ開始されます。この例ではグレース期間が1月1日に終了したと仮定します。 - 1月8日までに、そのうち10人が支払い問題を解決して更新した。 - 1月8日時点での1月1日のコンバージョン = (10 / 100) × 100% = 10% - 1月31日(請求サイクル終了)までに、さらに10人が更新した。 - 1月31日時点での1月1日のコンバージョン = ((10 + 10) / 100) × 100% = 20% これは、1月1日に請求問題ステートに入ったユーザーの20%が、請求サイクル終了前に問題を解決して更新したことを示しています。 </details> ## グループ化と期間 \{#grouping-and-time-ranges\} コンバージョンを選択した際の分析対象はチャートです。チャートはコンバージョン率が時間とともにどのように変化するかを表示します。日付ピッカーを使って期間のクイックオプションを選択してください。 チャートには通常複数のカーブが表示されます。デフォルトではグループ化リストから最大5つが選択されており、チャート右側のエリアにあるチェックボックスで選択を変更できます。 初めてページを開いたときは、デフォルトのグループ化としてプロダクトの期間が選択されます。その後、設定はキャッシュに保存され、次回アクセス時には最後に選択したグループが表示されます。 利用可能なグループ化は以下の通りです: - プロダクト - 国 - ストア - ペイウォール - 期間 - マーケティングアトリビューション 選択した日付範囲で結果が表示されない場合、関連する日付と日付範囲を自動調整するオプションを提案する通知が表示されます。ワンクリックで調整できます。 ## テーブル表示、フィルター、CSVエクスポート \{#table-view-filters-and-csv-export\} カーブの比較で全体像をつかめますが、さらに詳しく分析するにはチャート下のテーブル表示を使用してください。テーブルはチャートと同期しており、列にカーソルを合わせるとカーブ上に関連するポップアップが表示されます。 上述のグループ化はチャートとテーブルの両方に適用されます。プロダクトによるクイックフィルターや、プロダクト・国・ストア・期間・アトリビューションなどの高度なフィルターを設定できます。 数字を自分のやり方で扱えることが重要だと分かっています。そのため、コントロールパネルの右側にはファネルデータをCSVにエクスポートするボタンがあります。ExcelやGoogle Sheetsで開いたり、独自の分析システムにインポートして、好みの環境で分析や予測を続けることができます。 :::important アプリが手数料減額プログラムに登録されている場合は、Adaptyに通知してください。正確な計算のために、[アプリ設定](general)で[スモールビジネスプログラム](app-store-small-business-program)と[手数料減額サービスプログラム](google-reduced-service-fee)のステータスを指定してください。 ::: --- # File: reports --- --- title: "レポート" description: "Adapty で詳細なサブスクリプションレポートを生成し、アプリの収益とユーザー行動を分析します。" --- 収益、チャーン率、アクティブサブスクライバー数、アクティブトライアル数など、[チャート](charts)で確認できるのと同じ指標を、タイムリーかつ関連性の高い情報としてメールで受け取ることができます。レポートは毎日・毎週・毎月の頻度で届き、直近の期間と前の期間を比較した推移が確認できます。 レポートで送信されるデータは、[**Overview**](https://app.adapty.io/overview) ページで設定した内容(指標の種類・並び順・レポートのタイムゾーン・収益タイプ)に基づいています。 レポートの詳細レベルは、サマリーまたはアプリ別から選択できます。サマリーレポートは、全アプリ(または選択したアプリ)の集計情報を1通のメールにまとめたものです。アプリ別レポートは、選択した単一のアプリのデータのみを含みます。全アプリのサマリーレポートと、最近リリースしたアプリや優先度の高いアプリ、あるいは自分が担当しているアプリのアプリ別レポートを有効にすることをお勧めします。 詳細レベルにかかわらず、メールレポートはあなたのローカルタイムゾーンの午前9時に届きます。毎日レポートは毎日、毎週レポートは毎週月曜日、毎月レポートは毎月1日に送信されます。各レポートには最新のデータと前の期間との比較が含まれます(例:本日の毎日レポートであれば昨日と一昨日のデータを比較、本日の毎週レポートであれば先週と先々週のデータを比較、など)。 選択したレポートの種類に関係なく、最新かつ正確な情報が確実にメールで届きます。 ## レポートを有効にする \{#enable-reports\} 1. Adapty のトップメニューで [**Account**](https://app.adapty.io/account) セクションを開きます。 2. **Email reports** セクションで、受け取りたいレポートの種類(毎日・毎週・毎月)を選択します。 2. **Edit** ボタンをクリックして、各レポートタイプに含めるアプリをカスタマイズします。 3. レポートウィンドウで、含めたいアプリを選択します。 4. **Save changes** ボタンをクリックして選択内容を保存します。 ## タイムゾーンを設定する \{#set-your-time-zone\} 1. Adapty メインメニューで [**Overview**](https://app.adapty.io/overview) セクションを開きます。 2. **Edit** ボタンをクリックし、タイムゾーンを選択します。 3. **Done** ボタンをクリックして保存します。 --- # File: discrepancies-and-troubleshooting --- --- title: "データの相違をトラブルシューティングする" description: "データの乖離の原因を探る" --- Adapty ユーザーは、異なるソースから得た類似データを比較した際に**相違**が生じることがあります。特に以下のような比較で発生しやすいです: * Adapty チャートとストアレポートの比較 * Adapty チャートとサードパーティのチャートの比較 * Adapty 内の異なるチャート同士の比較 ## トラブルシューティングのアルゴリズム \{#troubleshooting-algorithm\} Adapty と他のプラットフォームの間に生じる相違のほとんどは、想定内であり正常です。**異なるソースが同じデータを異なる方法で処理する**ために発生します。 一方で、**Adapty の設定に問題**があることを示す場合もあります。 プラットフォーム間でデータが異なると疑われる場合は、[生データをエクスポート](export-analytics-api-requests)して**ファイルを比較する**のが最善です。 * ストアもデータの処理や表示に関する問題が発生することがあります。最も正確な比較のために、ストアの**生トランザクションデータ**にアクセスしてください。 * Adapty と別のアナリティクスプラットフォームを比較する場合は、ストアのトランザクションレポートを真実の源として比較の基準にしてください。 * 限られたデータセットで比較する方が不整合を見つけやすくなります。少量のデータを比較し、特定のプロダクトと 1 日分に絞って確認しましょう。 * 相違が**価格**の違いによるものか、**イベント数**の違いによるものかを特定してください。価格の問題は[プロダクトの価格更新](#product-pricing)で解決できます。イベントの問題は[サーバー側の問題](#issues-with-server-notifications-and-rtdn)を示している可能性があります。 * [イベントフィード](event-feed)を表示して受信イベントを監視してください。予期しない動作に気づくことがあります。 データがどこで乖離しているかを特定したら、以下の一般的な原因を調査してみてください: ## サーバー通知と RTDN の問題 \{#issues-with-server-notifications-and-rtdn\} ストア接続を正しく設定していない場合、Adapty は必要なイベントデータを受信できません。これは特に、サブスクリプションの更新や請求問題など、ユーザーが直接関与しないイベントに影響します。 できるだけ早くサーバー間の設定を完了し([App Store](enable-app-store-server-notifications) | [Play Store](enable-real-time-developer-notifications-rtdn))、ストアが接続を確立するまで[待機](#data-delays)してください。 不足している App Store Connect のデータは Adapty に[手動でアップロード](importing-historical-data-to-adapty)できます。 ## データの欠落 \{#missing-data\} ### 古いバージョンのアプリを使用しているユーザー \{#users-with-out-of-date-app-versions\} 一部のユーザーが Adapty SDK を含まない古いバージョンのアプリを使用している場合、Adapty はそれらのユーザーのデータを受信できません。そのため、Adapty と他のソースの数値が乖離します。 ### インテグレーションの問題 \{#integration-issues\} 一部の Adapty インテグレーション(Adjust や AppsFlyer など)は、動作するためにアプリケーションコードの追加が必要です。Adapty ダッシュボードを設定しても、アプリケーションを更新していない場合、必要なデータが Adapty に表示されません。 ### 過去データの欠落 \{#missing-historical-data\} Adapty は、[手動でインポート](importing-historical-data-to-adapty)しない限り、アプリケーションの過去データにアクセスできません。チャートの[期間](controls-filters-grouping-compare-proceeds#set-the-date-range)が Adapty を導入する前から始まっており、過去データをインポートしていない場合、その値は他のソースと異なります。 ## データの遅延 \{#data-delays\} Adapty はアプリケーションの経済状況をほぼリアルタイムで分析することを目指しています。ただし、以下の制限と例外があります: * Adapty を最初に導入した際、データはすぐに表示されない場合があります。 * サードパーティプラットフォームとのインテグレーションを有効にした際、データが完全に同期されるまでに遅延が生じる場合があります。 * Adapty がストアのデータを受信してから、Analytics ページで処理・表示されるまでに**15〜30 分**かかります。 * 関係する変数の数が多いため、Adapty とサードパーティ間のデータ交換は**常にリアルタイムとは限りません**。 * 一部の高度な指標([コホート予測](predicted-ltv-and-revenue)など)の計算には一定量のデータが必要です。十分なデータが集まったときのみ、Adapty はこれらの計算を実行します。 ## 時間とカレンダー \{#time-and-calendar\} #### 日付とタイムゾーン \{#dates-and-timezones\} データの相違として認識される最も一般的な原因の一つが、タイムゾーン設定の違いです。 Adapty は `UTC` タイムゾーンを基準に日数をカウントします。別のプラットフォームが異なるタイムゾーンを使用している場合、計算結果が異なります。スケールを大きくすると差異は小さくなります。 アプリケーションごとに[タイムゾーン設定を変更](general#3-reporting-timezone)できます。 #### Apple の会計カレンダー \{#the-apple-fiscal-calendar\} Apple は販売期間と支払い日を決定するために独自の[会計カレンダー](https://adapty.io/apple-fiscal-calendar/)を使用しています。 カレンダーの各「月」は**4 週または 5 週**で構成されており、**隣接するカレンダー月の日数が含まれる場合があります**。支払いは通常、販売期間終了後 30〜45 日以内に行われます。 例えば、「2026 年 1 月」の販売期間は、カレンダー月の開始より 4 日前となる 2025 年 12 月 28 日から始まります。この期間の推定支払い日は 3 月 5 日です。 Apple の支払いレポートのデータをカレンダー月と比較しないでください。代わりに、必要な販売期間に対応する[カスタム期間](controls-filters-grouping-compare-proceeds#set-the-date-range)を選択してください。 #### トランザクションの日付 \{#transaction-dates\} 一部のサービス(例:AppsFlyer)では、トランザクションの表示に[コホート](analytics-cohorts)ルールを適用し、トランザクションが発生した日付ではなく、アプリのインストール日に帰属させる場合があります。 ## 収益の計算 \{#revenue-calculation\} ### 手数料と税金 \{#fees-and-taxes\} [設定](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)によって、Adapty チャートは**グロス収益**、**ストア手数料差し引き後の収益**、または**ストア手数料と税金差し引き後の収益**を表示できます。 一部のストアやサードパーティプラットフォームでは、グロス収益を表示する機能がなかったり、税金を自動的に差し引いたりする場合があります。2 つの異なる収益チャート間で相違が見られる場合は、比較が適切かどうかを確認してください。 ### キャンセルと返金 \{#cancellations-and-refunds\} プラットフォームによって返金データの表示方法が異なります。Adapty は返金をマイナスの収益として扱います。ユーザーがサブスクリプションを購入し、翌日に返金を申請した場合、両方のイベントが Adapty チャートに反映されます(それぞれ別の日に)。他のプラットフォームでは、返金額を元のトランザクションから差し引く場合があります。 ## サンドボックス購入 \{#sandbox-purchases\} [イベントフィード](event-feed)にはサンドボックスアカウントによる購入が表示されます。アナリティクスチャートには表示されません。ただし、過去のインポートデータにサンドボックス購入が含まれている場合、Adapty はそれらを区別できないため、チャートに過去のサンドボックス購入が反映されます。 ## インストールとダウンロード \{#installs-and-downloads\} ストア(特に Apple App Store)はユーザーのダウンロードを直接追跡できます。統計にはアプリがインストールされたものの、一度も起動されなかったケースが含まれる場合があります。 Adapty は[インストールの定義](general#4-installs-definition-for-analytics)に関わらず、ユーザーがアプリを起動したときのみインストールを記録できます。 ## 国とストア \{#country-and-store\} 正確なレポートを確保するために、Adapty はユーザーの国を IP アドレスから[推測する場合があります](controls-filters-grouping-compare-proceeds#filter-and-group-data)。ストアは常にダウンロードと購入を特定のアプリストアに帰属させます。 両者を明確に区別する必要がある場合は、`Country by store account` 属性を持つ[新しいユーザーセグメントを作成](segments)し、[セグメントでアナリティクスをフィルタリング](controls-filters-grouping-compare-proceeds#filter-and-group-data)できます。 ## プロダクトの価格 \{#product-pricing\} 誤ったプロダクト価格が収益の相違を引き起こしている場合、価格を変更しても遡及的には修正されません。既存のトランザクションの価格を変更するには、正しいデータをインポートして強制的に上書きする必要があります。 価格変更後にユーザーが古い購入を復元した場合、Apple は購入価格を誤って報告する場合があります。Adapty が正しい値を反映するには、過去データをインポートする必要があります。 ## アトリビューションの競合 \{#attribution-conflicts\} Adapty は各トランザクションに対して[単一のアトリビューションソース](attribution-integration#prevent-data-issues)のみ使用できます。このデータを後から上書きすることはできません。 セットアップに互いに矛盾する複数のアトリビューションプロバイダーが含まれている場合、2 つの異なるプラットフォーム上の同じトランザクションが 2 つの異なるトラフィックソースを持つように見える場合があります。 ## 用語の違い \{#differences-in-terminology\} プラットフォームによっては、同じ概念に異なる名称を使用している場合があります。[収益](#fees-and-taxes)に関連する指標はプラットフォームによって名称が異なります: | Adapty | App Store Connect | Google Play Console | |--------|-------------------|----------------------| | **Gross revenue** | Sales | Gross Revenue | | **Proceeds after store commission** | N/A | N/A | | **Proceeds after store commission and taxes** | Proceeds | Earnings | | **ARPPU** | Proceeds per paying user | ARPPU | 他の指標も定義が異なる場合があります: - **サブスクリプション**: - Adapty は新規トライアルをサブスクリプションとしてカウントしません。[新規サブスクリプション](reactivated-subscriptions)は常に金銭的なトランザクションから開始されます。 - Google Play Console などの他のプラットフォームでは、最初の支払いが行われる前であっても、**各トライアルを新規サブスクリプションとしてカウント**する場合があります。 - **リテンション**: - Adapty はサブスクリプションの更新回数に基づいてリテンションを測定します。 - App Store Connect は、指定された日にアプリケーションを開いたユーザーをリテインしたとみなします。サブスクリプションを持たないユーザーもカウントされますが、その日にアプリを開かなかったサブスクリプションユーザーはカウントされません。 - Google Play Console の「Retained Installers」指標は、アプリケーションがユーザーのデバイスにインストールされたままの日数に基づいてリテンションを測定します。アプリを開かないユーザーもこの指標にカウントされます。 ## 新規サブスクリプション指標と `subscription_started` イベント \{#new-subscriptions-metric-vs-the-subscription_started-event\} [新規サブスクリプション](reactivated-subscriptions)指標と `subscription_started` [インテグレーションイベント](events)はそれぞれ異なるものをカウントするため、合計値は一致しません。この指標はトライアルなしで行われた初回購入とトライアルから有料への転換の両方をカウントします。`subscription_started` イベントはトライアルなしの初回購入のみで発火します。トライアルが有料に転換した場合、Adapty は代わりに `trial_converted` を送信します。その結果、アプリにトライアル転換がある場合、新規サブスクリプション数は `subscription_started` イベント数より多くなります。 --- # File: predicted-ltv-and-revenue --- --- title: "コホートでの予測" description: "AdaptyのAI予測分析を活用して、LTVと収益を予測しましょう。" --- Adaptyの予測は、次の質問に答えるために設計されています。 1. ユーザーコホートの予測ライフタイムバリュー(LTV)はどのくらいか? 2. 将来的に最も高い収益を生み出す可能性が高いコホートはどれか? 3. 予測されるリターンをもとに、どのくらい投資できるか? Adapty Predictionsを使えば、収益や成長に関してデータに基づいた意思決定ができます。 Adaptyの予測モデルは、アプリのユーザーコホートの長期的な収益ポテンシャルを推定します。各コホートについて、収益・有料サブスクライバー数・平均LTVが今後どのように推移するかを予測します。これにより、ユーザー獲得・マーケティング戦略・プロダクト開発に関してより的確な意思決定が可能になります。 Adapty は、課金ユーザーのコホートに対して、予測ライフタイムバリュー(LTV)と予測収益を提供しています。予測はコホート分析ページに表示され、コホート作成から 3、6、9、12、18、24 ヶ月後の値が確認できます。 履歴データが非常に少ないアプリの場合、モデルはアプリ横断の平均値にフォールバックするため、新しいアプリの予測は実際のユーザー行動を完全には反映していない可能性があります。 ## モデルの仕組み \{#how-the-model-works\} Adapty の予測モデルは、過去のコホートデータの継続率パターンを使って、将来の収益と LTV を予測します。 アプリとサブスクリプションの種類の組み合わせごとに、更新期間ごとの有料サブスクライバー数と総収益の変化を計測します。アプリの過去のコホートをもとに、サブスクライバー向けと収益向けの2つの継続率を算出し、その値を新しいコホートに適用することで、コホート作成から3・6・9・12・18・24か月後の成長を予測します。使用するデータは完全に匿名化されています。 このモデルは、各コホートに対して2つの値を出力します。 - **Predicted revenue**: 選択したホライズン内にコホートが生み出すと予測される総収益。 - **Predicted LTV**: 予測収益をコホート内の予測支払いサブスクライバー数で割った値。 ### アプリ固有のウェイトとクロスアプリのウェイト \{#app-specific-and-cross-app-weights\} デフォルトでは、コホートの予測には、そのアプリ自身の過去のコホートから学習した保持率ウェイトが使用されます。これにより、アプリ固有のユーザー行動が反映されます。 アプリに特定の予測期間に対する十分な履歴データがない場合、Adapty はその同じサブスクリプションタイプを持つすべてのアプリの平均リテンションウェイトにフォールバックします。たとえば、まだ6か月しか経過していないアプリの12か月予測には、クロスアプリフォールバックが使用されます。このフォールバックは予測期間ごとに独立して適用されるため、同じコホートでも3か月の予測にはアプリ固有のウェイトを使用し、12か月の予測にはクロスアプリのウェイトを使用するといったことが可能です。 ### 利用可能時期と更新頻度 \{#availability-and-updates\} 予測は、コホートが最初の更新期間を完了した後に利用可能になります。週次サブスクリプションでは作成から約 1 週間後、月次サブスクリプションでは約 4 週間後が目安です。以降は最新のトランザクションデータを使って毎日更新されるため、コホートの動向に合わせた最新の予測が常に提供されます。 ### 制限事項 \{#limitations\} - **データの質**:コホートの動作が通常と異なる場合や、有料サブスクリプション者が非常に少ないコホートは精度が低下します。有料サブスクリプション者が 100 名未満のコホートは、モデルのトレーニングデータから除外されます。 - **新しいアプリ**:十分な履歴がないアプリにはアプリ横断のフォールバック重みが使われるため、そのアプリ固有のユーザー行動を反映しない場合があります。 - **コホートの経過期間**:指定した予測期間をコホートが超えると、その予測は非表示になります。たとえば、3 ヵ月予測は 3 ヵ月を過ぎると表示されなくなり、24 ヵ月を超えたコホートには予測が表示されません。 ## ダッシュボードでの確認 \{#in-the-dashboard\} 予測を確認するには、Adapty ダッシュボードのコホート分析ページに移動してください。コホートの詳細については、[コホート分析](analytics-cohorts)をご覧ください。 <img src="/assets/shared/img/4d808b4-Export-1691486610612.gif" alt="予測収益と予測 LTV 列を表示したコホート分析ページ" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **Predicted revenue** 列は、コホート作成後の選択した期間内に、サブスクライバーのコホートが生み出すと予測される総収益を示します。この値は、アプリの過去のコホートリテンションパターンをもとに、Adapty の予測モデルを使って算出されます。 **Predicted LTV** 列は、選択したコホートの各ユーザーの推定生涯価値を示します。この値は、予測収益をコホート内の予測課金ユーザー数で割ることで算出されます。 ### 予測期間の選択 \{#select-the-horizon\} 予測期間を変更するには、**Predictions** ドロップダウンから値を選択してください。選択できるオプションは、コホート作成から 3・6・9・12・18・24 ヵ月後です。 ### プロダクトでフィルタリング \{#filter-by-product\} 予測収益と LTV をプロダクト別にフィルタリングできます。デフォルトではすべての購入データをもとに予測が構築されます。プロダクトでフィルタリングすると、各プロダクトの貢献度を確認できます。 <img src="/assets/shared/img/66a9c61-Export-1691486288948.gif" alt="プロダクト別にフィルタリングされたコホート分析" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 予測が利用できない場合 \{#when-predictions-are-unavailable\} コホートの予測を生成できない場合、「Predicted Revenue(予測収益)」列と「Predicted LTV(予測LTV)」列には値の代わりにダッシュ(—)が表示されます。これはいくつかの理由で発生する可能性があります: - **コホート作成からの時間が不足している**: 予測は、コホートが最初の更新期間を完了した後にのみ利用可能になります。週次サブスクリプションの場合は約1週間、月次サブスクリプションの場合は約4週間です。 - **コホートサイズが小さい**: 有料サブスクライバーの数が少なすぎるため、信頼性の高い予測を生成できません。 - **コホートの挙動が異常**: コホートがモデルの想定するパターンから大きく外れています。データが蓄積されるにつれて数週間後に解決する場合があります。 - **ホライズンを超過**: コホートが選択した予測ホライズンより古い。たとえば、3か月予測はコホートが3か月を経過すると非表示になり、12か月予測は12か月後に非表示になります。また、24か月を超えたコホートには予測が表示されません。 :::warning 予測を有効にする際は、収益とLTVの予測データがAdaptyダッシュボードに反映されるまで、最大24時間の遅延が発生する場合があることにご注意ください。 ::: --- # File: predictions-in-ab-tests --- --- title: "A/B テストの予測" description: "A/B テストの予測がサブスクリプション価格戦略の改善にどう役立つかを学びましょう。" --- Adapty の A/B テスト機能における予測分析のドキュメントへようこそ。このツールは、実行中の A/B テストの将来の結果に関するインサイトを提供し、Adapty の ML ベースの予測でデータに基づいた意思決定を素早く行えるよう支援します 🚀 ### A/B テストの予測とは? \{#what-are-ab-test-predictions\} Adapty の A/B テスト予測は、高度な機械学習技術(勾配ブースティングモデル)を活用して、A/B テストで比較されるペイウォールの長期的な収益ポテンシャルを予測します。 この予測モデルにより、テスト実行中に観察できる指標だけに頼るのではなく、1 年後の予測収益に基づいて最も効果的なペイウォールを選択できます。これにより、データが蓄積されるのを何週間も待つことなく、より確実かつ迅速に勝者を決定できます。 ### モデルはどのように機能するのか? \{#how-does-the-model-work\} このモデルは、さまざまなカテゴリのアプリから収集した大量の A/B テスト履歴データで学習されています。実験開始から 1 年後にペイウォールが生み出す収益を予測するために、幅広い特徴量を組み込んでいます。これらの特徴量には以下が含まれます。 - 異なる期間にわたるユーザーのトランザクションとコンバージョン率 - ユーザーの地理的分布 - プラットフォームの利用状況(iOS または Android) - オプトアウト率と返金率 - サブスクリプションプロダクトとその期間(日次・月次・年次など) - その他のトランザクション関連データ このモデルはペイウォールのトライアル期間も考慮しており、ユーザーがすでにコンバージョンしたかのように収益を予測するために、履歴のコンバージョン率を使用しています。アクティブなトライアルが将来的に収益をもたらす可能性についても考慮するため、トライアルオファーのあるペイウォールとないペイウォールを公平に比較できます。 ### 予測 P2BB と通常の P2BB の違いは? \{#how-is-predicted-p2bb-different-from-just-the-p2bb\} Adapty の A/B テストはベイズアプローチを採用しています。具体的には、ユーザーあたりの収益(「1,000 ユーザーあたりの収益」)の分布をモデル化し、一方の分布がもう一方よりも偶然ではなく「真に」優れている確率を計算します。これが「ベスト確率(P2BB)」と呼ばれるものです(詳細なアプローチについては[こちら](maths-behind-it)をご覧ください)。 重要な点として、この計算はテストが実行された期間中に蓄積された収益のみに基づいています。たとえば、年次サブスクリプションと週次サブスクリプションを比較するテストを実行する場合、どちらが優れているかを真に理解するまでに非常に長い時間がかかります。同様に、A/B テストでトライアルサブスクリプションと非トライアルサブスクリプションを比較する場合も同じ問題が起きます。勝者の動向を左右する可能性があるアクティブなトライアルが、収益の計算において常に考慮されないためです。 ここで予測モデルが活躍します。A/B テストの現在の収益分布を持ち、大規模なデータセットで学習されているこのモデルは、将来の収益分布(具体的には 1 年後)を予測できます。そして、その結果として「予測 P2BB」を算出します。これは、テストを 1 年間丸ごと実行した場合に得られるであろう P2BB です。 予測 P2BB が現在の P2BB と矛盾することがある点に注意してください。そのような場合、以下のようにバリアントの行が黄色でハイライト表示されます。 <img src="/assets/shared/img/74577c6-CleanShot_2024-02-15_at_13.08.452x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これは、勝者を確認するためにさらにデータを蓄積するか、A/B テストを深く掘り下げてその原因を調査すべきシグナルと考えています。一般的に、予測 P2BB はより多くのデータを考慮しているため、現在の P2BB よりも予測 P2BB を信頼することを推奨しますが、最終的な判断はもちろんユーザー自身に委ねられています。 ### モデルの精度と確実性 \{#model-accuracy-and-certainty\} このモデルは高い精度を実現しており、平均絶対誤差率(MAPE)は 10% をわずかに下回ります。この精度により、データに基づいた意思決定においてモデルの予測を自信を持って活用できます。 安定性をさらに確保するために、モデルは 3 つの要素に基づく「確実性」基準を採用しています。 - 予測区間が狭い — モデルが結果に高い確信を持っている - テスト内のサブスクリプション数と収益が十分である - テスト開始から少なくとも 2 週間が経過している これら 3 つの基準のうち少なくとも 2 つが満たされた場合に、予測が信頼できるとみなされます。 新しい A/B テストが開始されると、モデルは各ペイウォールについて 1 年先の 1,000 ユーザーあたりの収益(A/B テストのメイン指標)の予測を提供します。予測は確実性基準を満たした場合のみ表示されます。データが不十分な場合、モデルは「予測に必要なデータが不足しています」と表示します。 ### 制限事項と注意点 \{#limitations-and-considerations\} 予測モデルは強力なツールですが、その制限事項を理解しておくことが重要です。 モデルのパフォーマンスは、利用可能なデータの質と代表性に依存します。通常とは異なるコホートの挙動や、学習セットに含まれていない新しいアプリは、予測精度に影響を与える可能性があります。 それでも、予測は最新のデータとユーザー行動を反映するために毎日更新されます。これにより、受け取るインサイトが常に最新の情報に基づいていることが保証されます。 🚧 注意:このツールは、あなたの専門的な判断やアプリ独自のダイナミクスへの理解を補完するものであり、代替するものではありません。これらの予測は、他の指標や市場知識と組み合わせて活用し、情報に基づいた意思決定のためのガイドとしてご利用ください。 --- # File: adapty-ads-manager --- --- title: "Adapty Ads Manager" description: "Apple Adsのリアルタイム分析を取得し、キャンペーンを管理・最適化する" --- **Adapty Ads Manager**は、Apple Ads キャンペーンをより効率的に管理・最適化・スケールするために設計されたオールインワンプラットフォームです。MMPなしで、インストール数、トライアル、サブスクリプション、ライフタイムバリューなどの主要な収益指標とApple Search Adsのパフォーマンスを連携させます。 リアルタイム分析、AIによる予測、スマートな自動化機能により、煩雑な手動での入札調整やスプレッドシート管理、手探りの試行錯誤を排除し、明確なインサイトと迅速なアクションを可能にするツールへと置き換えます。 Adapty Ads Manager で得られるもの: - **[概要](ads-manager-overview)**: すべての主要指標を一目で確認 — 広告費、収益、ROAS、CPA など、それぞれの日次トレンドチャートとともに表示 - **[AI エージェント](ads-manager-ai-agent)**: 自然な言語で質問するだけで、ファネル全体の分析結果とレコメンデーションを取得 - **リアルタイムパフォーマンスデータ**: キャンペーン、広告グループ、キーワードを横断して確認 - **エンドツーエンドの収益トラッキング**: 検索 → インストール → トライアル → サブスクリプション → LTV まで一貫して追跡 - **AI 予測 & レコメンデーション**: 収益性の高いスケーリングを支援 - **一括管理**: 入札、予算、ステータス、構成を一括で操作 - **[ルールベースの自動化](ads-manager-automations)**: キーワードのライフサイクル全体を管理 - **[マーケットインテリジェンス](ads-manager-market-intelligence)**: 50 か国以上にわたる競合他社のキーワード戦略を分析 - **[CPP A/B テスト](ads-manager-cpp-ab-tests)**: カスタムプロダクトページを直接比較し、最良のパフォーマンスを発揮するページを特定 <CustomDocCardList ids={['adapty-ads-manager-get-started', 'ads-manager-overview', 'ads-manager-ai-agent', 'adapty-ads-manager-analytics', 'ads-manager-create-campaign', 'ads-manager-create-ad-group', 'ads-manager-manage-keywords', 'ads-manager-automations', 'ads-manager-market-intelligence', 'ads-manager-cpp-ab-tests']} /> ## Adapty Ads Managerを選ぶ理由は? \{#why-choose-adapty-ads-manager\} **市場で最も正確なデータ**を提供しているからです。 ネイティブのApple Adsコンソールやモバイル計測パートナー(MMP)とは異なり、当社のデータは**リアルタイムで欠損なく、トライアル・サブスクリプション・LTVと完全に連携**しています。遅延やアトリビューションのギャップは一切ありません。 簡単に導入でき、スムーズな操作感で、複数のツールを行き来することなく、すべてを1か所で管理できます。 ## 始めましょう \{#get-started\} Adapty Ads Manager を使い始めるには、[ガイド](adapty-ads-manager-get-started)に従って設定を完了すれば、すぐに利用できます。 --- # File: adapty-ads-manager-get-started --- --- title: "Adapty Ads Managerを使い始める" description: "Apple Adsの過去データをインポートし、ダッシュボードでリアルタイムの更新を受け取り始めましょう" --- [Adapty Ads Manager](adapty-ads-manager)は、Apple Ads向けの最適化・分析プラットフォームです。 このガイドでは、Adapty Ads Managerを2ステップで使い始める方法を説明します。 1. Adapty SDKをインストールし、購入データのトラッキングを開始します。 2. Adapty Ads ManagerをApple Adsアカウントに接続して、過去のデータをインポートし、リアルタイムの更新を追跡します。 :::note Adapty Ads Managerは、**App settings**の[Apple Ads連携](apple-search-ads)を使用しません。 Adapty Ads Managerを使用するには、このガイドで説明するセットアップを完了するだけで十分です。 ::: ## 1. Adapty SDKをインストールする \{#1-install-the-adapty-sdk\} :::important Adapty Ads Manager は**スタンドアロン製品**です。ペイウォール、サブスクリプション、アナリティクスをAdaptyで管理していなくても利用できます。スタック全体をAdaptyに移行する必要はありません。 正確な収益データを取得するための最小構成は、オブザーバーモードでAdapty SDKをインストールし、AdaptyでApp Serverの通知を有効にすることです。 ::: キャンペーンのパフォーマンスと収益データを連携させるには、Adaptyで購入を追跡できるようにしてください: 1. 最初のステップは、アプリ内課金がすでに実装されているかどうかによって異なります: - **Adapty でアプリ内課金をすでに実装している**場合は、この段階で他に何もする必要はありません。 - **Adapty を使わずにアプリ内課金をすでに実装していて**、Adapty への移行を予定していない場合は、オブザーバーモードでお使いのプラットフォーム向けの Adapty SDK をインストールしてください。この段階では、プロジェクトに SDK を追加し、オブザーバーモードを有効にして起動し、トランザクションを報告するだけで十分です: - [iOS](implement-observer-mode) - [Android](implement-observer-mode-android) - [React Native](implement-observer-mode-react-native) - [Flutter](implement-observer-mode-flutter) - [Unity](implement-observer-mode-unity) - [Kotlin Multiplatform](implement-observer-mode-kmp) - [Capacitor](implement-observer-mode-capacitor) - **アプリ内課金をまだ実装しておらず、Adapty を使いたい**場合は、[クイックスタートガイド](quickstart)の手順に従って、購入処理を Adapty に委任してください。 2. App Store から収益に関する更新を直接受け取るには、[Adapty で App Store サーバー通知を有効にしてください](enable-app-store-server-notifications)。 ## 2. Apple Ads を接続する \{#connect-apple-ads\} :::important Apple Ads を Adapty に接続するには、Apple Ads で **Account Admin** ロールが必要です。 ::: 次に、Adapty Ads Manager アカウントを Apple Ads アカウントに接続します。 1. ヘッダーの Adapty ロゴをクリックし、**Search Ads** を選択します。 2. **Continue with Apple** をクリックします。 3. Appleアカウントにサインインします。 4. Adapty Ads Managerに付与するアクセス権を選択します。 - **Read and Write**: すべてのキャンペーングループへのアクセスを提供します。 - **Limited access**: 特定のキャンペーングループを選択し、**Read & Write** ロールを割り当てて、そのグループのみにアクセスを制限します。 5. **Grant access** をクリックします。 それ以降、AdaptyはApple Adsの過去のデータの同期を開始します。Adapty Ads Managerの探索はすぐに始められますが、すべての過去のデータがインポートされるまでには多少時間がかかります。 ## 次のステップ \{#whats-next\} トランザクションデータの同期が完了したら、次の操作方法を確認しましょう。 - [キャンペーン、広告グループ、キーワードを管理する](ads-manager) - [キャンペーンパフォーマンスに基づいて入札を自動調整するオートメーションルールを設定する](ads-manager-automations) --- # File: ads-manager-overview --- --- title: "Adapty Ads ManagerのOverview" description: "Apple Adsの主要な指標をすべて1か所で確認でき、各指標にはトレンドチャートが付いています。" --- **Overview**ページでは、Apple Adsの主要な指標をすべて1か所で確認でき、各指標にはトレンドチャートが表示されます。 デフォルトでは、連携済みのすべてのアプリのデータが表示されます。特定のアプリのみ表示するには、ヘッダーのアプリドロップダウンから選択してください。 Adapty Ads Manager の左サイドバーにある **Overview** をクリックして開きます。 :::tip 各指標を確認する代わりに、注意が必要な項目の要約を確認するには、[AI エージェント](ads-manager-ai-agent)に質問してください。 ::: ## 指標 \{#metrics\} 各指標は、選択した期間のトレンドチャートとともにカードとして表示されます。指標の定義と計算式については、[Apple Ads Managerの指標](adapty-ads-manager-metrics)をご覧ください。 ## 表示する指標の設定 \{#configure-displayed-metrics\} **Overview** ページに表示する指標を変更するには、**Edit metrics** をクリックします。そこから以下の操作が可能です: - **指標を追加する**:**Add metric** をクリックし、追加したい指標のチェックボックスを選択します。 - **指標を削除する**:**Add metric** パネルでチェックボックスをオフにするか、指標の横にある **×** をクリックします。 ## コントロール \{#controls\} ページ上部のコントロールを使って、**Overview** ページの表示内容を調整できます: - **日付範囲**: プリセット期間(**Last 7 days**、**Last 30 days**、**Last 90 days**)を選択するか、カスタム範囲を入力します。すべてのチャートと集計値が選択した期間に合わせて更新されます。 - **チャートタイプ**: 積み上げ縦棒グラフ、折れ線グラフ、円グラフの表示を切り替えます。 - **収益の表示方法**: 収益指標の計算方法を選択します。 - **Gross revenue**: 控除前の総収益。 - **Proceeds after store commission**: Appleの手数料を差し引いた後の収益。 - **Proceeds after store commissions and taxes**: Appleの手数料と該当する税金の両方を差し引いた後の純収益。 --- # File: ads-manager-ai-agent --- --- title: "Adapty Ads ManagerのAIエージェント" description: "Apple Adsアカウントについて自然言語で質問し、ファネル全体の回答とレコメンデーションを取得できます。" --- AIエージェントは、Adapty Ads Managerに組み込まれたチャットアシスタントです。Apple Adsアカウントについて自然言語で質問できます。 インプレッション、インストール、トライアル、サブスクリプション、収益のファネル全体を参照するため、クリック数だけでなく、収益やROASについても分析します。Adaptyの組み込みアトリビューション機能により、このファネルデータをほぼリアルタイムでエージェントに提供できます。 エージェントはアドバイザリー機能として動作します。アカウントを分析して推奨アクションを提示しますが、キャンペーン、入札額、予算を直接変更することはありません。 ## 質問できる内容 \{#what-you-can-ask\} Apple Ads アカウントに関する任意の内容をエージェントに質問できます。エージェントができること: - **アカウント概要**: アカウント全体の状況を要約し、優先的に対応すべき事項を提示します。 - **パフォーマンス不足のオブジェクト**: 効果が出ていないキャンペーンやコンバージョンをもたらさないキーワードを特定します。 - **予算**: 日予算の上限に達したキャンペーンを特定し、引き上げるべきかどうかを提案します。 - **入札と停止の判断**: 入札を引き上げるべきか維持すべきか、またキャンペーンを停止すべきか継続すべきかを推奨します。 - **地域別パフォーマンス**: パフォーマンスが高い国と低い国を示し、予算の再配分先を提案します。 ## 質問の例 \{#example-questions\} エージェントが最も役立つ回答をするのは、指標、期間、および検討している意思決定を具体的に示したときです。例えば: - どのキーワードが最も高いROASを持ち、どのようにバジェットを配分すべきか? - 過去30日間でトライアルやサブスクリプションに至らなかった高スペンドのキーワードはどれか、また一時停止すべきものはどれか? - 収益性を維持しながら日次予算上限に達したキャンペーンはどれか、それぞれどれだけ引き上げるべきか? - 国別にROASとサブスクリプション獲得コストを比較して、バジェットをどこに移すべきか? - このキーワードの入札額を下げるべきか、一時停止すべきか、それとも様子を見るべきか?判断の根拠となるファネルデータを見せてほしい。 - 安価なインストールを集めながら有料サブスクリプションへの転換率が低いキーワードはどれか? ## AIエージェントを開く \{#open-the-ai-agent\} エージェントを開くには、アカウントヘッダーの **Ask AI Agent** をクリックします。 質問する前に、エージェントのスコープを設定するためにアプリを選択してください。その後、質問を入力して送信します。 エージェントはバックグラウンドでタスクを処理するため、回答が準備される間もAdapty Ads Managerで作業を続けることができます。 ## 過去のチャットを参照する \{#access-previous-chats\} コンパクトパネルには現在の会話のみ表示されます。過去のチャットを確認するには、パネル上部の展開ボタンをクリックしてフルスクリーンモードに切り替えてください。左側に **Chats** リストが表示され、過去の会話を検索したり、**New chat** で新しい会話を始めたりできます。 ## 制限事項 \{#limitations\} AI エージェントはアドバイザリー機能です。推奨アクションを提示しますが、実際に適用するのはあなた自身です。推奨内容を確認したうえで、[キャンペーンの管理](ads-manager-create-campaign)や[キーワードの管理](ads-manager-manage-keywords)を行う際に変更を適用してください。 --- # File: adapty-ads-manager-metrics --- --- title: "Apple Ads Managerの指標" description: "Apple Ads Managerでアプリのアナリティクスを確認します。" --- Apple Ads Managerでは、キャンペーンのパフォーマンスとユーザー行動を測定するための包括的な指標が提供されています。 ## パフォーマンス \{#performance\} | 指標 | 説明 | |--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Spend | 広告のタップごとのコストの合計。 | | Impressions | 指定期間内にApp Storeの検索結果でスポンサー広告が表示された回数。 | | CPM | 広告1,000インプレッションあたりの平均支払額。平均CPM = Spend / (Impressions / 1000) ※ CPT課金モデルのApp Store検索結果キャンペーンでは、実効CPMが表示されます。 | | Taps | 指定期間内にユーザーが広告をタップした回数。 | | CPT | 広告1タップあたりの平均支払額。平均CPT = Spend / Taps | | TTR | 広告がタップされた回数をインプレッションの合計数で割った値。TTR = Taps / Impressions × 100% | | Downloads (Total) | 指定期間内に広告からのタップスルーおよびビュースルーによる新規ダウンロードと再ダウンロードの合計数。 | | Downloads (View-Through) | 広告を24時間以内に閲覧したがタップしなかったユーザーによるダウンロードと再ダウンロードの数。 | | Downloads (Tap-Through) | 30日以内に広告をタップしたユーザーによる新規ダウンロードと再ダウンロードの合計数。 | | Avg CPA (Total) | 合計平均獲得単価(CPA)は、キャンペーンの総支出を、指定期間内に広告の閲覧またはタップによって発生したダウンロード数で割った値。 | | Avg CPA (Tap-Through) | タップスルーの平均獲得単価(CPA)は、キャンペーンの総支出を、指定期間内のタップスルーダウンロード数で割った値。 | | Download Rate (Total) | 広告の閲覧またはタップによって発生したダウンロードの合計を、指定期間内のタップ総数で割った値。計算式:Taps > 0 の場合 (Total Downloads / Taps) × 100%、そうでない場合は 0% | | Download Rate (Tap-Through) | 広告タップによって発生したダウンロード数を、指定期間内のタップ総数で割った値。計算式:Taps > 0 の場合 (Tap-Through Downloads / Taps) × 100%、そうでない場合は 0% | | DPM (Total) | Downloads per Mille(DPM)は1,000インプレッションあたりのダウンロード数。計算式:Impressions > 0 の場合 (Total Downloads / Impressions) × 1000、そうでない場合は 0 | ## コンバージョン \{#conversions\} :::note Revenue、ARPU、ARPPU、ARPAS、ROAS、ROI はコホート指標としても利用でき、ユーザーグループの時系列分析に活用できます。 ::: | 指標 | 説明 | |--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Conversions | Conversionsは、レポート期間中のコンバージョンイベントの合計数です。計算式:トライアル開始数 + サブスクリプション開始数 + 非サブスクリプション数 | | Conversion CR | Conversion CR(コンバージョン率)は、総ダウンロード数のうちコンバージョンに至った割合です。計算式:総ダウンロード数 > 0 の場合は(コンバージョン数 / 総ダウンロード数)× 100%、それ以外は 0% | | Cost per Conversion | Cost per Conversionは、総広告費をコンバージョン数で割った値です。計算式:コンバージョン数 > 0 の場合は 広告費 / コンバージョン数、それ以外は 0 | | Revenue | Revenueは、選択した期間内にアプリでの購入・更新・その他の収益化コンバージョンから得られた総収益額です(ストア手数料控除前)。 | | ROAS | ROAS(広告費回収率)は、広告による収益を広告費で割ってパーセントで表したものです。計算式:広告費 > 0 の場合は(収益 / 広告費)× 100%、それ以外は 0% | | ROI | ROI(投資収益率)は、広告費に対する純利益を計算します。計算式:広告費 > 0 の場合は((収益 − 広告費)/ 広告費)× 100%、それ以外は 0% | | ARPU | ARPU(ユーザー平均収益)は、ユーザー1人あたりの平均収益です。総収益をユニークユーザー数で割って算出します。例:収益 $60,000 / 5,000ユーザー = ARPU $12。このARPUをインストール単価(CPI)と比較することで、マーケティングキャンペーンの効果を評価できます。 | | ARPPU | ARPPU(課金ユーザー平均収益)は、課金ユーザー1人あたりの平均収益です。総収益をユニーク課金ユーザー数で割って算出します。例:収益 $60,000 / 1,000課金ユーザー = ARPPU $60。課金顧客が平均的にどれだけの収益をもたらすかを把握するのに役立ちます。 | | ARPAS | ARPASは、アクティブサブスクライバー1人あたりの平均収益です。総収益 / アクティブサブスクライバー数で算出します。ここでいうサブスクライバーとは、トライアル期間またはサブスクリプションを有効化したユーザーを指します。例:収益 $60,000 / 1,500サブスクライバー = ARPAS $40。 | | Installs | Installsは、初めてアプリをインストールしたユーザー数と、既存ユーザーによる再インストール数の合計です。同一ユーザーが複数の端末にインストールした場合もカウントされます。なお、ダウンロードが途中で中断された場合や、完了前にキャンセルされたインストールはカウントされません。 | | Installs CR | Installs CR(コンバージョン率)は、総ダウンロード数のうちアプリをインストールしたユーザーの割合です。計算式:総ダウンロード数 > 0 の場合は(インストール数 / 総ダウンロード数)× 100%、それ以外は 0% | | CPI | CPI(インストール単価)は、Adaptyが計測したインストール1件あたりのコストです。計算式:インストール数 > 0 の場合は 広告費 / インストール数、それ以外は 0 | | Trials | Trialsは、レポート期間中に新たに開始されたトライアルサブスクリプションの数です。 | | Trial CR | Trial CR(コンバージョン率)は、総ダウンロード数のうちトライアルを開始した割合です。計算式:総ダウンロード数 > 0 の場合は(トライアル数 / 総ダウンロード数)× 100%、それ以外は 0% | | Cost per Trial | Cost per Trialは、総広告費を新規トライアル開始数で割った値です。計算式:トライアル数 > 0 の場合は 広告費 / トライアル数、それ以外は 0 | | Trials converted | Trials convertedは、レポート期間内にトライアルサブスクリプションから有料サブスクリプションへ正常に転換した件数です。 | | Trial converted CR | Trial converted CR(コンバージョン率)は、トライアルサブスクリプションのうち有料サブスクリプションへ転換した割合です。計算式:トライアル数 > 0 の場合は(転換済みトライアル数 / トライアル数)× 100%、それ以外は 0% | | Cost per Trial converted | Cost per Trial convertedは、総広告費を同期間内の転換済みトライアル数で割った値です。計算式:転換済みトライアル数 > 0 の場合は 広告費 / 転換済みトライアル数、それ以外は 0 | | Subscriptions | Subscriptionsは、レポート期間中の新規サブスクリプション登録数(トライアルなし)の合計です。 | | Subscription CR | Subscription CR(コンバージョン率)は、総ダウンロード数のうち無料トライアルなしで有料サブスクリプションを開始した割合です。計算式:総ダウンロード数 > 0 の場合は(サブスクリプション数 / 総ダウンロード数)× 100%、それ以外は 0% | | Cost per Subscription | Cost per Subscriptionは、総広告費を新規サブスクリプション開始数で割った値です。計算式:サブスクリプション数 > 0 の場合は 広告費 / サブスクリプション数、それ以外は 0 | | Non-subscriptions started | Non-subscriptions startedは、サブスクリプション以外のアプリ内買い切り購入の合計件数です。 | | Non-subscription CR | Non-subscription CR(コンバージョン率)は、総ダウンロード数のうち非サブスクリプション購入を行った割合です。計算式:総ダウンロード数 > 0 の場合は(非サブスクリプション開始数 / 総ダウンロード数)× 100%、それ以外は 0% | | Cost per Non-subscription | Cost per Non-subscriptionは、総広告費を非サブスクリプション購入数で割った値です。計算式:非サブスクリプション開始数 > 0 の場合は 広告費 / 非サブスクリプション開始数、それ以外は 0 | ## 高度なダウンロード \{#advanced-downloads\} | 指標 | 説明 | |--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 新規ダウンロード(合計) | レポート期間内のタップスルーおよびビュースルーによる新規ダウンロードの合計数。 | | 新規ダウンロード(ビュースルー) | 広告を見たがタップせず、かつ過去にアプリをダウンロードしたことがないユーザーによる新規ダウンロード。24時間のウィンドウ内でカウントされます。 | | 新規ダウンロード(タップスルー) | 広告をタップし、過去にアプリをダウンロードしたことがないユーザーによる新規ダウンロード。30日間のアトリビューションウィンドウ内でカウントされます。 | | 新規ダウンロード割合(タップスルー) | タップによる総ダウンロード数のうち、新規ダウンロードが占める割合を示します(30日間のアトリビューションウィンドウ内で広告をタップしたユーザーが対象)。 | | 再ダウンロード(合計) | レポート期間内のタップスルーおよびビュースルーによる再ダウンロードの合計数。 | | 再ダウンロード(ビュースルー) | 24時間のウィンドウ内で広告を見たがタップしなかったユーザーによる再ダウンロード。広告を視聴後、アプリをダウンロードして削除し、同じデバイスまたは別のデバイスで再度ダウンロードした場合にカウントされます。 | | 再ダウンロード(タップスルー) | 30日間のアトリビューションウィンドウ内で広告をタップしたユーザーによる再ダウンロード。広告をタップ後、アプリをダウンロードして削除し、同じデバイスまたは別のデバイスで再度ダウンロードした場合にカウントされます。 | | 再ダウンロード割合(タップスルー) | タップによる総ダウンロード数のうち、再ダウンロードが占める割合を示します。 | ## インサイト \{#insights\} | 指標 | 説明 | |--------|------------------------------------------------------------------------------------------------------------------------------------------| | インプレッションシェア | インプレッションシェアとは、同一の検索キーワードにおける総インプレッション数に対して、自社広告が獲得したインプレッションの割合です。 | | ランク | ランク(現在)は、特定の国や地域において、選択した検索キーワードのインプレッションシェアにおけるアプリの現在の順位です。 | | 検索人気度 | 検索人気度(現在)は、国や地域ごとの検索キーワードの人気度です。1〜5のスケールで評価され、5が最も検索ボリュームが高いことを示します。 | --- # File: ads-manager-create-campaign --- --- title: "Adapty Ads Managerでキャンペーンを管理する" description: "Adapty Ads ManagerでApple Adsキャンペーンを作成・編集する。" --- Adapty Ads ManagerはApple Adsと双方向に連携しています。ほぼリアルタイムのパフォーマンスデータを取得できるだけでなく、ネイティブUIよりもはるかに便利な形で、Adapty ダッシュボードから直接キャンペーンを作成・編集することができます。 Apple Ads のネイティブダッシュボードでキャンペーンを作成すると、24時間以内に Adapty Ads Manager へ自動的に表示されます。 [キャンペーンの詳細な指標を確認する](adapty-ads-manager-analytics)ほか、すべてのキャンペーン設定を管理できます。 - キャンペーンの作成 - 既存キャンペーンの編集 - キャンペーンの開始・一時停止 :::tip 1日の予算上限に達したキャンペーンや費用対効果が出ていないキャンペーンなど、対応が必要なキャンペーンを見つけるには、[AI エージェント](ads-manager-ai-agent)に質問してみましょう。 ::: ## キャンペーンとは \{#what-is-a-campaign\} キャンペーンは1つのアプリに特化し、App Storeの1つのプレースメントで広告を配信します。各キャンペーンには、日予算と、アプリのプロモーション戦略に特化した[広告グループ](ads-manager-create-ad-group)が含まれます。キャンペーンは予算設定に基づいて継続的に支出します。 :::important キャンペーンは単独では機能しません。デフォルト入札額、オーディエンス、キーワードを設定するのは広告グループのレベルです。広告グループがなければ、キャンペーンにはターゲティングも入札も設定されず、配信されません。キャンペーンを作成したら、[少なくとも1つの広告グループを追加](ads-manager-create-ad-group)して有効化してください。 ::: ## キャンペーンを作成する \{#create-campaigns\} キャンペーンを作成するには: 1. **Ads Manager** ページを開き、**+** をクリックします。**Create campaign** を選択してキャンペーンウィザードを起動します。 2. 広告の **placement** を選択し、**Start** をクリックします: | プレースメント | 広告の掲載場所 | | --- | --- | | **Search Results** | App Store 検索結果の上部。 | | **Search Tab** | 検索前に表示される「検索」タブのおすすめアプリ一覧。 | | **Today Tab** | App Store の Today ページ。 | | **Product Pages** | 他のプロダクトページの **You Might Also Like** リスト。関連ページは Apple が自動的に選択します。 | | **Duplicate a Campaign** | 既存のキャンペーンからプレースメント、広告グループ、キーワードを再利用。 | 3. **検索結果キャンペーン**の場合、**キャンペーンタイプ**を選択します。キャンペーンをタイプでグループ化するとレポートデータが整理され、Adapty が適切なキーワード戦略を提案できるようになります。 :::note **Max Conversions** を選択すると、手動でのキーワード選択をスキップし、Apple の自動入札によってコンバージョンが最適化されます。 ::: | キャンペーンタイプ | 説明 | | --- | --- | | **Generic** | アプリの内容を説明する非ブランドキーワード。 | | **Competitor** | 競合他社のブランドキーワード。 | | **Discovery** | Search Matchが自動的に新しいキーワードを発掘し、効果の高いものを収集できる。 | | **Max Conversions** | コンバージョン最適化されたAppleの自動入札。設定ステップで **Target CPA** を指定する。 | | **Brand** | アプリのブランドに関連するキーワード。 | | **Custom** | 定義済み戦略なし。ゼロからキャンペーンを構築する。 | 4. **アプリ**(プロモートしたいもの)と**キャンペーングループ**(キャンペーンを運営・支払いするApple Adsアカウント)を選択します。 5. ターゲットとする**国または地域**を選択します。最適化を簡単にするために、国ごとに1つのキャンペーンを使用してください。 6. キャンペーンの**基本設定**を構成します。オーディエンスターゲティングとキーワードはキャンペーンの[広告グループ](ads-manager-create-ad-group)で設定します。キャンペーンの作成後に追加できます。 | 設定 | 説明 | | --- | --- | | **Campaign name** | アプリ、プレースメント、国から自動入力されます。いつでも編集できます。 | | **Daily budget** | キャンペーンが1日に使用できる金額。 | | **Target CPA** | 自動入札の目標獲得単価。Max Conversionsキャンペーンのみ表示されます。 | | **Ad scheduling** | 任意設定。開始日を指定しない場合、キャンペーンはすぐに開始されます。特定の日時に終了させる場合は終了日を追加してください。 | 与信枠アカウントの場合は、このステップで請求詳細も入力します。 7. サマリーを確認し、内容を確かめたら **Create campaign** をクリックします。 8. [広告グループの設定](ads-manager-create-ad-group)に進みます。キャンペーンは広告グループなしでは実行できません。広告グループがオーディエンスやキーワードを決定します。 ## キャンペーンの編集 \{#edit-campaigns\} 作成済みのキャンペーンを編集するには: 1. 以下のいずれかの方法でキャンペーン設定を開きます: - **Ads Manager > Campaigns** でキャンペーン名をクリックし、右上の **Edit campaign** をクリックします。 - または、キャンペーン名の横にあるチェックボックスを選択し、**Actions > Edit campaign settings** をクリックします。 2. キャンペーン設定を調整します。キャンペーン名、キャンペーンタイプ(検索結果キャンペーンの場合)、国、および1日の予算を編集できます。広告の配置、入札戦略、またはスケジュールを変更するには、代わりに新しいキャンペーンを作成してください。 3. **Save changes** をクリックします。 キャンペーンテーブルの **Campaign type** 列でインラインでキャンペーンのタイプを変更することもできます。 :::note Apple Ads で直接行った編集は自動的に Adapty Ads Manager に同期されますが、反映されるまでに時間がかかる場合があります。 ::: ## キャンペーンのエクスポート \{#export-campaigns\} キャンペーンテーブルをCSVとしてエクスポートするには、テーブル上部のダウンロードアイコンをクリックし、**Export current page** または **Export all pages** を選択します。 **Export all pages** を選択すると、全ページのキャンペーンを1つのファイルにまとめてダウンロードできます。ダウンロードの進行状況はモーダルで確認でき、いつでもキャンセル可能です。以下の任意フィルターを利用できます: - **Enabled only**:アクティブなキャンペーンのみを含めます。 - **With spend ≥**:指定した閾値以上の支出があるキャンペーンのみを含めます。 - **Group by country**:キャンペーンの各行を国別に分割して表示します。 テーブルは、ダッシュボード上で表示するよう選択した列のまま、そのままエクスポートされます。 ## キャンペーンの開始・一時停止 \{#launch--pause-campaigns\} Adapty Ads Manager からキャンペーンを開始または一時停止するには: 1. **Ads Manager > Campaigns** に移動します。 2. **Status** 列のキャンペーン名の横にあるトグルをオンまたはオフに切り替えます。 ## キャンペーンを削除する \{#delete-campaigns\} Adapty Ads Manager ではキャンペーンを削除できません。支出を止めながら設定やアナリティクスを保持したい場合は、代わりにキャンペーンを[一時停止](#launch-pause-campaigns)してください。 --- # File: ads-manager-create-ad-group --- --- title: "Adapty Ads ManagerでAdグループを管理する" description: "Adapty Ads ManagerでApple AdsのAdグループを作成・編集します。" --- Adapty Ads ManagerはApple Adsと双方向の連携を実現しています。ほぼリアルタイムのパフォーマンスデータを取得できるだけでなく、ネイティブUIよりもはるかに便利な方法で、Adaptyダッシュボードからキャンペーンを直接作成・編集できます。 Apple Ads のネイティブダッシュボードで広告グループを作成すると、24時間以内に Adapty Ads Manager に自動的に表示されます。 [包括的なキャンペーン指標の確認](adapty-ads-manager-analytics)に加えて、広告グループのすべての設定を管理できます: - 広告グループの作成 - 既存の広告グループの編集 - 広告グループの開始・一時停止 ## 広告グループとは \{#what-is-ad-group\} 広告グループは[キャンペーン](ads-manager-create-campaign)に属し、広告のターゲティングと入札戦略を設定する場所です。各広告グループには、入札設定、オーディエンスターゲティング、そして広告がいつ誰に表示されるかを決める[キーワード](ads-manager-manage-keywords)が含まれています。広告グループを使うことで、キャンペーン内の広告戦略を整理し、異なるターゲティングアプローチをテストできます。 :::important キャンペーンはアドグループなしでは配信できません。アドグループは、デフォルト入札単価・オーディエンス・キーワードを設定するレベルであるため、少なくとも1つのアドグループがないとターゲティングや入札が機能せず、広告が配信されません。まずキャンペーンを作成し、次に[アドグループを少なくとも1つ追加](ads-manager-create-ad-group)してアクティブ化してください。 ::: ## 広告グループを作成する \{#create-ad-groups\} 新しい Apple Ads 広告グループを作成するには: 1. サイドバーメニューから **Ads Manager** に移動します。任意のタブで、テーブル上部の **+** をクリックし、**Create ad group** を選択します。 2. 広告グループを追加するアプリを選択します。 3. 広告グループを追加するキャンペーンを選択します。 4. 広告グループの設定を行います。 - **Ad group name**: ダッシュボードで広告グループを識別・検索するために付けるラベルです。 - **Default max CPT bid**: 広告のタップに対して支払う最大金額です。広告グループ内のすべてのキーワードに適用されます(個別のキーワード入札を設定した場合を除く)。 - **CPA cap (limits impressions)**(任意): タップスルーコンバージョン(ダウンロードやその他のターゲットアクションなど)1件あたりに支払う最大金額を指定します。広告グループ内のすべてのキーワードに対する入札上限を設定します。 入札上限は、指定したCPAキャップにタップスルーのコンバージョン率を掛けて算出されます:`CPA Cap × CR (Tap-Through)`。キーワードの最大CPT入札額がこの値より低い場合は、低い方の最大CPT入札額が適用されます。 たとえば、CPAキャップが$5でタップスルーのコンバージョン率が65%の場合、広告グループ内のすべてのキーワードに適用される最大入札額は$3.25になります。最大CPTが$4に設定されている場合でも、適用される最大入札額は$3.25のままです。 - **Search Match**: 検索マッチを切り替えることで、キーワードを指定しなくても広告を関連する検索に自動的にマッチさせることができます。有効にすると、Apple Ads はアプリのメタデータやカテゴリに関連する検索に対して広告を表示する場合があります。 - **Audience**: 広告を表示するユーザーを決定するターゲティング条件です。 - **All eligible users**: キャンペーンの対象となるすべてのユーザーに広告を表示します。 - **Specific audiences**: 以下を設定して特定のユーザーセグメントをターゲットにします。 - **Devices**: iPad、iPhone、またはその両方をターゲットにします。 - **Customer type**: すべてのユーザー、新規ユーザー、またはリピートユーザーをターゲットにします。 - **Gender**: 性別またはすべてのユーザーをターゲットにします。 - **Age range**: 特定の年齢層またはすべてのユーザーをターゲットにします。 - **Ad scheduling**(オプション、**Specific audiences** を選択した場合に利用可能): 広告の配信開始タイミングを設定します。 - **Start date and time**: 広告グループが広告の配信を開始する日時。 - **End date**(オプション): 広告グループが広告の配信を停止する日時。 5. **Create** をクリックします。 6. キャンペーンのプレースメントタイプが **Search results** の場合は、[キーワードを追加](ads-manager-manage-keywords)して広告の配信を開始できます。その他のプレースメントタイプの場合は、設定完了です。 :::note **Max Conversions**キャンペーンでは、広告グループに**Bidding strategy**トグル(**Standard**または**Automated**)があります。**Default max CPT bid**フィールドはありません。**Automated**を選択すると、目標CPAを設定し、Appleが自動的に入札を最適化します。 ::: ## 広告グループを編集する \{#edit-ad-groups\} 作成済みの広告グループを編集するには: 1. 以下のいずれかの方法でキャンペーン設定を開きます: - **Ads Manager > Ad groups** でキャンペーン名をクリックし、右上の **Edit ad group** をクリックします。 - または広告グループ名の横にあるチェックボックスを選択し、**Actions > Edit ad group settings** をクリックします。 2. 広告グループの設定を調整します。アプリ、キャンペーン、オーディエンスタイプ、開始日時は変更できません。自動化された広告グループでは、名前のみ編集可能です。 3. **Save changes** をクリックします。 広告グループを複製するには、**Ads Manager > Ad groups** で対象の広告グループを選択し、**Actions > Duplicate ad group** をクリックします。 :::note Apple Ads で広告グループに直接加えた変更は、Adapty Ads Manager に自動的に同期されますが、Adapty Ads Manager に反映されるまで時間がかかる場合があります。 ::: ## 広告グループのエクスポート \{#export-ad-groups\} 広告グループのテーブルをCSVとしてエクスポートするには、テーブル上部のダウンロードアイコンをクリックし、**Export current page** または **Export all pages** を選択してください。 **Export all pages** を選択すると、全ページの広告グループが1つのファイルにまとめてダウンロードされます。ダウンロードの進行状況はモーダルで確認でき、いつでもキャンセル可能です。以下の任意フィルターも利用できます: - **Enabled only**:有効な広告グループのみを含めます。 - **With spend ≥**:指定した閾値以上の支出がある広告グループのみを含めます。 - **Group by country**:各広告グループの行を国別に分割します。 テーブルは、表示する列を選択した状態でダッシュボードに表示されている内容がそのままエクスポートされます。 ## 広告グループを開始・一時停止する \{#launch--pause-ad-groups\} Apple Ads Managerから広告グループを開始または一時停止するには: 1. **Ads Manager > Ad groups** に移動するか、キャンペーンページに移動してその広告グループを確認します。 2. **Status** 列の広告グループ名の横にあるトグルをオンまたはオフに切り替えます。 --- # File: ads-manager-manage-keywords --- --- title: "Adapty Ads Managerでキーワードを管理する" description: "Adapty Ads ManagerでApple Adsのキーワード、ネガティブキーワード、SKAGキーワードを追加・管理する方法を説明します。" --- Adapty Ads ManagerはApple Adsと双方向に連携しています。ほぼリアルタイムのパフォーマンスデータを取得できるほか、ネイティブUIよりもずっと便利な方法で、Adapty ダッシュボードから直接キーワードの作成・編集が行えます。 ネイティブのApple Adsダッシュボードでキーワードを作成すると、24時間以内にAdapty Ads Managerに自動的に表示されます。 [包括的なアナリティクスの確認](adapty-ads-manager-analytics)に加えて、キーワードのすべての設定を管理できます: - 広告グループへのキーワードの追加 - 除外キーワードの追加 - SKAG(Single Keyword Ad Group)としてのキーワードの追加 - テーブル内でのキーワードの直接編集 - 複数のキーワードへの一括操作 - キーワードの有効化と停止 :::tip アカウント全体でパフォーマンスの低いキーワード(例:費用が発生しているのにコンバージョンがないキーワード)を見つけるには、[AI エージェント](ads-manager-ai-agent)に聞いてみてください。 ::: ## キーワードとは \{#what-are-keywords\} キーワードとは、App Storeの検索結果に広告を表示させるための検索語句です。[広告グループ](ads-manager-create-ad-group)内に整理され、広告グループは[キャンペーン](ads-manager-create-campaign)に属します。この階層構造により、広告戦略を体系的に管理・整理できます。 :::important キーワードは**Search results**プレースメントタイプのキャンペーンにのみ適用されます。他のプレースメントタイプ(Search TabやProduct Pages)のキャンペーンにはキーワードは使用されません。 ::: ### 標準キーワード \{#standard-keywords\} 標準キーワードは、広告を表示させるために入札する主要な語句です。ユーザーがApp Storeでこれらの語句を検索すると、広告が検索結果に表示される場合があります。 ### 除外キーワード \{#negative-keywords\} 除外キーワードは、アプリに関連しない検索で広告が表示されるのを防ぎます。除外キーワードを追加することで、関連性の低い検索への無駄な費用を削減できます。 除外キーワードは広告グループレベルで追加するか、複数のキャンペーンに同時に適用するクロスグループ除外キーワードとして追加できます。 ### SKAGとしてのキーワード(Single Keyword Ad Group) \{#keywords-as-skag-single-keyword-ad-group\} SKAG(Single Keyword Ad Group)は、1つの広告グループに1つのキーワードのみを含む形で個別の広告グループを作成する戦略です。このアプローチにより、以下のメリットが得られます。 - 価値の高いキーワードに対する入札の精密なコントロール - キーワードレベルでのパフォーマンス分析の向上 SKAGは、パフォーマンスの高いキーワードを特定し、専用の広告グループを通じてその可能性を最大化するのに特に有効です。 ## キーワードを追加する \{#add-keywords\} 広告グループにキーワードを追加するには: :::note **Maximize Conversions** キャンペーンのキーワードには入札単価が適用されません。入札はキャンペーンのCPAターゲットによって自動的に管理されます。**CPT bid** フィールドはこれらのキャンペーンには適用されません。 ::: 1. サイドバーメニューから **Ads Manager** に移動します。任意のタブで、テーブル上部の **+** をクリックし、ドロップダウンから **Add keywords** を選択します。 2. モーダルで、キーワードを追加したいキャンペーンと広告グループを選択します。1つのキャンペーンで広告グループを選択した後、別のキャンペーンを選択してさらに広告グループをリストに追加できます。 3. **Select** をクリックして続行します。 4. **Add keywords** ダイアログで、**Keywords list** フィールドにキーワードを入力します。カンマ区切りのファイルにキーワードが含まれている場合は、その内容を貼り付けると Adapty Ads Manager がキーワードを一括でアップロードします。 5. テーブル内の各キーワードについて、以下を設定します: - **Match type**:**Exact**(完全一致)または **Broad**(部分一致)を選択します - **CPT bid**:このキーワードのタップあたりの最大入札額を設定します。空欄にすると、広告グループのデフォルトの最大 CPT 入札額が使用されます 6. キーワードを確認し、**Add X keywords**(X は追加するキーワード数)をクリックします。 :::important キーワードを保存した後は、マッチタイプを変更できません。マッチタイプを変更する必要がある場合は、キーワードを削除して、希望するマッチタイプで再度追加してください。 ::: ## ネガティブキーワードを追加する \{#add-negative-keywords\} ネガティブキーワードを追加するには: 1. サイドバーメニューから **Ads Manager** に移動します。任意のタブで、テーブル上の **+** をクリックし、ドロップダウンから **Add negative keywords** を選択します。 2. **Add negative keywords to** モーダルで、ネガティブキーワードを追加するレベルを選択します。 - **Selected campaigns**: キャンペーンレベルのネガティブキーワードを追加します。 - **Selected ad groups**: 広告グループレベルのネガティブキーワードを追加します。 - **All ad groups in selected campaigns**: 選択したキャンペーンのすべての広告グループに、広告グループレベルのネガティブキーワードを追加します。 :::note 以下の点に注意してください。 - 広告グループレベルのネガティブキーワードは、キャンペーンレベルのネガティブキーワードより優先されます。 - 選択したキャンペーンのすべての広告グループにネガティブキーワードを追加した場合、後からそのキャンペーンに新しい広告グループを追加する際は手動で追加する必要があります。 ::: 3. **Keywords list** フィールドにネガティブキーワードを入力します。カンマ区切りのキーワードファイルがある場合は、その内容を貼り付けることで、Adapty Ads Manager がキーワードを一括でアップロードします。 4. テーブル内の各キーワードに対して、**Match type** を選択します: - **Exact**:完全一致するキーワードまたは非常に近いバリエーションのみを除外します。 - **Broad**:キーワードおよび関連する検索語句を除外します。 または、キーワードの横にあるチェックボックスを選択して、マッチタイプを一括で変更します。 5. ネガティブキーワードを確認し、**Add X keywords**(X は追加するキーワードの数)をクリックします。 :::note クロスグループのネガティブキーワードは、複数のキャンペーンにまたがって特定の検索語句を一度に除外したい場合に特に役立ちます。時間を節約しながら、広告戦略全体で一貫性を保つことができます。 ::: ## キーワードをSKAGとして追加する \{#add-keywords-as-skag\} キーワードをSKAG(Single Keyword Ad Group)として追加するには: 1. サイドバーメニューから **Ads Manager** を開きます。任意のタブで、テーブル上部の **+** をクリックし、ドロップダウンから **Add keywords as SKAG** を選択します。 2. SKAG 広告グループを作成するキャンペーンを選択します。複数のキャンペーンを選択できます。 3. デフォルトでは、新しい広告グループはすべてのユーザーをターゲットにしたデフォルト設定で作成されます。変更する場合は、**Copy settings from ad group** を選択し、設定のコピー元となる既存の広告グループを選択します。 4. 新しい広告グループの設定を行います。 - **Ad group name prefix**: 各広告グループ名に追加するオプションのプレフィックスです(例:「SKAG_」と入力すると「SKAG_keyword1」「SKAG_keyword2」などが作成されます)。**Tag** をクリックすると、キーワード、キャンペーン名、国をグループ名に動的に追加できます。 - **CPT bid** と **CPA cap**: すべてのキーワードに一括でビッドを設定するか、**Set CPT bid and CPA cap for each word manually** を選択してキーワードごとに個別に設定します。 5. **Keywords list** フィールドにキーワードを入力します。カンマ区切りのキーワードファイルがある場合は、その内容を貼り付けることで Adapty Ads Manager がすべてのキーワードを一括アップロードします。 6. テーブル内の各キーワードについて、**Match type** を選択します。 - **Exact**: 完全に一致するキーワードまたは非常に近いバリエーションのみにマッチします - **Broad**: キーワードおよび関連する検索語にマッチします または隣のチェックボックスを選択して、マッチタイプを一括変更します。 7. **Check for duplicates in target campaign** を選択して、ターゲットキャンペーン内に同一のキーワードがないことを確認します。 8. **Create** をクリックして SKAG 広告グループを作成します。 選択した各キャンペーン内で、キーワードはそれぞれ独自の広告グループに配置されるため、個別に管理・最適化できます。 ## キーワードの編集 \{#edit-keywords\} 既存のキーワードを編集するには: 1. **Ads Manager > Keywords** または **Ads Manager > Negative keywords** に移動してテーブルから編集したいキーワードを見つけるか、キャンペーンページからアドグループページに移動してキーワードを探します。 2. テーブル内で直接値を編集します: - **CPT bid**:入札値をクリックして、新しいタップあたりの最大コスト入札額を入力します - **Status**:トグルスイッチを使用してキーワードを一時停止または有効化します :::note Apple Ads で直接キーワードに加えた変更は Adapty Ads Manager に自動的に同期されますが、Adapty Ads Manager に反映されるまでに時間がかかる場合があります。 ::: ## 一括操作 \{#bulk-actions\} 複数のキーワードに対して一括操作を実行すると、時間を節約してキーワードをより効率的に管理できます。 一括操作を実行するには: 1. **Ads Manager > Keywords** または **Ads Manager > Negative keywords** タブに移動します。 2. 管理したいキーワードの横にあるチェックボックスをオンにして、複数のキーワードを選択します。 3. **Actions** ドロップダウンをクリックし、以下のいずれかのオプションを選択します: - **Add as keywords**: 選択したキーワードを標準キーワードとして追加します - **Add as negative keywords**: 選択したキーワードを除外キーワードとして追加します - **Add as SKAG**: 選択したキーワードに対してSingle Keyword Ad Groupを作成します - **Activate**: 選択したキーワードを有効化します - **Pause**: 選択したキーワードを一時停止します - **Create segment from keywords**: 選択したキーワードからオーディエンスセグメントを作成します - **Copy keywords**: 選択したキーワード名をクリップボードにコピーします - **Edit CPT bids**: 選択したキーワードのCPT入札額を編集します。以下のいずれかの方法で編集できます: - **Set to**: 複数の入札額を特定の金額に設定します。 - **Increase by/decrease by**: 入札額をUSD単位またはパーセント単位で増減します。誤って使いすぎないよう、任意で入札額の上限を設定できます。 - **Set to average CPT**: CPT(タップ単価)指標に合わせて入札額を調整します。乗数係数を設定します。たとえば、パフォーマンスが期待を下回っている場合は0.9、上回っている場合は1.1に設定します。 - **Set to average CPA**: CPA(獲得単価)指標に合わせて入札額を調整します。乗数係数を設定します。 **Negative keywords** タブで使用できるアクションは限られています: - **Add as keywords** - **Add as negative keywords** - **Add as SKAG** - **Delete keywords** :::tip 一括操作は特に以下の場面で役立ちます: - キーワードを異なるタイプ(標準、ネガティブ、SKAG)間で変換する場合 - 複数のキーワードに対して他のマッチタイプのキーワードを素早く追加する場合 - 上位パフォーマンスのキーワードを絞り込んで入札額を調整する場合 - パフォーマンスの低いキーワードを特定して一時停止する場合 ::: ## キーワードのエクスポート \{#export-keywords\} キーワードテーブルをCSVでエクスポートするには、テーブル上部のダウンロードアイコンをクリックし、**Export current page** または **Export all pages** を選択してください。 **Export all pages** を選択すると、全ページのキーワードを1つのファイルにまとめてダウンロードできます。進捗を示すモーダルが表示され、途中でキャンセルすることも可能です。オプションのフィルターが2つ用意されています: - **Enabled only**:有効なキーワードのみを含めます。 - **With spend ≥**:指定した閾値以上の支出があるキーワードのみを含めます。 - **Group by country**:各キーワードの行を国別に分類します。 テーブルは、ダッシュボードで表示するよう選択した列ごと、そのままの形式でエクスポートされます。 ## キーワードレベルのチャートを確認する \{#explore-keyword-level-charts\} キーワードのチャートは、**Ads Manager > Keywords** テーブルから直接開けます。これにより、各キーワードの日別パフォーマンスを詳細に分析できます。 チャートを表示するには、テーブル内のキーワードの横にあるチャートアイコンをクリックします。 デフォルトでは、選択したキーワードの **Spend** 指標が表示されます。 複数の指標を同時に表示して、相関関係や経時的な変化を把握できます。**+** をクリックして指標を追加してください。 **リセット**をクリックして最初からやり直すか、指標のチェックボックスをオフにして非表示にしてください。 ## 入札履歴 \{#bid-history\} キーワードの入札履歴を表示するには、テーブル内のキーワード横にある**チャートアイコン**をクリックします。パネルが開き、**Metrics** と **Bid History** の2つのタブが表示されます。 - **Metrics** タブには、指標の時系列チャートが表示されます。指標の追加と削除は、キーワードレベルのチャートと同様に行えます。**+** をクリックして追加するか、チェックボックスをオフにして非表示にしてください。入札額が変更された各ポイントにマーカーが表示され、マーカーにカーソルを合わせるとその日の正確な入札額を確認できます。これを使って、入札の変更とパフォーマンスの変化を関連付けてください。指標が変更後に下落またはスパイクした場合、マーカーでいつ発生したかを特定できます。 - **Bid History** タブには、各入札変更の一覧が表示されます。日付、変更の種類、変更前後の値、変更の原因(手動変更またはオートメーションルール(ルールのIDとともに表示))が確認できます。 --- # File: ads-manager-manage-ads --- --- title: "Adapty Ads Managerで広告を管理する" description: "Adapty Ads ManagerでApple Ads広告を作成・編集します。" --- Adapty Ads ManagerはApple Adsと双方向に連携しており、ほぼリアルタイムのパフォーマンスデータを取得できるほか、ネイティブUIよりはるかに使いやすいAdaptyダッシュボードから直接広告を作成・編集できます。 Apple のネイティブ広告ダッシュボードで広告を作成すると、24 時間以内に Adapty Ads Manager に自動的に表示されます。 ## 広告とは \{#what-are-ads\} 広告とは、[キャンペーン](ads-manager-create-campaign)内の[広告グループ](ads-manager-create-ad-group)に割り当てられた広告クリエイティブです。1つの広告グループにつき、アクティブな広告を1つ割り当てることができます。 ## 広告を作成する \{#create-ads\} 始める前に、以下を作成しておく必要があります: - **Ad group**(広告グループ)。[Adapty Ads Manager ダッシュボードで直接作成](ads-manager-create-ad-group)できます。 - **Custom product page**(カスタムプロダクトページ)。[Apple Ads で直接設定](https://developer.apple.com/help/app-store-connect/create-custom-product-pages/configure-multiple-product-page-versions/)する必要があります。広告で使用する前に、App Store の審査に通過している必要があります。 :::note 選択した広告グループ内にすでにアクティブな広告がある場合、新しい広告を実行するために一時停止されます。 ::: 新しい Apple Ads の広告を作成するには: 1. サイドバーメニューから **Ads Manager** に移動します。任意のタブで、テーブル上部の **+** をクリックし、**Create ad** を選択します。 2. 広告を配信したいアプリを選択します。 3. 1つ以上の広告グループを選択します。選択した各広告グループにAdaptyが広告を作成します。 4. 広告名を入力します。 5. 広告のステータスを設定します。後で広告を開始したい場合は、**Status** トグルをオフにします。 6. **Select CPP** をクリックします。App Storeに承認済みのアプリのカスタムプロダクトページがすべて表示されます。選択できるカスタムプロダクトページは1つのみです。 7. **Create ad** をクリックします。 ## 広告を編集する \{#edit-ads\} :::note 広告を作成した後は、その名前とステータスを編集できます。CPP の変更や別の広告グループへの移動はできません。 ::: 広告名を編集するには、以下のいずれかの方法を使用してください: - **Ads Manager > Ads** で広告名をクリックします。広告名を編集し、その横にあるチェックマークをクリックします。 - 広告名の横にあるチェックボックスを選択し、**Actions > Edit ad** をクリックします。広告名またはステータスを変更し、**Save changes** をクリックします。 :::note Apple Ads で直接行った広告の編集内容は、Adapty Ads Manager に自動的に同期されますが、Adapty Ads Manager に反映されるまでに時間がかかる場合があります。 ::: ## 広告のエクスポート \{#export-ads\} 広告テーブルをCSVとしてエクスポートするには、テーブル上部のダウンロードアイコンをクリックし、**Export current page** または **Export all pages** を選択してください。 **Export all pages** を選択すると、すべてのページにわたる広告データが1つのファイルにダウンロードされます。ダウンロードの進捗はモーダルで確認でき、いつでもキャンセルできます。また、以下の任意フィルターも利用できます: - **Enabled only**: アクティブな広告のみを含めます。 - **With spend ≥**: 指定した閾値以上の支出がある広告のみを含めます。 - **Group by country**: 各広告の行を国別に分類します。 テーブルは、ダッシュボードに表示されている状態(選択した列)でそのままエクスポートされます。 ## 広告の起動と一時停止 \{#launch--pause-ads\} Adapty Ads Manager から広告を起動または一時停止するには、次のいずれかの方法を使用してください。 - **Ads Manager > Ads** の **Status** トグルをオンまたはオフに切り替える。 - 広告名の横にあるチェックボックスを選択し、**Actions > Edit ad** をクリックして **Status** トグルを切り替え、**Save changes** をクリックする。 --- # File: ads-manager-create-segments --- --- title: "Adapty Ads ManagerでApple Adsアトリビューションに基づくセグメントを作成する" description: "Adapty Ads Managerでキャンペーン、広告グループ、キーワードから2クリックでセグメントを作成します。" --- [Adapty Ads Manager](adapty-ads-manager)でキャンペーン、広告グループ、またはキーワードを選択し、数クリックでセグメントに変換することで、ユーザーの[セグメント](segments)を直接作成できます。これにより、セグメント条件を手動で設定することなく、獲得元に基づいてペイウォールやオファーを簡単にパーソナライズできます。 セグメントを作成したら、それを使って異なるプロダクトや価格を設定したり、A/B テストを実施したり、ペイウォールの外観をカスタマイズしたりできます。 ## ユースケース \{#use-cases\} 以下は、Apple Ads データから作成したセグメントを実際にどのように活用できるかの例です。 - **キーワードベースのペイウォール**。購買意欲の高いキーワードからのユーザーには機能重視のペイウォールを表示し、より広い探索系キーワードからのユーザーには汎用的なペイウォールを表示する。 - **キャンペーンレベルのオファー**。特定の Apple Ads キャンペーンからのユーザーには長めのトライアルや特別価格を提供し、それ以外のユーザーには標準的なオファーを維持する。 - **広告クリエイティブとペイウォールの一貫性**。特定の機能を訴求している広告グループからのユーザーを、その機能を前面に出したペイウォールへ誘導する。 - **高ROIキャンペーンの最適化**。生涯価値の高いユーザーを継続的に獲得しているキャンペーンからのユーザーに対して、プレミアム優先・定価のペイウォールを表示します。 ## セグメントの作成 \{#create-segments\} Adapty Ads Manager からセグメントを作成するには: 1. **Ads Manager** に移動し、**Campaigns**、**Ad groups**、または **Keywords** タブに切り替えます。使用したいエンティティの横にあるチェックボックスを選択します。複数のエンティティを選択した場合、それぞれに個別のセグメントが作成されるのではなく、すべてを対象とした1つのセグメントが作成されます。 2. **Actions > Create segment from campaigns/ad groups/keywords** をクリックします。 3. 必要に応じて、**Create segment** ウィンドウでセグメントの詳細を更新します: - **Adapty project**: このセグメントを作成したい Adapty のアプリ。 - **Build segment from campaign/ad group**: キャンペーンまたは広告グループからセグメントを作成する場合、このステップで選択したキャンペーンや広告グループを調整できます。 - **Segment name** - **Segment description** 4. **Create** をクリックします。 5. セグメントが作成されたら、使用する準備を行います: - [プレースメント](placements)に追加して、既存のペイウォールまたはオンボーディングと組み合わせて使用する - セグメントのユーザーに表示する新しい[ペイウォール](adapty-paywall-builder)または[オンボーディング](onboardings)をデザインする - [A/B テスト](ab-tests)を実施する --- # File: ads-manager-automations-keyword-rules --- --- title: "Adapty Ads Managerのキーワードルール" description: "キャンペーンのパフォーマンスに基づいて、入札額の調整、キーワードの有効化・一時停止、広告グループ間の移動など、キーワードのライフサイクルを自動管理します。" --- キーワードルールは、インストールからトライアル、サブスクリプション、収益に至るフルファネルのパフォーマンスに基づいて、キーワードに対して自動的にアクションを実行します。支出、CPA、ROAS、コホートデータなどの指標を使って条件を定義し、その条件が満たされたときにルールが何をするかを設定します。 ルールは設定したスケジュールで実行され、手動での対応なしにパフォーマンスの変化に応答します。 ## 利用可能なアクション \{#available-actions\} 各キーワードルールは、条件が満たされたときに1つのアクションを実行します。 | アクション | 内容 | |--------|-------------| | **Change bid** | CPT入札額を増加・減少・設定する | | **Enable keyword** | 停止中のキーワードを再有効化する | | **Pause keyword** | アクティブなキーワードを停止する | | **Add as keyword to…** | 指定した入札額とマッチタイプで別の広告グループにキーワードをコピーする | | **Add as negative keyword to…** | 指定した広告グループまたはキャンペーンにネガティブキーワードとして追加する | ## キーワードルールの作成 \{#create-a-keyword-rule\} キーワードルールは、テンプレートを使うか、ゼロから手動で作成できます。 ### テンプレートから作成する \{#from-a-template\} Adapty では、一般的な最適化シナリオに対応したすぐに使えるテンプレートを提供しています。主なテンプレートは以下のとおりです: - **コンバージョンしないキーワードの無駄を削減する**: Spend > X かつ Installs または Trials = 0 の場合に入札額を下げます。 - **効果的なキーワードをスケールする**: ROAS > 目標値 または CPA < 目標値 の場合に入札額を上げます。 テンプレートからルールを作成するには: 1. 左サイドバーで **Automations** に移動し、**Templates** をクリックします。 2. テンプレートを選択し、**Next** をクリックします。 3. あらかじめ入力された設定を確認・調整します: - **Rule name**:テンプレート名と現在の日付が自動的に設定されます(例:「Scale Winning Keywords - [2025-11-12]」)。 - **Apply to**:ルールを適用するキャンペーングループ、アプリ、キャンペーン、または広告グループを選択します。 - **Conditions**:事前設定された条件を必要に応じて変更します。 - **Action**:事前設定されたアクションを必要に応じて変更します。 - **Schedule**:ルールの実行頻度を設定します。 4. **Save** をクリックしてルールを有効化します。 ### 手動で作成する \{#manually\} カスタムキーワードルールをゼロから作成するには: 1. 左サイドバーの **Automations** に移動し、**Create rule** をクリックして、ルールタイプとして **Keywords** を選択します。 2. わかりやすい **Rule name** を入力します。 3. **Apply to** セクションで、ルールを適用するキャンペーングループ、アプリ、キャンペーン、または広告グループを選択します。 4. **Add condition** をクリックし、リストから[指標](adapty-ads-manager-metrics)を選択します。 指標は、アカウントの通貨で選択した期間について計算されます。データはほぼリアルタイムで更新されるため、ルールは常に最新のパフォーマンスデータを使用します。 5. 期間を設定し(例:過去3日間や過去7日間)、比較演算子を選択して、しきい値を入力します。 6. 条件を追加するには、**Add condition** をクリックし、左側で **And** または **Or** 演算子を選択します。 7. **Action** セクションで、条件が満たされたときの動作を選択します。 **入札額の変更** - **アクションタイプ**: **Increase by**(増加)、**Decrease by**(減少)、または **Set to**(指定値に設定)を選択します。 - **値のタイプ**: **$**(絶対値)と **%**(ルール実行時点の現在入札額に対する相対値)を切り替えます。 - **入札額の上限**(任意): ルールが強いシグナルに対して繰り返しトリガーされた際の過剰入札を防ぐための上限キャップです。 **キーワードの有効化** - 追加設定は不要です。条件を満たした一時停止中のキーワードを再有効化します。 **キーワードの一時停止** - 追加設定は不要です。条件を満たしたアクティブなキーワードを一時停止します。 - **Add as keyword to…** - **Target ad groups**: コピーしたキーワードを受け取る広告グループを選択します。 - **CPT bid**: コピーしたキーワードの初期入札額を設定します。 - **Match type**: **Exact** または **Broad** を選択します。 - **Skip if keyword already exists**: 有効にすると、ターゲット広告グループにすでに存在するキーワードをスキップします。 **Add as negative keyword to…** - **Scope**: 除外キーワードを追加する広告グループまたはキャンペーンを選択します。 - **Match type**: **Exact** または **Broad** を選択します。 8. **Schedule** セクションで以下を設定します: - 頻度を選択します:**Every day**、**Every 2 days**、**Every week** など。 - 実行時刻を選択します(すべてUTC時間)。 ルールはスケジュールされたUTC時刻に実行されます。通常、数分以内に完了し、ログとメインダッシュボードで変更を確認できます。 9. **Save** をクリックしてルールを作成します。 ## ベストプラクティス \{#best-practices\} - **狭いスコープから始める**:新しいルールを展開する前に、一部のキャンペーンや広告グループに限定して適用し、動作を検証する。 - **アクティブなキャンペーンには短いルックバックウィンドウを使用する**:動きの速いキャンペーンには、30日間より3〜7日間の方が適していることが多い。 - **支出とコンバージョンを組み合わせる**:単一の指標だけのルールは避け、Spendと Installs・Trials・ROASを組み合わせることで、より信頼性の高いシグナルが得られる。 - **入札変更ルールには入札上限を設定する**:強いシグナルがルールを複数回トリガーしても、入札の上限を設けることで入札が際限なく上昇するのを防げる。 - **コホートデータと組み合わせてキーワードを有効化する**:初期CPAが悪くて一時停止したキーワードも、コホートデータが成熟するにつれてD31やD61のROASが高くなる場合がある。コホートROASを条件に設定し、目標値を超えたら自動的に再有効化できる。 - **テストからスケールへのパイプラインには「Add as keyword to…」を活用する**:テストキャンペーンのキーワードがCPA目標を達成したら、自動的にスケールキャンペーンにコピーする。 - **Discoveryキャンペーンをクリーンに保つには「Add as negative keyword to…」を活用する**:キーワードが完全一致キーワードとして確定したら、DiscoveryキャンペーンやSearch Matchキャンペーンでネガティブキーワードとして設定し、同じクエリで競合しないようにする。 - **新しく昇格したキーワードへの入札ルール適用は少し待つ**:[検索語句の自動化](ads-manager-automations-search-terms)でキーワードキャンペーンに語句を昇格させた場合、データが蓄積されるまで1〜2日待ってから入札ルールを適用する。 --- # File: ads-manager-automations-search-terms --- --- title: "Adapty Ads Managerの検索ワード自動化" description: "勝利した検索ワードをキーワードに自動的に昇格し、発見トラフィックを手動作業なしでスケールさせるためにソースで除外する" --- Discovery および Search Match キャンペーンは検索語句データを生成します。そのデータを整理されたキーワードリストに変換するには、レポートをダウンロードし、語句をフィルタリングして、広告グループに手動で追加する必要があります。検索語句の自動化はこの作業を自動的に行います。語句が設定した条件を満たすと、ルールは設定したアクションに基づいてその語句を処理します。 検索語句ルールのアクションタイプは2種類あります。 - **Add as keyword**: ターゲットの広告グループにその語句を完全一致キーワードとして追加し、オプションでソースキャンペーンでは除外キーワードに設定することで重複出費を防ぎます。 - **Add as negative keyword**: プロモーションなしでその語句を直接除外します。ディスカバリーキャンペーンやサーチマッチキャンペーンから無関係または費用対効果の低い検索語句を除外するために使用します。 **Add as keyword** の典型的なユースケース: Discovery キャンペーンや Search Match キャンペーンで実際のユーザーの検索クエリを収集し、ルールを使ってパフォーマンスが一定のしきい値を超えた語句を検出して、完全一致キーワードとして Probing キャンペーンに追加しながら、元のキャンペーンではネガティブキーワードに設定します。Probing キャンペーンとは、プロモートするキーワードを管理された入札額でテストするために専用に作成された Apple Search Ads キャンペーンのことです。 **Add as negative keyword** の典型的なユースケース: インプレッション数が多いのにタップが一度もないような、頻繁に表示されても全くコンバージョンしない語句を自動でネガティブキーワードに設定し、無駄な予算消費を防ぎます。 ## 検索語句オートメーションルールを作成する \{#create-a-search-term-automation-rule\} 検索語句オートメーションルールはテンプレートから作成することも、最初から手動で作成することもできます。 :::note ルールを作成する前に、ディスカバリーキャンペーンまたはSearch Matchキャンペーンがアクティブに実行されており、検索語句データを収集していることを確認してください。完全一致のみのキャンペーンは検索語句レポートを生成しないため、ルールが処理する対象がなくなります。 ::: ### テンプレートからルールを作成する \{#from-a-template\} テンプレートからルールを作成するには: 1. 左サイドバーで **Automations** に移動し、**Templates** をクリックします。 2. テンプレートを選択して **Next** をクリックします。 3. あらかじめ入力された設定を確認・調整します。 - **Rule name**: テンプレート名と現在の日付が自動的に設定されます。 - **Apply to**: ルールが検索語を探すキャンペーングループ、アプリ、キャンペーン、または広告グループを選択します。 - **Conditions**: 必要に応じて事前設定された条件を変更します。 - **Actions**: 必要に応じてターゲットの広告グループ、CPT 入札額、ネガティブキーワードのスコープを調整します。 - **Schedule**: ルールの実行頻度を設定します。 4. **Save** をクリックしてルールを有効化します。 ### 手動で作成する \{#manually\} カスタム検索語句の自動化ルールをゼロから作成するには: 1. 左側のサイドバーで **Automations** に移動し、**Create rule** をクリックして、ルールタイプとして **Search terms** を選択します。 2. ルールの目的を識別できるわかりやすい **Rule name** を入力します。 3. **Apply to** セクションで、ルールが検索キーワードを検索するキャンペーングループ、アプリ、キャンペーン、または広告グループを選択します。 4. **Add condition** をクリックして、リストから[指標](adapty-ads-manager-metrics)を選択します。 指標はアカウントの通貨で選択した期間について計算されます。データはほぼリアルタイムで更新されるため、ルールは常に最新のパフォーマンスデータを使用します。 5. 期間(例:直近3日間や直近7日間)を設定し、比較演算子を選択して、しきい値を入力します。 6. 条件を追加するには、**Add condition** をクリックし、左側で **And** または **Or** 演算子を選択します。 7. **Action** セクションで、検索キーワードが条件を満たした場合の動作を選択します。 **キーワードとして追加** マッチする検索語句を、ターゲット広告グループに完全一致キーワードとして追加します。 - **Target ad groups**: ターゲットとする広告グループを選択します。ディスカバリーパイプラインを構築する場合は、Probing またはその他の構造化キャンペーン内の広告グループを選択してください。 - **CPT bid**: プロモートするキーワードごとに初期のタップ単価(CPT)を設定します。オプション:広告グループのデフォルト入札額、検索語句の現在の CPT、または指定した値。 - **Skip if keyword already exists**: 有効にすると、ターゲット広告グループにすでに存在する語句をスキップします。 - **Add as negative**: 同じ語句を除外キーワードとして追加し、同じトラフィックに二重で費用を払わないようにします。 - **Scope**: 除外キーワードを追加する広告グループを選択します。 :::tip **Add as negative** を同じルールで有効にすると、キーワードをストラクチャードキャンペーンに昇格させながら、ソースで除外設定も一括で行えます。これにより、ディスカバリーキャンペーンをクリーンに保ちつつ、キーワードファネルを自動的に構築できます。 ::: **Add as negative keyword** マッチした検索語句を昇格させずに除外します。 - **Scope**: 除外キーワードを追加する広告グループまたはキャンペーンを選択します。 - **Match type**: **Exact** または **Broad** を選択します。 DiscoveryおよびMax Conversionキャンペーンから、関連性の低い検索語句や品質の低い検索語句を除外する場合に使用します。たとえば、インプレッションが50件以上あってタップ数が0の語句を自動的に除外するといった使い方ができます。 8. **Schedule** セクションでは: - 頻度を選択します:**Every day**、**Every 2 days**、**Every week** など。 - 実行時刻を選択します(すべての時刻はUTCです)。 ルールはUTC時刻で設定したスケジュールに従って実行されます。通常は数分以内に完了し、その後はLogsおよびメインダッシュボードで変更内容を確認できます。 9. **Save** をクリックしてルールを作成します。 ルールが実行されたら、**Automations** → **Logs** に移動し、対象ルールのエントリを開きます。実行が成功した場合、評価された各検索語句がソースキャンペーン、ターゲット広告グループ、アクション結果、否定結果とともに一覧表示されます。語句が表示されない場合は、条件が満たされていません。しきい値を見直すか、ルックバックウィンドウを延長してください。 ## ベストプラクティス \{#best-practices\} - **ディスカバリーまたはサーチマッチキャンペーンをソースとして使用する**: これらのキャンペーンタイプは実際のユーザークエリを収集するため、ルールが評価できる検索語のプールが大きくなります。 - **しきい値をルックバックウィンドウに合わせる**: 7日間で2件以上のダウンロードが妥当な出発点です。ウィンドウを長くする(14〜30日)とハードルが実質的に下がり、コンバージョン頻度が低い語でも通過できるようになります。流入量の多いアプリでは、ウィンドウを短くしてしきい値を引き上げてください。 - **プロモート時は必ずソースでネガティブ設定する**: プロービングキャンペーンに語をキーワードとして追加したとき、ディスカバリーでネガティブ設定しないと、両方のキャンペーンが同じクエリで競合します。同じルール内で **Add as negative** を有効にしてください。 - **ターゲットの広告グループを意図的に選ぶ**: プロモートした語は、広範なキャンペーンではなく特定のプロービング広告グループにルーティングします。これによりキーワード構造が整理され、パフォーマンス分析がしやすくなります。 - **実行後はログを確認する**: ログタブでどの語がプロモートされ、どこに追加されたかを確認します。初期段階ではセットアップ後にルールを手動で実行し、期待どおりに動作しているか検証してください。ログの読み方については[オートメーション](ads-manager-automations#explore-logs)を参照してください。 - **プロモートしたキーワードにキーワードルールが作用するまで時間を置く**: 同じキャンペーンでキーワードルールも使用している場合、新しくプロモートしたキーワードを除外するか、ルールが適用されるまで1〜2日待ちましょう。パフォーマンス履歴がない新しい語にキーワードルールが発動すると、コンバージョンする前に入札が削られてしまうことがあります。 - **インプレッションは多いのにタップがゼロの語にはネガティブキーワードとして追加する**: ディスカバリーやMax Conversionキャンペーンでは、無関係な検索語が表示されることがよくあります。「インプレッション > 50 かつ タップ = 0」というルールを設定することで、こうした語を自動的にネガティブ設定し、無駄なインプレッションがこれ以上積み重ならないようにできます。 ## 検索語句をエクスポートする \{#export-search-terms\} 検索語句テーブルをCSVとしてエクスポートするには、テーブル上部のダウンロードアイコンをクリックして **Export current page** または **Export all pages** を選択します。 **Export all pages** は全ページにわたるすべての検索語句を1つのファイルにダウンロードします。進捗モーダルがダウンロードを追跡し、いつでもキャンセルできます。 テーブルは表示されている状態、つまり選択して表示している列でエクスポートされます。 --- # File: ads-manager-automations-ad-group-rules --- --- title: "Adapty Ads Managerにおける広告グループルール" description: "キャンペーンのパフォーマンスに基づいて、広告グループの入札額やCPA目標を自動的に調整し、広告グループを有効化または一時停止します。" --- **広告グループルール**は、広告グループのパフォーマンスに応じて設定を自動的に変更したい場合に追加します。キーワードルールが個々のキーワードに作用するのとは異なり、広告グループルールは広告グループ全体に一度に適用されます。 各ルールは、条件とアクションをペアにしています。たとえば、「広告グループが3日間で$50以上消費してもトライアルが発生していない場合、入札額を20%下げる」といった設定が可能です。Adaptyは設定したスケジュール(毎時、毎日、毎週など)に従って広告グループをチェックし、条件が満たされるたびにアクションを適用します。Adaptyはトライアル、サブスクリプション、収益を追跡しているため、インストール数だけでなく実際の収益に基づいた条件を設定できます。 ## 利用可能な条件 \{#available-conditions\} ルールは一連の広告グループを監視し、パフォーマンスが設定したしきい値を超えたときに発動します。まず、監視する広告グループを選択します。 - **Ad groups in selected campaign groups** - **Ad groups in selected apps** - **Ad groups in selected campaigns** - **Selected ad groups** 次に、ルールを発動させる条件を設定します。各条件は以下の要素を組み合わせて構成されます。 | パーツ | 説明 | 例 | | --- | --- | --- | | **指標** | [Adapty Ads Managerが追跡する指標](adapty-ads-manager-metrics)(支出、インストール数、トライアル数、サブスクリプション数、収益など)。 | 支出 | | **期間** | 指標を計測する期間。 | 直近3日間 | | **比較** | 指標を設定した値と比較する方法。 | より大きい | | **しきい値** | 比較対象となる値。 | $50 | 複数の条件を **And** または **Or** で組み合わせることで、より精度の高いターゲティングが可能です。例:支出 > $50 **and** トライアル数 = 0。 ## 利用可能なアクションとその設定 \{#available-actions-and-their-settings\} グループが条件を満たした場合、Adaptyは以下のいずれかのアクションを実行して設定を変更できます。 | アクション | 内容 | 使用タイミング | 設定 | | --- | --- | --- | --- | | **Change default bid** | 広告グループのデフォルト最大**クリック単価(CPT)入札額**(広告への1回のタップに支払う上限額)を増加・減少・設定する。 | コンバージョンが良い広告グループは強化し、成果が出ない広告グループは抑制する。 | **Action type**: Increase by、Decrease by、または Set to。<br/>**Value type**: $(絶対値)または %(現在の入札額に対する割合)。<br/>**Limit**(任意): 増加時は上限、減少時は下限 — 繰り返し実行した際に入札額が動く範囲を制限する。 | | **Change CPA goal** | 広告グループの**CPA目標(上限)**(目標獲得単価)を増加・減少・設定する。 | 最適化が進むにつれてコスト上限を引き締めたり、より多くの量を獲得するために緩めたりする。 | **Action type**: Increase by、Decrease by、または Set to。<br/>**Value type**: $ または %。<br/>**Limit**(任意): 増加時は上限、減少時は下限。 | | **Enable ad group** | 一時停止中の広告グループを再度有効にする。 | トライアルの遅延やサブスクリプション収益が入り次第、回復した広告グループを復活させる。 | なし。 | | **Pause ad group** | アクティブな広告グループを一時停止する。 | コンバージョンなしに費用だけ発生し続ける広告グループを停止する。 | なし。 | ## 広告グループルールの作成 \{#create-an-ad-group-rule\} 1. **Automations** に移動し、**Create rule** をクリックして **For ad groups** を選択します。 2. **Rule name** を入力します。 3. **Apply to** で[スコープ](#available-conditions)を選び、広告グループを選択します。 4. **Conditions** で1つ以上の[条件](#available-conditions)を追加します。論理演算子を使って条件を組み合わせることもできます。 5. **Action** で[アクション](#available-actions-and-their-settings)を選び、オプションを設定します。 6. **Schedule** でルールの実行頻度と開始時刻(UTC)を設定するか、**Run immediately** を選択します。 7. **Save** をクリックします。 保存すると、ルールが **Automations** タブに表示されます。**Date last run** 列と **Date next run** 列でスケジュールを確認できます。実行をまたいだステータス変更を確認するには、**Automations > Logs** を開いてください。ルールの一時停止、複製、削除、即時実行の方法については、[Automations](ads-manager-automations) を参照してください。 --- # File: ads-manager-automations-campaign-rules --- --- title: "Adapty Ads ManagerのキャンペーンルールAdapty Ads Manager" description: "パフォーマンスに基づいて、キャンペーンの日予算を自動調整したり、キャンペーンを有効化・一時停止したりします。" --- **キャンペーンルール**を追加すると、キャンペーンのパフォーマンスに基づいて予算やステータスを自動的に変更できます。広告グループルールが個別の広告グループに作用するのに対し、キャンペーンルールはキャンペーン全体に一括で適用されます。 各ルールは条件とアクションを組み合わせたものです。たとえば、「3日間でキャンペーンが$200以上使ってもサブスクリプションが取れなければ、1日の予算を20%削減する」といった設定が可能です。Adaptyは、あなたが設定したスケジュール(毎時・毎日・毎週など)でキャンペーンをチェックし、条件が満たされるたびにアクションを実行します。Adaptyはトライアルやサブスクリプションといったリアルな収益データを追跡しているため、インストール数だけでなく実際の収益に基づいた条件を設定できます。 ## 利用可能な条件 \{#available-conditions\} ルールは一連のキャンペーンを監視し、パフォーマンスが設定したしきい値を超えたときに発火します。まず、監視対象のキャンペーンを選択します: - **Campaigns in selected campaign groups** - **Campaigns in selected apps** - **Selected campaigns** 次に、ルールを発火させる条件を設定します。各条件は以下の要素を組み合わせて構成されます: | 項目 | 説明 | 例 | | --- | --- | --- | | **指標** | [Adapty Ads Managerが追跡する指標](adapty-ads-manager-metrics)(支出、インストール数、トライアル数、サブスクリプション数、収益など)。 | Spend | | **時間枠** | 指標を計測する期間。 | Yesterday | | **比較** | 指標を設定値と照合する方法。 | is greater than | | **しきい値** | 比較対象の値。固定金額、またはキャンペーン自身の **Daily Budget** を指定できます。 | Daily Budget | 複数の条件を **And** または **Or** で組み合わせることで、より精度の高いターゲティングが可能です。たとえば、支出 > Daily Budget **and** ROAS < 100% のように設定できます。 ## 利用可能なアクションとその設定 \{#available-actions-and-their-settings\} キャンペーンが条件を満たした場合、Adapty は以下のいずれかのアクションを実行してその設定を変更できます。 | アクション | 内容 | 使用タイミング | 設定 | | --- | --- | --- | --- | | **Change daily budget** | キャンペーンの**日予算**(1日の上限支出額)を増減または設定する。 | 過剰支出のキャンペーンは予算を削減し、収益性よくスケールしているキャンペーンは予算を引き上げる。 | **Action type**: Increase by、Decrease by、または Set to。<br/>**Value type**: $(絶対値)または %(現在の予算に対する割合)。<br/>**Limit**(任意): 増加時は上限、減少時は下限として機能し、繰り返し実行による予算の変動幅を制限する。 | | **Enable campaign** | 一時停止中のキャンペーンを再有効化する。 | トライアルやサブスクリプションの遅延収益が入ってきて回復したキャンペーンを再開する。 | なし。 | | **Pause campaign** | アクティブなキャンペーンを一時停止する。 | コンバージョンなしに支出が続くキャンペーンを停止する。 | なし。 | ## キャンペーンルールを作成する \{#create-a-campaign-rule\} プリセットから始めるには、**Automations** ヘッダーの **Templates** をクリックして **Decrease budget for low-performing campaigns** を選択し、内容を確認して保存します。ゼロからルールを作成するには: 1. **Automations** に移動し、**Create rule** をクリックして **For campaigns** を選択します。 2. **Rule name** を入力します。 3. **Apply to** で[スコープ](#available-conditions)を選択し、キャンペーンを指定します。 4. **Conditions** で1つ以上の[条件](#available-conditions)を追加します。論理演算子を使って条件を組み合わせることができます。 5. **Action** で[アクション](#available-actions-and-their-settings)を選択し、オプションを設定します。 6. **Schedule** でルールの実行頻度と開始時刻(UTC)を設定するか、**Run immediately** を選択します。 7. **Save** をクリックします。 保存後、ルールは **Automations** タブに表示されます。**Date last run** 列と **Date next run** 列でスケジュールを確認できます。実行間のステータス変化を確認するには、**Automations > Logs** を開いてください。ルールの一時停止、複製、削除、または即時実行の方法については、[Automations](ads-manager-automations) を参照してください。 --- # File: ads-manager-market-intelligence --- --- title: "Adapty Ads Managerのマーケットインテリジェンス" description: "50カ国以上で競合他社がApple Adsに出稿しているキーワードを確認し、そのままキャンペーンに追加できます。" --- Market Intelligence は、Apple Ads で競合他社がどのキーワードに入札しているかを 50 以上の国にわたって表示します。データは過去 30 日間を集計したもので、毎日更新されます。 以下の目的に活用できます。 - **ディスカバリーキャンペーンをスキップする**: 何が効くかを探るために予算を使う代わりに、競合他社がすでに入札しているキーワードを確認する。初日から実績あるキーワードリストでスタートできる。 - **競合の少ないキーワードを見つける**: 競合他社のShare of Voiceが低いロングテールキーワードを特定する。競合が少なく、タップ単価が下がり、CPAも改善できる。 - **ブランドを守る**: 競合他社が自分のアプリ名に入札しているか、またどの国で入札しているかを把握し、そのトラフィックを取り戻す。 - **データを持って新市場に参入する**: その国で広告を出す前に、競合他社がどのキーワードで出稿しているかを確認する。 - **見落としていた競合を発見する**: キーワードで検索して、自分のカテゴリのキーワードでオーガニックランキングされている競合を見つけ、分析対象に追加する。 ## Market Intelligence分析を実行する \{#run-a-market-intelligence-analysis\} ### 1. アプリを選択する \{#1-select-your-app\} 左サイドバーで **Market Intelligence** に移動します。ドロップダウンから分析したいアプリを選択し、**Continue** をクリックします。 ### 2. 競合他社を選択する \{#2-select-competitors\} 分析したい競合他社を追加します。 - **競合他社の候補**: Adapty がアプリのカテゴリをもとに競合候補を自動検出します。一覧を確認し、含めたい競合他社を選択してください。 - **キーワードまたはアプリ名で検索**: 検索フィールドにキーワード(例:「budget tracker」)またはアプリ名を入力します。必要に応じて国を変更し、検索結果からアプリを選択します。異なるキーワードで繰り返し検索することで、さまざまな検索意図の競合他社を発見できます。 - **保存済みリスト**: **Create list** をクリックすると、最大20件の競合他社を保存して今後の分析で再利用できます。以前に作成したリストを読み込むこともできます。 競合他社を選択したら、**Run analysis** をクリックします。 ### 3. 結果を確認する \{#3-explore-results\} 結果は **Overview**、**Most Contested**、**By App**、**By Country** の4つのタブに整理されています。 #### Overview \{#overview\} デフォルトのタブには、分析の概要が表示されます。 - **統計バー**: 分析した競合の総数、Apple Ads が有効な国の数、全市場で見つかったユニークキーワードの数、最も競争が激しい単一のキーワード。 - **国別キーワード数**: 上位 25 市場における国ごとのキーワード数を示す棒グラフ。 - **キーワードカバレッジ上位 10 社の競合**: 各競合のキーワード総数、平均 Share of Voice(Avg SOV)、活動している国をまとめたランキングテーブル。 #### 最も競合が集中するキーワード \{#most-contested\} 最も多くの競合が同時に出稿しているキーワードを表示します。このタブを使ってカテゴリ内の需要が高いキーワードを見つけ、競合が最も集中している場所を確認できます。検索フィールドを使ってキーワードでリストを絞り込めます。 #### アプリ別 \{#by-app\} 競合他社ごとのキーワードデータを表示します。このタブを使用して、特定のアプリのキーワード戦略を国別に詳しく調べることができます。**Add filter** をクリックして、アプリ、国、またはキーワードでフィルタリングできます。データをCSVとしてエクスポートするには、ダウンロードアイコンをクリックします。 #### 国別 \{#by-country\} 市場ごとにグループ化されたキーワードデータを表示します。特定の国の競合状況を把握したい場合(参入前や拡大前など)に活用してください。**Add filter** をクリックすると、アプリ・国・キーワードでフィルタリングできます。データを CSV でエクスポートするには、ダウンロードアイコンをクリックしてください。 ### 4. キャンペーンにキーワードを追加する \{#add-keywords-to-campaigns\} テストする価値があるキーワードが見つかったら、ツールを離れることなくキャンペーンに追加できます。 1. キーワードテーブルで、使用したいキーワードの横にあるチェックボックスを選択します。表示されているすべてのキーワードを選択するには、テーブルヘッダーのチェックボックスを使用してください。 2. **Add to campaign** をクリックします。 3. キーワード、除外キーワード、SKAG のいずれとして追加するかを選択します。次に、対象のキャンペーンと広告グループを選択し、マッチタイプと CPT 入札額を設定して確定します。 ## 確認すべき点 \{#what-to-look-for\} 結果の中で注目すべきパターンを紹介します: - **シェアオブボイスが低いロングテールキーワード**: 競合他社のインプレッションシェアが低いキーワードは、競争が少ない傾向があります。ユーザーの意図がより具体的なため、タップ単価が低く、コンバージョン率も高くなる傾向があります。 - **自社キャンペーンにまだ含まれていないキーワード**: 競合他社が使用しているが、自社ではまだ試していないキーワードを探しましょう。これらはカテゴリ内でApple Adsのトラフィックを獲得できることが実証済みのキーワードです。 - **ブランドキーワードのカバレッジ**: 自社アプリ名で検索してみましょう。競合他社が表示される場合、自社ブランドに対して入札していることを意味します。そのようなキーワードを積極的な入札額でキャンペーンに追加し、トラフィックを守りましょう。 - **国別のギャップ**: 競合他社がどの国で活動しているかを確認しましょう。競合他社の活動がほとんどない市場は参入しやすく、トラクションを得るために必要な予算も少なくて済みます。 --- # File: ads-manager-cpp-ab-tests --- --- title: "Adapty Ads ManagerにおけるCPP A/Bテスト" description: "Apple AdsでカスタムプロダクトページをA/Bテストして、最もパフォーマンスの高いページを見つけましょう。" --- CPP A/B テストを使うと、Apple Ads 内でカスタムプロダクトページ(CPP)同士を比較できます。2〜4ページのプロダクトページを選択すると、[Adapty Ads Manager](adapty-ads-manager) がトラフィックをローテーションしてパフォーマンスデータを収集し、どのページが最もコンバージョンしやすいかを教えてくれます。 デフォルトのプロダクトページをバリアントのひとつとして含めることができるので、カスタムページが現在のデフォルトよりも優れたパフォーマンスを発揮するかどうかをテストできます。 ## 前提条件 \{#prerequisites\} CPP A/B テストを作成する前に、以下を確認してください: - **Apple Ads Manager が接続されていること**:まだ接続していない場合は、[セットアップガイド](adapty-ads-manager-get-started)に従ってください。 - **テスト対象の広告グループにトラフィックがあること**:テストする広告グループは少なくとも28日以上稼働しており、その期間中にインプレッション、タップ、インストールの実績がある必要があります。Apple Ads Managerはこの履歴を使用して、テスト期間と必要なサンプルサイズを推定します。 - **少なくとも1つのカスタムプロダクトページがあること**:まずApp Store ConnectでCPPを作成してください。Apple Ads Managerは自動的にそれらを読み込みます。 ## CPP A/B テストを作成する \{#create-a-cpp-ab-test\} テストを作成するには、左のサイドバーで **CPP A/B Tests** に移動し、**Create A/B Tests** をクリックします。 ウィザードには4つのステップがあります:**Ad Group(s)**、**Ad Creative(s)**、**Testing Method**、**Review**。 ### 1. Ad Group(s) \{#1-ad-groups\} **Test Name** を入力し、**Select Ad Group** をクリックしてテストしたいCPPを持つ広告グループを選択します。同じキャンペーンから最大4つの広告グループを選択できますが、これは1つの広告クリエイティブを複数の広告グループでテストする場合のみです。複数のCPPを比較するには、1つの広告グループを選択してください。 ### 2. Ad Creative(s) \{#2-ad-creatives\} 比較するCPPを選択します。**Default Product Page**(**Control** としてマーク)と最大3つの**Custom Product Pages**を合わせて、合計2〜4つのバリアントを含めることができます。 - **Default Product Page**:**+ Add Default** をクリックして、既存のデフォルトプロダクトページをコントロールバリアントとして追加します。 - **Custom Product Pages**:**+ Select CPP** をクリックして、App Store Connectからカスタムプロダクトページを選択します。 ### 3. テスト方法 \{#3-testing-method\} テストの実行方法を設定します。Adapty Ads Manager は**テスト予測期間**、**開始時間**、**終了時間**を自動的に計算します。以下の3つの設定を変更すると、値が自動的に更新されます。 #### 切り替え時間プリセット \{#switch-time-preset\} システムがバリアントを切り替える頻度を設定します。トラフィックレベルに対して高すぎる値を選択した場合、システムが自動的に低い値に変更します。 | インターバル | 典型的なトラフィックレベル | スロット期間 | 典型的なテスト期間 | |--------------|----------------------------------------|---------------|---------------------| | **毎時** | 高(1日5,000インプレッション以上) | 7時間 | 数日 | | **毎日** | 通常 | 24時間 | 数週間 | | **毎週** | 低(1日400インプレッション未満) | 7日 | 数ヶ月 | **スロット**とは、システムが次のバリアントへの切り替えを検討するまで、バリアントが実行される基本時間のことです。 #### 希望する精度 \{#desired-precision\} テストが確実に検出できるコンバージョン率の最小差異です。選択肢は **1%**、**2%**、**3%**、**4%**、**5%** で、デフォルトは **5%** です。精度 1% のテストは小さな差異も検出できますが、より多くのデータが必要で実行期間も長くなります。精度 5% のテストは早く終わりますが、大きな差異しか検出できません。 | 精度 | 使用するタイミング | |-----------|-----------------------------------------------------------------------------------| | 1〜2% | CPP間の差が小さいと予想され、トラフィックの多い広告グループがある場合。 | | 3〜4% | ほとんどのテストに適したバランスのよいデフォルト値。 | | 5% | 明確な勝者が見込まれ、早く結果を得たい場合。 | #### 信頼水準 \{#confidence-level\} 結果がランダムなノイズではなく実際のものであると、どの程度確信したいかを指定します。オプション: **80%**、**85%**、**90%**、**95%**、**99%**。デフォルト: **90%**。信頼水準を高くするほど、より多くのデータが必要になります。 | 信頼度 | トレードオフ | |------------|---------------------------------------------------------------------------------| | 80–85% | 早く結論が出るが、結果がノイズである可能性が高い。 | | 90% | ほとんどのテストで推奨されるデフォルト値。 | | 95–99% | 最も保守的。最多のデータと最長のテスト期間が必要。 | ### 4. Review \{#4-review\} 概要(選択した広告グループ、クリエイティブ、テスト方法、期間、精度、信頼度)を確認し、**Start CPP A/B Tests** をクリックします。 テストを開始すると、システムはバリアントごとに広告グループを複製し、最初のバリアントをアクティブにします。テストのステータスは数分以内に **Running** に移行します。 ## 実行中のテストを監視する \{#monitor-a-running-test\} テスト一覧を開くには、左サイドバーの **CPP A/B Tests** をクリックします。ページ上部の4つのタブで、状態ごとにテストをフィルタリングできます。 - **Live**: 現在実行中のテスト。 - **Completed**: 完了したテスト。 - **Draft**: まだ開始されていないテスト。 - **Archive**: メインビューに表示する必要がなくなった古いテスト。 各テストカードには、テスト名、ステータス、切り替え間隔、目標精度、実行時間が表示されます。**View metrics** をクリックすると、バリアントテーブルが展開されます。 ### バリアントのパフォーマンス \{#variant-performance\} バリアントテーブルは、テスト内のすべてのバリアントのパフォーマンスを比較します。 | カラム | 説明 | |--------------------------|-----------------------------------------------------------------------------------------------------| | **Variant Name** | テスト対象のCPP。バリアントAは常に最初に追加したバリアントです。 | | **Confidence Level** | 必要なサンプルサイズに対する達成率(0〜100%)。 | | **Impressions** | Appleがこのバリアントの広告を表示した回数。 | | **TTR** | タップスルー率:インプレッション数に対するタップ数の割合。 | | **Tap → Download CR** | タップからダウンロードへのコンバージョン率。 | | **CPT** | タップあたりの平均コスト。 | | **Avg CPA (Tap-Through)** | タップスルーによるダウンロードに基づく獲得あたりの平均コスト。 | | **Spend** | このバリアントに帰属する総支出額。 | | **Revenue** | このバリアントに帰属する総収益。 | | **ROAS** | 広告費用対効果:支出額に対する収益の割合。 | 各バリアントのインプレッション数が同程度になるまで、Adapty Ads Manager は勝者を強調表示しません。データ収集中は、テーブルの上部に次のバナーが表示されます:**Winner highlighting is paused — variants don't have comparable impressions yet.** ### 詳細な指標 \{#detailed-metrics\} テストをさらに詳しく確認するには、**View metrics** をクリックして詳細指標ページを開きます。コホートのリテンションカーブ、ARPPUの比較、そして2つのセクションに分類された指標テーブルが含まれています。 - **Top of funnel · Apple Search Ads**: バリアントごとのTTR、ダウンロード率、CPM、CPT、平均CPA。 - **Bottom of funnel · Monetization**: バリアントごとの有料ユーザー数、有料CR、有料ユーザー獲得単価、ARPPU、収益、ROAS。 **Winner** 列には、各指標でリードしているバリアントが表示されます。バリアントが総合的な勝者として認定されるのは、主要指標でリードし、かつ信頼水準が 95% 以上に達した場合のみです。 指標の定義については、[Adapty Ads Manager の指標](adapty-ads-manager-metrics)をご覧ください。 ## テストを停止する \{#stop-a-test\} テストはいつでも停止できます。テストは **Stopped** としてマークされ、元の広告グループが復元され、複製された広告グループは一時停止されます。 実行中のテストを停止するには: 1. 左のサイドバーで **CPP A/B Tests** に移動します。 2. テストカードの **Stop A/B test** をクリックするか、テストを開いて **Stop Test** をクリックします。 3. **Stop A/B Test?** ダイアログで確認します。 :::important テストの停止は最終的な操作です。再開することはできません。これまでに収集された結果は **Completed** タブで引き続き確認できます。 ::: ## テストのステータス \{#test-statuses\} すべてのテストは、決まった一連のステータスを順に経由します: | ステータス | 意味 | |---------------|------------------------------------------------------------------------------------------| | **Draft** | テストは作成済みですが、まだ開始されていません。引き続き編集できます。 | | **Starting** | セットアップ中 — システムが広告グループを複製し、広告を作成しています。 | | **Running** | テストは稼働中です。バリアントがローテーションされ、指標が収集されます。 | | **Completed** | 設定した期間が終了したか、信頼度に達しました。元の広告グループが復元されます。 | | **Stopped** | テストを手動で停止しました。元の広告グループが復元されます。 | | **Failed** | セットアップに失敗したか、連続エラーが多すぎます。失敗したテストは再起動できます。 | ## 仕組み \{#how-it-works\} Adapty Ads Manager は **Ad Group Switch** という手法を使用しています。 1. テストが開始されると、システムはソース広告グループをバリアントごとに1回ずつ複製します。各クローンは異なるCPP(デフォルトページを使用できるものも含む)を指定します。 2. 同時に実行されるクローンは1つだけです。システムは固定スケジュール(毎時、毎日、または毎週)に従って、どのクローンをアクティブにするかをローテーションします。 3. テスト実行中は元の広告グループが一時停止されます。テスト終了時に以前の状態に復元されます。 4. Adapty Ads Managerはバリアントごとのインプレッション数、タップ数、ダウンロード数を収集し、各バリアントが統計的に有意なサンプル数にどれだけ近づいているかを追跡します。 5. 各バリアントに十分なデータが集まった時点、またはスケジュールされた期間に達した時点で、テストは自動的に終了します。 ## テスト実行中に何が起こるか \{#what-to-expect-while-a-test-runs\} 実行中のテストがダッシュボード上でどのように動作するかについて、いくつか知っておくべきことがあります。 - **バリアントは固定のタイマーで切り替わるわけではありません**: 切り替え間隔はあくまで基準値であり、Adapty Ads Manager は各バリアントが公平なインプレッション数を確保できるようタイミングを調整します。インプレッションが不足している場合、バリアントは1スロットより長く有効な状態を維持することがあります。 - **終了時刻は繰り延べされる場合があります**: 予定終了時刻が近づいた時点でデータが不足している場合、タップ数の収集を続けるためにテストが自動的に延長されます。新しい終了時刻はテストカードに表示されます。 - **テスト終了時、元の広告グループが復元されます**: クローンされたすべての広告グループは一時停止され、ソースの広告グループはテスト開始前の状態に戻ります。結果は **Completed** タブで引き続き確認できます。 --- # File: ads-manager-settings --- --- title: "Adapty Ads Managerの設定" description: "Adapty Ads Managerの設定を構成します。" --- Adapty Ads Managerダッシュボードの左下にある **Settings** に移動して、アカウント設定を構成します。 ## キャンペーングループ \{#campaign-groups\} **Campaign groups** タブでは、Adapty Ads Manager に接続済みのすべての Apple Ads アカウントを確認したり、新しいアカウントを追加したりできます。複数の Apple Ads アカウントを接続した場合、それらすべてのアナリティクスが単一の Adapty Ads Manager ダッシュボードに集約されます。 新しい Apple Ads アカウントを追加するには、**Connect Apple Ads account** をクリックし、[ガイド](adapty-ads-manager-get-started)に従って進めてください。 ## サブスクリプションの管理 \{#manage-subscription\} **Manage subscription** タブでは、現在のサブスクリプションプランを確認したり、支払い方法を更新したりできます。 ## ユーザー設定 \{#user-settings\} **User settings** タブでは、**Hide Paused by Default** スイッチをオンにできます。有効にすると、一時停止中のキャンペーン、広告グループ、キーワードが非表示になり、アクティブなパフォーマンスデータに集中しやすくなります。 キャンペーン、広告グループ、キーワードの開始・一時停止を頻繁に試している場合は、このオプションを有効にしないようにしてください。一時停止中のアイテムにいつでもアクセスしたい場面があるためです。 --- # File: adapty-user-acquisition --- --- title: "Adapty アトリビューション" description: "MMP を不要にし、アプリ全体のエコノミーを一か所で計算します。" --- <CustomDocCardList ids={['user-acquisition', 'ua-analytics', 'ua-integrations', 'ua-tracking-links', 'ua-deferred-data']} /> Adapty Attributionは、広告プラットフォーム・トラッキングリンク・アプリのデータを組み合わせることで、広告キャンペーンとアプリインストールおよびサブスクリプション収益を紐づけるアトリビューションソリューションです。すべての獲得データを一か所に集約した統合マーケティング分析ダッシュボードを提供します。 - すべてのチャネルにわたるROAS(広告費用対効果)を算出 - アプリ全体の収益状況を一か所で把握 - より良い意思決定のための正確なアトリビューションデータを取得 - コホートのパフォーマンスとユーザー行動を時系列で分析 :::tip Adapty のアトリビューション機能についてもっと詳しく知りたい方は、[お問い合わせください](https://calendly.com/tnurutdinov-adapty/30min)。 ::: ## Adapty アトリビューションを選ぶ理由 \{#why-choose-adapty-attribution\} ユーザー獲得のパフォーマンス計測は難しいものです。データは複数のプラットフォームに分散し、プライバシー規制の変化でアトリビューションが困難になり、独自ソリューションの構築には多大な時間がかかります。 Adapty Attribution は、組み込みのアトリビューションと統合されたアナリティクスを1つのマーケティングダッシュボードで提供します。広告費からインストール数、サブスクリプション収益まで、すべての獲得指標が自動的に統合され、リアルタイムで更新されます。スプレッドシート間でデータを照合したり、複数のツールを切り替えたりする必要はもうありません。データ管理システムではなく、アプリの成長に集中できます。 ## 仕組み \{#how-it-works\} Adapty Attribution は、広告プラットフォーム、トラッキングリンク、アプリからのデータを組み合わせて、アプリのインストールおよびサブスクリプション収益を広告キャンペーンにアトリビュートします。 大まかな流れは以下のとおりです: - 広告プラットフォームがキャンペーン構成と広告費用を提供する - Adapty Attribution で生成されたトラッキングリンクが、ウェブからアプリインストールへのキャンペーンのコンテキストを伝える - Adapty SDK がアプリからインストールおよび収益イベントを送信する アトリビューションのフローは以下のように機能します: 1. **トラッキングリンクがAdapty アトリビューションで生成され、広告キャンペーンに追加されます。** リンクには、プラットフォーム、キャンペーン、広告セット、クリエイティブなどのキャンペーンパラメーターが含まれています。 2. **ユーザーが広告をクリックし、アプリストアからアプリをインストールします。** ユーザーはトラッキングリンク経由でリダイレクトされ、App StoreまたはGoogle Playからアプリをインストールします。 3. **アプリがAdaptyにインストールイベントを送信します。** 初回起動時に、AdaptyのSDKがインストールイベントを送信します。Adaptyはこのインストールに関連するキャンペーンパラメーターを抽出します。 4. **インストールがキャンペーンにアトリビューションされます。** トラッキングリンクのキャンペーンパラメータを使用して、Adaptyはインストールをそれを生み出したキャンペーンに紐付けます。 5. **広告費用と収益が連携されます。** Adaptyは対応する広告プラットフォーム(現時点では Meta Ads と TikTok for Business)から広告費用データを取得し、サブスクリプションや購入イベントをアトリビューション済みのインストールに紐付けます。 その結果、Adapty はインストール数、収益、LTV、ROAS などのキャンペーンレベルの指標を一元化されたアナリティクスダッシュボードで提供します。コホートを分析したり、時系列でパフォーマンスを追跡したり、データドリブンな最適化の意思決定を行ったりできます。異なるソースのデータを手動で突き合わせる必要はありません。 :::tip トラッキングリンクにカスタムパラメーターを含めることもできます。これにより、アプリがインストールイベントを処理する際に [ディファードディープリンク](ua-deferred-data) の処理やキャンペーンデータへの対応が可能になります。 ::: --- # File: user-acquisition --- --- title: "Adapty Attributionを始める" description: "Adapty Attributionと連携して、広告費とサブスクリプション収益を組み合わせ、アプリ全体の収益状況を一か所で確認しましょう。" --- Adapty Attributionは、ウェブからアプリへのキャンペーンにおける広告費用とサブスクリプション収益を紐付け、アプリの経済全体を一か所で把握できるようにします。 Adapty Attributionで収益データを確認するには、まずAdaptyダッシュボードでインテグレーションを有効にする必要があります。APIキー、トークン、識別子などを渡す必要はありません。Adapty SDKを更新・設定するだけです。 :::important Adapty Attribution は以下のバージョンから利用できます: - iOS、Android、Flutter SDK バージョン 3.9.1 以上 - React Native および Capacitor SDK バージョン 3.10.0 以上 - Unity SDK バージョン 3.12.0 以上 - Kotlin Multiplatform SDK バージョン 3.15.0 以上 ::: ## 始める前に \{#before-you-start\} 収益データとキャンペーンのパフォーマンスを連携させるために、Adapty で購入を追跡できるよう設定してください: - すでに **Adapty を使ってアプリ内課金を実装済みの場合**、この段階では他に何もする必要はありません。 - **アプリ内課金をまだ実装していなく、Adapty を使いたい場合**は、[クイックスタートガイド](quickstart) の手順を完了して、購入処理を Adapty に委任してください。 - **Adapty を使わずにアプリ内課金をすでに実装済みで、Adapty への移行を予定していない場合**は、[オブザーバーモードでお使いのプラットフォーム向けに Adapty SDK をインストール](implement-observer-mode)してください。この段階では、プロジェクトに SDK を追加し、オブザーバーモードを有効にして起動し、トランザクションを報告するだけで構いません。 このセットアップにより、ウェブからアプリへのアトリビューションが有効になります: - ユーザーがアプリをインストールすると、Adapty SDKがリンクパラメータからインストールの詳細を取得し、Adapty アトリビューションがキャンペーンの詳細を取得できるようになります - Adapty SDKはアプリ内のすべての収益関連イベントを把握し、それらをウェブキャンペーンにアトリビュートできます。 ## ステップ 1. Adapty Attribution を開く \{#step-1-open-adapty-attribution\} :::important Adapty ロゴをクリックしても **Attribution** が表示されない場合は、ブラウザの設定で adapty.io の Cookie とサイトデータを削除してから、ページをリロードしてください。 ::: ヘッダーの Adapty ロゴをクリックし、**Attribution** を選択します。 サブスクリプションイベントは自動的に Adapty Attribution に流れ込み始めます。キャンペーンデータは、ステップ 2 でデータソースを接続した後に表示されます。 イベント配信を一時停止するには、Adapty ダッシュボードで **Integrations > Adapty** を開き、トグルをオフにしてください。 ### サポートされているイベント \{#supported-events\} デフォルトでは、Adaptyはユーザーアクイジションへ3つのグループのイベントを送信します: - トライアル - サブスクリプション - 問題 サポートされているイベントの全一覧は[こちら](events)で確認できます。 <img src="/assets/shared/img/events-ua.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 2. 広告プラットフォームを連携してトラッキングリンクを追加する \{#step-2-connect-your-ad-platform-and-add-tracking-links\} Adapty はトラッキングリンクを使って、アプリのインストールとキャンペーンデータを紐付けます。 Adapty Attribution で計測したい広告キャンペーンには、必ずトラッキングリンクをリンク先 URL として設定してください。 複数の広告プラットフォームで広告を配信している場合は、プラットフォームごとに個別にトラッキングリンクを設定してください。 Adapty が広告プラットフォームと連携する方法は 2 つあります。 - **ネイティブ連携(Meta Ads、TikTok Ads)。** Adapty が広告プラットフォームに直接接続します。トラッキングリンクは自動的に生成され、キャンペーンパラメータはリンクの使用箇所に応じて動的に入力されます。異なるキャンペーン、広告セット、クリエイティブに同じリンクを使い回しても、Adapty が正しいキャンペーンデータと広告費を自動的に受け取ります。 - **トラッキングリンクのみ(その他すべての広告プラットフォーム)。** Adapty は広告プラットフォームに接続しません。トラッキングリンクは手動で作成し、リンク作成時にすべてのキャンペーンパラメーターを明示的に定義する必要があります。これらのプラットフォームでは広告費用データは利用できません。 <Tabs> <TabItem value="meta" label="Meta Ads" default> Meta Ads のトラッキングリンクを作成するには: 1. Adapty Attribution ダッシュボードの [Integrations > Meta](https://app.adapty.io/ua/integrations/facebook/accounts) に移動し、**Continue with Facebook** をクリックします。 2. Facebookアカウントでサインインし、**Continue** をクリックします。 3. 要求されるアクセス許可を確認し、**Save** をクリックします。 4. **Web campaigns** タブに切り替え、**Create campaign** をクリックします。アプリを選択し、**Save** をクリックします。 5. **General** タブで **iOS** および/または **Android** セクションを展開し、App StoreおよびまたはGoogle PlayのアプリケーションURLを貼り付けます。その後、**Save** をクリックします。 6. **Click link** フィールドの値を**1つのリンク**またはプラットフォーム別リンクからコピーします。次に、Meta Ads Manager で広告を開き、このリンクを宛先 URL として貼り付けます。 :::important **Website URL** フィールドには `https://api-ua.adapty.io/api/v1/attribution/click` を貼り付けてください。リンクの残りの部分は、**Tracking** セクションの **URL parameters** フィールドに貼り付けてください。これにより、Meta 広告の審査が通りやすくなります。詳しくは、[Meta Ads Manager での広告設定に関する推奨事項](meta-create-campaign)をご覧ください。 ::: 7. Meta Ads で広告を開始すると、そのデータが Adapty Attribution ダッシュボードで分析できるようになります。 </TabItem> <TabItem value="tiktok" label="TikTok for Business"> TikTok for Business のトラッキングリンクを作成するには: 1. Adapty Attribution ダッシュボードの [Integrations > TikTok Ads](https://app.adapty.io/ua/integrations/tiktok/accounts) に移動し、**Continue with TikTok** をクリックします。 2. TikTok アカウントでサインインし、**Continue** をクリックします。 3. 要求された権限を確認し、**Save** をクリックします。 4. **Web campaigns** タブに切り替え、**Create campaign** をクリックします。アプリを選択して **Save** をクリックします。 5. **General** タブで **iOS** および/または **Android** セクションを展開し、App Store および/または Google Play のアプリケーション URL を貼り付けます。その後、**Save** をクリックします。 6. **1つのリンク**またはプラットフォーム別リンクの **Click link** フィールドの値をコピーします。次に、TikTok Ads Manager で広告を作成する際、**Advanced Settings** セクションの **Tracking URL** フィールドにこの値を貼り付けます。これにより、Adapty はインストールと購入を TikTok の広告に紐付けることができます。詳しくは[TikTok Ads でキャンペーンを設定するガイド](tiktok-create-campaign)をご覧ください。 7. TikTok for Business で広告を配信すると、そのデータが Adapty のアトリビューション ダッシュボードで分析できるようになります。 </TabItem> <TabItem value="others" label="その他の広告プラットフォーム"> その他の広告プラットフォーム向けのトラッキングリンクを作成するには: 1. Adapty Attribution ダッシュボードで、サイドバーメニューから **Tracking links** に移動します。そこで **Create link** をクリックします。 2. リストからアプリを選択し、**Next** をクリックします。 3. リンクのパラメーターを入力して、トラッキングしたいキャンペーンと広告に紐づけます。 4. デフォルトでは One Link が作成されます。これはユーザーのプラットフォームを自動的に検出し、クリックをトラッキングした後に App Store または Google Play へリダイレクトします。 プラットフォームごとに別々のリダイレクト URL を使いたい場合は、**One Link** チェックボックスをオフにして、プラットフォーム別のストアリンクを手動で入力してください。 5. **Create** をクリックします。 6. トラッキングリンクのページを開き、いずれかのセクションから **Click link** をコピーします。 - **One link** – クリックを計測しつつ、ユーザーを適切なストアに自動リダイレクトする場合はこちらを使います。 - **iOS link** または **Android link** — ストアごとに個別のリンクを用意したい場合に使うオプションのリンクです。 7. 広告プラットフォームに移動し、広告の遷移先 URL としてリンクを貼り付けます。 </TabItem> </Tabs> ## ステップ3. ウェブからアプリへのキャンペーンを開始して結果を確認する \{#step-3-launch-your-web-to-app-campaign-and-view-results\} キャンペーンが稼働し、ユーザーがアプリをインストールし始めると、Adaptyはインストールと収益をキャンペーンにアトリビュートし始めます。 [Adapty UAアナリティクスダッシュボード](ua-analytics)では、以下のようなキャンペーンレベルの指標を確認できます: - インストール数とコンバージョン数 - サブスクリプションと購入による収益 - 広告プラットフォーム、キャンペーン、広告セット、クリエイティブ別のパフォーマンス内訳 指標は、アプリからインストールおよび収益イベントを受信した時点で表示されます。広告費用データはネイティブインテグレーションを持つプラットフォームでのみ利用できます。 ## 詳細を学ぶ \{#learn-more\} Adapty アトリビューション分析の詳細ドキュメントや、主要な広告プラットフォームでのキャンペーン運用に関する実践的なガイドをご覧ください: - [**Adapty アトリビューションのアナリティクス**](ua-analytics): アナリティクスダッシュボードを効果的に活用する方法をご確認ください。 - [**Adapty アトリビューションの指標**](ua-metrics): ユーザー獲得分析に使用できる指標を確認しましょう。 - [**インテグレーション**](ua-integrations): Adapty アトリビューションがサポートする広告プラットフォームとインテグレーションを確認してください。 - [**Meta 広告マネージャーでの広告配信**](meta-create-campaign): Meta 広告マネージャーでキャンペーンを設定・配信する方法をご確認ください。 - [**TikTok for Business での広告配信**](tiktok-create-campaign): TikTok for Business でキャンペーンを設定・配信する方法をご確認ください。 --- # File: ua-metrics --- --- title: "Adapty UA の指標" description: "Adapty UA で利用可能な指標について説明します。" --- Adapty User Acquisition は、キャンペーンのパフォーマンスとユーザー行動を測定するための包括的な**指標**を提供します。これらの指標は標準値として利用でき、一部の指標はユーザーグループの時系列分析用の**コホート指標**としても提供されます。 ## 標準指標 \{#standard-metrics\} | **指標** | 説明 | コホート | |-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------| | **Spend** | 広告がタップされるたびに発生するコストの合計。 | No | | **Impressions** | 選択した期間内に広告が表示された回数。 | No | | **Clicks** | レポート期間内にユーザーが広告をクリックした回数。 | No | | **CPI** | **CPI(インストール単価)** はインストール1件あたりの支払い金額。<br/>**計算式**: `Spend / Installs` | No | | **CPC** | **CPC(クリック単価)** は広告クリック1件あたりの支払い金額。<br/>**計算式**: `Spend / Clicks` | No | | **CPM** | **CPM(1,000インプレッション単価)** は広告1,000回表示あたりの支払い金額。<br/>**計算式**: `Spend / (Impressions / 1000)` | No | | **ICR** | **ICR(インストールコンバージョン率)** は広告クリックのうちインストールに至った割合。<br/>**計算式**: `(Installs / Clicks) × 100%` | No | | **IPM** | **IPM(1,000インプレッションあたりインストール数)** は広告1,000回表示あたりのインストール数。<br/>**計算式**: `(Installs / Impressions) × 1000` | No | | **CTR** | **CTR(クリック率)** はインプレッションのうちクリックに至った割合。<br/>**計算式**: `(Clicks / Impressions) × 100%` | No | | **Inline link clicks** | 広告クリエイティブまたはアプリページのインラインリンクをユーザーがクリックした回数。 | No | | **Cost per inline link click** | インラインリンクのクリック1件あたりの平均支払い金額。<br/>**計算式**: `Spend / Inline Link Clicks` | No | | **Inline link click CTR** | インプレッションのうちインラインリンクのクリックに至った割合。<br/>**計算式**: `(Inline Link Clicks / Impressions) × 100%` | No | | **Installs** | レポート期間内にアプリをインストールしたユーザーの合計数(再インストールを含む)。 | No | | **Revenue** | 選択した期間内にこのキャンペーンに紐づく購入から発生した売上の合計(ストア手数料控除前)。 | Yes | | **ROAS** | **ROAS(広告費用対効果)** は広告売上を広告費で割ったもので、パーセンテージで表示。<br/>**計算式**: `(Revenue / Spend) × 100%(Spend > 0 の場合、それ以外は 0%)` | Yes | | **ARPU** | **ARPU(ユーザーあたり平均収益)** はコホート内のユーザー1人あたりの平均収益。<br/>**計算式**: `Revenue / Users` | Yes | | **LTV** | **LTV(ライフタイムバリュー)** はユーザー1人が生涯にわたってもたらす平均収益。<br/>**計算式**: `Revenue / Installs` | No | | **Cost per trial** | トライアル開始1件あたりの平均支払い金額。<br/>**計算式**: `Spend / Count trial started` | No | | **Cost per subscription** | サブスクリプションプロダクトの購入1件あたりの平均支払い金額。<br/>**計算式**: `Spend / Count subscription started` | No | | **Count subscription events** | レポート期間内のサブスクリプション関連イベントをカウントする指標グループ。含まれる指標:<br/>- Count subscription started<br/>- Count subscription renewed<br/>- Count subscription renewal cancelled<br/>- Count subscription renewal reactivated<br/>- Count subscription expired<br/>- Count [subscription deferred](https://adapty.io/glossary/subscription-purchase-deferral/)<br/>- Count subscription refunded | Yes | | **Count trial events** | レポート期間内のトライアル関連イベントをカウントする指標グループ。含まれる指標:<br/>- Count trial started<br/>- Count trial converted<br/>- Count trial expired<br/>- Count trial renewal reactivated | Yes | | **Count billing issue detected** | レポート期間内に検出された請求の問題の件数。 | Yes | | **Count entered grace period** | 請求の問題によりグレース期間に入ったサブスクリプションの件数。 | Yes | | **Count non-subscription events** | レポート期間内のサブスクリプション以外の関連イベントをカウントする指標グループ。含まれる指標:<br/>- Count non-subscription purchased<br/>- Count non-subscription refunded | Yes | | **Subscription events rate** | レポート期間内のアプリインストール数に対するサブスクリプション関連イベントの比率を示す指標。含まれる指標:<br/>- Rate subscription started<br/>- Rate subscription renewed<br/>- Rate subscription renewal cancelled<br/>- Rate subscription renewal reactivated<br/>- Rate subscription expired<br/>- Rate [subscription deferred](https://adapty.io/glossary/subscription-purchase-deferral/)<br/>- Rate subscription refunded | Yes | | **Trial events rate** | レポート期間内のアプリインストール数に対するトライアル関連イベントの比率を示す指標。含まれる指標:<br/>- Rate trial started<br/>- Rate trial converted<br/>- Rate trial expired<br/>- Rate trial renewal reactivated | Yes | | **Rate billing issue detected** | レポート期間内のアプリインストール数に対する請求の問題の比率。 | Yes | | **Rate entered grace period** | レポート期間内のアプリインストール数に対してグレース期間に入ったサブスクリプションの比率。 | Yes | | **Non-subscription events rate** | レポート期間内のアプリインストール数に対するサブスクリプション以外の関連イベントの比率を示す指標。含まれる指標:<br/>- Rate non-subscription purchased<br/>- Rate non-subscription refunded | Yes | ## 予測指標 \{#predicted-metrics\} 予測指標は、アプリ自身の過去のデータをもとに、コホートの将来のパフォーマンスを予測します。D30、D60、D90、D180、D360など複数のコホート期間に対応しており、日数単位でカスタム期間を追加することもできます。算出方法の詳細については、[Adapty アトリビューションの予測指標](ua-predicted-metrics)をご覧ください。 | **指標** | 説明 | コホート | |---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------| | **pRevenue** | 対象のホライズンまでにコホートが生み出すと予測される総収益。アプリの過去のコホートリテンションからモデル化されます。 | あり | | **pROAS** | 同じホライズンにおける広告費用対効果の予測値。**計算式**: `(pRevenue / Spend) × 100%` | あり | | **pAdProfit** | ホライズンにおける広告費を差し引いた予測収益。**計算式**: `pRevenue − Spend` | あり | | **pARPU** | ホライズンにおけるインストール1件あたりの予測平均収益(予測LTV)。**計算式**: `pRevenue / Installs` | あり | | **pARPPU** | ホライズンにおける課金ユーザー1人あたりの予測平均収益。**計算式**: `pRevenue / paying users at d{N}`(`d{N}` は選択したホライズンに対応) | あり | --- # File: ua-predicted-metrics --- --- title: "Adapty アトリビューションにおける予測指標" description: "Adapty アトリビューションのコホートにおける収益、ROAS、広告利益、LTV を予測します。" --- :::important この記事は、Adapty アトリビューションにおける予測についてのみ説明しています。コホート分析ページでの予測 LTV と収益については、[コホートにおける予測](predicted-ltv-and-revenue)を参照してください。 ::: Adapty アトリビューションは、各コホートの将来の収益とユニットエコノミクスを予測するため、キャンペーンが成熟する前に比較することができます。予測はアプリ自身の過去のコホートデータをもとに生成され、毎日更新されます。サブスクリプションサイクルが完了していない直近のコホートを評価する際に特に役立ちます。 ## 予測指標 \{#predicted-metrics\} | **指標** | 説明 | |---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **pRevenue** | コホートが目標ホライズンまでに生成すると予測される総収益。アプリの過去のコホートリテンションからモデル化されます。 | | **pROAS** | 同じホライズンにおける広告費用対効果の予測値。**計算式**: `(pRevenue / Spend) × 100%` | | **pAdProfit** | ホライズンにおける広告費用を差し引いた予測収益。**計算式**: `pRevenue − Spend` | | **pARPU** | ホライズンにおけるインストール1件あたりの予測平均収益(予測LTV)。**計算式**: `pRevenue / Installs` | | **pARPPU** | ホライズンにおける課金ユーザー1人あたりの予測平均収益。**計算式**: `pRevenue / paying users at d{N}`(`d{N}` は選択したホライズンに対応) | `pRevenue` はベースとなる値です。その他の4つの指標は、モデルを個別に実行するのではなく、観測されたコホートデータ(支出、インストール数、課金ユーザー数)を使って `pRevenue` から導出されます。 各予測指標は、D0、D3、D7、D30、D60、D90、D180、D360 の複数のコホート期間で利用できます。日数を指定してカスタム期間を追加することも可能です。この期間は、コホートのインストール日から将来のどの時点まで値を予測するかを定義します。 ## 予測の計算方法 \{#how-predictions-are-calculated\} 予測は各アプリの過去のコホートをもとに構築されます。モデルはベースライン日以降に過去コホートの収益がどのように増加したかを計測し、同じ軌跡を使って現在のコホートの将来を予測します。 ### ベースライン日 \{#baseline-day\} 予測は、コホートがベースライン日に達した後にのみ利用可能になります。ベースライン日とは、コホートの初期収益の90%が通常受け取られる最初の日です。初期収益には、サブスクリプションの開始、トライアルのコンバージョン、および買い切り購入が含まれます。更新はこの閾値にはカウントされません。 ベースライン日は、アプリのトライアル期間とプロダクトの組み合わせによって異なります。 - **トライアルなしのアプリ**: ベースラインは通常、インストール後の最初の数日以内に設定されます。 - **短期トライアルのあるアプリ**: ベースラインは通常、トライアルが転換した直後に設定されます。 - **長期トライアルのあるアプリ**: 初期収益のほとんどはトライアル完了後に発生するため、ベースラインはインストールから1週間以上後になることがあります。 ### サブスクリプションタイプ別の予測 \{#projection-by-subscription-type\} ベースライン日において、コホートの初期収益は月次・年次・週次・四半期サブスクリプション、および買い切り購入の5つのカテゴリに分類されます。各カテゴリは過去のコホートから計測された軌跡を使って独立して予測されます。 モデルは、直近のコホートや、1取引あたりの収益が近く、プロダクト構成が似ているなど経済的に類似したコホートを重視します。したがって、予測はアプリ内で最も直近かつ最も類似したコホートの実際のパフォーマンスを反映したものになります。 ## 予測が表示されるタイミング \{#when-predictions-are-available\} 予測は、コホートに十分なデータがある場合にのみ表示されます。値を算出できない場合、該当の列にはダッシュ(`—`)が表示されます。 予測が利用できない主な理由: - **コホートがベースライン日に達していない**:モデルが将来の推計を行うには、コホートの初期収益が安定するまで待つ必要があります。 - **アプリの過去データが不足している**:対象サブスクリプションタイプの過去のコホートデータが十分にない場合、モデルは信頼性の高い継続率を算出できません。 予測は最新のトランザクションデータをもとに毎日再計算されるため、より多くの収益が観測されるにつれて、同じコホートの値が変動することがあります。 --- # File: ua-tracking-links --- --- title: "Adapty アトリビューションのトラッキングリンク" description: "キャンペーンをトラッキングし、あらゆる場所で成果を計測しましょう。" --- トラッキングリンクを使うと、ユーザーの流入元を計測し、インストールを広告キャンペーンに紐づけることができます。 ユーザーが広告をクリックすると、Adapty はそのクリックを記録し、後で SDK から送信されたインストールイベントと照合します。これにより、[Analytics ページ](ua-analytics)でどのチャネル・キャンペーン・広告セット・広告が最も多くの収益をもたらしているかを確認できます。 作成できるトラッキングリンクは次の 2 種類です: - **One link** — ユーザーのプラットフォームを自動検出し、クリックを記録して App Store または Google Play にリダイレクトするユニバーサルリンクです。 - **ストア固有リンク** — プラットフォームに応じたリンクで、クリックを記録しつつ App Store または Google Play へ自動でリダイレクトします。遅延ディープリンクのパラメーターを追加することもできます。 ## トラッキングリンクを作成する \{#create-tracking-links\} トラッキングリンクを作成するには: 1. Adapty Attribution ダッシュボードのサイドバーメニューから **Tracking links** に移動し、**Create link** をクリックします。 2. リストからアプリを選択し、**Next** をクリックします。 3. トラッキングしたいキャンペーンや広告に合わせて、リンクのパラメーターを入力します。 | パラメータ | 説明 | |-----------|------| | **Name** | トラッキングリンクの内部名称。 | | **Channel** | Meta、Reddit、TikTok などのトラフィックの流入元。アナリティクスでキャンペーンをグループ化するために使用されます。 | | **Campaign ID** | 広告プラットフォームにおけるキャンペーンの一意識別子。 | | **Campaign name** | キャンペーンのわかりやすい名称。 | | **Ad set ID** | 広告プラットフォームにおける広告セット(広告グループ)の一意識別子。 | | **Ad set name** | 広告セットの名称。 | | **Ad ID** | 個々の広告クリエイティブの一意識別子。 | | **Ad name** | 広告クリエイティブまたはバリエーションの名称。 | 4. デフォルトでは、One Link が作成されます。これはユーザーのプラットフォームを自動的に検出し、クリックを追跡した後、App Store または Google Play にリダイレクトします。 プラットフォームごとに別々のリダイレクト URL を使用したい場合は、**One Link** チェックボックスをオフにして、プラットフォーム固有のストアリンクを手動で入力してください。 5. **Create**をクリックします。 6. トラッキングリンクのページを開き、いずれかのセクションから**クリックリンク**をコピーします: - **One link** – クリックを計測し、ユーザーを自動的に適切なストアにリダイレクトするリンクです。 - **iOS link** または **Android link** — ストアごとに別々のリンクを使いたい場合のオプションです。 :::tip [遅延データを扱う](ua-deferred-data)ために追加のリンクパラメーターを設定することもできます。たとえば、遅延ディープリンクを実装できます。 ::: 7. 広告プラットフォームにアクセスして、広告のリンクを広告の遷移先 URL として貼り付けてください。 これにより、アプリのインストールがどの広告やキャンペーンから来たかと照合され、**Analytics** ページでキャンペーンの効果を測定できるようになります。 --- # File: ua-deferred-data --- --- title: "Adapty アトリビューションでのディファードディープリンク" description: "Adapty アトリビューションでディファードディープリンクを設定します。" --- ディファードディープリンクを使うと、ユーザーが広告をクリックしてアプリをインストールした際に、カスタムデータをアプリに渡すことができます。たとえば、インストール後に初めてアプリを起動したとき、特定の画面に直接ナビゲートするといったことが可能です。 仕組みは次のとおりです: 1. ユーザーが広告をクリックすると、Adapty はクリックデータを保存します。 2. Adapty がインストールイベントを検知すると、クリック時のディファードデータを取得します。 3. ユーザーがアプリをインストールして初回起動すると、Adapty は保存されたデータを取り出し、アプリがカスタムパラメーターを受け取ります。これにより、アプリのコード内でさまざまな値に応じた処理を行えます。 Adapty は以下の遅延データパラメーターをサポートしています: - `ios_deferred_data` - `android_deferred_data` - `deferred_data_sub[1-10]` 遅延データパラメーターを追加するには、キャンペーン設定のリンクにパラメーターを追記します: 1. **Integrations -> Meta/TikTok Ads** ページからキャンペーンを開くか、**Tracking links** ページからトラッキングリンクを開きます。キャンペーンで使用するクリックリンクをコピーしてください。 2. 広告プラットフォーム(Meta、TikTok、Google Adsなど)で、そのリンクを広告の遷移先URL欄に貼り付け、遅延データのパラメーターを追加のクエリパラメーターとして末尾に付加します。各パラメーターの先頭には `&` を付けてください。たとえば、インストール後にiOSユーザーを「Welcome」画面に誘導したい場合は、`&ios_deferred_data=welcome` を追加します。最終的な遷移先URLは次のようになります。 ``` https://api-ua.adapty.io/api/v1/attribution/click?adpt_cid=__ADAPTY__ID__&ios_deferred_data=welcome&campaign_id=__CAMPAIGN_ID__&adset_id=__AID__&ad_id=__CID__&campaign_name=__CAMPAIGN_NAME__&adset_name=__AID_NAME__&ad_name=__CID_NAME__&redirect_url=__APP_LINK__ ``` 3. アプリのコードでパラメーターを処理します。なお、遅延データのパラメーターは `payload` パラメーターに含まれており、`payload` パラメーターはエスケープされた JSON であるため、アプリのコード内でパースする必要があります。 たとえば、`ios_deferred_data` が `welcome` のインストールを処理する方法は次のとおりです。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers Adapty.delegate = self nonisolated func onInstallationDetailsSuccess(_ details: AdaptyInstallationDetails) { guard let payloadStr = details.payload, let data = payloadStr.data(using: .utf8), let payload = try? JSONSerialization.jsonObject(with: data) as? [String: Any], let deeplink = payload["ios_deferred_data"] as? String, deeplink == "welcome" else { return } DispatchQueue.main.async { print("Navigate to welcome screen") // navigate to your screen here } } ``` </TabItem> <TabItem value="android" label="Kotlin"> ```kotlin showLineNumbers Adapty.setOnInstallationDetailsListener(object : OnInstallationDetailsListener { override fun onInstallationDetailsSuccess(details: AdaptyInstallationDetails) { details.payload?.let { runCatching { val json = JSONObject(it) if (json.optString("android_deferred_data") == "welcome") { println("Navigate to welcome screen") // navigate here } }.onFailure(Throwable::printStackTrace) } } }) ``` </TabItem> <TabItem value="rn" label="React Native" default> ```typescript showLineNumbers adapty.addEventListener('onInstallationDetailsSuccess', details => { // Parse the payload JSON and navigate to welcome screen if needed try { if (details.payload) { const payload = JSON.parse(details.payload); if (payload.ios_deferred_data === 'welcome') { // Navigate to welcome screen // Replace with your app's navigation logic // For example, using React Navigation: // navigation.navigate('Welcome'); console.log('Navigate to welcome screen'); } } } catch (error) { console.error('Error parsing installation details payload:', error); } }); ``` </TabItem> <TabItem value="flutter" label="Flutter"> ```dart showLineNumbers Adapty().onUpdateInstallationDetailsSuccessStream.listen((details) { final payloadStr = details.payload; if (payloadStr == null) return; final payload = json.decode(payloadStr) as Map<String, dynamic>; if (payload['ios_deferred_data'] == 'welcome') { print('Navigate to welcome screen'); } }); ``` </TabItem> </Tabs> --- # File: ua-attribution-data --- --- title: "アプリでアトリビューションデータを受け取る" description: "Adaptyがインストールをキャンペーンに紐付けた後、アプリ内でキャンペーンのアトリビューションデータにアクセスします。" --- Adaptyがインストールをキャンペーンに紐付けると、`onInstallationDetailsSuccess` コールバックを通じてアプリにアトリビューションデータが返されます。このデータを使って、インストールを促したチャネルやキャンペーンに基づいてユーザー体験をパーソナライズできます。 アトリビューションデータは、`payload` フィールド内にネストされた `attribution` オブジェクトとして返されます。以下のフィールドが含まれます: | フィールド | 説明 | |---|---| | `channel` | 獲得チャネル(例: `facebook`、`tiktok`、`google`、`organic`) | | `campaign_id` | キャンペーン識別子 | | `campaign_name` | キャンペーン名 | | `adset_id` | 広告セット / 広告グループの識別子 | | `adset_name` | 広告セット / 広告グループ名 | | `ad_id` | 広告 / クリエイティブの識別子 | | `ad_name` | 広告 / クリエイティブ名 | すべてのフィールドは任意です。オーガニックインストールの場合や、アトリビューションを特定できなかった場合、`payload` フィールドに `attribution` オブジェクトは含まれません。 アプリでアトリビューションデータを読み取るには: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers Adapty.delegate = self nonisolated func onInstallationDetailsSuccess(_ details: AdaptyInstallationDetails) { guard let payloadDict = details.payload?.dictionary, let attribution = payloadDict["attribution"] as? [String: Any] else { return } let channel = attribution["channel"] as? String let campaignName = attribution["campaign_name"] as? String let adName = attribution["ad_name"] as? String print("Channel: \(channel ?? "organic")") } ``` </TabItem> <TabItem value="android" label="Kotlin"> ```kotlin showLineNumbers Adapty.setOnInstallationDetailsListener(object : OnInstallationDetailsListener { override fun onInstallationDetailsSuccess(details: AdaptyInstallationDetails) { val payloadStr = details.payload ?: return runCatching { val payload = JSONObject(payloadStr) val attribution = payload.optJSONObject("attribution") ?: return val channel = attribution.optString("channel") val campaignName = attribution.optString("campaign_name") val adName = attribution.optString("ad_name") println("Channel: $channel") }.onFailure(Throwable::printStackTrace) } }) ``` </TabItem> <TabItem value="rn" label="React Native"> ```typescript showLineNumbers adapty.addEventListener('onInstallationDetailsSuccess', details => { try { if (!details.payload) return; const payload = JSON.parse(details.payload); const attribution = payload.attribution; if (!attribution) return; const channel = attribution.channel; const campaignName = attribution.campaign_name; const adName = attribution.ad_name; console.log('Channel:', channel ?? 'organic'); } catch (error) { console.error('Error parsing payload:', error); } }); ``` </TabItem> <TabItem value="flutter" label="Flutter"> ```dart showLineNumbers Adapty().onUpdateInstallationDetailsSuccessStream.listen((details) { final payloadStr = details.payload; if (payloadStr == null) return; final payload = json.decode(payloadStr) as Map<String, dynamic>; final attribution = payload['attribution'] as Map<String, dynamic>?; if (attribution == null) return; final channel = attribution['channel'] as String?; final campaignName = attribution['campaign_name'] as String?; final adName = attribution['ad_name'] as String?; print('Channel: ${channel ?? 'organic'}'); }); ``` </TabItem> </Tabs> --- # File: ua-facebook --- --- title: "Meta AdsをAdapty Attributionと連携する" description: "Meta AdsをAdapty Attributionに接続して、Facebook、Instagram、Messenger、Audience Networkにわたるキャンペーンのパフォーマンスをトラッキング・最適化しましょう。" --- Adapty アトリビューションの Meta 連携を使うと、Facebook、Instagram、Messenger、Audience Network にわたるキャンペーンのパフォーマンスをトラッキング・最適化できます。 :::tip [Meta Ads Manager での広告設定ガイド](meta-create-campaign)もご覧ください。 ::: ## ステップ 1. Facebookアカウントを連携する \{#step-1-connect-your-facebook-account\} Meta Ads を Adapty のアトリビューションに連携するには、左サイドバーから **Integrations > Meta** に移動します。接続方法は 2 種類あります。 - **Continue with Facebook**: OAuth 経由で接続します。個人または法人の Facebook アカウントで Meta Ads Manager にサインインしている場合はこちらを使用してください。 - **Add system token**: 永続的なシステムユーザートークンを使って接続します。組織が Meta Business のシステムユーザーを通じて広告アカウントを管理している場合はこちらを使用してください。 <Tabs> <TabItem value="oauth" label="Continue with Facebook"> :::important Facebookアカウントが必要なキャンペーンとピクセルにアクセスできることを確認してください。 ::: 1. **Continue with Facebook** をクリックします。 2. Facebookアカウントでサインインし、**Continue** をクリックします。 3. リクエストされた権限を確認し、**Save** をクリックします。 </TabItem> <TabItem value="system" label="Add system token"> Meta Business Settingsで[システムユーザーアクセストークン](https://developers.facebook.com/documentation/ads-commerce/marketing-api/collaborative-ads/managed-partner-ads/api-guide/prerequisites/generate-access-token-system-user)を生成し、Adapty Attributionに追加します。 :::important 始める前に、Meta Businessポートフォリオに[システムユーザー](https://www.facebook.com/business/help/503306463479099)が必要です。このシステムユーザーには、トラッキング対象の広告アカウントが割り当て済みである必要があります。また、ポートフォリオにアプリが追加されている必要があります(トークン生成時にこのアプリを選択します)。 ::: **Meta Business Settings でトークンを生成します:** 1. **Business Settings** を開きます。 2. **Users** の下にある **System users** を選択します。 3. システムユーザーを選択し、**Generate new token** をクリックします。 4. ドロップダウンからアプリを選択します。 5. 権限リストで `ads_read` を有効にします。これが、Adapty Attribution がキャンペーンおよび広告データを読み取るために必要な唯一の権限です。 6. **Generate token** をクリックします。 7. トークンをコピーし、安全な場所に保存します。Meta はトークンを一度しか表示しません。 :::note **トークンの有効期限**設定は、接続をアクティブに保つ期間を制御します。有効期限が設定されたトークンは、期限が切れる前に再生成して再接続する必要があります。そうしないとアトリビューションが停止します。有効期限なしのトークンはこの問題を回避できますが、長期間有効な認証情報です。安全な場所に保管し、漏洩した場合はすぐに失効させてください。 ::: **Adapty Attribution でトークンを追加します:** 1. **Add system token** をクリックします。 2. トークンを貼り付けて、**Connect** をクリックします。 </TabItem> </Tabs> この設定が完了すると、すべての広告アカウントが Adapty Attribution に追加されます。次に、キャンペーンの追加に進んでください。 ## ステップ 2. キャンペーンを追加する \{#step-2-add-campaigns\} Meta のキャンペーンを Adapty Attribution に追加して、Meta 広告の効果を Adapty でトラッキングするには: 1. **Web Campaigns** タブに切り替え、**Create configuration** をクリックします。 2. **General** タブで **iOS** および/または **Android** セクションを展開し、App Store および/または Google Play のアプリケーション URL を貼り付けます。 3. **Click link** フィールドの値をコピーします。次に、Meta Ads Manager で広告を開き、このリンクを貼り付けます。これにより、Adapty がインストールおよび購入を Meta の広告に紐付けられるようになります。 4. Meta にコンバージョンイベントを送り返すには、Meta のピクセルを Adapty Attribution のキャンペーンに紐付けることもできます。**Pixel** ドロップダウンから既存のピクセルを選択してください。ピクセルを選択した後、**Send test event** をクリックして接続を確認できます。 ## ステップ 3. イベントのマッピング \{#step-3-map-events\} キャンペーン最適化のためにコンバージョンイベントを Meta に送り返すには、**Events names** セクションでイベントマッピングを設定する必要があります。これにより、ユーザーがアプリ内でアクションを実行したときに、Adapty がサブスクリプションイベントを自動的に Meta ピクセルに送信できるようになります。 **Events names** セクションで、Meta Ads Manager でトラッキングしたいイベントをオンにします。有効にした各イベントについて、ドロップダウンから対応する Meta イベントを選択するか、カスタムイベントを設定してください。デフォルトでは、Adapty のイベントは Meta の標準イベントにマッピングされています。 **Save** をクリックして、イベントマッピングの設定を適用します。 ## 追加設定 \{#additional-configuration\} ### 追加パラメーター \{#additional-parameters\} **Additional parameter** フィールドでは、Adapty 外での分析に使用するカスタムデータを追加できます。特定のキャンペーンやユーザーデータを外部の分析ツールやアトリビューションパートナーに渡す必要がある場合に便利です。 **Additional parameter** フィールドに、アトリビューショントラッキングに含めたいカスタムデータを入力してください。追加パラメーターは Meta に送信されるすべてのアトリビューションデータに含まれ、高度なキャンペーン分析や最適化に活用できます。 例えば、同じキャンペーンで複数のバリエーションを運用している場合、`variant=A` や `variant=B` を追加してクリエイティブアプローチの違いを区別できます。 :::important 追加パラメータを設定すると、Meta Ads Manager に貼り付ける **Click link** が変わります。すでにこのリンクをコピーして貼り付けた後にカスタムパラメータを追加した場合は、そのパラメータを含む最新のクリックリンクをコピーし直して貼り付けてください。 ::: <br/> ### 設定 \{#settings\} **Settings** タブでは、Adapty がユーザーのアクションを Meta Ads のキャンペーンに紐づける方法を設定できます。ここでは、確定的アトリビューションと確率的アトリビューションのマッチング時間枠を指定します。 設定するには、キャンペーン設定の **Settings** タブに移動してください。調整できる主な設定は次の2つです。 - **決定論的マッチングウィンドウ**: これは正確なデバイス識別子(iOS の IDFA や Android の Advertising ID など)を使用して、ユーザーをキャンペーンに高精度でマッチングします。最大限のアトリビューション精度を得るために、これを 168 時間(7 日間)に設定してください。これはデフォルトかつ推奨値です。ユーザーが Meta 広告をクリックし、このウィンドウ内にアプリをインストールした場合、Adapty はデバイス識別子を使用してそのインストールを特定の広告クリックに確実にアトリビュートできます。 - **Probabilistic matching window**: 確率的マッチングが利用できない場合(プライバシー設定などの要因により決定論的マッチングができないユーザーに対して)、統計モデリングとデバイスフィンガープリンティングを使用してユーザーをマッチングします。ほとんどのキャンペーンでは6時間に設定することをおすすめします。これはデフォルト値であり、ほとんどのユースケースで適切に機能します。クリック数が多いキャンペーンの場合は、1〜2時間に短縮することも可能です。 設定を適用するには **Save** をクリックしてください。 ### 収益のオーバーライド \{#revenue-override\} トライアルイベントを追跡し、Metaに収益をアトリビューションさせたい場合は、**Revenue override** セクションを使用します。このセクションは **Trial started** イベントが有効になっているときに表示されます。 各トライアルイベントのターゲットに対して、収益としてレポートするサブスクリプション価格の割合を設定します。たとえば、30% に設定すると、Adapty はトライアルイベントのコンバージョン値としてサブスクリプション価格の 30% を送信します。 オーバーライドを追加するには: 1. **Events names** セクションで **Trial started** を有効にします。 2. **Revenue override** で **Add override** をクリックします。 3. 対象イベントを選択し、収益の割合(0〜100)を入力します。 4. **Save** をクリックします。 ### すべてのイベントを送信する \{#send-all-events\} デフォルトでは、AdapyはMetaキャンペーンにアトリビュートされたユーザーのイベントのみをピクセルに送信します。**Send all events** を有効にすると、オーガニックユーザーやアトリビュートされていないユーザーのイベントもピクセルに転送されます。 有効にすると、キャンペーンのアトリビューションに関わらず、すべてのインストールおよびトランザクションイベントがピクセルに送信されます。オーディエンスモデリングやキャンペーン最適化のためにMetaにより広範なコンバージョンデータを提供したい場合に使用してください。 このオプションを有効にするには、キャンペーン設定で **Send all events (forward organic/non-attributed events to this pixel)** を選択し、**Save** をクリックします。 --- # File: ua-tiktok --- --- title: "Adapty アトリビューションへの TikTok for Business の統合" description: "TikTok for Business を Adapty アトリビューションに接続して、TikTok 広告マネージャーでキャンペーンのパフォーマンスを追跡・最適化しましょう。" --- Adapty アトリビューションの TikTok for Business 連携を使うと、TikTok でのキャンペーンパフォーマンスをトラッキング・最適化できます。 :::tip [TikTok for Business での広告設定ガイド](tiktok-create-campaign)もご覧ください。 ::: ## ステップ1. TikTokアカウントを接続する \{#step-1-connect-your-tiktok-account\} 1. 左サイドバーから **Integrations > TikTok Ads** に移動し、**Continue with TikTok** をクリックします。 2. TikTokアカウントでサインインし、**Continue** をクリックします。 3. 要求される権限を確認し、**Save** をクリックします。 完了すると、すべての広告アカウントがAdapty UAに追加されます。続けてキャンペーンを追加できます。 ## ステップ 2. キャンペーンを追加する \{#step-2-add-campaigns\} TikTok for Business のキャンペーンを Adapty アトリビューションに追加し、TikTok 広告の効果を Adapty で追跡するには: 1. **Web Campaigns** タブに切り替えて、**Create configuration** をクリックします。 2. **General** タブで、**iOS** および/または **Android** セクションを展開し、App Store および/または Google Play のアプリケーション URL を貼り付けます。 3. **Click link** フィールドの値をコピーします。次に、TikTok Ads Manager で広告を作成する際、**Advanced Settings** セクションの **Tracking URL** フィールドにこの値を貼り付けます。これにより、Adapty はインストールと購入を TikTok の広告に紐付けることができます。 4. (任意)コンバージョンイベントをTikTokに送り返すには、TikTokのピクセルをAdapty AttributionのキャンペーンとひもづけることもできThat。そのためには、**Pixel**ドロップダウンから既存のピクセルを選択してください。ピクセルを選択したら、**Send test event**をクリックして接続を確認できます。 ## ステップ 3. イベントをマッピングする \{#step-3-map-events\} キャンペーンの最適化のためにTikTokにコンバージョンイベントを送信するには、**Events names** セクションでイベントのマッピングを設定する必要があります。これにより、ユーザーがアプリ内でアクションを実行した際に、AdaptyがサブスクリプションイベントをTikTokピクセルに自動的に送信できるようになります。 **Events names** セクションで、TikTok Ads Managerでトラッキングしたいイベントをオンに切り替えます。有効にした各イベントについて、ドロップダウンから対応するTikTokイベントを選択するか、カスタムイベントを設定します。デフォルトでは、AdaptyのイベントはTikTokの標準イベントにマッピングされます。 **Save** をクリックして、イベントマッピングの設定を適用します。 ## 追加設定 \{#additional-configuration\} ### 追加パラメーター \{#additional-parameters\} **Additional parameter** フィールドでは、Adapty 外での分析に使うカスタムデータを追加できます。特定のキャンペーンやユーザーデータを外部の分析ツールやアトリビューションパートナーに渡したい場合に便利です。 **Additional parameter** フィールドに、アトリビューショントラッキングに含めたいカスタムデータを入力してください。追加パラメーターは TikTok に送信されるすべてのアトリビューションデータに含まれ、高度なキャンペーン分析や最適化に活用できます。 例えば、同じキャンペーンで複数のバリエーションを実施している場合、`variant=A` や `variant=B` を追加して、異なるクリエイティブアプローチを区別することができます。 :::important 追加パラメーターを設定すると、TikTok Ads Manager に貼り付ける **Click link** が変わります。すでにこのリンクをコピーして貼り付けた後にカスタムパラメーターを追加した場合は、カスタムパラメーターを含む更新済みのクリックリンクをコピーして貼り直してください。 ::: <br/> ### 設定 \{#settings\} **Settings** タブでは、Adapty がユーザーのアクションを TikTok Ads キャンペーンに紐付ける方法を設定します。決定論的および確率論的アトリビューションマッチングの時間枠をここで指定します。 設定するには、キャンペーン設定の **Settings** タブを開きます。調整できる主な設定は次の 2 つです。 - **決定論的マッチングウィンドウ**: これはデバイスの正確な識別子(iOS の IDFA や Android の Advertising ID など)を使用して、ユーザーをキャンペーンに高精度でマッチングします。最大限のアトリビューション精度を得るために 168 時間(7 日間)に設定してください。これはデフォルトかつ推奨値です。ユーザーが TikTok 広告をクリックしてこのウィンドウ内にアプリをインストールした場合、Adapty はデバイス識別子を使ってそのインストールを特定の広告クリックに確実に紐付けることができます。 - **Probabilistic matching window**: これは統計モデリングとデバイスフィンガープリンティングを使用して、決定論的マッチングが不可能な場合にユーザーをマッチングします。ほとんどのキャンペーンではこれを6時間に設定してください。これがデフォルトであり、多くのユースケースで適切に機能します。クリック数の多いキャンペーンでは、1〜2時間に短縮することもできます。プライバシー設定などの要因で決定論的にマッチングできないユーザーについては、Adapty はこの短いウィンドウ内で確率論的マッチングを使用します。 **Save** をクリックして設定を適用します。 ### 収益のオーバーライド \{#revenue-override\} トライアルイベントを追跡し、TikTok にその収益をアトリビューションさせたい場合は、**Revenue override** セクションを使用します。このセクションは、**Trial started** イベントが有効になっている場合に表示されます。 トライアルイベントの各ターゲットに対して、収益として報告するサブスクリプション価格の割合を設定します。たとえば、30% に設定すると、Adapty はトライアルイベントのコンバージョン値としてサブスクリプション価格の 30% を送信します。 オーバーライドを追加するには: 1. **Events names** セクションで **Trial started** を有効にします。 2. **Revenue override** の **Add override** をクリックします。 3. 対象のイベントを選択し、収益の割合(0〜100)を入力します。 4. **Save** をクリックします。 ### すべてのイベントを送信する \{#send-all-events\} デフォルトでは、AdaptyはTikTokキャンペーンにアトリビューションされたユーザーのイベントのみをピクセルに送信します。**Send all events** を有効にすると、オーガニックや未アトリビューションのユーザーのイベントもピクセルに転送されます。 有効にすると、キャンペーンのアトリビューションに関わらず、すべてのインストールおよびトランザクションイベントがピクセルに送信されます。これにより、TikTokにより広範なコンバージョンデータを提供し、オーディエンスモデリングやキャンペーン最適化に活用できます。 このオプションを有効にするには、キャンペーン設定で **Send all events (forward organic/non-attributed events to this pixel)** を選択し、**Save** をクリックします。 --- # File: ua-funnelfox --- --- title: "FunnelFoxをAdapty Attributionと連携する" description: "FunnelFoxのウェブ・トゥ・アプリファネルをAdapty Attributionと接続して、ウェブのタッチポイントから有料サブスクリプションへの完全なアクイジションパスを追跡します。" --- [FunnelFox](https://funnelfox.com) は、App Store の手数料やその他の制限を回避しつつ、ストア外でユーザーを獲得・課金できる web2app ファネル構築プラットフォームです。 連携が完了すると、FunnelFox はトランザクションイベントを Adapty のアトリビューションに送信し、ウェブのタッチポイントから有料サブスクリプションまでの完全なアトリビューションパスを確認できるようになります。 インテグレーションを設定するには、**Project ID** を使って 1 つ以上の FunnelFox プロジェクトをお使いの Adapty アプリにリンクしてください。 ## 仕組み \{#how-it-works\} ユーザーが FunnelFox のファネルで購入を完了すると、FunnelFox はトランザクションイベントを Adapty Attribution に送信します。Adapty は **Project ID** を使用して、そのトランザクションがどのアプリに属するかを識別します。イベントは保存され、Adapty Attribution のアナリティクスに表示されます。 各トランザクションには以下が含まれます: - **サブスクリプションライフサイクルイベント**: 開始、更新、キャンセル、トライアル変換、返金など - **アトリビューションデータ**: キャンペーン、広告セット、広告識別子、UTMパラメーター、プラットフォームのクリックID(fbclid、ttclid、gclid) - **ファネルおよび実験データ**: FunnelFoxのファネル名と実験名(A/B テストのバリアントを比較するために使用) Adaptyはトランザクション内のクリックIDから**チャンネル**(Facebook、TikTok、Google、またはオーガニック)を自動的に判別します。手動での設定は不要です。 :::note FunnelFox のトランザクションは、ウェブ購入にはアプリのインストールイベントがないため、インストール日ではなく**初回課金日**をコホート日として使用します。 ::: ## 連携を設定する \{#configure-integration\} ### ステップ 1. FunnelFox で Project ID を取得する \{#step-1-get-your-project-id-in-funnelfox\} 1. FunnelFox ダッシュボードの左サイドバーで **Settings** をクリックします。 2. **Project info** セクションで **ID** の値をコピーします。 ### ステップ 2. Adapty UA でプロジェクトを追加する \{#step-2-add-the-project-in-adapty-ua\} 1. Adapty UA で [**Integrations > FunnelFox**](https://app.adapty.io/ua/integrations/funnelfox) に移動します。 2. FunnelFox からコピーした Project ID を貼り付けます。 3. **Save** をクリックします。 追加の FunnelFox プロジェクトを接続するには、**Add project** をクリックし、プロジェクトごとに両方のステップを繰り返してください。 --- # File: ua-custom-s3 --- --- title: "Adapty アトリビューションのカスタム S3" description: "高度な分析とレポートのために、ユーザー獲得データをカスタム S3 互換ストレージにエクスポートします。" --- Adapty Attributionとカスタムのs3互換ストレージとの統合により、ユーザー獲得キャンペーンデータを独自のS3互換ストレージに安全に保存できます。キャンペーンのパフォーマンスデータ、アトリビューションデータ、ユーザー獲得イベントを.csvファイルとしてカスタムS3バケットに保存できます。 この統合を設定するには、S3互換ストレージのコンソールとAdapty Attributionダッシュボードでいくつかの簡単な手順を実行する必要があります。 :::note Adapty Attributionは、UTC 4:00に**24時間**ごとにデータを送信します。 各ファイルには、UTC で前日の 1 日分(カレンダー上)に作成されたイベントのデータが含まれます。たとえば、3 月 8 日の 4:00 UTC に自動エクスポートされたデータには、3 月 7 日の 00:00:00 ~ 23:59:59 UTC に作成されたすべてのイベントが含まれます。 ::: ## Custom S3 インテグレーションのセットアップ \{#set-up-custom-s3-integration\} データの受信を開始するには、Adapty Attribution でインテグレーションを設定します。 1. [**Integrations** -> **Custom S3**](https://app.adapty.io/ua/integrations/custom-s3) に移動します。 2. **Export install events to custom S3** トグルをオンにします。 3. 必須フィールドに入力して、カスタム S3 ストレージと Adapty Attribution プロファイルの接続を構築します。 | フィールド | 説明 | |:----------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Access Key ID** | S3互換ストレージサービスへのアクセスを認証するための一意の識別子です。ストレージプロバイダーのコンソールで確認できます。 | | **Secret Access Key** | Access Key IDと組み合わせて、S3互換ストレージサービスへのアクセスを認証するための秘密鍵です。ストレージプロバイダーのコンソールで確認できます。 | | **S3 Bucket Name** | ストレージ環境内の特定のS3バケットを識別するグローバルに一意の名前です。S3バケットはシンプルなストレージサービスで、ファイルや画像などのデータオブジェクトをクラウドに保存・取得できます。 | | **Region**(任意) | Management ConsoleでRegionを確認してください。 | | **Folder Inside the Bucket**(任意) | 選択したS3バケット内に作成するフォルダの名前です。S3ではオブジェクトキーのプレフィックスを使用してフォルダを疑似的に表現しており、これが実質的なフォルダ名となります。 | | **Custom Endpoint URL** | S3互換ストレージサービスのエンドポイントURLです。ストレージプロバイダー(MinIO、DigitalOcean Spaces、Wasabiなど)から提供されます。 | :::note S3バケット名フィールドでは、`adapty-ua-events/com.sample-app` のようにネストされたディレクトリも指定できます。 ::: ## 手動データエクスポート \{#manual-data-export\} カスタム S3 ストレージへの自動イベントデータエクスポートに加えて、Adapty UA では手動でのファイルエクスポート機能も提供しています。この機能を使用すると、ユーザー獲得データの日付を指定して、S3 バケットに手動でエクスポートできます。これにより、エクスポートするデータとタイミングをより細かく制御できます。 ## テーブル構造 \{#table-structure\} カスタム S3 インテグレーションでは、Adapty Attribution がインストールイベントの履歴データを保存するテーブルを提供します。このテーブルには、ユーザープロファイル、収益と手取り額、オリジンストアなど、さまざまなデータが含まれています。 :::warning この構造は、Adapty または連携するサードパーティによる新しいデータの追加に伴い、今後拡張される可能性があります。このデータを処理するコードは、構造全体に依存せず、特定のフィールドのみを参照するよう、堅牢に実装してください。 ::: イベントのテーブル構造は以下のとおりです。 | カラム | 説明 | |--------------------------|-------------------------------------------| | `adapty_profile_id` | Adapty プロファイルの一意識別子 | | `install_id` | インストールの一意識別子 | | `created_at` | レコード作成タイムスタンプ(ISO 8601) | | `installed_at` | アプリインストールタイムスタンプ(ISO 8601)| | `store` | アプリストア(`ios`、`android`) | | `country` | ユーザーの国コード(ISO 3166-1 alpha-2) | | `ip_address` | クライアント IP アドレス | | `idfa` | iOS 広告識別子(IDFA) | | `idfv` | iOS ベンダー識別子(IDFV) | | `gaid` | Google 広告 ID(Android) | | `android_id` | Android デバイス ID | | `app_set_id` | Android App Set ID | | `bundle_id` | アプリバンドル識別子(例:`com.example.app`)| | `device_brand` | デバイスブランド(例:`Apple`、`Samsung`)| | `device_model` | デバイスモデル(例:`iPhone15,2`) | | `os_version` | OS のメジャーバージョン | | `app_version` | Adapty SDK が報告するアプリバージョン | | `sdk_version` | Adapty SDK バージョン | | `channel` | アトリビューションチャネル | | `campaign_id` | キャンペーン識別子 | | `campaign_name` | キャンペーン名 | | `adset_id` | 広告セット識別子 | | `adset_name` | 広告セット名 | | `ad_id` | 広告識別子 | | `ad_name` | 広告名 | | `keyword_id` | キーワード識別子 | | `keyword_name` | キーワード名 | | `asa_org_id` | Apple Search Ads 組織 ID | | `asa_keyword_match_type` | ASA キーワードマッチタイプ(`Exact`、`Broad`)| | `asa_attribution` | ASA アトリビューションデータ(JSON 文字列)| | `asa_conversion_type` | ASA コンバージョンタイプ | | `asa_country_or_region` | ASA の国またはリージョン | | `asa_creative_set_name` | ASA クリエイティブセット名 | | `fbclid` | Facebook クリック ID | | `ttclid` | TikTok クリック ID | | `utm_source` | UTM source パラメータ | | `utm_medium` | UTM medium パラメータ | | `utm_campaign` | UTM campaign パラメータ | | `utm_term` | UTM term パラメータ | | `utm_content` | UTM content パラメータ | --- # File: ua-amazon-s3 --- --- title: "Adapty アトリビューションにおける Amazon S3" description: "高度な分析とレポートのためにユーザー獲得データを S3 にエクスポートします。" --- Adapty Attribution と Amazon S3 の連携により、ユーザー獲得キャンペーンのデータを安全に一か所で管理できます。キャンペーンのパフォーマンスデータ、アトリビューションデータ、ユーザー獲得イベントを .csv ファイルとして Amazon S3 バケットに保存できます。 この連携を設定するには、AWS コンソールと Adapty Attribution ダッシュボードでいくつかの簡単な手順を行う必要があります。 :::note Adapty Attribution は毎日 **UTC 4:00** にデータを送信します(送信間隔:**24 時間**)。 各ファイルには、UTC基準で前日1日分のイベントデータが含まれます。たとえば、3月8日4:00 UTC に自動エクスポートされるデータには、3月7日の00:00:00〜23:59:59(UTC)に作成されたすべてのイベントが含まれます。 ::: ## Amazon S3 インテグレーションのセットアップ方法 \{#how-to-set-up-amazon-s3-integration\} データの受信を開始するには、以下の認証情報が必要です: 1. アクセスキー ID 2. シークレットアクセスキー 3. S3 バケット名 4. S3 バケット内のフォルダ名 :::note ネストされたディレクトリ Amazon S3 バケット名フィールドにネストされたディレクトリを指定できます。例:adapty-ua-events/com.sample-app ::: ### ステップ 1. Amazon S3 認証情報の作成 \{#step-1-create-amazon-s3-credentials\} このガイドでは、AWS コンソールで必要な認証情報を作成する手順を説明します。 #### 1.1. アクセスポリシーの作成 \{#11-create-access-policy\} 1. AWS コンソールの [IAM ポリシーダッシュボード](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/policies) に移動します 2. **Create Policy** を選択します <img src="/assets/shared/img/7af075c-CleanShot_2023-03-21_at_10.52.002x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ポリシーエディターに以下の JSON を貼り付け、`adapty-s3-integration-test` をご自身のバケット名に変更してください: ```json showLineNumbers title="Json" { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListObjectsInBucket", "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::adapty-s3-integration-test" }, { "Sid": "AllowAllObjectActions", "Effect": "Allow", "Action": "s3:*Object", "Resource": [ "arn:aws:s3:::adapty-s3-integration-test/*", "arn:aws:s3:::adapty-s3-integration-test" ] }, { "Sid": "AllowBucketLocation", "Effect": "Allow", "Action": "s3:GetBucketLocation", "Resource": "arn:aws:s3:::adapty-s3-integration-test" } ] } ``` <img src="/assets/shared/img/d4e474a-CleanShot_2023-03-21_at_10.56.212x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. ポリシーの設定が完了したら、タグを追加することもできます(任意)。その後、**Next** をクリックして最終ステップに進みます。 5. このステップでは、ポリシーに名前を付けて、**Create policy** ボタンをクリックするだけで作成が完了します。 <img src="/assets/shared/img/7dcb02f-CleanShot_2023-03-21_at_11.03.372x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### 1.2. IAM ユーザーを作成する \{#12-create-iam-user\} Adapty アトリビューションがバケットへ生データレポートをアップロードできるようにするには、対象バケットへの書き込み権限を持つユーザーのアクセスキー ID とシークレットアクセスキーを提供する必要があります。 1. IAM コンソールに移動し、[Users セクション](https://console.aws.amazon.com/iamv2/home#/users)を選択します 2. **Add users** ボタンをクリックします <img src="/assets/shared/img/bb612c8-CleanShot_2023-03-21_at_11.12.392x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. ユーザー名を入力し、**Access key – Programmatic access** を選択して、権限の設定に進みます <img src="/assets/shared/img/467ee4d-j6aoX.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 次のステップでは、**Add user to group** オプションを選択し、**Create group** ボタンをクリックしてください。 <img src="/assets/shared/img/bfd0e80-CleanShot_2023-03-21_at_11.24.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 次に、User Groupに名前を付け、先ほど作成したポリシーを選択します 6. ポリシーを選択したら、**Create group** ボタンをクリックしてプロセスを完了します <img src="/assets/shared/img/df29c12-CleanShot_2023-03-21_at_11.28.052x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. グループの作成が完了したら、**それを選択**して次のステップに進んでください <img src="/assets/shared/img/1f3722e-CleanShot_2023-03-21_at_11.36.192x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. このセクションの最後のステップですので、**Create User** ボタンをクリックして次に進んでください。 <img src="/assets/shared/img/ea43722-CleanShot_2023-03-21_at_11.40.462x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. 最後に、認証情報を **.csv 形式でダウンロード**するか、ダッシュボードから直接コピー&ペーストすることができます。 <img src="/assets/shared/img/bcf35e1-S3created.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ステップ 2. Adapty Attribution でインテグレーションを設定する \{#step-2-configure-integration-in-adapty-attribution\} 1. [**Integrations** -> **Amazon S3**](https://app.adapty.io/ua/integrations/s3) に移動します。 2. **Export install events to Amazon S3** トグルをオンにします。 3. Amazon S3 と Adapty Attribution プロファイルの接続を構築するために、以下のフィールドを入力します。 | フィールド | 説明 | |:-----------------------------| :----------------------------------------------------------- | | **Access Key ID** | AWS サービスへのアクセスを認証するために使用される一意の識別子です。このIDはダウンロードした [csv ファイル](ua-amazon-s3#step-1-create-amazon-s3-credentials) に記載されています。 | | **Secret Access Key** | Access Key ID と組み合わせて、AWS サービスへのアクセスを認証するために使用されるプライベートキーです。このキーはダウンロードした [csv ファイル](ua-amazon-s3#step-1-create-amazon-s3-credentials) に記載されています。 | | **S3 Bucket Name** | AWS クラウド内の特定の S3 バケットを識別するグローバルに一意の名前です。S3 バケットはシンプルなストレージサービスで、ファイルや画像などのデータオブジェクトをクラウドに保存・取得できます。 | | **Folder Inside the Bucker** | 選択した S3 バケット内に作成するフォルダーの名前です。S3 ではオブジェクトキープレフィックス(実質的にはフォルダー名)を使ってフォルダーを擬似的に表現していることにご注意ください。 | | **Region**(オプション) | AWS マネジメントコンソールの IAM ユーザーアカウントからリージョンを確認してください。 | ## 手動データエクスポート \{#manual-data-export\} Amazon S3 への自動イベントデータエクスポートに加えて、Adapty UA では手動ファイルエクスポート機能も提供しています。この機能を使用すると、ユーザー獲得データの特定の日付を選択して、S3 バケットに手動でエクスポートできます。これにより、エクスポートするデータとそのタイミングをより細かく制御できます。 ## テーブル構造 \{#table-structure\} AWS S3 インテグレーションでは、Adapty アトリビューションはインストールイベントの履歴データを保存するテーブルを提供します。このテーブルには、ユーザープロファイル、収益と手取り額、オリジンストアなど、さまざまなデータポイントの情報が含まれています。 :::warning この構造は、Adapty または連携しているサードパーティによって新しいデータが追加されると、今後変更される可能性があります。処理するコードは、構造全体に依存せず、特定のフィールドに基づいて動作するよう堅牢に設計してください。 ::: イベントのテーブル構造は以下のとおりです: | カラム | 説明 | |--------------------------|-------------------------------------------| | `adapty_profile_id` | Adaptyプロファイルの一意な識別子 | | `install_id` | インストールの一意な識別子 | | `created_at` | レコード作成タイムスタンプ(ISO 8601) | | `installed_at` | アプリインストールタイムスタンプ(ISO 8601)| | `store` | アプリストア(`ios`、`android`) | | `country` | ユーザーの国コード(ISO 3166-1 alpha-2) | | `ip_address` | クライアントIPアドレス | | `idfa` | iOS広告識別子(IDFA) | | `idfv` | iOSベンダー識別子(IDFV) | | `gaid` | Google広告ID(Android) | | `android_id` | AndroidデバイスID | | `app_set_id` | Android App Set ID | | `channel` | アトリビューションチャネル | | `campaign_id` | キャンペーン識別子 | | `campaign_name` | キャンペーン名 | | `adset_id` | 広告セット識別子 | | `adset_name` | 広告セット名 | | `ad_id` | 広告識別子 | | `ad_name` | 広告名 | | `keyword_id` | キーワード識別子 | | `keyword_name` | キーワード名 | | `asa_org_id` | Apple Search Ads組織ID | | `asa_keyword_match_type` | ASAキーワードマッチタイプ(`Exact`、`Broad`)| | `asa_attribution` | ASAアトリビューションデータ(JSON文字列) | | `asa_conversion_type` | ASAコンバージョンタイプ | | `asa_country_or_region` | ASAの国またはリージョン | | `asa_creative_set_name` | ASAクリエイティブセット名 | | `fbclid` | FacebookクリックID | | `ttclid` | TikTokクリックID | | `utm_source` | UTMソースパラメータ | | `utm_medium` | UTMメディアパラメータ | | `utm_campaign` | UTMキャンペーンパラメータ | | `utm_term` | UTMタームパラメータ | | `utm_content` | UTMコンテンツパラメータ | --- # File: ua-google-cloud-storage --- --- title: "Adapty アトリビューションにおける Google Cloud Storage" description: "Google Cloud Storage を Adapty アトリビューションと統合して、ユーザー獲得データを安全に保存しましょう。" --- Adapty AttributionとGoogle Cloud Storageの連携により、ユーザー獲得キャンペーンデータを一か所に安全に保存できます。キャンペーンパフォーマンスデータ、アトリビューションデータ、ユーザー獲得イベントを.csvファイルとしてGoogle Cloud Storageバケットに保存できます。 この連携を設定するには、Google Cloud ConsoleとAdapty Attribution ダッシュボードでいくつかの簡単な手順を実行する必要があります。 :::note スケジュール Adapty Attributionは毎日UTC 4:00にGoogle Cloud Storageへデータを送信します。 各ファイルには、UTC基準で前日の1日分(カレンダーデー)に作成されたイベントのデータが含まれます。たとえば、3月8日 4:00 UTC に自動エクスポートされるデータには、3月7日の 00:00:00〜23:59:59 UTC に作成されたすべてのイベントが含まれます。 ::: ## Google Cloud Storage 連携の設定方法 \{#how-to-set-up-google-cloud-storage-integration\} ### ステップ 1. Google Cloud Storage の認証情報を作成する \{#step-1-create-google-cloud-storage-credentials\} このガイドでは、Google Cloud Platform コンソールで必要な認証情報を作成する手順を説明します。 Adapty Attribution が指定したバケットにローデータレポートをアップロードするには、サービスアカウントのキーと、対応するバケットへの書き込みアクセス権が必要です。サービスアカウントのキーを提供し、バケットへの書き込みアクセスを許可することで、Adapty Attribution がプラットフォームからストレージ環境へローデータレポートを安全かつ効率的に転送できるようになります。 :::warning サービスアカウントのHMACキー認証のみをサポートしています。Google Cloud Storageへの適切なアクセスを有効にするため、サービスアカウントのHMACキーに「Storage Object Viewer」、「Storage Legacy Bucket Writer」、「Storage Object Creator」のロールが追加されていることを確認してください。 ::: #### 2.1. サービスアカウントの作成 \{#21-create-service-account\} 1. Google Cloudアカウントの[IAM](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts)セクションに移動し、対象のプロジェクトを選択するか、新しいプロジェクトを作成します。 <img src="/assets/shared/img/30a81ef-CleanShot_2023-03-17_at_15.22.142x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 次に、「+ CREATE SERVICE ACCOUNT」ボタンをクリックして、Adapty アトリビューション用の新しいサービスアカウントを作成します。 <img src="/assets/shared/img/98f8ebf-CleanShot_2023-03-17_at_15.40.062x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. アクセス権限は後の手順で付与するため、最初のステップではフィールドに必要事項を入力してください。このページの詳細については、[こちら](https://docs.cloud.google.com/iam/docs/service-accounts-create)のドキュメントをご参照ください。 <img src="/assets/shared/img/2190c50-CleanShot_2023-03-17_at_15.48.552x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. [プライベートJSONキー](https://docs.cloud.google.com/iam/docs/keys-create-delete)を作成してダウンロードするには、KEYSセクションに移動し、「ADD KEY」ボタンをクリックします <img src="/assets/shared/img/8a45468-CleanShot_2023-03-17_at_15.58.092x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. DETAILS セクションで、先ほど作成したサービスアカウントに紐づいている Email の値を見つけ、コピーしてください。この情報は、後続の手順でアカウントを認証し、バケットへの書き込みを許可するために必要になります。 <img src="/assets/shared/img/6ccd0f0-CleanShot_2023-03-17_at_16.03.162x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### 2.2. バケットの権限を設定する \{#22-configure-bucket-permissions\} 6. Google Cloud Storageの[Buckets](https://console.cloud.google.com/storage/browser)ページに移動し、既存のバケットを選択するか、Adapty アトリビューションのユーザー獲得データレポートを保存するための新しいバケットを作成します。 7. **PERMISSIONS**セクションに移動し、[アクセスを付与する](https://docs.cloud.google.com/identity/docs/how-to?hl=en)オプションを選択します。 <img src="/assets/shared/img/3cdd937-CleanShot_2023-03-17_at_16.14.232x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. PERMISSIONS セクションで、先ほど第5ステップで取得したサービスアカウントのメールアドレスを入力し、Storage Object Creator ロールを選択します 9. 最後に SAVE をクリックして変更を適用します <img src="/assets/shared/img/62801f4-CleanShot_2023-03-17_at_16.17.312x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 10. バケット名は後で使用するため、必ず控えておいてください。 11. これらの手順が完了すると、Google Cloud Console での必要なセットアップが完了です!最後のステップとして、バケット名を入力し、Adapty アトリビューションで使用するための JSON ファイルをダウンロードします。 <img src="/assets/shared/img/c967e16-CleanShot_2023-03-17_at_16.23.332x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ステップ 2. Adapty Attribution でインテグレーションを設定する \{#step-2-configure-integration-in-adapty-attribution\} 1. [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/ua/integrations/google-cloud-storage) に移動します 2. **Export install events to Google Cloud Storage** トグルをオンにします 3. Google Cloud Storage と Adapty Attribution 間の接続を構築するために、必要なフィールドを入力します: | フィールド | 説明 | |:------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Google Cloud service account key file** | ダウンロードしたプライベート [JSON キーファイル](ua-google-cloud-storage#step-1-create-google-cloud-storage-credentials)。 | | **Google Cloud bucket name** | データを保存する Google Cloud Storage 上のバケット名。Google Cloud Storage 環境内で一意である必要があり、スペースを含めることはできません。 | | **Folder inside the bucket** | バケット内でデータを保存するフォルダ名。バケット内で一意である必要があり、データの整理に利用できます。このフィールドへの入力は任意です。 | ## 手動データエクスポート \{#manual-data-export\} Google Cloud Storage への自動イベントデータエクスポートに加えて、Adapty UA は手動ファイルエクスポート機能も提供しています。この機能を使用すると、ユーザー獲得データの特定の日付を選択し、GCS バケットへ手動でエクスポートできます。エクスポートするデータとタイミングをより細かく制御できます。 ## テーブル構造 \{#table-structure\} Google Cloud Storage 連携では、Adapty アトリビューションがインストールイベントの履歴データを保存するテーブルを提供します。テーブルには、ユーザープロファイル、収益と手取り額、配信元ストアなどのデータが含まれます。 :::warning この構造は、Adapty または連携している第三者サービスによる新しいデータの追加により、今後変更される可能性があります。この構造に依存するコードを作成する際は、特定のフィールドのみを参照するよう、堅牢な実装を心がけてください。 ::: イベントのテーブル構造は以下のとおりです。 | カラム | 説明 | |--------------------------|-------------------------------------------| | `adapty_profile_id` | Adapty プロファイルの一意識別子 | | `install_id` | インストールの一意識別子 | | `created_at` | レコード作成タイムスタンプ(ISO 8601) | | `installed_at` | アプリインストールタイムスタンプ(ISO 8601) | | `store` | アプリストア(`ios`、`android`) | | `country` | ユーザーの国コード(ISO 3166-1 alpha-2) | | `ip_address` | クライアント IP アドレス | | `idfa` | iOS 広告識別子(IDFA) | | `idfv` | iOS ベンダー識別子(IDFV) | | `gaid` | Google 広告 ID(Android) | | `android_id` | Android デバイス ID | | `app_set_id` | Android App Set ID | | `channel` | アトリビューションチャネル | | `campaign_id` | キャンペーン識別子 | | `campaign_name` | キャンペーン名 | | `adset_id` | 広告セット識別子 | | `adset_name` | 広告セット名 | | `ad_id` | 広告識別子 | | `ad_name` | 広告名 | | `keyword_id` | キーワード識別子 | | `keyword_name` | キーワード名 | | `asa_org_id` | Apple Search Ads 組織 ID | | `asa_keyword_match_type` | ASA キーワードマッチタイプ(`Exact`、`Broad`) | | `asa_attribution` | ASA アトリビューションデータ(JSON 文字列) | | `asa_conversion_type` | ASA コンバージョンタイプ | | `asa_country_or_region` | ASA の国またはリージョン | | `asa_creative_set_name` | ASA クリエイティブセット名 | | `fbclid` | Facebook クリック ID | | `ttclid` | TikTok クリック ID | | `utm_source` | UTM source パラメータ | | `utm_medium` | UTM medium パラメータ | | `utm_campaign` | UTM campaign パラメータ | | `utm_term` | UTM term パラメータ | | `utm_content` | UTM content パラメータ | --- # File: adapty-mail --- --- title: "Adapty Mail" description: "AI生成のメールキャンペーンで、トライアルユーザーを有料サブスクライバーに転換します。" --- <CustomDocCardList ids={['mail-get-started', 'mail-brand', 'mail-collect-emails', 'mail-send-data-via-api', 'mail-sending-domain', 'mail-create-campaign', 'mail-analytics']} /> Adapty Mailは、AdaptyのユーザーデータをAI生成のメールシーケンスに変換し、トライアルユーザーを有料サブスクライバーに転換します。Adaptyプロジェクトにすでに存在するプロファイルデータを活用して、キャンペーンの構築・送信・アトリビューションを行います。別のメールプラットフォームは必要ありません。 ## Adapty Mailを使う理由 \{#why-adapty-mail\} ターゲットを絞ったメールキャンペーンを送るには、コピー、デザイン、送信インフラ、そして収益アトリビューションが必要です。これらはそれぞれ個別に解決すべき問題です。 Adapty Mailはそのすべてを担います。ブランドプロファイルはストアのURLやその他の追加ソースから構築され、完全なメールシーケンスが2分以内に生成されます。独自ドメインから送信され、パーソナライズされたチェックアウトリンクと購入アトリビューション付きです。 ## 仕組み \{#how-it-works\} 1. **メールを収集する**: アプリがSDK経由でユーザーのメールアドレスと`customer_user_id`をAdaptyに渡します。Adapty Mailはこのデータを使って受信者を特定し、各購入を起点となったメールにアトリビュートします。[Adapty Mail API](mail-send-data-via-api)を使ってサーバーからこのデータを送ることもできます。 2. **Webペイウォールを構築する**: すべてのメールがリンクするチェックアウトページです。 3. **シーケンスを生成する**: AIがブランドプロファイルをもとに1〜15通のメールを生成します。コピー、デザイン、ヒーロー画像、そしてアプリのカテゴリとブランドボイスに合わせたパーソナライズされたチェックアウトリンクが含まれます。 4. **フローを開始する**: トリガー(未購入、更新キャンセル、請求の問題、サブスクリプション期限切れ、または返金)とセグメントを選択してキャンペーンを紐付けます。メールは自動的に送信が始まり、メール経由の購入による収益は転換を生んだ特定のメールにアトリビュートされます。 ## 要件 \{#requirements\} Adapty Mailを使用するには以下が必要です: - Adaptyアカウント - アプリでのメール収集の設定 — [ユーザーメールを収集する](mail-collect-emails)を参照 - Adapty SDKでの`customer_user_id`の設定 - DNSの設定にアクセスできる、自分が管理するドメイン - Webの決済プロバイダー(Stripe、Paddle、またはPayPal) ## はじめる \{#get-started\} [Adapty Mailをはじめる](mail-get-started)ガイドに従って、セットアップを完了し、最初のキャンペーンを開始しましょう。 --- # File: mail-get-started --- --- title: "Adapty Mail を始めよう" description: "Adapty Mail をセットアップして、最初のメールフローを起動しましょう。" --- このガイドでは、Adapty Mail をセットアップして、最初のメールフローを起動する手順を説明します。 :::note Adapty SDK を使わず、独自のサーバーから Adapty Mail にデータを送ることも可能です。ユーザーのメールアドレスや購入情報をバックエンドで管理している場合、または別のソースからサブスクライバーをインポートする場合は、[Adapty Mail API 経由でメールとトランザクションを送信する](mail-send-data-via-api)をご参照ください。 ::: セットアップは6つのパートに分かれています: 1. [Adapty SDK を設定する](#1-configure-your-adapty-sdk) 2. [送信ドメインを設定する](#2-set-up-your-sending-domain) 3. [ウェブペイウォールを作成する](#3-create-a-web-paywall) 4. [AI でキャンペーンを生成する](#4-generate-a-campaign-with-ai) 5. [フローを起動する](#5-launch-a-flow) 6. [送信を有効にする](#6-enable-sending) :::tip Adapty 経由で Adapty Mail にサインアップした場合、**ブランドプロファイル**はプロジェクトのストア URL から自動的に作成されます。**Brand** をいつでも開いて確認・修正できます — [ブランド](mail-brand)を参照してください。スタンドアロンでサインアップした場合は、キャンペーンやウェブペイウォールを作成する前に同じページでブランドを設定してください。 ::: ## 始める前に \{#before-you-start\} 開始前に以下を確認してください: - **DNSアクセス**: ルートドメインにレコードを追加できること。 - **Web決済プロバイダー**: サブスクリプションプロダクトが設定済みのStripe、Paddle、またはPayPalアカウントを持っていること。 ## 1. Adapty SDKを設定する \{#1-configure-your-adapty-sdk\} :::important Adapty Mailは**スタンドアロンプロダクト**です。ペイウォール、サブスクリプション、アナリティクスをAdaptyで管理していなくても利用できます。既存のスタック全体を移行する必要はありません。 正確な収益データを取得するには、最低限の設定としてAdapty SDKをオブザーバーモードでインストールし、App Serverの通知を有効にしてください。 ::: Adapty Mailがアプリに必要なものは3つです。購入データ(各コンバージョンを誘導したメールに収益を紐付けるため)、安定したユーザー識別子、そしてユーザーのメールアドレスです。 1. **Adaptyで収益を追跡する。** 最初のステップは、すでにアプリ内課金を実装しているかどうかによって異なります: - **AdaptyでアプリIn内課金をすでに実装している**場合は、この段階で追加の作業は不要です。 - **Adaptyを使わずにアプリ内課金をすでに実装していて**、Adaptyへの移行を予定していない場合は、各プラットフォームのAdapty SDKをオブザーバーモードでインストールしてください。この段階では、SDKをプロジェクトに追加し、オブザーバーモードを有効にして起動し、トランザクションを報告するだけで構いません。プラットフォーム別ガイド:[iOS](implement-observer-mode)、[Android](implement-observer-mode-android)、[React Native](implement-observer-mode-react-native)、[Flutter](implement-observer-mode-flutter)、[Unity](implement-observer-mode-unity)、[Kotlin Multiplatform](implement-observer-mode-kmp)、[Capacitor](implement-observer-mode-capacitor)。 - **アプリ内課金をまだ実装しておらず、Adaptyを使いたい**場合は、[クイックスタートガイド](quickstart)の手順に従って、購入処理をAdaptyに委任してください。 次に、[Adapty で App Store サーバー通知を有効化](enable-app-store-server-notifications)して、App Store から収益関連の更新を直接受け取れるようにします。 2. **ユーザー識別を設定する。** バックエンドのユーザー ID、Firebase UID などの安定した ID を、`Adapty.identify()` を呼び出すか、SDK 起動時に `.activate()` へ `customerUserId` として渡すことで設定します。`customer_user_id` は、Adapty Mail がキャンペーン、クリック、購入を正しいプロファイルに紐付けるための識別子です。 プラットフォームガイド: [iOS](identifying-users), [Android](android-identifying-users), [React Native](react-native-identifying-users), [Flutter](flutter-identifying-users), [Unity](unity-identifying-users), [Kotlin Multiplatform](kmp-identifying-users), [Capacitor](capacitor-identifying-users). 3. **ユーザーのメールアドレスを収集する。** ユーザーがアプリ内でメールアドレスを入力したタイミング(サインアップやチェックアウトなど)で、`updateProfile` にメール属性を指定して Adapty に渡してください。キャンペーンの受信者全員にこの値が必要です。 プラットフォーム別ガイド: [iOS](setting-user-attributes)、[Android](android-setting-user-attributes)、[React Native](react-native-setting-user-attributes)、[Flutter](flutter-setting-user-attributes)、[Unity](unity-setting-user-attributes)、[Kotlin Multiplatform](kmp-setting-user-attributes)、[Capacitor](capacitor-setting-user-attributes) アプリでまだメールアドレスを収集していない場合は、[メール収集戦略](mail-collect-emails#email-collection-strategies)をご覧ください。 ## 2. 送信ドメインを設定する \{#set-up-your-sending-domain\} Adapty Mail を開く: ヘッダーの Adapty ロゴをクリックして **Mail** を選択します。 Adapty Mail はあなた自身のドメインから送信します。DNS レコードを一度追加すれば、すべてのキャンペーンで同じ検証済みドメインが使われます。 1. Adapty Mail で **Settings → Email Domains** に移動します。 2. ルートドメイン(例:`yourapp.com`)を入力し、**Preview** をクリックします。受け付けられるのは apex ドメインのみです。`app.yourapp.com` のようなサブドメインは入力時に拒否されます。 3. Adaptly は2つの送信サブドメイン(`mail.yourapp.com` と `email.yourapp.com`)を生成します。**Confirm** をクリックして、必要な DNS レコードを表示します。 4. ドメインレジストラーで、表示された 10 件の DNS レコードを追加します(サブドメインごとに 5 件): - サブドメインごとに CNAME レコード 3 件(DKIM) - サブドメインごとに MX レコード 1 件(Mail-From) - サブドメインごとに TXT レコード 1 件(SPF、`v=spf1 include:amazonses.com ~all`) 5. 任意で、ルートドメインに DMARC TXT レコードを追加します(推奨)。 6. **Settings → Email Domains** に戻り、**Check Verification** をクリックします。 確認のタイミングについて: - **自動ポーリング**:送信後約5分で最初のチェックが実行されます。レコードが見つかるまで、間隔は最大1時間ごとに拡大されます。 - **手動チェック**:**Check Verification** をクリックすると、いつでも即座にチェックを実行できます。 - **DNS伝播**:通常は数分で完了しますが、まれに最大48時間かかる場合があります。 - **確認ウィンドウ**:7日間です。期限が切れても、DNSレコードはそのまま残ります。**Settings → Email Domains** でドメインを再入力すると、新しいウィンドウが開始されます。 各レコードタイプとドメインウォームアップの詳細については、[送信ドメインの設定](mail-sending-domain)を参照してください。 ## 3. Webペイウォールを作成する \{#3-create-a-web-paywall\} すべてのメールはWebペイウォールにリンクしています — CTAをクリックしたユーザーが訪れるチェックアウトページです。2つの選択肢があります: - **AIで生成する**: バンドルされたWebペイウォールビルダーがアプリ向けに自動生成します。 - **独自のホスト済みペイウォールを使用する**: すでにホストしているペイウォールを接続します。 開始するには、Adapty Mailで**Web Paywalls → Create**に移動します。 ### オプション A: AIで生成する \{#option-a-generate-with-ai\} ページに表示される **Prerequisites** チェックリストのインラインボタンを順番に進めてから、戻って生成してください。チェックリストには、ペイウォールビルダーへのログイン、Stripeの接続、プロダクトの追加、結果の確認が含まれています。詳細な手順は[チェックアウトの設定](mail-checkout)を参照してください。 すべての前提条件が緑になったら、**Generate** をクリックして生成ダイアログを開きます: - **Environment**: **Production** または **Sandbox** を選択します。Sandbox は Stripe のテストモードプロダクトを使用し、開発環境やローカル環境ではこちらが安全なデフォルトです。 - **Plans**: **Stripe のプランを最大 3 つ**選択します(各プランはプロダクト+価格の組み合わせです)。これらが、生成されたペイウォールでチェックアウト時にユーザーに提示されるオファーになります。 **Generate** をクリックしてビルドを実行します。完了したら、エディターを開いて内容を確認し、公開してください。 :::important ペイウォールは公開しないとチェックアウトのトラフィックを処理できません。未公開のペイウォールは、ユーザーがメールのチェックアウトリンクをクリックするとエラーを返します。 ::: ### オプションB: 独自のホスト済みペイウォールを使用する \{#option-b-use-your-own-hosted-paywall\} 1. **Enter URL manually**を選択します。 2. ホスト済みペイウォールのURLを貼り付けます。URLにはクエリパラメーターとして`{email}`と`{external_profile_id}`のプレースホルダーを含める必要があります — Adapty Mailが受信者ごとにこれらを埋め込むことで、チェックアウトページが訪問者を識別できるようになります。例: ``` https://example.com/paywall?email={email}&profile={external_profile_id} ``` 3. 保存して公開します。 チェックアウトファネルの構造とパーソナライゼーションの仕組みについては、[チェックアウトの設定](mail-checkout)をご覧ください。 ## 4. AIでキャンペーンを生成する \{#generate-a-campaign-with-ai\} AIがメールシーケンス全体を自動生成します — コピー、デザイン、ヒーロー画像、パーソナライズされたチェックアウトリンクまで、すべてあなたのブランドに合わせて作成されます。 1. Adapty Mail で **Campaigns** に移動し、**Create** をクリックします。 2. キャンペーン名を設定します。 3. **Web paywall** ドロップダウンで、前のステップで追加したウェブペイウォールを選択します。 4. **Generate emails** をクリックします。 5. 生成ダイアログに入力します。トーン、言語、任意のカスタムプロンプト(最大2,000文字)、メール数(1〜15件、デフォルト4件)を設定します。各フィールドの詳細は[キャンペーンを作成する](mail-create-campaign)を参照してください。 6. **Generate**をクリックします。生成には通常数分かかります。完了できない場合は5分後にタイムアウトするので、その場合は再試行してください。 7. 各メールをプレビューで確認します。プレビューのヘッダーには**Theme toggle**(Auto・Light・Dark)があり、プレビューの表示方法を切り替えられます。なお、生成されたコンテンツ自体はどのモードでも同じです。メールを個別に再生成したり、文章を編集したり、HTMLエディターを開いて細かく調整したりすることもできます。 8. **Create**をクリックしてキャンペーンを保存します。 キャンペーンは**下書き**として保存され、まだ送信されません。キャンペーンはフローに紐付けられたときにのみ有効になります(次のステップ)。キャンペーンエディター内に「公開」という独立したアクションはありません。 ## 5. フローを起動する \{#launch-a-flow\} フローは**トリガー**(サブスクリプションの期限切れなどのイベント)と**セグメント**を組み合わせ、そのセグメントに選択した**キャンペーン**を送信します。Adapty Mail には5つの固定トリガーが用意されており、それぞれ専用のフロービューがあります。 1. Adapty Mail で **Flows** に移動し、設定したいトリガーを開きます: - **Never purchased** — サインアップしたがまだ購入していないユーザー。 - **Renewal cancelled** — 自動更新をオフにしているが、まだアクティブなサブスクリプションを持つユーザー。 - **Billing issue** — 支払い失敗、カード拒否・期限切れ、またはグレース期間中のユーザー。 - **Expired** — サブスクリプションが失効し、アクセスが失われたユーザー。 - **Refunded** — 購入後に返金を申請したユーザー。 各トリガーの目的とトーンについては、[フロー](mail-flows)を参照してください。 2. **Create** をクリックしてダイアログを開きます。 3. ダイアログで以下を設定します: - **Segment** を選択します(例:**All Users** でこのトリガーに到達した全員を対象にする、またはプロファイル属性に基づいて新しいセグメントを作成する)。 - コンテンツタイプは **Campaign** のままにします(A/B テストオプションについては [A/B テスト](mail-ab-testing) を参照してください)。 - ステップ 4 で保存した **Campaign** を選択します。 4. **Save** をクリックします。 フローはすぐに有効になります — 別途起動する手順はありません。この時点から、セグメントに一致するユーザーはトリガーイベントに到達した時点でキャンペーンの受信が始まります。 :::note 1つのトリガーに複数のセグメント→キャンペーン行を追加できます。行は優先順位の高い順に実行されます。**All Users** 行を使用する場合は、より具体的なセグメントにマッチしなかったすべてのユーザーをキャッチできるよう、最後(最低優先順位)の行に配置してください。 ::: ## 6. 送信を有効にする \{#enable-sending\} ここまでの設定でキャンペーンは接続されていますが、まだ実際には動作していません。サブスクリプションイベントを Adapty Mail に同期する **Adapty integration** がまだオフになっているためです。これをオンにすることが最後のステップです。イベントが流れ始め、セグメントがマッチし始め、メールが送信され始めます。 このステップはステップ 5 が完了した後にのみ実行できます。フローを起動する前は、**Settings → Integrations** の **Enable** ボタンが無効になっており、*「Set up at least one flow before enabling Adapty integration.」* というツールチップが表示されます。 1. Adapty Mail で、**Settings → Integrations** に移動します。 2. **Enable Adapty integration**(または、以前のセットアップからインテグレーションが既に存在する場合は **Enable**)をクリックします。 有効にすると、Adapty はすべてのサブスクリプションイベント(新規サブスクリプション、更新、トライアル、コンバージョン、返金、請求の問題)を Adapty Mail に送信します。これらのイベントにより、セグメントのメンバーシップ、キャンペーンのルーティング、およびユーザーがコンバートしたときにシーケンスを一時停止するストップ条件が機能します。 :::note **Settings** の **Adapty integration** トグルは、Adapty Mail にサインインした Adapty パートナーワークスペースとは異なります。パートナーワークスペースはアカウントを作成し(Adapty 経由でサインアップした場合は)ブランドを作成したものです。ここにある integration トグルはイベントの同期を制御するもので、プロジェクトごとに有効にする必要があります。 ::: ## トラブルシューティング \{#troubleshooting\} | 問題 | 解決策 | | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | DNS検証がスタックしている | レコードが正確に一致していることを確認してください(末尾のドット不要、CNAMEターゲットが正しいか)。5〜10分待ってから **Check Verification** をクリックしてください | | 検証ウィンドウが期限切れ | レコードはそのまま残っています。**Settings → Email Domains** でドメインを再入力して新しいウィンドウを開始してください | | 生成に失敗またはタイムアウト | インターネット接続を確認して再試行してください。問題が解決しない場合は、Adaptyサポートにお問い合わせください | ## 詳細情報 \{#learn-more\} - **[ユーザーメールアドレスの収集](mail-collect-emails)**: アプリでまだ収集していない場合のメールカバレッジ取得戦略。 - **[送信ドメインの設定](mail-sending-domain)**: DNSレコードの詳細、ウォームアップ階層、トラブルシューティング。 - **[チェックアウトの設定](mail-checkout)**: チェックアウトファネルの構造とパーソナライゼーション。 - **[キャンペーンアナリティクス](mail-analytics)**: 配信、エンゲージメント、収益のトラッキング。 - **[A/B テスト](mail-ab-testing)**: 複数のシーケンスバージョンのテスト。 --- # File: mail-collect-emails --- --- title: "Adapty Mailのユーザーメール収集" description: "ユーザーメールと安定した識別子をAdaptyに渡して、キャンペーンがユーザーに届くようにします。" --- Adapty Mailがメールを配信するには、各ユーザーに対して安定した `customer_user_id` とメールアドレスが必要です。キャンペーンを開始する前に、アプリのコードで両方を設定しておきましょう。 ## ユーザーメールの収集 \{#collect-user-emails\} 各ユーザーについて、Adaptyに渡す必要がある値は2つです。ユーザーを識別する安定した `customer_user_id` と、メールアドレスそのものです。識別が先決です。識別なしでは、Adaptyにはメールを紐付けるプロファイルがありません。 1. **ユーザーを識別する。** バックエンドのユーザーID、Firebase UID などの安定したIDを渡します。SDKの起動時に `.activate()` の `customerUserId` として渡すか、後から(例えばログイン時に)`Adapty.identify()` を呼び出す方法があります。いずれの場合も、ペイウォールを表示する前にIDを設定する必要があります。 プラットフォームガイド: [iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)、[Kotlin Multiplatform](kmp-identifying-users)、[Capacitor](capacitor-identifying-users)。 2. **メールアドレスを渡す。** ユーザーがメールアドレスを提供したら、すぐに `updateProfile` の `email` パラメーターを使ってAdaptyに送信します。 プラットフォームガイド: [iOS](setting-user-attributes)、[Android](android-setting-user-attributes)、[React Native](react-native-setting-user-attributes)、[Flutter](flutter-setting-user-attributes)、[Unity](unity-setting-user-attributes)、[Kotlin Multiplatform](kmp-setting-user-attributes)、[Capacitor](capacitor-setting-user-attributes)。 :::important - `customer_user_id` は常に**安定した**値を渡してください。匿名の識別子は使用しないでください。ユーザーがアプリをアンインストールして再インストールした場合、AdaptyはこのIDを使って再インストールを既存のプロファイルに紐付け、購入を正しいユーザーに帰属させます。 - メールアドレスをAdaptyに収集・送信する前に、ユーザーから明示的な同意を取得してください。対象市場におけるGDPR、CAN-SPAMおよび類似の規制への準拠はお客様の責任となります。 ::: <Details> <summary>メール収集のカバレッジを確認する</summary> 収集を実装したら、Adaptyでカバレッジを確認しましょう。 1. **Customers → Profiles** に移動します。 2. メールアドレスが設定されているプロファイルでフィルタリングします。 最初のキャンペーンを開始する前に、アクティブユーザーの少なくとも30〜50%のメールカバレッジを目標にしてください。100%になるまで待つ必要はありません。30%に達したらすぐに開始しましょう。後でメールアドレスを提供したユーザーは、条件を満たした時点でアクティブなキャンペーンに自動的に登録されます。 </Details> ## メール収集の戦略 \{#email-collection-strategies\} 多くのアプリはデフォルトではメールを収集しません。アプリの現状に合ったアプローチを選んでください。 | 戦略 | 最適なケース | 仕組み | | ---------------------------------- | -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | **既存の認証** | ログイン機能のあるアプリ | すでにメールアドレスを持っているので、ユーザーが認証した後にAdaptyへ渡すだけです。どこで読み取るかは以下の認証方法リファレンスを参照してください。 | | **ペイウォール前のメールゲート** | 認証なしのアプリ(健康・ウェルネス・占星術・フォトエディターなど) | オンボーディングとペイウォールの間にメール入力画面を1つ追加します。ユーザーがすでに時間を投資しているため、コンバージョンは通常70〜90%に達します。 | | **Webペイウォールビルダーのチェックアウト** | SDKの作業を最小限に抑え、Webでメールを収集する場合 | Webペイウォールビルダーの最初の画面でメールアドレスを収集し、Adaptyに渡します。アプリ内ゲートが稼働する前にキャンペーンをクリックしたユーザーに有効です。 | | **オンボーディングのステップ** | クイズ形式のオンボーディング(フィットネス・栄養・教育) | オンボーディングの2〜3ステップ目にメール入力を配置します。価値の提供として訴求し(「パーソナライズされたプランをメールでお送りします」など)、スキップ可能にしないようにしましょう。 | | **Adapty Mail API** | AdaptyのSDKを使わずにサーバーからメールを送信する場合 | Adapty Mail APIの [プロファイルを保存](api-mail/operations/saveProfile) エンドポイントにプロファイルを送信します。詳細は [Adapty Mail APIを使ったメールとトランザクションの送信](mail-send-data-via-api) を参照してください。 | ## 制限事項 \{#limitations\} - **匿名ユーザー**: 安定した `customer_user_id` を持たないユーザーはキャンペーンを受け取ることができません。アカウント作成時やログイン時に識別することで、その後にメールアドレスを提供すればAdaptyのプロファイルと紐付けられます。 - **メールアドレスのないユーザー**: メールアドレスのないプロファイルはキャンペーン配信から除外され、キャンペーンの分析にも表示されません。メールアドレスを提供した時点で、以降のキャンペーンの対象となります。 --- # File: mail-send-data-via-api --- --- title: "Adapty Mail APIでメールとトランザクションを送信する" description: "Adapty SDKを使わずに、サーバーから直接Adapty Mailにユーザープロファイルとトランザクションを送信します。" --- Adapty Mail APIを使うと、Adapty SDKを経由せずに、サーバーから直接Adapty Mailにユーザープロファイルとトランザクションを送信できます。以下のような場合に活用してください: - Adapty Mailにまだベースがない状態でサブスクライバーを追加したい場合 - 他のアプリのサブスクライバーベースを再利用したい場合 - バックエンドをソースオブトラスとして、サーバー間でAdapty Mailにデータを送りたい場合 :::note **APIとSDK、どちらを使う?** ほとんどのアプリは、メールや購入情報を自動収集するAdapty SDKを通じてAdapty Mailにデータを送信します。アプリにAdapty SDKがない場合、データがすでにサーバー上にある場合、または別のソースからサブスクライバーをインポートする場合にAPIを選択してください。 ::: ## 始める前に \{#before-you-start\} :::warning データを送信する前に、Adapty Mailのセットアップを完了させてください。具体的には、キャンペーン、セグメント(必要な場合)、ウェブペイウォール、そして起動済みのフローが必要です。Adapty Mailは、このセットアップ完了後に作成されたプロファイルにのみメールを送信します。それより前に送信したプロファイルはメールを受信しません。まず[Adapty Mailをはじめる](mail-get-started)に従ってセットアップを完了させてから、こちらに戻ってください。 ::: APIキーとベースURLも必要です: - **シークレットAPIキー**: Adapty Mailの **Settings** に移動し、シークレットAPIキーをコピーします。キーはプロジェクト固有であるため、APIはどのプロジェクトのデータかを識別できます。 - **ベースURL**: すべてのリクエストは `https://api-mail.adapty.io` に送信します。 - **認証**: **Authorization** ヘッダーに `Bearer {your_secret_api_key}` の形式でキーを送信します。 :::important メールを収集してAdapty Mailに送信する前に、明示的な同意を取得してください。GDPR、CAN-SPAM、および各市場の関連法規への準拠はお客様の責任となります。 ::: ## ユーザープロファイルを送信する \{#send-user-profiles\} プロファイルには、ユーザーのメールアドレスと属性が含まれます。プロファイルを作成または更新するには、`/api/v1/profile/save/` にPOSTリクエストを送信します。 以下の3つのフィールドが必須です: - アプリまたはバックエンドが管理する安定した `external_profile_id` - Adapty Mailがキャンペーンを配信する `email` - ユーザー作成日時を示す `external_created_at`(セグメントで使用可能) :::important `external_profile_id` には必ず安定した値を使用し、匿名値やインストールごとの値は使わないでください。Adapty Mailはこれを使用して、メール、クリック、購入を1つのプロファイルに紐付けます。 ::: ```bash curl --request POST \ --url 'https://api-mail.adapty.io/api/v1/profile/save/' \ --header 'Authorization: Bearer {your_secret_api_key}' \ --header 'Content-Type: application/json' \ --data '{ "external_profile_id": "user_12345", "external_created_at": "2026-06-01T10:30:00Z", "email": "jane@example.com", "country": "US", "custom_attributes": { "plan": "trial" } }' ``` 利用可能なすべてのフィールドについては、[プロファイルを保存する](api-mail/operations/saveProfile)のリファレンスを参照してください。 ## トランザクションイベントを送信する \{#send-transaction-events\} :::note **一度も購入していない**フローでユーザーにリーチするには、メールアドレスを持つプロファイルがあれば十分です。それ以外のすべてのフローでは、トランザクションイベントも必要です。 ::: **一度も購入していない**フローを除くすべてのフローは、購入履歴によって動作します。購入、更新、キャンセルを処理する際にトランザクションイベントを送信することで、Adapty Mailはプロファイルを適切なフローに振り分けられます。トランザクションイベントは収益アトリビューションにも活用されます。**一度も購入していない**キャンペーンのみを実施する場合は省略できます。 トランザクションを記録するには、`/api/v1/profile/transaction-event/save/` にPOSTリクエストを送信します。プロファイルの送信時と同じ `external_profile_id` を使用することで、Adapty Mailがトランザクションを正しいユーザーに紐付けられます。 ```bash curl --request POST \ --url 'https://api-mail.adapty.io/api/v1/profile/transaction-event/save/' \ --header 'Authorization: Bearer {your_secret_api_key}' \ --header 'Content-Type: application/json' \ --data '{ "event_type": "subscription_started", "event_id": "evt_abc123", "event_datetime": "2026-06-10T14:20:05Z", "external_profile_id": "user_12345", "store": "app_store", "store_product_id": "premium_monthly", "store_transaction_id": "1000000123456789", "store_original_transaction_id": "1000000123456789", "purchased_at": "2026-06-10T14:20:00Z", "originally_purchased_at": "2026-06-10T14:20:00Z", "price_usd": "9.99" }' ``` 利用可能なすべてのフィールドについては、[トランザクションイベントを保存する](api-mail/operations/saveTransactionEvent)のリファレンスを参照してください。 ### イベントをフローにマッピングする \{#map-your-events-to-flows\} 発生した内容に合った `event_type` を送信してください。Adapty Mailはイベント履歴からプロファイルの状態を導き出し、対応するフローにルーティングします。 | `event_type` | 送信するタイミング | フロー | | --- | --- | --- | | `subscription_started` | ユーザーが新しいサブスクリプションを開始したとき | アクティブ — リエンゲージメントフローなし | | `subscription_renewed` | サブスクリプションが自動更新されたとき | アクティブ — リエンゲージメントフローなし | | `subscription_renewal_reactivated` | ユーザーが自動更新を再度有効にしたとき | アクティブ — リエンゲージメントフローなし | | `non_subscription_purchase` | ユーザーが買い切り購入をしたとき | アクティブ — リエンゲージメントフローなし | | `subscription_renewal_cancelled` | ユーザーが自動更新をオフにしたとき(有効期限まではアクティブ) | 更新キャンセル | | `billing_issue_detected` | 更新の支払いが失敗したとき | 請求問題 | | `entered_grace_period` | 支払いが失敗したがユーザーがグレース期間中のとき | 請求問題 | | `subscription_expired` | サブスクリプションが失効しアクセスが終了したとき | 期限切れ | | `subscription_refunded` | サブスクリプションの購入が返金されたとき | 返金済み | | `non_subscription_purchase_refunded` | 買い切り購入が返金されたとき | 返金済み | --- # File: mail-brand --- --- title: "Adapty Mailのブランド" description: "メール生成やウェブペイウォールを支えるブランドプロファイルを確認・改善しましょう。" --- **ブランド**とは、Adapty Mailがアプリの公開情報(App StoreまたはGoogle Playのリスティング、ランディングページ、利用規約・プライバシーページ、ソーシャルプロフィール)から構築する統合プロファイルです。メールのコピー、トーン、ビジュアル、ウェブペイウォールのコンテンツ、デモに活用されます。プロジェクトごとにブランドは1つで、すべての下流機能が同じプロファイルを参照します。 ブランドは、Adapty Mailのサイドバーにある **Brand** からアクセスできます。 - **AdaptyからAdapty Mailに登録した場合**: AdaptyプロジェクトのストアURLからブランドが自動的に作成されます。Brandページにはプロファイル全体が表示され、確認・改善をすぐに始められます。 - **スタンドアロンで登録した場合**: Brandページはセットアップ画面で開きます。詳しくは[ゼロからセットアップする](#set-up-from-scratch)をご覧ください。 ## ブランドプロファイルの内容 \{#whats-in-a-brand-profile\} ブランドには13のセクションがあります。Adapty Mailはこれらをメールおよびウェブペイウォール生成に直接使用します。 - **Identity**: アプリ名、短い説明、タグライン。 - **Visual identity**: カラー(プライマリ、バックグラウンド、セカンダリ、アクセント、テキスト、CTA)、タイポグラフィ、スタイルノート、ロゴURL。 - **Audience**: デモグラフィクス、言語、マーケット。 - **Features**: 各機能には名前、提供するベネフィット、オプションの説明があります。 - **Insights**: ユニークバリュープロポジション、観察事項、よくある反論と対応策のペア、タグ。 - **Brand voice**: トーン、フォーマリティレベル、語彙、感情的なレジスター。 - **Voice samples**: サンプルヘッドライン、サンプルCTA、メール生成時に使用されるトーンプリセット。 - **Social proof**: ユーザー数、評価、評価数、プレスメンション、主要指標。 - **Social links**: Twitter、Instagram、TikTok、YouTube、Facebook、LinkedIn。 - **Legal links**: 利用規約URL、プライバシーURL、サポートメール。 - **Reviews**: ストアソースから抽出したユーザーレビュー(内容、投稿者、評価、ソース)。 - **Pain points**: レビューやソーシャルシグナルに基づいた課題のステートメント。 - **FAQs**: メールコンテンツおよびウェブペイウォールセクションで使用される質問と回答。 ## セクションを手動で編集する \{#edit-a-section-manually\} ブランドビューの各セクションには **Edit** ボタンがあります。クリックするとそのセクションのインラインエディターが開きます。 1. 変更したいセクションの **Edit** をクリックします。 2. フィールドをその場で更新します。Adapty Mailは未保存の変更をドラフトとして追跡します。 3. ページ上部のドラフトバナーの **Save** をクリックして適用します。変更を破棄するには **Discard** をクリックします。 同時に開けるセクションは1つだけです。2つ目のセクションを開こうとすると、最初のセクションで完了またはキャンセルを求めるプロンプトが表示されます。 :::important ソースが処理中の間は編集が一時停止されます。処理中のソースが進行中の変更を上書きする可能性があるためです。処理が開始されると開いているエディターは自動的に閉じられ、処理が完了するまでドラフトバナーの **Save** ボタンは無効のままです。 ::: ## AIで改善する \{#refine-with-ai\} 右下の **Refine with AI** ボタンをクリックすると、ブランドの横にチャットパネルが開きます。自然な言葉で変更内容を説明すると、AIが改善案のドラフトを提示します。保存するか却下するかを選べます。 1. **Refine with AI** をクリックします。 2. 変更内容を説明します。チャットはブランド編集のみを対象としており、一般的な質問への回答やブランドプロファイル外のコピーの書き直しは行いません。 3. メインビューで提案されたドラフトを確認します。Adapty Mailは変更されたセクションをハイライト表示します。 4. ドラフトバナーの **Save** をクリックして適用するか、**Discard** をクリックして保存済みのブランドを維持します。 活用例のプロンプト: - 「トーンをもっと遊び心あるものにして。」 - 「オフラインモード機能を追加して。」 - 「ユニークバリュープロポジションを強化して。」 - 「オーディエンスの説明をUSマーケット向けに書き直して。」 ## ソースを追加する \{#add-more-sources\} ストアソースがプロファイルの基盤となります。追加のソースタイプは特定のセクションを補完します。ランディングページはビジュアルアイデンティティとコピーを改善し、利用規約・プライバシーページはリーガルリンクを改善し、ソーシャルプロフィールはボイスサンプルとソーシャルプルーフを改善します。 ブランドビューの **Sources** パネルには、すべてのソースとその下の **Add** フォームが表示されます。タイプを選び、URLを貼り付けて **Add** をクリックします。 - **App Store**: `https://apps.apple.com/...` - **Google Play**: `https://play.google.com/store/apps/details?id=...` - **Landing page**: マーケティングサイト(例: `https://yourapp.com`)。 - **Terms / Privacy**: 利用規約またはプライバシーページへの直接リンク。 - **Social profile**: Twitter、Instagram、TikTok、YouTube、Facebook、またはLinkedFBのURL。 ソースはタイプごとに1つだけです。そのタイプのソースが処理中または完了済みの場合、セレクターは無効になります。ソースを置き換えるには、ブランドを削除して再オンボーディングが必要です。個別のソースは削除できません。 ## ゼロからセットアップする \{#set-up-from-scratch\} プロジェクトにまだブランドがない場合(スタンドアロンのAdapty Mail登録の場合に一般的)、**Brand** ページはセットアップ画面で開きます。ストアソース(App StoreまたはGoogle Play)が基盤となり、他のソースタイプは後から追加できます。 1. ストア(**App Store** または **Google Play**)を選び、リスティングURLを貼り付けます。 2. **Build my brand** をクリックします。Adapty Mailがページを取得し、レビューを解析し、ブランドボイスを推定します。処理は通常1分以内に完了します。 3. 処理が完了すると、13のセクションすべてが入力された状態でブランドビューが開きます。 ソースが失敗した場合(無効なURL、アクセスできないページ、パーサーエラー)、画面にエラーメッセージと **Try again** ボタンが表示されます。URLを修正して再送信してください。 ## ブランドの使用場所 \{#where-the-brand-is-used\} ブランドは、アプリのサウンドとビジュアルを把握する必要があるすべての下流機能で使用されます。 - **メール生成**: コピー、トーン、ビジュアル、送信者ブロック、ヒーロー画像はすべてブランドから読み取られます。詳しくは[キャンペーンの作成](mail-create-campaign)をご覧ください。 - **ウェブペイウォールビルダー**: ブランドはペイウォール生成の前提条件です。`brand_saved` がない場合、生成はブロックされます。詳しくは[チェックアウトのセットアップ](mail-checkout)をご覧ください。 - **オンボーディング**: オンボーディングチェックリストの **Set up brand** ステップは、ブランドが存在すると完了に切り替わります。 ## ブランドを削除する \{#delete-a-brand\} **Delete brand** アクションは、ブランドビュー下部の **Danger zone** にあります。 1. Danger zoneセクションの **Delete** をクリックします。 2. ダイアログで確認します。 削除するとブランドプロファイルとすべてのソースが削除されます。元に戻す方法はありません。復元するには、スタート画面でApp StoreまたはGoogle PlayのURLを貼り付けて、ゼロからオンボーディングしてください。 :::warning 既存のキャンペーンは生成時のブランドスナップショットを保持しますが、新しいキャンペーンやペイウォール生成はブランドを再オンボーディングするまでブロックされます。 ::: ## 制限事項 \{#limitations\} - **プロジェクトごとに1つのブランド**: 各Adapty Mailプロジェクトには1つのブランドがあります。別のアプリをターゲットにするには、新しいプロジェクトを作成してください。 - **タイプごとに1つのソース**: ブランドはApp Store、Google Play、ランディングページ、利用規約・プライバシー、ソーシャルプロフィールのソースをそれぞれ1つずつ持てます。 - **ソースの個別削除不可**: 個別のソースはUIから削除できません。ソースを置き換える必要がある場合は **Delete brand** を使用してください。 - **処理中は編集が一時停止**: ソースが `pending` または `processing` 状態の間は、セクション編集、リファインチャットの保存、ブランド削除がすべてブロックされます。 - **失敗したソースはリストに残る**: `failed` 状態のソースはエラーメッセージとともにパネルに表示され続けます。同じタイプを再度送信して再試行してください。新しいスケジュールが成功すると、失敗したエントリは置き換えられます。 --- # File: mail-sending-domain --- --- title: "Adapty Mailの送信ドメインを設定する" description: "DNSレコードの追加、ドメインの確認、ウォームアップの仕組みを理解して、Adapty Mailがあなたの代わりにメールを送信できるようにします。" --- Adapty Mailは共有アドレスではなく、あなた自身のドメインからキャンペーンを送信します。そのため、送信者レピュテーションはあなたの管理下に置かれます。設定は一度行うだけで、すべてのキャンペーンに同じ確認済みドメインが使用されます。最小限の手順については、[Adapty Mailを始める](mail-get-started#2-set-up-your-sending-domain)のドメインセクションをご覧ください。この記事では、完全なセットアップ手順、確認の仕組み、および自動ウォームアップの動作について説明します。 ## 要件 \{#requirements\} - **Apexドメイン**: ルートドメイン(例:`yourapp.com`)を入力してください。サブドメインは使用できません。`app.yourapp.com`のような入力は検証時に拒否されます。 - **有効なNSレコード**: ドメインが解決できる必要があります。Adapty Mailはセットアップ中にDNSルックアップを実行し、有効なNSレコードがないドメインは拒否します。 - **Adaptyプロジェクトごとに1ドメイン**: ドメインは複数のプロジェクト間で共有できません。そのドメインがすでに別のプロジェクト(あなたのものか他の人のもの)に登録されている場合、セットアップは失敗します。 ## 送信ドメインを設定する \{#set-up-your-sending-domain\} セットアップウィザードには3つの画面があります:ドメインの入力、生成されたサブドメインの確認、DNSレコードの追加です。これらはすべて **Settings → Email Domains** にあります。 1. **ドメインを入力する。** **Domain** フィールドにApexドメインを入力し、**Preview** をクリックします。Adapty Mailは形式を検証し(ASCII、2つのラベル、先頭または末尾にハイフンなし、2文字以上のTLD)、DNSが解決できるか確認します。 2. **サブドメインを確認する。** Adapty Mailは固定プレフィックスを持つ2つの送信サブドメインを生成します — `mail.yourapp.com` と `email.yourapp.com` — それぞれが独自のSESアイデンティティを持ちます。また、各サブドメインの下にMail-Fromサブドメインも作成されます(`hello.mail.yourapp.com` と `hello.email.yourapp.com`)。内容を確認して **Confirm** をクリックします。 3. **DNSレコードを追加する。** 最後の画面には追加が必要なすべてのレコードが表示されます — 合計10件、送信サブドメインごとに5件、ルートにオプションのDMARCレコード1件です。**Download CSV** でリスト全体をエクスポートするか、レジストラに1件ずつコピーしてください。レコードを追加したら **Done** をクリックします。 <Details> <summary>DNSレコードリファレンス</summary> 各送信サブドメイン(`mail.yourapp.com` と `email.yourapp.com`)に対して、以下を追加します: **DKIM — CNAMEレコード3件。** メールが転送中に改ざんされていないことを証明する暗号署名。 | フィールド | 形式 | | ----- | ----------------------------------- | | タイプ | CNAME | | 名前 | `{token}._domainkey.{subdomain}` | | 値 | `{token}.dkim.amazonses.com` | **Mail-From — MXレコード1件。** バウンスを処理します。 | フィールド | 形式 | | -------- | -------------------------------------------------------- | | タイプ | MX | | 名前 | `hello.{subdomain}`(例:`hello.mail.yourapp.com`) | | 優先度 | `10` | | 値 | `feedback-smtp.{region}.amazonses.com` | **SPF — TXTレコード1件。** Adaptyがあなたの代わりに送信することを認証します。 | フィールド | 形式 | | ----- | -------------------------------------- | | タイプ | TXT | | 名前 | `hello.{subdomain}` | | 値 | `"v=spf1 include:amazonses.com ~all"` | ルートドメインにはオプションのDMARCレコードを追加します: | フィールド | 形式 | | ----- | --------------------- | | タイプ | TXT | | 名前 | `_dmarc.{domain}` | | 値 | `v=DMARC1; p=reject` | トークン、リージョン、その他の値はセットアップ時にAWS SESから提供されます。このリファレンスではなく、必ずAdapty MailのDNSレコード画面からコピーしてください。 </Details> ## 確認の仕組み \{#how-verification-works\} DNSレコードを追加すると、Adapty MailはDNSを自動的にポーリングします。手動でチェックをトリガーすることもできます。 - **自動ポーリング**: 送信後5分でポーリングが開始され、その後は各ラウンドごとに間隔が倍になります — 10分、20分、40分 — その後60分で上限に達します。レコードが見つかるか7日間のウィンドウが閉じるまで継続されます。 - **手動チェック**: **Check Verification** をクリックして即時チェックを強制します。手動チェックの間には60秒のクールダウンがあります — 素早く実行しすぎると *「Verification check is on cooldown.」* と返されます。 - **ステータスの状態**: 各サブドメインのDKIMとMail-Fromは独立して **Pending**、**Success**、**Failed** として追跡されます。4つのステータスすべてが **Success** になった場合にのみ、ドメインは完全に確認済みとみなされます。 - **7日間の期限**: 7日以内に確認が完了しない場合、アイデンティティは **Failed** とマークされます。DNSレコードはレジストラに残ります — **Settings → Email Domains** でドメインを再入力して新しいウィンドウを開始してください。 - **確認後**: 後でDNSレコードを削除または変更した場合、AWS SESはいずれアイデンティティをダウングレードします。送信を続ける限り、レコードはそのままにしておいてください。 - **DNS伝播**: 通常は数分で完了しますが、まれに最大48時間かかる場合があります。 ## ドメインウォームアップ \{#domain-warm-up\} 新しいドメインはGmailやYahooなどのメールプロバイダーに対してレピュテーションがないため、新しいドメインから大量に送信するとスパムに分類されるリスクがあります。Adapty Mailは14段階のティアにわたって1日あたりの送信上限を段階的に引き上げることで、自動的にウォームアップを処理します。設定は不要です。 ### ティアの仕組み \{#how-tiers-work\} ドメインは **Tier 1**(1日200件)から始まり、配信到達性の指標が良好な状態を維持すると自動的に進級します。バウンス率が上昇したり苦情率が増加したりすると、進級が一時停止され、レピュテーションが回復するまで逆行することもあります。 | ティア | 1日あたりの上限 | | ---- | ----------- | | 1 | 200 | | 2 | 400 | | 3 | 800 | | 4 | 1,500 | | 5 | 2,500 | | 6 | 4,000 | | 7 | 6,000 | | 8 | 8,000 | | 9 | 10,000 | | 10 | 13,000 | | 11 | 16,000 | | 12 | 20,000 | | 13 | 25,000 | | 14 | 30,000 | 現在のティアと1日あたりの上限は **Settings → Email Domains** で確認できます。 ### オーディエンスサイズによる開始時の影響 \{#impact-on-launch-by-audience-size\} | オーディエンスサイズ | 開始時の影響 | | ---------------- | ----------------------------------- | | 200人未満 | 1日目にオーディエンス全員に到達 | | 200〜2,000人 | 配信が数日間にわたって分散 | | 2,000人以上 | 配信が1〜2週間にわたって分散 | :::tip DNS確認が完了したらすぐに最初のキャンペーンを開始しましょう。送信を早く始めるほど、ドメインのティアが早く上がり、1日あたりの最大送信数に早く到達できます。 ::: ## 制限事項 \{#limitations\} - **プロジェクトごとに1ドメイン**: Adaptyプロジェクトごとに送信ドメインは1つだけ使用できます。別のドメインに切り替えるにはサポートに連絡してください — ダッシュボードに「ドメイン変更」の操作はありません。 - **プロジェクト間の一意性**: 別のプロジェクトにすでに登録されているドメインは再利用できません。 *「Domain is already registered to another project」* と表示された場合は、別のドメインを選択するかサポートにお問い合わせください。 - **確認済みドメインは削除不可**: いずれかのサブドメインが **Success** に達すると、ダッシュボードでの削除がブロックされます。保留中のドメインは削除できますが、レジストラからDNSレコードを手動で削除する必要があります。 - **固定サブドメインプレフィックス**: `mail.`、`email.`、および `hello.` のMail-Fromプレフィックスはハードコードされており、カスタマイズできません。これらのサブドメインがDNSですでに使用されている場合、セットアップが競合します。 - **Apexドメインのみ**: サブドメイン入力、末尾のドット、シングルラベルのホスト名は拒否されます。 - **国際化ドメイン非対応**: PunycodeとIDNはサポートされていません。ドメインはASCIIのみである必要があります。 ## トラブルシューティング \{#troubleshooting\} | 問題 | 解決策 | | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | | "Enter a valid domain (e.g. example.com)" | 入力を確認してください:Apexのみ、ASCIIのみ、2文字以上のTLD、先頭または末尾にハイフンなし。 | | "Domain does not have valid DNS records" | Apexドメイン自体が解決できる必要があります。再試行前にNSレコードが有効であることを確認してください。 | | "Domain is already registered to another project" | 別のドメインを選択するか、登録が間違いだと思われる場合はサポートにお問い合わせください。 | | "Verification check is on cooldown" | 手動チェックの間は60秒待ってください。自動ポーリングはバックグラウンドで継続されています。 | | 確認がPendingのまま止まっている | DNSレコードが正確に一致しているか確認してください — 末尾のドットなし、正しいCNAMEターゲット。DNSの伝播には最大48時間かかる場合があります。 | | "Cannot delete domain: one or more identities have been successfully verified" | 確認済みドメインはダッシュボードから削除できません。サポートにお問い合わせください。 | | メールがスパムに振り分けられる | DMARCレコードが公開されているか確認してください。新しいドメインはウォームアップ期間が必要です — [ドメインウォームアップ](#domain-warm-up)をご確認ください。 | | バウンス率が高い | オーディエンスリストに有効なオプトイン済みのアドレスが含まれているか確認してください。バウンスはティアの進級を遅らせるか停止させます。 | --- # File: mail-checkout --- --- title: "Adapty Mail のチェックアウトを設定する" description: "ウェブペイウォールを構築して決済プロバイダーを接続し、メールキャンペーンにパーソナライズされたウェブチェックアウトを追加しましょう。" --- Adapty Mail が送信するメールには、受信者ごとに固有のチェックアウトリンクが含まれています。リンクをクリックすると、プロファイルで受信者を識別し、オファーを表示して決済を処理するウェブチェックアウトファネルに誘導されます。チェックアウトファネルは Adapty Mail 内の **Web Paywalls** に存在し、付属の**ウェブペイウォールビルダー**で編集します。 ## 要件 \{#requirements\} - サブスクリプションプロダクトが設定済みのウェブ決済プロバイダー。**Generate with AI** は Stripe のみに対応しており、ビルダー内で接続します。**Use your own hosted paywall** は、決済がユーザー側で処理されるため、Stripe、Paddle、PayPal、その他のプロバイダーに対応しています。 ウェブペイウォールビルダー用に別アカウントを用意する必要はありません。Adapty Mail に付属しており、初回ログイン時にワークスペースが自動的にプロビジョニングされ、Adapty の認証情報でエディターにサインインできます。これは、メインの Adapty ダッシュボードのペイウォールページで設定したウェブペイウォールとは独立しています — Adapty Mail のウェブペイウォールは別エンティティとして、Adapty Mail 内で完結して管理されます。 ## チェックアウトファネルを設定する \{#set-up-your-checkout-funnel\} Adapty Mail で **Web Paywalls → Create** に移動します。2 つの方法があります: - **Generate with AI**:Adapty Mail 付属のウェブペイウォールビルダーがファネルを自動生成します。Stripe のみ対応 — Paddle または PayPal を使用する場合は次のオプションを選択してください。 - **Use your own hosted paywall**:すでにホスティングしているペイウォールを接続し、任意の決済プロバイダーを使用できます。 ### Generate with AI \{#generate-with-ai\} 作成ページの上部に **Prerequisites** パネルが表示され、各前提条件(ブランドの準備状況、ビルダーへのログイン、Stripe の接続、プロダクト、最終確認・公開ステップ)を案内するインラインアクションボタンが並んでいます。順番に進めると、各ステップが完了するたびにパネルが更新されます。 前提条件がすべて緑色になったら、**Generate** をクリックして生成ダイアログを開きます。2 つの選択肢があります: - **Environment**:**Production** または **Sandbox** を選択します。Sandbox は Stripe のテストモードプロダクトを使用し、開発・ローカル環境での安全なデフォルトです — アカウントは本番環境から分離されているため、テスト取引がライブデータに影響することはありません。 - **Plans**:最大 **3 つの Stripe プラン**を選択します。各プランはプロダクトと価格の組み合わせです。ペイウォールはこれらをチェックアウト時のオファーとして表示します。3 つ未満を選択した場合、ペイウォールは選択したプランのみを表示します。 **Generate** をクリックしてビルドを実行します。完了したら、ビルダーのエディターを開いて結果を確認し、公開します。その後、**Save** をクリックします。 :::important ペイウォールはチェックアウトトラフィックを処理する前に公開されている必要があります。未公開のペイウォールは、ユーザーがメールのチェックアウトリンクをクリックするとエラーを返します。 ::: ビルダー内の決済プロバイダーの詳細(Stripe アカウント、テストモードとライブモード、プロダクト設定)については、[ウェブペイウォールの設定](web-paywall-configuration)を参照してください。 ### Use your own hosted paywall \{#use-your-own-hosted-paywall\} 1. 作成ページで **Enter URL manually** を選択します。 2. ホスティングしているペイウォールの URL を貼り付けます。クエリパラメーターとして `{email}` と `{external_profile_id}` プレースホルダーを含める必要があります — Adapty Mail が受信者ごとにこれらを埋め込むことで、ページが訪問者を識別できます。例: ``` https://example.com/paywall?email={email}&profile={external_profile_id} ``` 3. 保存します。 この方法は任意の決済プロバイダーで動作します — Adapty Mail はリダイレクトとパラメーター置換のみを担当し、決済とパーソナライズはすべてユーザー側で処理されます。 ## チェックアウトの外観 \{#what-the-checkout-looks-like\} ユーザーがチェックアウトリンクをクリックすると、**メインコンバージョンページ**に誘導されます。決済を試みると、**Payment success** または **Payment failed** のいずれか一方が表示されます。 **メインコンバージョンページ** フルページのセールスプレゼンテーションです。AI が各セクションのコピーと画像を生成します: | セクション | AI が生成する内容 | |---|---| | Headline | 太字のベネフィット訴求型ヘッドライン | | Subheadline | 補足的な価値提案 | | Offer badge | 緊急性バッジ(架空の価格なし — 曖昧なプロモーション表現を使用) | | CTA button | アクション指向のテキスト、2〜5 語 | | Benefits | 3〜6 個の絵文字+テキストのベネフィットカード | | Features | タイトルとサブタイトル付きの 3〜8 個の機能説明 | | Plans | プラン選択タイトルとオファータイマーテキスト | | Social proof | コミュニティ証明テキストと 3〜5 件のリアルなユーザーレビュー | | FAQ | 3〜6 件のよくある質問と回答 | | Guarantee | 返金保証または満足保証テキスト | **Payment success** 次のステップを示す祝福メッセージと AI 生成画像。 **Payment failed** ユーザーに再試行を促すフレンドリーなメッセージ。チェックアウトの状態は保持されます。 ## パーソナライズの仕組み \{#how-personalization-works\} すべてのメールには、受信者の `customer_user_id` とメールアドレスがパラメーターとして埋め込まれた固有のチェックアウト URL が含まれています: ``` https://your-funnel.com/?cid={{customer_user_id}}&email={{email}} ``` Adapty は各メール送信時にこれらの URL を自動的に生成します — ウェブペイウォールビルダーでの設定は不要です。ユーザーがクリックすると、ビルダーがパラメーターを読み取って識別します。購入が完了すると、Adapty はその収益をコンバージョンを促したメールに紐付けます。このデータは[キャンペーン分析](mail-analytics)に表示されます。 ## トラブルシューティング \{#troubleshooting\} | 問題 | 解決策 | |---|---| | チェックアウトリンクが開かない | ペイウォールがウェブペイウォールビルダーで公開されていることを確認する | | チェックアウト時にユーザーが識別されない | メール送信前に正しいユーザー ID で `Adapty.identify()` が呼び出されていることを確認する | | 購入がメールに紐付かない | チェックアウト URL に `cid` パラメーターが含まれているか確認する — パラメーターが欠落している場合はサポートに連絡する | --- # File: mail-email-campaigns --- --- title: "Adapty MailのEメールキャンペーン" description: "複数メールのシーケンスを設計し、適切なトーンを選択して、適切なユーザーをターゲットにします。" --- Adapty Mailのキャンペーンは、アプリ向けに一度で生成される、コピー・デザイン・ヒーロー画像・配信間隔を含む完全なマルチメールシーケンスです。キャンペーン単体では送信されず、**下書き**として保存され、トリガーとオーディエンスを紐付ける[フロー](mail-create-flow)に関連付けた後にのみ配信が開始されます。 以下のガイドを使って、キャンペーンの作成、適切なトーンの選択、ターゲットユーザーの設定を行ってください。 <CustomDocCardList ids={['mail-create-campaign', 'mail-suppression']} /> --- # File: mail-create-campaign --- --- title: "Adapty Mail でキャンペーンを作成する" description: "アプリのストアメタデータから完全なメールシーケンスを生成し、フローに紐付ける前に内容を確認・調整します。" --- Adapty Mail は、アプリのストアメタデータからメールシーケンス全体(コピー、デザイン、ヒーロー画像、件名、送信間隔)を自動生成します。コピーライティングやデザイン作業は不要です。キャンペーンはドラフトとして保存され、[フロー](mail-create-flow)に紐付けた時点ではじめて配信が開始されます。 ## 始める前に \{#before-you-start\} - **保存済みのウェブペイウォール**: すべてのキャンペーンはウェブペイウォールにリンクする必要があります。ウェブペイウォールがないとバックエンドがキャンペーンを拒否します。まだ作成していない場合は、[ウェブペイウォールを作成する](mail-get-started#3-create-a-web-paywall)をご覧ください。 - **ブランドプロファイル**: AI はブランドプロファイルを使って、シーケンス全体のコピー、トーン、ビジュアルを調整します。まだ設定していない場合は、Adapty Mail の **Brand** から設定してください — [Brand](mail-brand)をご参照ください。 ## 1. シーケンスを生成する \{#1-generate-the-sequence\} 1. Adapty Mail で **Campaigns** に移動し、**Create** をクリックします。 2. キャンペーン名を設定します。 3. **Web paywall** ドロップダウンで、メールのリンク先となるウェブペイウォールを選択します。 4. **Generate emails** をクリックします。 5. 生成ダイアログに入力します: - **Tone**: リストから選択します。選択肢はアプリのカテゴリに応じて生成されるため、別のアプリでは異なる選択肢が表示されます。選択したトーンは、すべてのメールの件名・見出し・本文・CTAに反映されます。レイアウトやヒーロー画像には影響しません。 - **Language**: メールの言語を選択します。 - **Custom prompt**(任意): 最大2,000文字の自由記述欄です。プロモーション情報、特別なイベント、オーディエンスの特性、必ず含めたいポイント、プリセットでは表現しきれないトーンの細かい指示などを記入できます。 - **Number of emails**: デフォルトでは、AI がベストプラクティスとアプリのコンテキストに基づいて件数を決定します。手動で設定する場合は **Set number manually** をクリックし、値(**1〜15**、デフォルト **4**)を選択します。 **Generate** をクリックすると、そのキャンペーンのトーンが固定されます。別のトーンを試したい場合は新しいキャンペーンを作成してください — 生成のたびに異なる選択肢が表示されることがあります。 6. **Generate** をクリックします。生成には通常数分かかります。完了できない場合、バックエンドは5分後にタイムアウトします — その際は再試行してください。 ## 2. 確認と調整 \{#2-review-and-refine\} 生成が完了すると、シーケンス全体がプレビューとして表示されます。各メールで確認できる内容は以下のとおりです: - **件名のバリエーション**: メールごとに3つの件名の候補があります。Adapty Mail は配信時にそれらをテストし、最もパフォーマンスの高いものを送り続けます — [A/B テスト](mail-ab-testing)をご参照ください。 - **見出し、本文、CTA**: メインのコンテンツブロックです。 - **ヒーロー画像**: メールのコンテンツとブランドに合わせて生成された画像です。 - **レイアウトと送信間隔**: メールの構成と、前のメールからの送信間隔です。 プレビューのヘッダーには **Theme toggle**(Auto、Light、Dark)があります — プレビューペイン右上のアイコンボタンです。これはプレビューの表示方法のみを制御するもので、生成されたコンテンツはどのモードでも同一です。再生成せずに各カラースキームでの見た目を確認するために使用できます。 以下の操作が可能です: - **個別メールの再生成**: AI が1通のメールのコピーとヒーロー画像を書き直します。位置、タイミング、全体のデザインシステム(色、タイポグラフィ、ダークモード)はそのまま維持され、対象のメールのみが変更されます。 - **HTML の直接編集**: HTML コードエディタを開いて、AI が意図どおりに生成できなかった部分を細かく制御できます。 :::note メールは自動的に適応されます。マルチカラムのデザインは620px未満の画面では1カラムに折り畳まれ、すべてのレイアウトはGmail(ウェブおよびモバイル)、Apple Mail(macOSおよびiOS)、Outlookデスクトップ、Yahoo Mail、Samsung Mail でライトモードとダークモードの両方においてテスト済みです。 ::: ## 3. ドラフトとして保存する \{#3-save-as-a-draft\} **Create** をクリックしてキャンペーンをドラフトとして保存します。この時点ではメールはまだ送信されません — キャンペーンエディタには「公開」や「開始」の操作はありません。 キャンペーンのステータスは、ライブフローへの紐付け状況を示します: - **draft**: どのフローにも紐付けられていない状態。 - **live**: フローに紐付けられており、現在ユーザーをルーティング中。 - **inactive**: 紐付けられていたが、フローの A/B テストが終了した状態。 - **archived**: ダッシュボードから削除された状態。 :::important ドラフトのキャンペーンは単独では送信されません。メールの配信を開始するには、以下のいずれかが必要です: - キャンペーンを[フロー](mail-create-flow)に直接紐付ける、または - [A/B テスト](mail-ab-testing)に組み込み、その A/B テストをフローに紐付ける。 どちらかが完了するまで、キャンペーンは `draft` のままとなり、受信者には届きません。 ::: --- # File: mail-suppression --- --- title: "Adapty Mailの購読解除とサプレッション" description: "Adapty Mailがユーザーへの送信を停止する仕組み — 購読解除、SESバウンス、苦情、ストップ条件について。" --- Adapty Mailは、2つの異なる条件でユーザーへの送信を停止します。 - **サプレッション**: ユーザーがこのプロジェクト内の将来のすべての送信から除外されます(購読解除、バウンス、苦情、拒否、またはスロットル)。 - **ストップ条件**: ユーザーがコンバージョンしたため、現在のシーケンスがキャンセルされます。サプレッションではなく、他のキャンペーンの対象として残ります。 どちらの仕組みもプロジェクト単位で機能します。あるAdaptyプロジェクトでのサプレッションは、別のプロジェクトには影響しません。 ## 購読解除 \{#unsubscribe\} Adapty Mailが送信するすべてのメールのフッターには、購読解除リンクが含まれています。 1. ユーザーがリンクをクリックします。Adapty Mailが確認ページを開きます。 2. ユーザーが確認します。バックエンドがプロファイルに `suppression_reason = 'unsubscribe'` を設定し、残りのシーケンスをキャンセルして、プロジェクト内の将来の送信からそのプロファイルを除外します。 購読解除URLのトークンには `profile_id` と `scheduled_email_id` がエンコードされているため、ログイン不要で利用できます。 :::note Adapty Mailは、`List-Unsubscribe-Post: List-Unsubscribe=One-Click` と合わせて `List-Unsubscribe: <URL>, <mailto:>` ヘッダーも送信します。GmailとYahooはバルク送信者にこれを要求しています(RFC 8058)。このヘッダーに対応しているメールクライアントでは、受信トレイから直接ワンクリックで購読解除できるボタンが表示されます — 確認ページは不要です。 ::: ## 自動サプレッション \{#automatic-suppression\} Adapty MailはSNS経由でAWS SESの配信イベントを監視し、以下のいずれかのイベントが発生した際に即座にユーザーをサプレッションします。 | イベント | 理由コード | 意味 | | --------- | ----------- | ------------------------------------------------------------------------------- | | バウンス | `bounce` | メールアドレスが無効、メールボックスが満杯、またはドメインが存在しない。 | | 苦情 | `complaint` | ユーザーがメールをスパムとしてマークした。 | | 拒否 | `reject` | SESが送信前にメッセージを拒否した。 | | スロットル | `throttle` | 送信レートがドメインの安全制限を超えた。 | どのイベントでも結果は同じです。ユーザーがサプレッションリストに追加され、残りのシーケンスがキャンセルされ、プロジェクト内の将来の送信から除外されます。 :::important Adapty Mailはハードバウンスとソフトバウンスを**区別しません**。メールボックスが満杯のような一時的な状態によるバウンスも含め、あらゆるバウンスが即座にユーザーをサプレッションします。リトライウィンドウはありません。 ::: ## ストップ条件 \{#stop-condition\} ユーザーがシーケンスの途中でコンバージョンした場合、Adapty Mailは残りのメールを `stop_condition` 理由でキャンセルします。コンバージョンとは、サブスクリプションの状態が**Subscribed**に、または買い切り購入の状態が**Purchased**に達することを意味します。 ストップ条件はサプレッションとは異なります。 - **サプレッション**: プロジェクト内の将来のすべての送信からユーザーを除外します。 - **ストップ条件**: 現在のシーケンスのみをキャンセルします。ユーザーは他のキャンペーンの対象として残ります — たとえば、アクティブなサブスクライバーを対象とした更新やウィンバックフローなどです。 ストップ条件によるキャンセルは、キャンペーン分析においてサプレッションと並んで表示されます。 ## サプレッションの管理 \{#managing-suppression\} Adapty Mailには、サプレッションされたユーザーを確認・削除するためのダッシュボードUIはありません。プロファイルのサプレッションを解除する場合(たとえば、テストメールを誤ってスパムとしてマークした場合など)は、Adaptyサポートにお問い合わせください。 ## コンプライアンスのためにAdapty Mailが対応する内容 \{#what-adapty-mail-handles-for-compliance\} Adapty Mailには以下が含まれています。 - **購読解除リンク**: すべてのメールフッターに含まれ、ユーザーが確認した際に即座に処理されます。 - **List-Unsubscribeヘッダー**: 受信トレイからのワンクリック購読解除のためにすべてのメールで送信されます(RFC 8058)。 - **自動サプレッション**: SESのバウンス、苦情、拒否、スロットルイベント時にトリガーされます。 お客様が責任を負う部分: - **物理的な郵送先住所**: CAN-SPAMではメールフッターへの記載が必要です。Adapty Mailは自動挿入しません — キャンペーンデザインで追加してください。 - **明示的なオプトイン同意**: ユーザーのメールアドレスをAdaptyに渡す前に取得してください。[ユーザーメールの収集](mail-collect-emails)を参照してください。 - **GDPRの削除リクエスト**: Adapty Mailには「データ削除」エンドポイントがありません。ユーザーが削除権を行使した場合は、Adaptyサポートと連携してください。 --- # File: mail-flows --- --- title: "Adapty Mail のフロー" description: "フローがキャンペーンを適切なタイミングで適切なユーザーにルーティングする仕組み — トリガー、セグメント、優先度のルール。" --- <CustomDocCardList ids={['mail-create-flow']} /> **フロー**は、保存済みキャンペーンをスケジュール配信に変換します。トリガーイベント(ユーザーのサブスクリプション状態)、セグメント(対象ユーザー)、そして配信するキャンペーンを紐付けます。Adapty Mail は対象のイベントが発生するたびにすべてのフローを評価します — ポーリングも、cron も、手動起動も不要です。 ## トリガー \{#triggers\} Adapty Mail には5つの固定トリガーが用意されており、それぞれ **Flows** 配下に専用のフロービューがあります: - **Never purchased**: 登録済みだが、まだ購入を行っていないユーザー。目標はアクティベーションと初回コンバージョンです。トライアルユーザーはここに含まれません — トライアルを開始することはアクティブなサブスクリプションとして扱われます。 - **Renewal cancelled**: 自動更新をオフにしたが、まだアクティブなサブスクリプションを持つユーザー。有料サブスクライバーと、コンバージョン前にキャンセルしたトライアルユーザーの両方が対象です。ユーザーはまだアクセス権を持っているため、引き止めるための最も重要な時間帯です。メッセージを変える必要がある場合は、セグメントフィルターで有料ユーザーとトライアルユーザーのオーディエンスを分けてください。 - **Billing issue**: 支払いが失敗した — カードが拒否・期限切れ、または更新漏れ後のグレース期間。目標はセールスプッシュではなく、迅速で親切なリカバリーです。すでに支払う意思があったユーザーをすばやく回復させましょう。 - **Expired**: サブスクリプションが失効し、アクセス権がなくなったユーザー。有料サブスクリプションの失効と、コンバージョンせずに終了したトライアルの両方が対象です。目標はウィンバックです。セグメントフィルターを使って、トライアル失効と有料失効のオーディエンスでコピーをカスタマイズできます。 - **Refunded**: 購入後に返金をリクエストしたユーザー。目標は問題点を把握し、より適切なオプションを提案することです。トーンはハードな再販売ではなく、謙虚で好奇心のあるものにしてください。 トリガーは設定不可能です — カスタムトリガーの作成やリストの拡張はできません。 ## All Users セグメント \{#the-all-users-segment\} Adapty Mail には、フィルターのない組み込みの **All Users** セグメントが用意されており、プロジェクト内のすべてのユーザーが対象になります。フロー内では、上位の特定のセグメントにマッチしなかったユーザーをすべて受け取るキャッチオール行として最も役立ちます。All Users は編集も削除もできません。詳細については [セグメント](mail-segments) を参照してください。 ## 優先度 \{#priority\} 各トリガービューには、優先度順に並んだ **セグメント → キャンペーン**(またはセグメント → A/B テスト)の行のリストがあります。ユーザーがトリガーに到達すると、Adapty Mail は: 1. 行を上から下へ順番に確認します。 2. セグメントが一致した最初の行のキャンペーンを送信します。 3. 停止します。そのユーザーに対して、それ以降の行は評価されません。 順序が重要です。幅広いセグメントが狭いセグメントより上に配置されると、本来狭い行にマッチするはずのすべてのユーザーを吸収してしまいます。 並び替えるには、任意の行の左側にあるハンドルをドラッグします — バックエンドは保存された順序に基づいて優先度番号 1、2、3… を再割り当てします。 :::important **All Users** 行が存在する場合、必ず最後(最低優先度)に配置してください。All Users が最終スロットにない状態での保存はバックエンドが拒否します — そうでなければ、より特定のセグメントがマッチする機会を得る前に、すべてのユーザーを吸収してしまいます。 ::: ## コンテンツタイプ \{#content-types\} 行は単一のキャンペーンまたは A/B テストのいずれかを配信できます: - **Campaign**: セグメントにマッチしたすべてのユーザーに1つのキャンペーンを送信します。 - **A/B Test**: 設定可能なウェイトで2つ以上のキャンペーンをラップし、受信ユーザーをランダムに振り分け、バリアントごとの指標を追跡します。[A/B テスト](mail-ab-testing) を参照してください。 ## ライフサイクル \{#lifecycle\} フローの行にはドラフト状態がありません。行は保存した瞬間からライブになります — それ以降、トリガーに到達してセグメントにマッチしたユーザーはそのキャンペーンにルーティングされます。 - **行を作成**: 保存後すぐに配信が開始されます。 - **行を編集**: 変更はそれ以降にトリガーに到達したユーザーに適用されます。すでにシーケンスの途中にいるユーザーは、以前の設定で継続されます。 - **行を削除**: 新規ユーザーのシーケンスへの流入が停止します。すでにシーケンスの途中にいるユーザーは、スケジュールされたメールを引き続き受信する場合があります — 自動キャンセルはありません。 A/B テストの行は、行自体とは別に制御される独自のライフサイクル(**draft → live → finished**)に従います。[A/B テスト](mail-ab-testing) を参照してください。 --- # File: mail-create-flow --- --- title: "Adapty Mailでフローの行を作成・管理する" description: "フロー内の行を追加、並び替え、編集、削除して、キャンペーンをユーザーにルーティングする方法を説明します。" --- 各[フロー](mail-flows)は、固定されたトリガービュー内に**セグメント → キャンペーン**の行を優先順位付きで並べたリストです。このガイドでは、これらの行の追加・並び替え・編集・削除方法を説明します。トリガー、優先順位、コンテンツタイプの概念については、[フロー](mail-flows)を参照してください。 ## 行を追加する \{#add-a-row\} 1. Adapty Mailで**Flows**に移動し、設定したいトリガーを開きます。 2. **Create**をクリックしてダイアログを開きます。 3. ダイアログで以下を設定します: - **Segment**:セグメントを選択するか、全ユーザーに適用する場合は**All Users**を選択します。 - **Content type**:単一のキャンペーンを送る場合は**Campaign**、複数を比較する場合は**A/B Test**を選択します — [A/Bテスト](mail-ab-testing)を参照してください。 - **Campaign**:送信するキャンペーンを選択します。 4. **Save**をクリックします。 行はすぐに有効になります。トリガーが発火してセグメントに一致したユーザーは、その時点からキャンペーンを受け取り始めます。 ## 行を並び替える \{#reorder-rows\} 行の左側にあるハンドルをドラッグして優先順位を変更します。Adapty Mailは保存された順序に基づいて`priority: 1, 2, 3…`を自動的に割り当てます。 **All Users**の行は必ず最後のスロットに置く必要があります — 別の行の上にドラッグしようとすると、保存時にブロックされます。 ## 行を編集する \{#edit-a-row\} 行の**Change content**をクリックすると、現在の値が入力済みの状態でダイアログが再度開きます。セグメント、コンテンツタイプ、キャンペーンを変更し、**Save**をクリックして適用します。 A/Bテストを使用している行は、テストが**draft**状態の間のみ編集できます。テストが開始されると、終了するまでコンテンツはロックされます。 ## 行を削除する \{#delete-a-row\} 行のアクションメニューを開いて**Delete**をクリックします。確認ダイアログは表示されず、行はすぐに削除されます。 - **キャンペーンの行**:いつでも削除できます。 - **ライブ中のA/Bテストがある行**:削除できません。先に**Finish A/B test**でテストを終了してから、行を削除してください。 :::note 行を削除すると、新しいユーザーがシーケンスに入れなくなります。すでにシーケンスの途中にいるユーザーは、スケジュールされたメールを引き続き受信する場合があります — 自動的なキャンセルは行われません。 ::: --- # File: mail-segments --- --- title: "Adapty Mail のセグメント" description: "プロファイルと購入データに基づいて再利用可能なオーディエンスのスライスを作成し、フローや A/B テストのターゲティングに活用できます。" --- **セグメント**は再利用可能なオーディエンスのスライスです。**Segments** で一度定義すれば、フローや A/B テストから参照できます。セグメントはスナップショットではなくフィルター定義です。フロートリガーが発火したタイミングで都度評価されるため、メンバーシップは常に最新のプロファイルデータを反映します。 ## セグメントを作成する \{#create-a-segment\} 1. Adapty Mail で **Segments** に移動し、**+ Create** をクリックします。作成ページが開き、タイトルに **New Segment** と表示されます。 2. セグメントの **Name**(必須)と任意の **Description** を入力します。 3. **Filters** の下にある **Add filter** をクリックして、追加したい[ルール](#available-filter-fields)をそれぞれ設定します。各フィルターは **Filter 1**、**Filter 2** のように折りたたみ可能なカードとして表示されます。 4. 各フィルターにフィールド、演算子、比較値を設定します。 5. セグメントを保存します。 :::important フィルターは **AND** で組み合わされます。ユーザーがセグメントに含まれるには、すべてのフィルター条件を満たす必要があります。OR ロジックやネストされたグループはサポートされていません。各フィールドはセグメントごとに1回のみ使用できます。同じフィールドを複数の値で比較したい場合は、ロジックを別々のセグメントに分けてください。 ::: ## Adapty からセグメントをインポートする \{#import-a-segment-from-adapty\} フィルターを使ってセグメントを作成する代わりに、Adapty ダッシュボードから既存のオーディエンスセグメントをインポートすることもできます。 1. **Segments** ページで **Import** をクリックします。 2. 一覧を確認します。**インポート可能なセグメント**はチェックボックスとフィルター条件が表示されます。**インポートできないセグメント**は、サポートされていないフィールド(例:Apple Ads のアトリビューションデータ)、サポートされていない演算子、Adapty Mail に対応する設定がないサブスクリプション状態といった具体的な理由とともにグレーアウト表示されます。 3. インポートしたいセグメントにチェックを入れ、**Import** をクリックします。 :::important インポートは、インポート時点でのセグメントのフィルター条件の独立したコピーを作成します。元の Adapty セグメントとは同期されず、Adapty Mail は重複を検出しないため、同じセグメントを再度インポートすると別のコピーが作成されます。 ::: インポートされたセグメントは、手動で作成したセグメントと同様に **Draft** 状態で開始されるため、すぐにフィルターを編集できます。 ## 利用可能なフィルターフィールド \{#available-filter-fields\} | グループ | フィールド | タイプ | | -------------- | ------------------------- | ------- | | プロファイル | メール | String | | プロファイル | 年齢 | Integer | | プロファイル | 国 | String | | プロファイル | 外部プロファイル ID | String | | プロファイル | 作成日時 | Date | | 購入状態 | 総収益(USD) | Decimal | | 購入状態 | サブスクリプション状態 | Enum | | 購入状態 | サブスクリプション購入日時 | Date | | 購入状態 | サブスクリプション有効期限 | Date | | 購入状態 | 買い切り購入状態 | Enum | | 購入状態 | 買い切り購入日時 | Date | **サブスクリプション状態の値**: Never purchased、Subscribed、Auto-renew off、Billing issue、Grace period、Expired、Refunded。 **買い切り購入の状態の値**: Never purchased、Purchased、Refunded。 フィールドの種類ごとに使用できる演算子: - **String(文字列)**: equals、not equals、is set、is not set。 - **Number(数値)**: equals、not equals、less than、greater than、less than or equal、greater than or equal、between、is set、is not set。 - **Date(日付)**: equals、not equals、before、after、on or before、on or after、between、is set、is not set。 ## All Usersシステムセグメント \{#the-all-users-system-segment\} Adapty Mailには、フィルターのないビルトインの**All Users**セグメントが用意されています。プロジェクト内のすべてのユーザーが対象となります。このセグメントは編集・削除できません。フローで使用する場合は、最下位の受け皿として機能します(優先順位のルールについては[フロー](mail-flows)を参照してください)。 ## ライフサイクル \{#lifecycle\} セグメントの状態は、その使われ方によって決まります。 - **Draft**:作成済みだが、フローやA/B テストにはまだ紐付けられていない。 - **Live**:アクティブなフローまたはA/B テストに紐付けられている。 - **Inactive**:以前は紐付けられていたが、A/B テストが終了したかフローの行が削除された。 - **Archived**:ソフト削除され、メインリストから非表示になっている。 セグメントページのツールバーには状態フィルターがあり、これらの状態で絞り込むことができます。 ## セグメントの編集と削除 \{#edit-and-delete-a-segment\} - **名前と説明**: 常に編集可能です。 - **下書きセグメントのフィルター**: 完全に編集可能です。 - **ライブセグメントのフィルター**: ロックされています。セグメントがアクティブなフロー行またはA/B テストで参照されると、フィルターは読み取り専用になります。名前の変更や説明の更新のみ可能です。ターゲティングを変更するには、新しいセグメントを作成してフロー行を入れ替えてください。 - **削除**: セグメントを論理削除します。ライブセグメントは削除できません。先にフローから削除する(またはA/B テストを終了する)必要があります。 ## 制限事項 \{#limitations\} - **OR ロジックとネストは不可**: フィルターは AND のみで組み合わせられます。 - **セグメントごとに1つのフィールド**: 同じフィールドに対して2つのフィルターを設定することはできません(例:2つの国チェック)。 - **サイズプレビューなし**: エディターでは、現在フィルターに一致するユーザー数は表示されません。 - **公開後はフィルターをロック**: アクティブなセグメントは、名前と説明を除いて読み取り専用になります。 --- # File: mail-profiles --- --- title: "Adapty Mailのプロファイル" description: "プロジェクト内のすべての顧客を確認できます。属性、購入状態、メールエンゲージメント、アクティビティの全履歴が表示されます。" --- **プロファイル**とは、プロジェクト内の1人の顧客を表します。**Profiles**ページには、Adapty Mailが把握しているすべての顧客が一覧表示され、各ユーザーの購入状況、メールエンゲージメント、アクティビティの全履歴を確認できます。プロファイルは自動的に追加されます。Adapty SDKが収集したメールアドレスから、またはAdapty Mail APIを通じて送信したデータから生成されます。 :::tip フローやA/B テスト向けに再利用可能なオーディエンスへプロファイルをグループ化するには、[セグメント](mail-segments)を参照してください。 ::: ## プロファイルが Adapty Mail に登録される仕組み \{#how-profiles-get-into-adapty-mail\} Adapty Mail は、2 つのソースから自動的にプロファイルを作成します。 - **Adapty SDK**: SDK がアプリからメールアドレスと購入情報を収集します。詳しくは[ユーザーメールの収集](mail-collect-emails)をご覧ください。 - **Adapty Mail API**: バックエンドからサーバー間でプロファイルとトランザクションを送信します。詳しくは[API 経由でデータを送信する](mail-send-data-via-api)をご覧ください。 Adapty Mail は、すべてのメール・クリック・購入を、安定した `external_profile_id` によってプロファイルに紐付けます。プロファイルページは読み取り専用です。プロファイルの閲覧や購読解除はできますが、作成・編集・削除はできません。データの所有権は、連携元アプリまたは API にあります。 ## プロファイルリスト \{#the-profiles-list\} リストにはプロファイルが1件1行で新しい順に表示されます。検索ボックスを使って、メールアドレス、プロファイルID、または外部プロファイルIDでプロファイルを検索できます。 | カラム | 表示内容 | | --- | --- | | Profile | 顧客のメールアドレスと、最もメールを送信したキャンペーン。 | | Status | プロファイルの購入状態。[プロファイルのステータス](#profile-status)を参照。 | | Country | 顧客の国。 | | Open rate | 全メールの送信数に対する開封数の割合。メールがまだ送信されていない場合はダッシュが表示されます。 | | LTV | ライフタイムバリュー(LTV)— すべてのソースにわたるこのプロファイルの総収益。 | | Joined | プロファイルが Adapty Mail に初めて登録された日時。 | | Last activity | メールの送信・開封・クリックなど、最後にメールに対してアクションを行った日時。 | :::important **Joined** は、プロファイルが初めて Adapty Mail に登録された日付であり、「顧客開始日」として使用されます。これはデータ取り込み時刻であり、アプリの元のサインアップ日付ではありません。 ::: ### プロファイルのステータス \{#profile-status\} **Status** 列には、プロファイルの購入状態(サブスクリプションや買い切り購入の状況)が表示されます。 | ステータス | 意味 | | --- | --- | | Never purchased | プロファイルは何も購入していません。 | | Purchased | プロファイルが買い切り購入を行いました。 | | Active subscriber | プロファイルは有効なサブスクリプションを持っています。 | | Cancelling | 自動更新がオフになっており、現在の期間が終了するまでアクセスが継続されます。 | | Billing issue | 更新の支払いが失敗しました。 | | Grace period | 支払いは失敗しましたが、ストアのグレース期間中はアクセスが継続されます。 | | Churned | サブスクリプションの有効期限が切れ、アクセスが終了しました。 | | Refunded | 購入が返金されました。 | :::note 購入ステータスはメールの購読状況とは別に管理されます。プロファイルは**アクティブなサブスクライバー**でありながらメールは**未登録**の場合もあれば、**解約済み**でもメールは**登録済み**の場合もあります。メールステータスはプロファイルページに表示され、Adapty Mail がそのプロファイルにメールを送信できるかどうかを制御します。 ::: ## プロファイルの詳細 \{#profile-details\} プロファイルをクリックすると、詳細ページが開きます。ヘッダーにはメールアドレス、国、プラットフォーム、「顧客登録日」が表示されます。また、購入ステータス、開封率、**Subscribed** または **Unsubscribed** の3つのステータスバッジも表示されます。 ページ上部には5つのエンゲージメント指標が並んでいます: - **Sent**:プロファイルに送信されたメール数。 - **Delivered**:メールボックスプロバイダーが受信を承認したメール数。 - **Opened**:プロファイルが開封したメール数。 - **Clicked**:プロファイルがリンクをクリックしたメール数。 - **Revenue**:2つの数値 — アトリビューション収益と生涯価値。 :::note **帰属収益**とは、メールによって生まれた収益です。つまり、キャンペーンに接触した後にそのプロファイルが行った購入です。**顧客生涯価値(LTV)**は、メールが関与したかどうかに関わらず、すべてのソースを合計したプロファイルの総収益です。ヘッダーには帰属収益が先に表示され、次にLTVが表示されます。 ::: **Profile** カードには、顧客の属性が一覧表示されます。 - **Platform**: 顧客のデバイスプラットフォーム(iOS または Android など)。 - **Country**: 顧客の国。 - **Store country**: 顧客の App Store または Google Play アカウントの国。 - **Gender**: 顧客の性別(判明している場合)。 - **Age**: 誕生日が提供されている場合の顧客の年齢。 - **Profile ID**: プロファイルに対する Adapty Mail の内部識別子。 - **External ID**: アプリまたはバックエンドからの `external_profile_id`。 - **Custom attributes**: プロファイルと共に送信したキーと値のペア。 ### 購入状態 \{#purchase-state\} **Purchase state** カードには、プロファイルの収益と購入履歴が表示されます。上部にはライフタイムバリューが表示され、その下に最大2つのセクションが続きます。 - **Subscription**: プロファイルのサブスクリプションの価格、ストア、開始日、更新日または有効期限、プロダクト ID。 - **One-time purchase**: 最新の買い切り購入の価格、ストア、購入日、プロダクト ID。 プロファイルがまだ何も購入していない場合、カードには **No purchase yet** と表示されます。 **Segments** カードには、プロファイルが現在一致しているすべてのセグメントが一覧表示されます。一致するものがない場合は **Not in any segment** と表示されます。メンバーシップはリアルタイムで評価されるため、常に最新のプロファイルデータが反映されます。セグメントの作成方法については、[セグメント](mail-segments)を参照してください。 ## アクティビティジャーニー \{#the-activity-journey\} **Journey** セクションには、そのプロファイルに関するすべての出来事がタイムライン形式で表示されます。**Profile created** から始まり、2種類のイベントが時系列に並びます。 - **メールイベント**: プロファイルに送信された各メール(配信・開封・クリックのアクティビティを含む)。メールを展開すると、プロファイルがクリックしたリンクや、そのメールが起因となった購入を確認できます。 - **トランザクションイベント**: サブスクリプションや買い切り購入に関する主要な出来事(開始・更新・キャンセル・請求エラー・有効期限切れ・返金など)。 トランザクションイベントは、次のジャーニーラベルに対応しています。 | `event_type` | Journey ラベル | | --- | --- | | `subscription_started` | Subscription started | | `subscription_renewed` | Subscription renewed | | `subscription_renewal_cancelled` | Renewal cancelled | | `subscription_renewal_reactivated` | Renewal resumed | | `billing_issue_detected` | Billing issue | | `entered_grace_period` | Entered grace period | | `subscription_expired` | Subscription expired | | `subscription_refunded` | Subscription refunded | | `non_subscription_purchase` | One-time purchase | | `non_subscription_purchase_refunded` | Purchase refunded | これらのイベントは、Adapty SDK を通じて自動的に Adapty Mail に届くか、API 経由で手動で送信することもできます。イベントリファレンスについては、[トランザクションイベントの送信](mail-send-data-via-api#send-transaction-events)を参照してください。 ## プロファイルのメール配信を停止する \{#unsubscribe-a-profile\} プロファイルへのメール送信を停止するには、プロファイルページを開き、**...** をクリックして **Unsubscribe** を選択します。Adapty Mail はそのプロファイルを配信停止済みとしてマークし、抑制リストに追加します。これにより、キャンペーンやフローでスキップされるようになります。 この操作は冪等です。すでに配信停止済みのプロファイルは、配信停止済みのままになります。抑制の仕組みやプロファイルが自分で配信停止する方法の詳細については、[配信停止と抑制](mail-suppression)を参照してください。 --- # File: mail-ab-testing --- --- title: "Adapty Mail の A/B テスト" description: "フローに A/B テストを追加して、複数のメールキャンペーン全体を比較します。" --- Adapty Mail の A/B テストは、2 つ以上のメールキャンペーン全体を比較します。各バリアントは独立した完全なキャンペーンです。ユーザーが[フロー](mail-flows)内のテストのセグメントに一致すると、Adapty Mail は設定されたウェイトに基づいていずれかのバリアントにルーティングし、バリアントごとの配信数・エンゲージメント・収益を追跡します。 ## バリアントとは \{#what-a-variation-is\} 各バリアントは完全なキャンペーンです。コピー、ヒーロー画像、トーン、シーケンスの長さ、メール間の送信タイミングなど、キャンペーンで変更できるものならすべて異なる設定にできます。A/B テスト自体にこれらの設定項目が直接あるわけではなく、それぞれのキャンペーンを個別に作成してバリアントとして追加します。 ## A/B テストを作成する \{#create-an-ab-test\} 1. まず **Campaigns** でキャンペーンを作成します。各バリアントにそれぞれのキャンペーンが必要です。 2. Adapty Mail で **A/B Tests** に移動し、**Create** をクリックします。 3. 各キャンペーンをバリアントとして追加し、ウェイトを設定します。ウェイトの合計は **100%** になる必要があります。 4. テストを適用するユーザーを制御するためのセグメントを割り当てます。 5. 保存します。 テストは **draft(下書き)** として保存され、この時点ではまだ何も送信されません。公開するにはフローに追加する必要があります。 ## フローから起動する \{#launch-from-a-flow\} A/B テストは A/B Tests ページからは起動できません。起動と終了はどちらもフローの行内で行います。 1. Adapty Mail で **Flows** に移動し、テストを実行したいトリガーを開きます。 2. 新しい行の **Create** をクリックします。ダイアログで **Content type** を **A/B Test** に設定し、保存したテストを選んで **Save** をクリックします。 3. 行上で **Launch A/B test** をクリックします。 テストのステータスが **draft** から **live** に移行し、セグメントに一致する新規ユーザーへのバリアントルーティングが始まります。フローの行について詳しくは[フローを作成する](mail-create-flow)を参照してください。 ## ルーティングの仕組み \{#how-routing-works\} ユーザーがフローのトリガーに到達し、A/B テストのセグメントに一致すると、Adapty Mail は**加重ランダム**選択を使ってバリアントを決定します。各バリアントのウェイトが抽選のシェアを決めます。ルーティングはユーザー単位で決定論的ではありません。 ## 結果を確認する \{#read-results\} A/B Tests ページでは、各バリアントの生の集計数値と導出されたレートが表示されます: - **Delivery**(配信): Sends(送信数)、Deliveries(到達数)、Bounces(バウンス数) - **Engagement**(エンゲージメント): Opens(開封数)、Clicks(クリック数)、Unsubs(配信停止数) - **Revenue**(収益): Purchases(購入数)、Revenue(収益) 各指標の計測方法や収益のアトリビューションについては、[キャンペーン分析](mail-analytics)を参照してください。 ## テストを終了する \{#finish-the-test\} 起動と同様に、終了も A/B Tests ページではなくフローの行から行います。 1. テストが実行中のフローの行を開きます。 2. **Finish A/B test** をクリックします。 3. **Finish A/B test** ダイアログで、**Replace with campaign** ドロップダウンから勝者キャンペーンを選択します。空のままにするとセグメントをフローから完全に削除します。 4. 確認します。 :::note いずれかのバリアント(勝者・敗者問わず)のシーケンス途中にいるユーザーは、引き続きスケジュールされたメールを受け取ります。勝者に切り替わることはありません。 ::: ## ライフサイクル \{#lifecycle\} A/B テストは 4 つのステータスを経由します: - **Draft**(下書き): 作成済み、まだライブのフロー行に追加されていない。 - **Live**(公開中): 追加・起動済みで、入力ユーザーをルーティング中。 - **Finished**(終了): **Finish A/B test** によって停止済み。 - **Archived**(アーカイブ): リストからソフト削除済み。 --- # File: mail-analytics --- --- title: "Adapty Mailのアナリティクス" description: "キャンペーン、セグメント、A/Bバリアント、メッセージ、またはトリガーごとにキャンペーンのパフォーマンスを分析し、配信、エンゲージメント、収益を並べて確認できます。" --- **Analytics** ページでは、キャンペーン・セグメント・A/B バリアント・メッセージ・トリガーの5つの軸でキャンペーンのパフォーマンスを確認できます。配信指標と各メールに紐づく収益を並べて表示するので、バリアントの比較、優秀なセグメントの特定、収益が集中している箇所の把握が簡単に行えます。 ページ上部にチャート、下部にブレークダウンテーブルが表示されます。任意の行をクリックすると、その個別エンティティの詳細に移動します。 ## 期間を選択する \{#pick-a-time-range\} ページ上部のツールバーで、表示期間とバケット単位を設定します。 - **Date range**:プリセット(直近 7 / 14 / 30 / 90 日、今月、先月、直近 12 ヶ月、年初来)または **Custom range** ピッカー。デフォルトは直近 30 日間です。 - **Granularity**:**Daily**(日次)、**Weekly**(週次)、**Monthly**(月次)のバケット。期間が広がると自動的に粗くなります — 92 日を超えると **Daily** が **Weekly** に切り替わり、366 日を超えると両方が **Monthly** に切り替わります。 - **Chart style**:**Line**、**Area**、または **Bar**。 「range too wide」の警告が表示された場合は、期間を短くするか、粒度を粗くするか、フィルターを適用してください。 ## グループ化・ブレークダウン・フィルター \{#group-break-down-filter\} ツールバーの下にある3つのコントロールで、チャートとテーブルの表示内容を調整します。 - **Group by**:データセットを行に分割する軸。**Campaigns**、**Segments**、**A/B variants**、**Triggers** が選択できます。**No grouping** を選択すると、すべてのデータが1つの集計 **All** 行にまとまります。 - **Breakdown**:各行をサブ行に分割するための第2の軸。**Group by** と **Breakdown** を両方設定すると、テーブルの各行を展開してサブグループを確認できます。**Messages** を含む任意の軸を指定できますが、**Group by** に設定済みの軸は選択できません。 - **Add filter**:特定のキャンペーン、セグメント、A/B バリアント、またはトリガーにデータを絞り込みます。フィルターはチャートとテーブルの両方に適用されます。 :::note **Messages** はブレークダウンとして利用できますが、トップレベルの **Group by** やフィルターとしては使用できません。個別のメッセージを分析するには、**Messages** ブレークダウンを設定して **Campaigns** でグループ化し、キャンペーン行を展開するか、ドリルダウンからメッセージを開いてください。 ::: ## チャートを読む \{#read-the-chart\} チャートには、選択した指標が指定期間にわたって描画されます。 - **Metric category**:**Email actions**(Sent、Delivered、Opened、Clicked、Bounced、Unsubscribed、Converted)と **Revenue** を切り替えられます。 - **Metric pills**:プロットする指標を選択します。集計モード(グループ化なし)では、複数の指標を同じチャートに表示できます。グループ化が有効な場合、チャートには1つの指標のみが表示され、グループごとに1本のラインが描かれるため、グループを視覚的に区別しやすくなります。 - **Legend**:グループ化が有効な場合、右側の凡例にすべてのグループが一覧表示され、各系列の表示/非表示を切り替えられます。 指標テーブルの表示チェックボックスでも、チャートに表示される行を制御できます。 ## 指標テーブルを読む \{#read-the-metrics-table\} チャートの下に、グループごとに1行ずつ表示される指標テーブルがあります。テーブル上部のサマリー行には、全行の集計値が表示されます。 - **ソート可能な列**:列ヘッダーをクリックすると、Name、Sent、Delivered、Delivery rate、Opened、Open rate、Clicked、Click rate、Converted、Revenue、Bounced、Unsubscribed でソートできます。 - **表示チェックボックス**:その行をチャートに表示するかどうかを切り替えます。 - **行の展開**:**Breakdown** が設定されている場合、各行の左側にあるシェブロンをクリックするとサブグループが表示されます。 - **ドリルダウンを開く**:行の名前をクリックすると、そのエンティティの詳細ビューが開きます。 ドリルダウンには以下が表示されます。 - メインページと同じチャートおよび指標セレクター(1つのエンティティに絞り込まれた状態)。 - 下部に8つのサマリーカード:**Sent**、**Delivered**(配信率付き)、**Opened**(開封率付き)、**Clicked**(クリック率付き)、**Bounced**、**Unsubscribed**、**Converted**、**Revenue**。 期間と粒度はメインページの設定が引き継がれます。パンくずリストの **Back** をクリックして戻ることができます。 ## 計測対象 \{#whats-tracked\} :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: Analytics ページ、ドリルダウン、および以下で説明するインラインビューのいずれにおいても、各行には同じ生データのカウントが表示されます: - **Sent**:SES に送信されたメール数。 - **Delivered**:SES で確認されたインボックスへの配信数。 - **Bounced**:SES が報告したバウンス数。ハードバウンスとソフトバウンスは区別されず、どちらも 1 件の **Bounced** としてカウントされます。 - **Opened**:ピクセルの読み込み数。Apple Mail プライバシー保護は iOS 15 以降で画像をプリフェッチするため、この数値が水増しされます — 強いシグナルとしてはクリックや収益を参照してください。 - **Clicked**:メール本文内のリンクのクリック数。 - **Unsubscribed**:フッターリンクまたは `List-Unsubscribe` ヘッダーからの購読解除数。 - **Converted**:指定期間内に帰属購入があったグループ内のユニークプロファイル数。コンバージョンは購入日でバケット化されます — 3月のクリックに続く4月の購入は4月にカウントされます。1つのプロファイルが複数回購入しても1回としてカウントされます。 - **Revenue**:サブスクリプション開始、更新、買い切り購入に帰属する収益の合計(USD)。 ## 派生レート \{#derived-rates\} 各レートは上記の生カウントから算出されます。 | レート | 計算式 | | ------------- | -------------------- | | Delivery rate | Delivered / Sent | | Open rate | Opened / Delivered | | Click rate | Clicked / Delivered | ドリルダウンでも、サマリーカードの横に同じ3つのレートが表示されます。 ## 収益アトリビューション \{#revenue-attribution\} 収益は追跡リンクの**ラストクリック**で帰属付けされます。 1. 受信者がメール内のリンクをクリックすると、Adapty Mail は短期ストアにそのプロファイルに対する `scheduled_email_id` を保存します。 2. その後、既存のアトリビューションがない購入イベントが到着した場合、Adapty Mail はトランザクションに保存済みの `scheduled_email_id` をバックフィルします — ただし購入タイムスタンプがクリック後であることが条件です。 3. 追跡クリックが先行しない購入はアトリビューションなしのままになります。 追跡されるパラメーターは `scheduled_email_id` です。チェックアウト URL には `{email}` および `{external_profile_id}` プレースホルダーを介して受信者の識別情報も含まれており、ウェブペイウォールでフローをパーソナライズできます — これはアトリビューションとは別の仕組みです。詳しくは[チェックアウトの設定](mail-checkout)を参照してください。 ## フローと A/B テストのインラインアナリティクス \{#inline-analytics-in-flows-and-ab-tests\} 同じ指標がインラインでも表示されます。 - **Flows ページ**:トリガービューの各セグメント行に、配信・エンゲージメント・収益のカウントが表示されます。 - **A/B Tests ページ**:バリエーションが同じ指標セットで並んで表示されるため、バリアントの直接比較に便利です。 キャンペーン間の比較や特定エンティティへのドリルダウンには Analytics ページを使用し、特定のフロー行や A/B テストで作業している場合はインラインビューを使用してください。上記の指標の定義、派生レート、アトリビューションルールは3つのビューすべてで同じように適用されます。 ## 制限事項 \{#limitations\} - **ソフトバウンスとハードバウンスの区別なし**:一時的か恒久的かに関わらず、すべてのバウンスが1つの **Bounced** カウントに集約されます。 - **リアルタイムではなく結果整合性**:カウントはイベントテーブルから集計されます。最新のイベントは通常数分以内に反映されますが、ストリーミングの保証はありません。 - **期間サイズの上限あり**:非常に広い期間と細かい粒度を組み合わせると、チャートのセル上限を超える場合があります。ページに「range too wide」の警告が表示されたら、期間を短くするか、粒度を粗くするか、フィルターを適用してください。 --- # File: configuration --- --- title: "サードパーティ連携の設定" description: "Adaptyの設定を最適化してサブスクリプション管理を改善する方法を学びましょう。" --- Adaptyの連携機能を使えば、サブスクリプションイベントや購入データをお好みのプラットフォームやワークフローにスムーズに送信できます。ユーザー行動の分析、カスタマーエンゲージメント戦略の構築、マーケティングチーム向けのプロダクトアナリティクスの強化など、Adaptyはアプリ内課金イベントを選択した連携先に簡単に転送します。 Adaptyはトライアル、コンバージョン、更新、解約といったアプリ内課金およびサブスクリプションの[イベント](events)を自動的に追跡し、設定した連携先に送信します。これにより、ユーザーの現在のステージに応じたアプローチや、アプリ内の収益関連アクティビティの分析が可能になります。 ## 連携の設定 \{#integration-settings\} <img src="/assets/shared/img/20bf659-CleanShot_2023-08-22_at_13.26.562x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 連携には、この連携を通じて送信されるすべてのイベントに影響する以下の設定オプションがあります: | 設定 | 説明 | |:--------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Reporting Proceeds** | 収益値の表示方法を選択します。App StoreおよびPlay Storeの手数料を差し引いた後の金額、または差し引く前の金額(グロス)を選択できます。「Send sales as proceeds」チェックボックスをオンにすると、App Store / Play Storeの手数料を差し引いた後のプロシーズとして売上が表示されます。 | | **Send Trial Price** | チェックすると、Trial Startedイベントのサブスクリプション価格をAdaptyが送信します。 | | **Exclude Historical Events** | ユーザーがAdapty SDKを含むアプリをインストールする前に発生したイベントを除外するオプションです。イベントの重複を防ぎ、正確なレポートを確保します。たとえば、ユーザーが1月10日に月額サブスクリプションを開始し、3月6日にAdapty SDKを含むアプリに更新した場合、Adaptyは3月6日より前のイベントを省略し、それ以降のイベントのみを保持します。 | | **Report User's Currency** | 売上をユーザーの通貨で報告するか、米ドルで報告するかを選択します。 | | **Send User Attributes** | 言語設定などのユーザー固有の属性を送信したい場合で、かつOneSignalプランが10タグ以上をサポートしている場合に選択します。このオプションを有効にすると、デフォルトの10タグを超える追加情報を含めることができます。タグの上限を超えるとエラーが発生する場合があります。 | | **Send Attributions** | アトリビューション情報(例:AppsFlyerのアトリビューション)を送信して関連する詳細を受け取るには、このオプションを有効にします。 | | **Send Play Store purchase token** | 必要に応じて購入を再検証するためのPlay Storeトークンを受け取るには、このオプションを有効にします。イベントに`play_store_purchase_token`パラメータが追加されます。 | | **Delay events with future datetime** | **AppsFlyerおよびカスタムWebhookのみ**: 有効にすると、更新イベントとトライアルコンバージョンイベントが実際に発生した日付に送信されます。無効(デフォルト)の場合、これらのイベントは検出された時点で即座に送信されます(日付が未来であっても同様です)。 | | **Data residency** | **MixpanelおよびAmplitudeのみ**: イベントが処理・保存される場所を決定するデータレジデンシーを選択します。 | ## イベントの設定 \{#configure-the-events\} 認証情報の下に、Adaptyから選択した連携プラットフォームに送信できる3つのグループのイベントがあります。必要なものをオンにしてください。 イベント名のカスタマイズは一部の連携で利用可能ですが、他の連携ではイベント名が固定されており変更できません。また、[Airbridge](airbridge#configure-events-and-tags)などの一部の連携では、1つのAdaptyイベントに複数のイベント名を関連付けることもできます。Adaptyが提供するイベントの全リストは[こちら](events)でご確認いただけます。 <img src="/assets/shared/img/c79f5cd-screencapture-app-adapty-io-integrations-pushwoosh-2023-08-22-13_31_07.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyのデフォルトのイベント名を使用することをお勧めしますが、特定の要件に合わせてイベント名を自由にカスタマイズすることも可能です。 --- # File: events --- --- title: "サードパーティ連携に送信するイベント" description: "Adaptyのアナリティクスツールを使って、主要なサブスクリプションイベントを追跡しましょう。" --- Apple と Google は、[App Store Server Notifications](enable-app-store-server-notifications) と [Real-time Developer Notifications (RTDN)](enable-real-time-developer-notifications-rtdn) を通じてサブスクリプションイベントをサーバーに直接送信します。そのため、モバイルアプリがリアルタイムにアナリティクスシステムへイベントを送信することは難しい場合があります。たとえば、ユーザーがサブスクリプションを開始してもアプリを再度開かなかった場合、サーバーがなければ開発者はサブスクリプションのステータス更新を受け取れません。 Adapty はこのギャップを埋めるため、サブスクリプションデータを収集して人間が読みやすいイベントに変換します。これらの連携イベントは JSON 形式で送信されます。すべてのイベントは同じ構造を持ちますが、イベントの種類・ストア・設定内容によってフィールドが異なります。各イベントに含まれる正確なフィールドは、それぞれの連携ページで確認できます。 イベントが正常に処理されたかどうか、あるいは問題が発生したかどうかを判断する方法については、[イベントステータス](event-statuses)ページをご覧ください。 ## イベントの種類 \{#event-types\} ほとんどのイベントは、有効化されているすべての連携に作成・送信されます。ただし、**Access level updated** イベントは、[webhook 連携](webhook)が設定されていてこのイベントが有効になっている場合にのみ発火します。このイベントは [Event Feed](https://app.adapty.io/event-feed) に表示され、webhook にも送信されますが、他の連携には共有されません。 webhook 連携が設定されていない場合、またはこのイベントタイプが有効になっていない場合、**Access level updated** イベントは作成されず、[Event Feed](https://app.adapty.io/event-feed) にも表示されません。 | イベント名 | 説明 | |:-----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | subscription_started | トライアル期間なしで有料サブスクリプションを開始したとき(つまり即座に課金されたとき)にトリガーされます。 | | subscription_renewed | サブスクリプションが更新され、ユーザーに課金されたときに発生します。このイベントはトライアルあり・なしを問わず、2回目以降の請求から記録されます。 | | subscription_renewal_cancelled | ユーザーがサブスクリプションの自動更新をオフにしました。有料サブスクリプション期間が終了するまでプレミアム機能へのアクセスは継続されます。 | | subscription_renewal_reactivated | ユーザーがサブスクリプションの自動更新を再度有効にしたときにトリガーされます。 | | subscription_expired | キャンセルされたサブスクリプションが完全に終了したときにトリガーされます。たとえば、12月12日にサブスクリプションをキャンセルしても12月31日まで有効な場合、イベントは12月31日に記録されます。 | | subscription_paused | ユーザーが[サブスクリプションの一時停止](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause)を有効にしたときに発生します(Android のみ)。 | | subscription_deferred | サブスクリプションの購入が[延期](https://adapty.io/glossary/subscription-purchase-deferral/)され、ユーザーが支払いを先送りしながらプレミアム機能へのアクセスを維持できる場合にトリガーされます。この機能は Google Play Developer API を通じて利用可能で、無料トライアルや支払いが困難なユーザーへの対応に活用できます。 | | non_subscription_purchase | 永続アクセスやゲーム内コインなどの消耗型アイテムといった、サブスクリプション以外のすべての購入。 | | trial_started | ユーザーがトライアルサブスクリプションを開始したときにトリガーされます。 | | trial_converted | トライアルが終了してユーザーに課金されたとき(初回購入)に発生します。たとえば、1月14日までトライアル期間があるにもかかわらず1月7日に課金された場合、イベントは1月7日に記録されます。 | | trial_renewal_cancelled | トライアル期間中にユーザーがサブスクリプションの自動更新をオフにしました。トライアルが終了するまでプレミアム機能へのアクセスは継続されますが、課金やサブスクリプションの開始は行われません。 | | trial_renewal_reactivated | トライアル期間中にユーザーがサブスクリプションの自動更新を再度有効にしたときに発生します。 | | trial_expired | サブスクリプションに転換されずにトライアルが終了したときにトリガーされます。 | | entered_grace_period | 支払い試行が失敗し、ユーザーがグレース期間(有効な場合)に入ったときに発生します。この期間中もユーザーはプレミアム機能にアクセスできます。 | | billing_issue_detected | 課金試行中に請求エラーが発生したとき(例:カード残高不足)にトリガーされます。 | | subscription_refunded | サブスクリプションが返金されたとき(例:Apple サポートによる返金)にトリガーされます。 | | non_subscription_purchase_refunded | サブスクリプション以外の購入が返金されたときにトリガーされます。 | | access_level_updated | ユーザーのアクセスレベルが更新されたときに発生します。 | 上記のイベントは、購入に関するユーザーの状態を完全にカバーしています。いくつかの例を見てみましょう。 ### 例 1 \{#example-1\} _ユーザーが4月1日に7日間のトライアル付き月次サブスクリプションを開始し、4日目に解約した。_ この場合、以下のイベントが送信されます: 1. `trial_started`:4月1日 2. `trial_renewal_cancelled`:4月4日 3. `trial_expired`:4月7日 ### 例 2 \{#example-2\} _ユーザーが4月1日に7日間のトライアル付き月次サブスクリプションを開始し、10日目に解約した。_ この場合、以下のイベントが送信されます: 1. `trial_started`:4月1日 2. `trial_converted`:4月7日 3. `subscription_renewal_cancelled`:4月10日 4. `subscription_expired`:5月1日 各シナリオでどのイベントが発火するかの詳細については、[イベントフロー](event-flows)をご確認ください。 --- # File: event-flows --- --- title: "イベントフロー" description: "Adaptyのサブスクリプションイベントフローの詳細スキームを確認しましょう。サブスクリプションイベントの生成方法やインテグレーションへの送信方法を学び、顧客ジャーニーの重要な瞬間を追跡するのに役立てましょう。" --- Adaptyでは、アプリ内での顧客のジャーニーを通じてさまざまなサブスクリプションイベントを受け取ります。これらのサブスクリプションフローは、ユーザーがサブスクリプションを開始・キャンセル・再有効化する際にAdaptyが生成するイベントを理解するための一般的なシナリオを示しています。 Appleはサブスクリプションの実際の開始・更新時間より数時間前に支払い処理を行います。以下のフローでは、図をわかりやすくするために、サブスクリプションの開始・更新と課金が同時に発生するように示しています。 また、同じアクションに関連するイベントは同時に発生するため、図に示した順序とは異なる順序で **Event Feed** に表示される場合があります。 ## サブスクリプションのライフサイクル \{#subscription-lifecycle\} ### 初回購入フロー \{#initial-purchase-flow\} このフローは、顧客がトライアルなしで初めてサブスクリプションを購入したときに発生します。この場合、以下のイベントが生成されます: - **Subscription started** - **Access level updated**:ユーザーへのアクセス付与 サブスクリプションの更新日が来ると、サブスクリプションが更新されます。この場合、以下のイベントが生成されます: - **Subscription renewal**:サブスクリプションの新しい期間の開始 - **Access level updated**:サブスクリプションの有効期限を更新し、さらに1期間のアクセスを延長 支払いが成功しない場合やユーザーが更新をキャンセルした場合については、それぞれ [請求問題の結果フロー](event-flows#billing-issue-outcome-flow) と [サブスクリプションキャンセルフロー](event-flows#subscription-cancellation-flow) をご参照ください。 <img src="/assets/shared/img_webhook_flows/Initial_Purchase_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### サブスクリプションキャンセルフロー \{#subscription-cancellation-flow\} ユーザーがサブスクリプションをキャンセルすると、以下のイベントが生成されます: - **Subscription renewal canceled**:現在の期間が終了するまでサブスクリプションが有効であり、その後ユーザーはアクセスを失うことを示す - **Access level updated**:アクセスの自動更新を無効化 サブスクリプションが終了すると、**Subscription expired (churned)** イベントがトリガーされ、サブスクリプションの終了を示します。 <img src="/assets/shared/img_webhook_flows/Subscription_Cancellation_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 返金が承認された場合、**Subscription expired (churned)** の代わりに以下のイベントが生成されます: - **Subscription refunded**:サブスクリプションを終了し、返金の詳細を提供 <img src="/assets/shared/img_webhook_flows/Subscription_Cancellation_Flow_with_a_Refund.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Stripeでは、残りの期間をスキップしてサブスクリプションを即時キャンセルすることができます。この場合、すべてのイベントが同時に生成されます: - **Subscription renewal cancelled** - **Subscription expired (churned)** - **Access Level updated**:ユーザーのアクセスを削除 返金が承認された場合、承認時に **Subscription refunded** イベントも発生します。 <img src="/assets/shared/img_webhook_flows/Subscription_Immediate_Cancellation_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### サブスクリプション再有効化フロー \{#subscription-reactivation-flow\} ユーザーがサブスクリプションをキャンセルして期限切れになり、その後同じサブスクリプションを再購入した場合、**Subscription renewed** イベントが生成されます。アクセスが途切れた場合でも、Adaptyは `vendor_original_transaction_id` によってリンクされた単一のトランザクションチェーンとして扱います。そのため、再購入は更新とみなされます。 **Access level updated** イベントは2回生成されます: - サブスクリプション終了時にユーザーのアクセスを取り消すとき - サブスクリプション再購入時にアクセスを付与するとき <img src="/assets/shared/img_webhook_flows/Subscription_Rejoin_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### サブスクリプション一時停止フロー(Androidのみ) \{#subscription-pause-flow-android-only\} このフローは、ユーザーがAndroidでサブスクリプションを一時停止し、後で再開する場合に適用されます。 サブスクリプションの一時停止には遅延効果があります。ユーザーが更新前にサブスクリプションを一時停止した場合、サブスクリプションは有効なままで、ユーザーは請求期間の残り期間中、有料アクセスを維持します。 1. ユーザーがサブスクリプションを一時停止すると、**Subscription paused (Android only)** イベントがトリガーされます。 2. サブスクリプション期間終了時に、Adaptyは **Access level updated** イベントをトリガーしてユーザーのアクセスを取り消します。 3. ユーザーがサブスクリプションを再開すると、以下のイベントがトリガーされます: - **Subscription renewed** - **Access level updated**:ユーザーのアクセスを復元 これらのサブスクリプションは、同じ **vendor_original_transaction_id** でリンクされた同一のトランザクションチェーンに属します。 <img src="/assets/shared/img_webhook_flows/Subscription_Paused_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## トライアルフロー \{#trial-flows\} アプリでトライアルを使用している場合、トライアル関連の追加イベントが発生します。 ### 変換成功のトライアルフロー \{#trial-with-successful-conversion-flow\} 最も一般的なフローは、ユーザーがトライアルを開始し、クレジットカードを登録して、トライアル期間終了時に通常のサブスクリプションへ正常に変換される場合です。この場合、トライアル開始時に以下のイベントが生成されます: - **Trial started**:トライアル開始を示す - **Access level updated**:アクセスを付与 通常のサブスクリプションが開始されると **Trial converted** イベントが生成されます。 <img src="/assets/shared/img_webhook_flows/Trial_Flow_with_Successful_Conversion.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 変換失敗のトライアルフロー \{#trial-without-successful-conversion-flow\} ユーザーがトライアルをサブスクリプションに変換する前にキャンセルした場合、キャンセル時に以下のイベントが生成されます: - **Trial renewal cancelled**:トライアルからサブスクリプションへの自動変換を無効化 - **Access level updated**:アクセス更新を無効化 ユーザーはトライアル終了まで引き続きアクセスでき、トライアルの終了を示す **Trial expired** イベントが生成されます。 <img src="/assets/shared/img_webhook_flows/Trial_Flow_without_Successful_Conversion.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 期限切れトライアル後のサブスクリプション再有効化フロー \{#subscription-reactivation-after-expired-trial-flow\} トライアルが(請求の問題またはキャンセルにより)期限切れになり、ユーザーが後でサブスクリプションを購入した場合、以下のイベントが生成されます: - **Access level updated**:ユーザーへのアクセス付与 - **Trial converted** トライアルとサブスクリプションの間に空白期間があっても、Adaptyは `vendor_original_transaction_id` を使って両者をリンクします。この変換は、ゼロ価格のトライアルから始まる継続的なトランザクションチェーンの一部として扱われます。そのため、**Subscription started** ではなく **Trial converted** イベントが生成されます。 <img src="/assets/shared/img_webhook_flows/Subscription_Reactivation_Flow_after_Expired_Trial.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## プロダクトの変更 \{#product-changes\} このセクションでは、アップグレード、ダウングレード、別グループのプロダクトの購入など、アクティブなサブスクリプションに加えられた変更について説明します。 ### 即時プロダクト変更フロー \{#immediate-product-change-flow\} ユーザーがプロダクトを変更した後、サブスクリプション終了前にシステムで即時変更が適用される場合があります(主にアップグレードまたはプロダクトの置き換えの場合)。この場合、プロダクト変更時に以下のイベントが生成されます: - アクセスレベルが変更され、2つの **Access level updated** イベントが生成されます: 1. 最初のプロダクトへのアクセスを削除 2. 2番目のプロダクトへのアクセスを付与 - 古いサブスクリプションが終了し、返金が行われます(**Subscription refunded** イベントが `cancellation_reason` = `upgraded` で生成されます)。**Subscription expired (churned)** イベントは生成されず、**Subscription refunded** イベントに置き換えられます。 - 新しいサブスクリプションが開始されます(新しいプロダクトの **Subscription started** イベントが生成されます)。 <img src="/assets/shared/img_webhook_flows/Immediate_Product_Change_Flow_Upgrade.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ユーザーがサブスクリプションをダウングレードした場合、最初のサブスクリプションは有料期間の終了まで継続し、終了時に新しい下位プランのサブスクリプションに置き換えられます。この場合、アクセスの自動更新を無効化する **Access level updated** イベントのみが即時に生成されます。その他のイベントはサブスクリプションが実際に置き換えられる時点で生成されます: - 別の **Access level updated** イベントが生成され、2番目のプロダクトへのアクセスを付与 - **Subscription expired (churned)** イベントが生成され、最初のプロダクトのサブスクリプションを終了 - **Subscription started** イベントが生成され、新しいプロダクトの新しいサブスクリプションを開始 <img src="/assets/shared/img_webhook_flows/Delayed_Product_Change_Downgrade.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 遅延プロダクト変更フロー \{#delayed-product-change-flow\} サブスクリプション更新時にプロダクトを変更するバリアントもあります。このバリアントは前のケースと非常に似ており、古いプロダクトのアクセス自動更新を無効化する **Access level updated** イベントが1つ即時に生成されます。その他のイベントはユーザーがサブスクリプションを変更してシステムで反映される時点で生成されます: - 別の **Access level updated** イベントが生成され、2番目のプロダクトへのアクセスを付与 - **Subscription expired (churned)** イベントが生成され、最初のプロダクトのサブスクリプションを終了 - **Subscription started** イベントが生成され、新しいプロダクトの新しいサブスクリプションを開始 <img src="/assets/shared/img_webhook_flows/Product_Change_on_Renewal_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 請求問題の結果フロー \{#billing-issue-outcome-flow\} トライアルの変換またはサブスクリプションの更新が請求問題により失敗した場合、次の動作はグレース期間が有効かどうかによって異なります。 グレース期間が設定されている場合、支払いが成功すればトライアルが変換されるかサブスクリプションが更新されます。失敗した場合、アプリストアはユーザーへの課金を繰り返し試み、それでも失敗するとアプリストアがトライアルまたはサブスクリプションを終了します。 したがって、請求問題が発生した時点でAdaptyに以下のイベントが生成されます: - **Billing issue detected** - **Entered grace period**(グレース期間が有効な場合) - **Access level updated**:グレース期間終了までのアクセスを提供 後で支払いが成功した場合、Adaptyは **Trial converted** または **Subscription renewed** イベントを記録し、ユーザーはアクセスを失いません。 最終的に支払いが失敗してアプリストアがサブスクリプションをキャンセルした場合、Adaptyは以下のイベントを生成します: - **Trial expired** または **Subscription expired (churned)**(`cancellation_reason: billing_error` 付き) - **Access level updated**:ユーザーのアクセスを取り消す <img src="/assets/shared/img_webhook_flows/Billing_Issue_Outcome_Flow_with_Grace_Period.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> グレース期間なしの場合、請求再試行期間(アプリストアがユーザーへの課金を繰り返し試みる期間)が即時に開始されます。 グレース期間終了まで支払いが成功しない場合のフローは同じで、アプリストアがサブスクリプションを自動終了したときに同じイベントが生成されます: - **Trial expired** または **Subscription expired (churned)**(`cancellation_reason` が `billing_error` のもの) - **Access level updated**:ユーザーのアクセスを取り消す <img src="/assets/shared/img_webhook_flows/Billing_Issue_Outcome_Flow_without_Grace_Period.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ユーザーアカウント間での購入共有フロー \{#sharing-purchases-across-user-accounts-flows\} <InlineTooltip tooltip="カスタマーユーザーID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration)、[Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> が、別の <InlineTooltip tooltip="カスタマーユーザーID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration)、[Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> にすでに紐付いているサブスクリプションを復元または延長しようとした場合、Adaptyの **Sharing paid access between user accounts** 設定でアクセス管理方法が制御されます。選択したオプションによってフローが異なります。 :::note Apple Family Sharingのトランザクション(`in_app_ownership_type=FAMILY_SHARED`)の場合、**Access level updated** イベントのみが発火し、以下のプロダクト別サブスクリプションイベントは発生しません。完全なイベントマトリクスについては [Apple Family Sharing](apple-family-sharing) をご参照ください。 ::: :::note ユーザーが **Restore Purchases** をタップしても、同じプロファイルですでにアクセスがある場合、リストアは何も行わず、Webhookイベントは発生しません。このセクションのイベントは、プロファイル間でアクセスが実際に移行する場合にのみ発生します。 ::: 2番目のプロファイルが既存のサブスクリプションを要求したときにどのイベントが発生するかを一目で確認するには、以下のマトリクスを参照してください。その後のセクションでは、各フローの完全なJSONペイロードを示します。 | イベント | 有効(デフォルト) | 新しいユーザーにアクセスを移行 | 無効 | | --- | --- | --- | --- | | 新しいプロファイル:**Access level updated**(`is_active=true`) | 発生する | 発生する | 発生しない | | 古いプロファイル:**Access level updated**(`is_active=false`) | 発生しない — 両方のプロファイルがアクセスを保持 | 新しい識別済みデバイスがトランザクションを伝播したときに発生 | 発生しない — 元のプロファイルがアクセスを保持 | | 新しいイベントの `profiles_sharing_access_level` フィールド | アクセスレベルを共有している他のプロファイルを一覧表示 | `null` | 該当なし — イベントは発生しない | 移行されたサブスクリプションの更新、返金、期限切れは、現在アクセスレベルを保持しているプロファイルで `subscription_renewed`、`subscription_refunded`、`subscription_expired` イベントを引き続き発生させます。移行イベント自体は `subscription_started` イベントを発生させません。新しいトランザクションは記録されず、アトリビューションのみが変更されるためです。 モード別の詳細については、[実用的なリファレンス](sharing-paid-access-between-user-accounts#practical-reference)をご参照ください。 ### 新しいユーザーへのアクセス移行フロー \{#transfer-access-to-new-user-flow\} 推奨オプションは、新しいユーザーにアクセスレベルを移行することです。これにより、一貫したアナリティクスのために元のユーザーのトランザクション履歴が保持されます。生成される **Access level updated** イベントは2つのみです: 1. 最初のユーザーのアクセスを削除 2. 2番目のユーザーにアクセスを付与 <img src="/assets/shared/img_webhook_flows/Transfer_Access_to_New_User_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このシナリオで生成されるイベントにおける、アクセスレベルの割り当てと移行に関連するフィールドの内訳は以下の通りです: - **ユーザーA:Access level updated(ユーザーAがアプリでサブスクリプションを購入したときに送信)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": UserA, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": null } ``` - **ユーザーA:Access level updated(アプリが再インストールされてユーザーBがログインし、ユーザーAのアクセスが取り消されたときに送信)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": UserA, "event_properties": { "profile_has_access_level": false, }, "profiles_sharing_access_level": null } ``` - **ユーザーB:Access level updated(ユーザーBがログインしてアクセスが付与されたときに送信)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000001", "customer_user_id": UserB, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": null } ``` ### ユーザー間でのアクセス共有フロー \{#shared-access-between-users-flow\} このオプションでは、デバイスが同じApple/Google IDでサインインしている場合、複数のユーザーが同じアクセスレベルを共有できます。これは、ユーザーがアプリを再インストールして別のメールアドレスでログインした場合でも、以前の購入へのアクセスを維持できるため便利です。このオプションでは、複数の識別済みユーザーが同じアクセスレベルを共有できます。アクセスレベルを共有している間、すべてのトランザクションは完全なトランザクション履歴とアナリティクスを維持するために、元の <InlineTooltip tooltip="カスタマーユーザーID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration)、[Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> の下に記録されます。 したがって、生成されるイベントは1つのみです:**Access level updated**(2番目のユーザーにアクセスを付与)。 <img src="/assets/shared/img_webhook_flows/Share_Access_Between_Users_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このシナリオで生成されるイベントにおける、アクセスレベルの割り当てと共有に関連するフィールドの内訳は以下の通りです: **ユーザーB:Access level updated(ユーザーBがログインしてアクセスが付与されたときに送信)** ```json showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": UserA, "event_properties": { "profile_has_access_level": true, }, "profiles_sharing_access_level": [ { "profile_id": "00000000-0000-0000-0000-000000000001, "customer_user_id": UserB } ] } ``` ### ユーザー間でアクセスを共有しないフロー \{#access-not-shared-between-users-flow\} このオプションでは、最初にアクセスレベルを取得したユーザープロファイルのみが永続的にそれを保持します。購入を単一の <InlineTooltip tooltip="カスタマーユーザーID">[iOS](identifying-users#set-customer-user-id-on-configuration)、[Android](android-identifying-users#setting-customer-user-id-on-configuration)、[React Native](react-native-identifying-users#setting-customer-user-id-on-configuration)、[Flutter](flutter-identifying-users#setting-customer-user-id-on-configuration)、[Unity](unity-identifying-users#setting-customer-user-id-on-configuration)</InlineTooltip> に紐付ける必要がある場合に最適です。 <img src="/assets/shared/img_webhook_flows/Share_Access_Between_Users_Disabled_Flow.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: event-statuses --- --- title: "インテグレーションイベントのステータス" description: "" --- Adapty は HTTP ステータスコードに基づいて配信可否を判定し、`200-399` の範囲外のレスポンスはすべて失敗として扱います。 インテグレーションイベントのステータスは、Adapty ダッシュボードの **Event List** で確認できます。特定のイベントタイプが特定のインテグレーションで有効になっているかどうかに関わらず、すべての有効なインテグレーションのステータスが表示されます。 - 黒: イベントが正常に送信されました。 - <span style={{ color: 'grey' }}>グレー:</span> このインテグレーションではイベントタイプが無効になっています。 - <span style={{ color: 'red' }}>赤:</span> インテグレーションに対応が必要な問題があります。 失敗したイベントの詳細を確認するには、インテグレーション名にカーソルを合わせると、具体的なエラー情報がツールチップで表示されます。 <img src="/assets/shared/img/event-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **Event Feed** は、パフォーマンスを最適化するために過去2週間分のデータを表示します。この制限によりページの読み込み速度が向上し、ユーザーがイベントをスムーズに確認・分析できます。 --- # File: adjust --- --- title: "Adjust" description: "Adjustをアダプティに接続して、サブスクリプションのトラッキングと分析を改善します。" --- [Adjust](https://www.adjust.com/) は、マーケティングキャンペーンのデータを収集・提供する主要なMMP(モバイル計測パートナー)プラットフォームの一つです。企業はこれを活用してキャンペーンのパフォーマンスを把握できます。 Adaptyは、ストアからのサブスクリプションイベントを一か所で追跡できる完全なデータセットを提供します。Adaptyを使えば、ユーザーの行動を把握し、好みを理解した上で、ターゲットを絞った効果的なコミュニケーションが可能になります。このインテグレーションにより、Adjustでサブスクリプションイベントを追跡し、キャンペーンが生み出す収益を正確に分析できます。 AdaptiとAdjustのインテグレーションは、主に2つの方法で機能します。 1. **AdaptiがAdjustからアトリビューションデータを受け取る** Adjustインテグレーションを設定すると、AdaptiはAdjustからアトリビューションデータを受け取り始めます。このデータはユーザーのプロファイルページで簡単に確認できます。 <img src="/assets/shared/img/98769d9-CleanShot_2023-08-11_at_14.39.182x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **AdaptiがサブスクリプションイベントをAdjustに送信する** Adaptyは、インテグレーションで設定したすべてのサブスクリプションイベントをAdjustに送信できます。これにより、Adjustのダッシュボードでこれらのイベントを追跡できます。このインテグレーションは、広告キャンペーンの効果測定に役立ちます。 ## インテグレーションの設定 \{#set-up-integration\} ### AdaptiをAdjustに接続する \{#connect-adapty-to-adjust\} 1. Adapty ダッシュボードを開き、[Integrations > Adjust](https://app.adapty.io/integrations/adjust) に移動します。 2. ページ上部のトグルをオンにします。 3. フィールドに入力し、アクセス認証情報を設定します。 <img src="/assets/shared/img/5064125-CleanShot_2023-08-11_at_14.43.382x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. AdjustプラットフォームでOAuth認証を有効にしている場合は、iOSおよびAndroidアプリのインテグレーション中に**OAuth Token**を提供することが必須です。 4. 次に、iOSおよびAndroidアプリの**app token**を入力します。Adjustのダッシュボードを開くと、登録済みのアプリが表示されます。 <img src="/assets/shared/img/adjust-apps.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note iOSとAndroidで異なるAdjustアプリケーションを使用している場合があるため、Adaptyにはそれぞれ独立したセクションが用意されています。Adjustアプリが1つだけの場合は、同じ情報を両方に入力してください。 ::: 5. リストからアプリを選択し、**App Token**をコピーします。トークンをAdaptyダッシュボードの対応するフィールドに貼り付けます。 <img src="/assets/shared/img/adjust-token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### イベントとタグの設定 \{#configure-events-and-tags\} Adjustは他のプラットフォームとは少し異なる仕組みで動作します。Adjustのダッシュボードでイベントを手動で作成し、イベントトークンを取得して、Adaptyの対応するイベントに貼り付ける必要があります。 最初のステップは、Adaptyに送信したいすべてのイベントのイベントトークンを確認することです。手順は以下のとおりです: 1. Adjustのダッシュボードでアプリを開き、**Events**タブに切り替えます。 <img src="/assets/shared/img/adjust-events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. イベントトークンをコピーしてAdaptiに貼り付けます。認証情報の下には、AdaptiからAdjustに送信できるイベントが3つのグループに分かれて表示されます。Adaptyが提供するイベントの全リストは[こちら](events)で確認できます。 <img src="/assets/shared/img/adjust-event-token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyはサーバー間インテグレーションを使用してサブスクリプションイベントをAdjustに送信するため、Adjustのダッシュボードですべてのサブスクリプションイベントを確認し、それらを広告獲得キャンペーンに関連付けることができます。 :::important 以下の点にご注意ください: - Adjustは58日以上前のイベントをサポートしていません。58日を超えるイベントはAdaptiからAdjustに送信されますが、イベントの日時は現在のタイムスタンプに置き換えられます。 - AdjustはIPv6をサポートしていません。**App settings**またはSDKのアクティベーション時にSDKでのIP収集を無効にした場合、バックエンドのIPv6のみが送信され、トラッキングが失敗する可能性があります。IPv4が使用されるよう、SDKのIP収集は有効のままにしておいてください。 ::: ### アプリをAdjustに接続する \{#connect-your-app-to-adjust\} 上記の手順が完了したら、以下の2つのメソッドをアプリに追加します。これらはアプリとAdjust間の通信を確立します: 1. **サブスクリプションデータをAdjustに送信する**: Adjustのデバイス IDを`setIntegrationIdentifier()` SDKメソッドに渡します。 2. **Adjustからアトリビューションデータを受け取る**: `updateAttribution()` SDKメソッドでアトリビューションデータを更新します。 Adjustバージョン5.0以降では、以下の例を使用してください: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers class AdjustModuleImplementation { func updateAdjustAdid() { Adjust.adid { adid in guard let adid else { return } // Adapty SDK 4.x Adapty.setIntegrationIdentifier(.adjustDeviceId(adid)) // Adapty SDK 3.x Adapty.setIntegrationIdentifier(key: "adjust_device_id", value: adid) } } func updateAdjustAttribution() { Adjust.attribution { attribution in guard let attribution = attribution?.dictionary() else { return } // Adapty SDK 4.x Adapty.updateAttribution(attribution, source: .adjust) // Adapty SDK 3.x Adapty.updateAttribution(attribution, source: "adjust") } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adjust.getAdid { adid -> if (adid == null) return@getAdid Adapty.setIntegrationIdentifier("adjust_device_id", adid) { error -> if (error != null) { // handle the error } } } Adjust.getAttribution { attribution -> if (attribution == null) return@getAttribution Adapty.updateAttribution(attribution, "adjust") { error -> // handle the error } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adjust.getAdid(adid -> { if (adid == null) return; Adapty.setIntegrationIdentifier("adjust_device_id", adid, error -> { if (error != null) { // handle the error } }); }); Adjust.getAttribution(attribution -> { if (attribution == null) return; Adapty.updateAttribution(attribution, "adjust", error -> { // handle the error }); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers var adjustConfig = new AdjustConfig(appToken, environment); // Before submiting Adjust config... adjustConfig.setAttributionCallbackListener(attribution => { // Make sure Adapty SDK is activated at this point // You may want to lock this thread awaiting of `activate` adapty.updateAttribution(attribution, "adjust"); }); // ... Adjust.create(adjustConfig); Adjust.getAdid((adid) => { if (adid) adapty.setIntegrationIdentifier("adjust_device_id", adid); }); ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers 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<String, String>(); 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!; await Adapty().updateAttribution(attribution, source: "adjust"); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity" default> ```csharp showLineNumbers // 1. To update ADID Adjust.GetAdid((adid) => { if (adid == null) { // handle the error return; } Adapty.SetIntegrationIdentifier("adjust_device_id", adid, (error) => { if (error != null) { // handle the error return; } }); }); // 2. To update Attribution // in your adjust configuration scope: adjustConfig.AttributionChangedDelegate = AttributionChangedCallback; public void AttributionChangedCallback(AdjustAttribution attributionData) { var attribution = new Dictionary<string, string>(); 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; // you will probably need to install Newtonsoft.Json package, if not yet var attributionJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(attribution); Adapty.UpdateAttribution(attributionJsonString, "adjust", (error) => { if (error != null) { // handle the error } }); } ``` </TabItem> </Tabs> ## イベント構造 \{#event-structure\} Adaptyは、[**Adjust Integration page**](https://app.adapty.io/integrations/adjust)の**Events names**セクションで設定された内容に従い、選択したイベントをAdjustに送信します。各イベントの構造は以下のとおりです: ```json { "event_token": "EVENT_TOKEN_FROM_CONFIG", "app_token": "APP_TOKEN_FROM_CONFIG", "s2s": 1, "environment": "production", "created_at_unix": 1709294400, "currency": "USD", "revenue": 9.99, "customer_user_id": "user_12345", "external_device_id": "user_12345", "ip_address": "192.168.100.1", "user_agent": "Mozilla/5.0 (Linux; Android 14; SM-S901B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36", "android_id": "875646c2-4a56-4211-8931-168532479006", "gps_adid": "875646c2-4a56-4211-8931-168532479006", "callback_params": "{\"integration_event_id\":\"550e8400-e29b-41d4-a716-446655440000\",\"customer_user_id\":\"user_12345\",\"vendor_product_id\":\"com.example.app.yearly.premium\",\"transaction_id\":\"GPA.3312-4512-1100-55923\",\"original_transaction_id\":\"GPA.3312-4512-1100-55923\",\"store\":\"play_store\",\"store_country\":\"US\",\"price_usd\":9.99,\"proceeds_usd\":8.49,\"price_local\":9.99,\"proceeds_local\":8.49,\"net_revenue_usd\":8.49,\"net_revenue_local\":8.49,\"tax_amount_usd\":0.0,\"tax_amount_local\":0.0,\"consecutive_payments\":3,\"rate_after_first_year\":false}", "partner_params": "{\"integration_event_id\":\"550e8400-e29b-41d4-a716-446655440000\",\"customer_user_id\":\"user_12345\",\"vendor_product_id\":\"com.example.app.yearly.premium\",\"transaction_id\":\"GPA.3312-4512-1100-55923\",\"original_transaction_id\":\"GPA.3312-4512-1100-55923\",\"store\":\"play_store\",\"store_country\":\"US\",\"price_usd\":9.99,\"proceeds_usd\":8.49,\"price_local\":9.99,\"proceeds_local\":8.49,\"net_revenue_usd\":8.49,\"net_revenue_local\":8.49,\"tax_amount_usd\":0.0,\"tax_amount_local\":0.0,\"consecutive_payments\":3,\"rate_after_first_year\":false}" } ``` 各パラメーターの説明: | パラメーター | 型 | 説明 | |:---------------------|:--------|:---------------------------------------------------------------------------------------------------------------------------------------------| | `app_token` | String | インテグレーション設定に登録されているAdjustのApp Token。 | | `event_token` | String | 特定のAdaptiイベントに対応するAdjustのEvent Token。 | | `s2s` | Integer | サーバー間イベントフラグ。 | | `environment` | String | `sandbox` または `production`。 | | `created_at_unix` | Integer | イベントのタイムスタンプ(秒単位)。 | | `currency` | String | 取引の通貨コード(例: "USD")。収益が0.001を超える場合にのみ含まれます。AdjustはrevenueとcurrencyをセットでRequireするためです。 | | `revenue` | Float | 取引の収益額。値が0.001を超える場合にのみ含まれます。なお、返金イベントはrevenue属性なしで送信されます(Adjustは負の収益値をサポートしていないため)。 | | `customer_user_id` | String | ユーザーのCustomer User ID。 | | `external_device_id` | String | `customer_user_id`と同じ値。 | | `ip_address` | String | ユーザーのIPアドレス(IPv4のみ)。 | | `user_agent` | String | デバイスのUser Agent文字列。 | | `adid` | String | AdjustのデバイスID(判明している場合)。 | | `android_id` | String | **Androidのみ**。Google Advertising ID。 | | `gps_adid` | String | **Androidのみ**。Google Advertising ID。 | | `idfa` | String | **iOSのみ**。広告主向け識別子(IDFA)。 | | `idfv` | String | **iOSのみ**。ベンダー向け識別子(IDFV)。 | | `callback_params` | String | 利用可能な[イベントフィールド](webhook-event-types-and-fields#for-most-event-types)をすべて含むJSON文字列。null以外のフィールドのみが含まれます。 | | `partner_params` | String | `callback_params`と同じ内容。 | ## トラブルシューティング \{#troubleshooting\} ### 収益の不一致 \{#revenue-discrepancy\} AdaptiとAdjust間で収益に差異がある場合、Adapty SDKを含むアプリバージョンを使用していないユーザーが存在することが原因として考えられます。データの一貫性を確保するには、Adapty SDKを搭載したバージョンへのアップデートをユーザーに促すことをお勧めします。 --- # File: airbridge --- --- title: "Airbridge" description: "AdaptyとAirbridgeを連携して、マーケティングとアトリビューションのインサイトを追跡します。" --- [Airbridge](https://www.airbridge.io/) は、複数のデバイス、プラットフォーム、チャネルから収集したデータを統合することで、ウェブサイトとモバイルアプリの統合マーケティングパフォーマンス分析を提供します。AirbridgeのIdentity Resolution Engineを使用すると、ウェブとアプリのインタラクションから得た断片的な顧客IDデータを統合した人ベースのIDに集約でき、より精度の高いアトリビューションを実現できます。 Adaptyは、ストアからの[サブスクリプションイベント](events)を一元管理できる完全なデータセットを提供します。Adaptyを使えば、ユーザーの行動を簡単に把握し、好みを理解した上で、ターゲットを絞った効果的なコミュニケーションに活かすことができます。 AdaptyとAirbridgeの連携は、主に2つの方向で機能します。 1. **Airbridgeからのアトリビューションデータの受信** Airbridge連携を設定すると、AdaptyはAirbridgeからアトリビューションデータの受信を開始します。このデータはユーザーページで簡単に確認できます。 2. **Airbridgeへのサブスクリプションイベントの送信** Adaptyは、連携設定で指定したすべてのサブスクリプションイベントをAirbridgeに送信できます。これにより、Airbridgeのダッシュボード内でこれらのイベントを追跡できるようになります。この連携は、広告キャンペーンの効果測定に役立ちます。 ## 連携の設定 \{#set-up-integration\} ### AdaptyをAirbridgeに接続する \{#connect-adapty-to-airbridge\} Airbridgeを連携するには、[Integrations > Airbridge](https://app.adapty.io/integrations/airbridge) に移動し、トグルをオンにして各フィールドを入力します。 まず、AirbridgeとAdaptyプロファイル間の接続を構築するための認証情報を設定します。AirbridgeのアプリネームとAirbridge APIトークンが必要です。 <img src="/assets/shared/img/2b31d90-Untitled-1_1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> どちらもAirbridgeダッシュボードの [Third-party Integrations > Adapty](https://app.airbridge.io/app/testad/integrations/third-party/adapty) セクションで確認できます。 <img src="/assets/shared/img/5a2f627-Screenshot_2023-02-21_at_11.19.29_AM.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty APIトークンフィールドはAdaptyバックエンドで事前に生成されています。Adapty APIトークンの値をコピーし、AirbridgeダッシュボードのAdapty Authorization Tokenフィールドに貼り付けてください。 <img src="/assets/shared/img/ff422d1-CleanShot_2023-03-01_at_17.11.412x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### イベントとタグの設定 \{#configure-events-and-tags\} 認証情報の下には、AdaptyからAirbridgeに送信できる3グループのイベントがあります。 <img src="/assets/shared/img/eb4e3a9-CleanShot_2023-08-22_at_13.58.472x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 必要なものをオンにするだけです。 ### アプリをAirbridgeに接続する \{#connect-your-app-to-airbridge\} 連携のために、以下の例のように `airbridge_device_id` をプロファイルビルダーに渡し、`setIntegrationIdentifier` を呼び出してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "airbridge_device_id", value: AirBridge.deviceUUID() ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Airbridge.getDeviceInfo().getUUID(object: AirbridgeCallback.SimpleCallback<String>() { override fun onSuccess(result: String) { Adapty.setIntegrationIdentifier("airbridge_device_id", result) { error -> if (error != null) { // handle the error } } } override fun onFailure(throwable: Throwable) { } }) ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers final deviceUUID = await Airbridge.state.deviceUUID; try { await Adapty().setIntegrationIdentifier( key: "airbridge_device_id", value: deviceUUID, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers try { const deviceId = await Airbridge.state.deviceUUID(); await adapty.setIntegrationIdentifier("airbridge_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> airbridgeDeviceIdの詳細については、[Airbridgeのドキュメント](https://help.airbridge.io/en/developers/airbridge-device-id-faq)をご覧ください。 サブスクリプションイベント後、AdaptyがAirbridgeのアトリビューションデータを受信するまで最大24時間かかる場合があります。受信後はダッシュボードに即座に表示されます。 ## イベント構造 \{#event-structure\} Adaptyは、[**Airbridge Integration page**](https://app.adapty.io/integrations/airbridge) の **Events names** セクションで設定された内容に従い、選択したイベントをAirbridgeに送信します。各イベントの構造は以下の通りです。 ```json { "user": { "externalUserID": "user_12345", "externalUserEmail": "user@example.com", "attributes": { "is_premium": true } }, "device": { "deviceUUID": "550e8400-e29b-41d4-a716-446655440000", "deviceModel": "iPhone 14 Pro", "osName": "iOS", "osVersion": "17.0.1", "locale": "en-US", "timezone": "America/New_York", "ifa": "00000000-0000-0000-0000-000000000000", "ifv": "00000000-0000-0000-0000-000000000000" }, "app": { "packageName": "com.example.app", "version": "1.2.3" }, "eventUUID": "d4f6f1f4-96fb-4a31-bafd-599fef77be90", "eventTimestamp": 1709294400000, "eventData": { "goal": { "category": "airbridge.subscribe", "customAttributes": { "isTrialConverted": true }, "semanticAttributes": { "transactionID": "GPA.3383-4699-1373-07113", "totalValue": 9.99, "currency": "USD", "period": "P1M", "isRenewal": true, "renewalCount": 2, "products": [ { "productID": "yearly.premium.6999", "name": "yearly.premium.6999", "position": 1 } ] } } } } ``` 各パラメータの説明: | パラメータ | 型 | 説明 | |:----------------------------------------------|:---------|:-------------------------------------------------------------------| | `user` | Object | ユーザー情報。 | | `user.externalUserID` | String | ユーザーのCustomer User ID。 | | `user.externalUserEmail` | String | ユーザーのメールアドレス(利用可能な場合)。 | | `user.attributes` | Object | カスタムユーザー属性。 | | `device` | Object | デバイス情報。 | | `device.deviceUUID` | String | AirbridgeのDevice UUID。 | | `device.deviceModel` | String | デバイスモデル(例: "iPhone 14 Pro")。 | | `device.osName` | String | OS名(例: "iOS"、"Android")。 | | `device.osVersion` | String | OSバージョン。 | | `device.ifa` | String | **iOSのみ**。ID for Advertisers。 | | `device.ifv` | String | **iOSのみ**。ID for Vendors。 | | `device.gaid` | String | **Androidのみ**。Google Advertising ID。 | | `app` | Object | アプリ情報。 | | `app.packageName` | String | アプリのパッケージ名 / バンドルID。 | | `app.version` | String | アプリのバージョン。 | | `eventUUID` | String | Adaptyにおけるイベントの一意ID。 | | `eventTimestamp` | Long | イベントのタイムスタンプ(ミリ秒)。 | | `eventData` | Object | イベントの詳細。 | | `eventData.goal.category` | String | Airbridgeのイベントカテゴリ(Adaptyイベントからマッピングされる)。 | | `eventData.goal.semanticAttributes` | Object | 標準イベント属性。 | | `...semanticAttributes.transactionID` | String | ストアのTransaction ID。 | | `...semanticAttributes.totalValue` | Float | 売上金額。 | | `...semanticAttributes.currency` | String | 通貨コード(例: "USD")。 | | `...semanticAttributes.period` | String | ISO 8601の期間形式によるサブスクリプション期間(例: "P1M")。 | | `...semanticAttributes.isRenewal` | Boolean | 更新トランザクションの場合は `true`。 | | `...semanticAttributes.renewalCount` | Integer | 成功した更新回数。 | | `...semanticAttributes.products` | Array | イベントに関与するプロダクトのリスト。 | | `...semanticAttributes.products[].productID` | String | ストアのプロダクトID(例: "yearly.premium.6999")。 | | `...semanticAttributes.products[].name` | String | `productID` と同じ。 | | `...semanticAttributes.products[].position` | Integer | リスト内のプロダクトの位置(常に1)。 | --- # File: apple-search-ads --- --- title: "Apple Ads" description: "Adapty と Apple Ads を統合してサブスクリプションのコンバージョンを最適化しましょう。" --- :::important **App settings** の Apple Ads 統合は、基本的なアナリティクスおよび SplitMetrics Acquire と Asapty の統合にのみ使用されます。 [Adapty Ads Manager](adapty-ads-manager)は別の接続を使用します。Apple Ads アカウントを[Adapty Ads Manager](adapty-ads-manager-get-started)で接続してください。 ::: Adapty は Apple Ads からアトリビューションデータを取得し、キャンペーンおよびキーワードのセグメンテーションで指標を分析するのに役立ちます。Adapty は SDK と AdServices Framework を通じて、Apple Ads のアトリビューションデータを自動的に収集します。 Apple Ads インテグレーションを設定すると、Adapty は Apple Ads からアトリビューションデータの受信を開始します。このデータはプロファイルページで簡単に確認できます。 <img src="/assets/shared/img/ba4a3e9-CleanShot_2023-08-21_at_15.14.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 連携の設定 \{#set-up-integration\} ### AdServicesフレームワークをAdaptyに接続する \{#connect-adapty-to-the-adservices-framework\} [AdServices](https://developer.apple.com/documentation/adservices)を使ったApple Adsは、Adapty ダッシュボードでの設定が必要です。また、アプリ側での有効化も必要です。AdServicesフレームワークを使ってAdapty経由でApple Adsを設定するには、以下の手順に従ってください。 #### ステップ1:公開鍵を取得する \{#step-1-obtain-public-key\} Adapty ダッシュボードで[Settings -> Apple Ads](https://app.adapty.io/settings/apple-search-ads)に移動します。 あらかじめ生成された公開鍵(Adaptyがキーペアを提供します)を見つけてコピーします。 <img src="/assets/shared/img/baa5998-CleanShot_2023-08-21_at_14.55.542x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Apple Ads のアトリビューションに別のサービスや独自のソリューションを使用している場合は、独自のプライベートキーをアップロードできます。 ::: #### ステップ 2: Apple Ads でユーザー管理を設定する \{#step-2-configure-user-management-on-apple-ads\} [Apple Ads アカウント](https://ads.apple.com/app-store)で **Settings > User Management** ページに移動します。Adapty がアトリビューションデータを取得するには、別の Apple ID アカウントを招待し、API Account Manager のアクセス権を付与する必要があります。既存のアカウントを使用することも、この目的専用に新しいアカウントを作成することもできます。重要なのは、その Apple ID で Apple Ads にログインできる必要があるという点です。 <img src="/assets/shared/img/ec183b2-kdjsfldsfjkdsfdfd.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### ステップ 3: API 認証情報を生成する \{#step-3-generate-api-credentials\} 次に、Apple Ads に新しく追加したアカウントでログインします。Apple Ads の画面で Settings -> API に移動し、先ほどコピーした公開鍵を所定のフィールドに貼り付けて、新しい API 認証情報を生成してください。 #### ステップ 4: Apple Ads の認証情報を Adapty に設定する \{#step-4-configure-adapty-with-apple-ads-credentials\} Apple Ads の設定画面から Client ID、Team ID、Key ID の各フィールドをコピーし、Adapty ダッシュボードの対応するフィールドに貼り付けます。 <img src="/assets/shared/img/7356113-CleanShot_2023-08-21_at_15.08.512x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### アプリを AdServices ネットワークに接続する \{#connect-your-app-to-the-adservices-network\} [AdServices フレームワークの設定](#connect-the-adservices-framework)が完了すると、Adapty は Apple Search Ad のアトリビューションデータの収集を自動的に開始します。SDK コードを追加する必要はありません。 iOS アプリケーションでは、このアトリビューションデータは**常に**他のソースからのデータより優先されます。この動作が不要な場合は、以下の手順で ASA アトリビューションを*無効化*してください。 ## インテグレーションを無効にする \{#disable-integration\} Apple Search Ads のアトリビューションをオフにするには、[**App Settings** -> **Apple Search Ads** タブ](https://app.adapty.io/settings/apple-search-ads)を開き、**Receive Apple Search Ads attribution** スイッチをオフにしてください。 <img src="/assets/shared/img/asa-disable.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning この設定を無効にすると、ASA アナリティクスの受信が完全に停止します。その結果、ASA はアナリティクスで使用されなくなり、インテグレーションにも送信されなくなります。また、SplitMetrics Acquire と Asapty は ASA アトリビューションに依存して動作しているため、機能しなくなります。 この変更以前に受信済みのアトリビューションには影響しません。 ::: ## 独自のキーをアップロードする \{#uploading-your-own-keys\} :::note オプション これらの手順は Apple Ads アトリビューションには必要ありません。Asapty などの他のサービスや独自ソリューションと連携する場合にのみ必要です。 ::: ASA アトリビューションに他のサービスや独自ソリューションを使用している場合は、独自の公開鍵・秘密鍵ペアを使用できます。 ### ステップ 1 \{#step-1\} ターミナルで秘密鍵を生成する ```text showLineNumbers title="Text" openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem ``` Adapty の Settings -> Apple Ads でアップロードする(**Upload private key** ボタン) ### ステップ 2 \{#step-2\} ターミナルで公開鍵を生成する ```text showLineNumbers title="Text" openssl ec -in private-key.pem -pubout -out public-key.pem ``` この公開鍵は、API Account Manager ロールを持つアカウントの Apple Ads 設定で使用できます。これにより、生成された Client ID、Team ID、Key ID の値を Adapty や他のサービスで利用できます。 --- # File: switch-from-appsflyer-s2s-api-2-to-3 --- --- title: "AppsFlyer S2S API 2 から 3 への切り替え" description: "Adapty で AppsFlyer S2S API 2 から 3 へアップグレードする方法。" --- [AppsFlyer の公式 What's New](https://support.appsflyer.com/hc/en-us/articles/20509378973457-Bulletin-Upgrading-the-AppsFlyer-S2S-API) によると、API 利用をより安全にし、不正を減らすために、AppsFlyer はアプリ内イベント向けのサーバー間 (S2S) API をアップグレードしました。既存のエンドポイントは将来的に廃止される予定であるため、切り替えの計画を早めに始めることをおすすめします。 Adapty は AppsFlyer S2S API 3 に対応しており、API 2 からスムーズに切り替えられます。ただし、この切り替えは一方向です。一度変更すると API 2 に戻すことはできません。 AppsFlyer S2S API 2 から 3 に切り替えるには: 1. [AppsFlyer サイト](https://www.appsflyer.com/home)を開いてログインします。 2. ダッシュボード左上の **Your account name** -> **Security Center** をクリックします。 <img src="/assets/shared/img/be299ea-appsflyer_security_center.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Manage your account security** ウィンドウで、**Manage your AppsFlyer API and S2S tokens** ボタンをクリックします。 4. S2S トークンがない場合は **New token** ボタンをクリックします。すでにある場合は手順 8 に進んでください。 <img src="/assets/shared/img/7934920-appsflyer_new_token.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **New token** ウィンドウで、トークンの名前を入力します。この名前はあなただけの管理用です。 6. **Choose type** リストから **S2S** を選択します。 7. **Create new token** ボタンをクリックして新しいトークンを保存することを忘れずに。 8. **Tokens** ウィンドウで S2S トークンをコピーします。 <img src="/assets/shared/img/d014c25-appsflyer_tokens.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. Adapty ダッシュボードで [**Integrations** -> **AppsFlyer**](https://app.adapty.io/integrations/appsflyer) を開きます。 10. **AppsFlyer S2S API** フィールドで **API 3** を選択します。 <img src="/assets/shared/img/c0b3e72-appsflyer_switch_API.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 11. コピーした S2S キーを **Dev key for iOS** と **Dev key for Android** フィールドに貼り付けます。 12. **Save** ボタンをクリックして切り替えを確定します。 この操作が完了すると、インテグレーションは即座に AppsFlyer S2S API 3 に切り替わり、新しいイベントは新しい URL `https://api3.appsflyer.com/inappevent` に送信されます。 --- # File: asapty --- --- title: "Asapty" description: "AdaptyのサブスクリプションエコシステムにおけるAsaptyとその役割を詳しく説明します。" --- [Asapty](https://asapty.com/) インテグレーションを使用すると、Search Ads キャンペーンを最適化できます。AdaptyはサブスクリプションイベントをAsaptyに送信するため、Apple Search Adsアトリビューションに基づいたカスタムダッシュボードをAsapty上で構築できます。 このインテグレーションはAdaptyにアトリビューションデータを追加しません。[ASA](apple-search-ads) から直接必要なデータをすべて取得しているためです。 ## インテグレーションの設定 \{#set-up-integration\} ### AdaptyとAsaptyを接続する \{#connect-adapty-to-asapty\} Asaptyを連携するには、Adapty ダッシュボードの [Integrations > Asapty](https://app.adapty.io/integrations/asapty) に移動し、Asapty IDのフィールドに値を入力してください。 <img src="/assets/shared/img/895de2b-CleanShot_2023-08-14_at_18.57.462x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Asapty IDは、Asaptyアカウントの Settings > General セクションで確認できます。 ### イベントとタグを設定する \{#configure-events-and-tags\} 認証情報の下には、AdaptyからAsaptyに送信できるイベントが3つのグループに分かれています。必要なものをオンにするだけです。Adaptyが提供するイベントの全リストは[こちら](events)で確認できます。 <img src="/assets/shared/img/58ddf41-CleanShot_2023-08-15_at_15.11.072x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Asaptyが提供するデフォルトのイベント名を使用することを推奨しますが、必要に応じてイベント名を変更することもできます。 ### アプリをAsaptyに接続する \{#connect-your-app-to-asapty\} 上記の手順を完了すると、Adaptyは自動的にAsaptyからアトリビューションデータを受信します。アプリのコードでアトリビューションデータを明示的にリクエストする必要はありません。アトリビューションデータの精度を高めるために、各イベントのデータに `customerUserId` を含めるようAsaptyを設定してください。 ## Asaptyイベントの構造 \{#asapty-event-structure\} AdaptyはGETリクエストのクエリパラメーターを使用してAsaptyにイベントを送信します。各イベントのURLは次のような形式になります。 ``` https://asapty.com/_api/mmpEvents/?source=adapty&asaptyid=a1b2c3d4&keywordid=12345&adgroupid=67890&campaignid=11223&conversiondate=1709294400000&event_name=subscription_renewed&install_time=1709100000&app_name=MyApp&json=%7B%22af_revenue%22%3A%229.99%22%2C%22af_currency%22%3A%22USD%22...%7D ``` クエリパラメーター: | パラメーター | 型 | 説明 | |:-----------------|:-------|:-----------------------------------------------------| | `source` | String | 常に "adapty"。 | | `asaptyid` | String | 認証情報のAsapty ID。 | | `keywordid` | String | Apple Search AdsのキーワードID(利用可能な場合)。 | | `adgroupid` | String | Apple Search AdsのADグループID(利用可能な場合)。 | | `campaignid` | String | Apple Search AdsのキャンペーンID(利用可能な場合)。 | | `conversiondate` | Long | イベントのタイムスタンプ(**ミリ秒**単位)。 | | `event_name` | String | イベント名(Adaptyイベントからマッピングされたもの)。| | `install_time` | Long | インストールのタイムスタンプ(秒単位)。 | | `app_name` | String | Adaptyのアプリタイトル(利用可能な場合)。 | | `json` | String | イベントの詳細を含むURLエンコードされたJSON文字列(下記参照)。 | `json` パラメーターは、以下のフィールドを含むURLエンコードされたJSON文字列です: | パラメーター | 型 | 説明 | |:--------------------------|:-------|:---------------------------------------------| | `af_revenue` | String | 収益金額(文字列形式)。 | | `af_currency` | String | 通貨コード(例:"USD")。 | | `transaction_id` | String | ストアのトランザクションID。 | | `original_transaction_id` | String | ストアの元のトランザクションID。 | | `purchase_date` | Long | 購入タイムスタンプ(ミリ秒単位)。 | | `original_purchase_date` | Long | 元の購入タイムスタンプ(ミリ秒単位)。 | | `environment` | String | `Production` または `Sandbox`。 | | `vendor_product_id` | String | ストアのプロダクトID。 | | `profile_country` | String | ユーザーのIPに基づく国コード。 | | `store_country` | String | ストアユーザーの国コード。 | ## トラブルシューティング \{#troubleshooting\} - AdaptyでApple Search Adsを設定し、[認証情報をアップロード](https://app.adapty.io/settings/apple-search-ads)していることを確認してください。設定がないとAsaptyは機能しません。 - 詳細な非オーガニックASAアトリビューションを持つプロファイルのみが、Asaptyにイベントを送信します。アトリビューションが不十分な場合は、"The user profile is missing the required integration data." と表示されます。 - インテグレーションの設定前に作成されたプロファイルは、Asaptyにイベントを送信できません。 - 正しく設定しているにもかかわらずAdaptyとのインテグレーションが機能しない場合は、[**App Settings** -> **Apple Search Ads** タブ](https://app.adapty.io/settings/apple-search-ads)で **Receive Apple Search Ads attribution in Adapty** トグルが有効になっているか確認してください。 --- # File: branch --- --- title: "Branch" description: "Branch と Adapty を統合して、ディープリンクとアプリのコンバージョンを追跡します。" --- [Branch](https://www.branch.io/) を使うと、さまざまなデバイス・チャネル・プラットフォームをまたいでユーザーへのリーチ、エンゲージメント、効果測定ができます。あらゆるデバイス・チャネル・プラットフォームで機能する専用リンクを通じて、モバイル収益を高めるために設計された使いやすいプラットフォームです。 Adapty は、ストアからの[サブスクリプションイベント](events)を一か所で追跡できる完全なデータセットを提供します。Adapty を使えば、サブスクライバーの行動を簡単に把握し、好みを理解した上で、ターゲットを絞った効果的なコミュニケーションに役立てることができます。 Adapty と Branch の連携は、主に 2 つの方法で動作します。 1. **Branch からアトリビューションデータを受信する** Branch 連携を設定すると、Adapty は Branch からアトリビューションデータを受信し始めます。このデータはユーザーのプロファイルページで簡単に確認できます。 <img src="/assets/shared/img/49f4aa7-CleanShot_2023-08-11_at_17.36.072x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **サブスクリプションイベントを Branch に送信する** Adapty は、連携で設定されたすべてのサブスクリプションイベントを Branch に送信できます。これにより、Branch ダッシュボード内でこれらのイベントを追跡し、獲得キャンペーンと紐付けることができます。 ## 連携のセットアップ \{#set-up-integration\} ### Adapty を Branch に接続する \{#connect-adapty-to-branch\} Branch を連携するには、Adapty ダッシュボードの [Integrations > Branch](https://app.adapty.io/integrations/branch) に移動し、トグルをオンにして各フィールドに入力してください。 <img src="/assets/shared/img/817a051-CleanShot_2023-08-11_at_15.54.372x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **Branch Key** の値を取得するには、Branch の [Account Settings](https://dashboard.branch.io/account-settings/profile) を開き、**Branch Key** フィールドを確認してください。Adapty ダッシュボードの **Key test**(サンドボックス用)または **Key live**(本番用)フィールドに使用します。Branch 側では、Live と Test の環境を切り替えて適切なキーを取得してください。 <img src="/assets/shared/img/130e58b-CleanShot_2023-08-11_at_15.24.162x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### イベントとタグを設定する \{#configure-events-and-tags\} 認証情報の下には、Adapty から Branch に送信できるイベントが 3 つのグループに分かれています。必要なものをオンにするだけです。Adapty が提供するイベントの全一覧は[こちら](events)で確認できます。 収益(Apple/Google の手数料差し引き後)または売上金額のみでイベントを送信できます。また、ユーザーの通貨でレポートするチェックボックスもあります。 <img src="/assets/shared/img/a645cf8-CleanShot_2023-08-11_at_15.18.282x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty が提供するデフォルトのイベント名を使用することを推奨します。ただし、必要に応じてイベント名を変更することも可能です。 Adapty はサーバー間連携を使って Branch にサブスクリプションイベントを送信するため、Branch ダッシュボードですべてのサブスクリプションイベントを確認し、獲得キャンペーンと紐付けることができます。 ### アプリを Branch に接続する \{#connect-your-app-to-branch\} 1. `.setIntegrationIdentifier()` SDK メソッドを呼び出して接続を初期化します。Branch の Identity ID を `customerUserId` パラメータに渡すことができます。 :::note サードパーティSDKはユーザーIDを非同期で生成します。`Adapty.activate()` の実行時にIDがまだ準備できていない場合があります。**Customer User ID** がこれらのSDKのいずれかから取得される場合は、IDなしで `Adapty.activate()` を呼び出してください。IDが取得できたら、`setIntegrationIdentifier()` を呼び出し、次にCUIDで `identify()` を呼び出してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.branchId(<BRANCH_IDENTITY_ID>)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "branch_id", value: <BRANCH_IDENTITY_ID> ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers // login and update attribution and identifier Branch.getAutoInstance(this) .setIdentity("YOUR_USER_ID") { referringParams, error -> referringParams?.let { data -> Adapty.updateAttribution(data, "branch") { error -> if (error != null) { //handle the error } } } } // logout Branch.getAutoInstance(context).logout() ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers import 'package:flutter_branch_sdk/flutter_branch_sdk.dart'; FlutterBranchSdk.setIdentity('YOUR_USER_ID'); ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers Branch.setIdentity("your user id"); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers import branch from 'react-native-branch'; branch.setIdentity('YOUR_USER_ID'); ``` </TabItem> </Tabs> 2. `.updateAttribution()` メソッドを使用してアトリビューションデータを保存します。前のステップで Branch のユーザー ID を指定しなかった場合は、ここで `networkUserId` パラメータに渡してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers class YourBranchImplementation { func initializeBranch() { // Pass the attribution you receive from the initializing method of Branch iOS SDK to Adapty. Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in if let data { // Adapty SDK 4.x Adapty.updateAttribution(data, source: .branch) // Adapty SDK 3.x Adapty.updateAttribution(data, source: "branch") } } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers //everything is in the above snippet for Android ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers try { await Adapty().setIntegrationIdentifier( key: "branch_id", value: <BRANCH_IDENTITY_ID>, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; Branch.initSession(delegate(Dictionary<string, object> parameters, string error) { string attributionString = JsonUtility.ToJson(parameters); Adapty.UpdateAttribution( attributionString, "branch", (error) => { // handle the error }); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers import { adapty, AttributionSource } from 'react-native-adapty'; import branch from 'react-native-branch'; branch.subscribe({ enComplete: ({ params, }) => { adapty.updateAttribution(params, "branch"); }, }); ``` </TabItem> </Tabs> ## イベント構造 \{#event-structure\} Adapty は、[**Branch Integration ページ**](https://app.adapty.io/integrations/branch)の **Events names** セクションで設定された内容に従って、選択したイベントを Branch に送信します。各イベントは次のような構造になっています: ```json { "branch_key": "key_live_kaFuWw8WvY7n1ss7...", "name": "PURCHASE", "user_data": { "os": "iOS", "developer_identity": "user_12345", "country": "US", "ip": "192.168.100.1", "idfa": "00000000-0000-0000-0000-000000000000", "idfv": "00000000-0000-0000-0000-000000000000", "aaid": "00000000-0000-0000-0000-000000000000" }, "event_data": { "transaction_id": "GPA.3383-4699-1373-07113", "revenue": 9.99, "currency": "USD" }, "custom_data": { "vendor_product_id": "yearly.premium.6999", "original_transaction_id": "GPA.3383-4699-1373-07113", "store": "play_store", "environment": "production" } } ``` 各パラメータの説明: | パラメータ | 型 | 説明 | |:-------------------------------|:-------|:------------------------------------------------------------------------------------------------------------------------| | `branch_key` | String | Branch Key。 | | `name` | String | Branch イベント名(Adapty イベントからマッピングされたもの。例:"PURCHASE")。 | | `user_data` | Object | ユーザー情報。 | | `user_data.os` | String | "Android" または "iOS"。 | | `user_data.developer_identity` | String | ユーザーの Customer User ID。 | | `user_data.country` | String | ユーザーの IP に基づく国コード。 | | `user_data.ip` | String | ユーザーの IP アドレス。 | | `user_data.idfa` | String | **iOS のみ**。広告主向け識別子(ID for Advertisers)。 | | `user_data.idfv` | String | **iOS のみ**。ベンダー向け識別子(ID for Vendors)。 | | `user_data.aaid` | String | **Android のみ**。Google 広告 ID。 | | `event_data` | Object | 標準イベント指標(PURCHASE など該当イベントにのみ含まれます)。 | | `event_data.transaction_id` | String | ストアのトランザクション ID。 | | `event_data.revenue` | Float | 収益額。 | | `event_data.currency` | String | 通貨コード(例:"USD")。 | | `custom_data` | Object | 詳細なイベント属性(利用可能なすべての[イベントフィールド](webhook-event-types-and-fields#for-most-event-types)を含みます)。 | --- # File: facebook-ads --- --- title: "Facebook Ads" description: "Facebook AdsをAdaptyと統合して、効果的なサブスクリプションマーケティングを実現します。" --- Facebook Ads連携を利用すると、Meta Analyticsでアプリの統計情報を簡単に確認できます。AdaptyはMeta Ads Managerにイベントを送信し、サブスクリプションに基づいた類似オーディエンスの作成をサポートすることで、より高いリターンを実現します。これにより、広告がサブスクリプションからどれだけの収益を生み出しているかを正確に把握できます。 AdaptyとFacebook Adsの連携は次のように動作します。Adaptyは、連携で設定されたすべてのサブスクリプションイベントをFacebook Adsに送信します。この連携は、広告キャンペーンの効果を評価するのに役立ちます。 ## 連携のセットアップ \{#set-up-integration\} ### AdaptyをFacebook Adsに接続する \{#connect-adapty-to-facebook-ads\} Facebook Adsと連携してアプリの指標を分析するには、Meta Analyticsとの連携をセットアップします。Meta Ads Managerにイベントを送信することで、更新などのサブスクリプションイベントを基に類似オーディエンスを作成できます。この連携を設定するには、Adapty ダッシュボードの [Integrations > Facebook Ads](https://app.adapty.io/integrations/facebookanalytics) に移動し、必要な認証情報を入力してください。 :::note Facebook Ads連携は、ATTの同意を得たユーザーに対してiOS 14.5以降でのみ動作します。 ::: <img src="/assets/shared/img/fd84ddf-CleanShot_2023-08-15_at_15.45.442x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. App IDを確認するには、[App Store Connect](https://appstoreconnect.apple.com/) でアプリのページを開き、**General** セクションの **App Information** ページに移動して、画面左下の **Apple ID** を確認します。 2. [Meta for Developers](https://developers.facebook.com/) プラットフォームでアプリケーションが必要です。アプリにログインして詳細設定を開くと、ヘッダーに **App ID** が表示されます。 <img src="/assets/shared/img/4b326c4-001563-August-23-4tO3JVso.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Meta Ads Managerでの収益の二重カウントを防ぐため、Meta SDKの設定でクライアントサイドのトラッキングを無効にしてください。この設定は、Meta Developer Consoleの **App Settings > Advanced Settings** にあります。**Log in-app events automatically** を「No」に設定してください。これにより、収益イベントはAdaptyの連携経由でのみトラッキングされます。 インストールや使用状況のイベントをトラッキングするには、コード内でMeta SDKを有効化する必要があります。各プラットフォームのMeta SDKドキュメントで実装の詳細を確認できます: - [iOS SDK](https://developers.facebook.com/docs/ios/getting-started) - [Android SDK](https://developers.facebook.com/docs/android/getting-started) - [Unity SDK](https://developers.facebook.com/docs/unity/getting-started/canvas) <img src="/assets/shared/img/c4eb8eb-001565-August-23-483KKBbC.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> この連携はAndroidアプリでも利用できます。**App Settings** でAndroid SDKの設定を行っている場合は、**Facebook App ID** を設定するだけで十分です。 ### イベントとタグの設定 \{#configure-events-and-tags\} Facebook Ads連携は、Metaを広告キャンペーンに活用し、顧客行動に基づいて最適化している企業向けです。Metaの標準イベントを最適化目的でサポートしています。そのため、Meta Ads連携ではイベント名の変更はできません。Adaptyはお客様の顧客イベントを対応するMetaイベントに正確にマッピングします。 | Adaptyイベント | Meta Adsイベント | | :---------------------------- | :-------------------------- | | Subscription initial purchase | Subscribe | | Subscription renewed | Subscribe | | Subscription cancelled | CancelSubscription | | Trial started | StartTrial | | Trial converted | Subscribe | | Trial cancelled | CancelTrial | | Non subscription purchase | fb_mobile_purchase | | Billing issue detected | billing_issue_detected | | Entered grace period | entered_grace_period | | Auto renew off | auto_renew_off | | Auto renew on | auto_renew_on | | Auto renew off subscription | auto_renew_off_subscription | | Auto renew on subscription | auto_renew_on_subscription | StartTrial、Subscribe、CancelSubscriptionは標準イベントです。 <img src="/assets/shared/img/8a5df9d-CleanShot_2023-07-04_at_12.47.312x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 特定のイベントを有効にするには、必要なものをトグルでオンにするだけです。複数のイベント名が選択された場合、Adaptyはすべての選択されたイベントのデータを1つのAdaptyイベント名にまとめます。 ### アプリをFacebook Adsに接続する \{#connect-your-app-to-facebook-ads\} 上記の手順を完了すると、FacebookはAdaptyからサブスクリプションデータを自動的に受信します。 iOS 14.5でのIDFAの変更を受け、ユーザーの`facebookAnonymousId`をFacebookからリクエストすることをお勧めします。これにより、ユーザーのIDFAが取得できない場合でも連携が継続して機能します。このパラメーターを設定するには、<InlineTooltip tooltip="ユーザー属性設定ガイド">[iOS](setting-user-attributes)、[Android](android-setting-user-attributes)、[React Native](react-native-setting-user-attributes)、[Flutter](flutter-setting-user-attributes)、[Unity](unity-setting-user-attributes)</InlineTooltip> をご参照ください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "facebook_anonymous_id", value: AppEvents.shared.anonymousID ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier( "facebook_anonymous_id", AppEventsLogger.getAnonymousAppDeviceGUID(context) ) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers try { const anonymousId = await AppEventsLogger.getAnonymousID(); await adapty.setIntegrationIdentifier("facebook_anonymous_id", anonymousId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```text There is no official SDK for Flutter ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp anonymousID is not available in the official SDK https://github.com/facebook/facebook-sdk-for-unity/issues/676 ``` </TabItem> </Tabs> ## イベント構造 \{#event-structure\} AdaptyはGraph API経由でFacebook Ads(Meta)にイベントを送信します。各イベントは次のような構造になっています: ```json { "event": "CUSTOM_APP_EVENTS", "app_user_id": "user_12345", "advertiser_id": "00000000-0000-0000-0000-000000000000", "advertiser_tracking_enabled": 1, "application_tracking_enabled": 1, "custom_events": "[{\"_eventName\":\"Subscribe\",\"_logTime\":1709294400,\"fb_num_items\":1,\"fb_content_type\":\"in_app\",\"fb_content_id\":\"yearly.premium.6999\",\"fb_currency\":\"USD\",\"fb_order_id\":\"GPA.3383...\",\"fb_transaction_id\":\"GPA.3383...\",\"_valueToSum\":9.99}]", "extinfo": "[\"i2\",\"com.example.app\",\"1.0.0\",\"100\",\"17.0.1\",\"iPhone14,3\",\"en_US\",\"GMT+3\",\"\",0,0,0,0,0,0,\"GMT+3\"]", "anon_id": "facebook_anon_id_123" } ``` 各パラメーターの説明: | パラメーター | 型 | 説明 | |:---|:---|:---| | `event` | String | 常に「CUSTOM_APP_EVENTS」。 | | `app_user_id` | String | ユーザーのCustomer User ID。 | | `advertiser_id` | String | IDFA(iOS)またはAdvertising ID(Android)。 | | `advertiser_tracking_enabled` | Integer | トラッキングが有効(ATT承認済み)の場合は`1`、それ以外は`0`。 | | `application_tracking_enabled` | Integer | 常に`1`。 | | `custom_events` | String | イベントオブジェクトのJSON形式の文字列(下記参照)。 | | `extinfo` | String | アプリ・デバイス情報(バージョン、OS、ロケールなど)を含むJSON形式の文字列。 | | `anon_id` | String | Facebook Anonymous ID(利用可能な場合)。 | `custom_events` パラメーターはオブジェクトのJSON配列で、以下の情報を含みます: | パラメーター | 型 | 説明 | |:---|:---|:---| | `_eventName` | String | Meta Adsのイベント名(例:「Subscribe」)。 | | `_logTime` | Long | イベントのタイムスタンプ(秒単位)。 | | `_valueToSum` | Float | 収益金額。 | | `fb_content_id` | String | ストアのプロダクトID。 | | `fb_currency` | String | 通貨コード(例:「USD」)。 | | `fb_order_id` | String | オリジナルトランザクションID。 | | `fb_transaction_id` | String | オリジナルトランザクションID。 | | `fb_content_type` | String | 常に「in_app」。 | | `fb_num_items` | Integer | 購入イベントでは常に1。 | --- # File: singular --- --- title: "Singular" description: "AdaptyとSingularを統合して、マーケティングとサブスクリプションデータを分析します。" --- [Singular](https://www.singular.net/) は主要なMobile Measurement Partner(MMP)プラットフォームの1つで、マーケティングキャンペーンのデータを収集・可視化します。これにより、企業はキャンペーンのパフォーマンスを追跡できます。 Adaptyは、ストアからの[サブスクリプションイベント](events)を一か所で追跡できる完全なデータセットを提供します。Adaptyを使えば、サブスクライバーの行動を簡単に把握し、ユーザーの好みを理解し、ターゲットを絞った効果的なコミュニケーションに活用できます。この連携により、Singularでサブスクリプションイベントを追跡し、キャンペーンが生み出す収益を正確に分析できます。 Adaptyは、連携で設定されたすべてのサブスクリプションイベントをSingularに送信できます。その結果、Singularダッシュボード内でこれらのイベントを追跡できるようになります。この連携は、広告キャンペーンの効果を評価する際に役立ちます。 ## 連携のセットアップ \{#set-up-integration\} ### AdaptyとSingularを接続する \{#connect-adapty-to-singular\} Singularとの連携をセットアップするには、Adapty ダッシュボードの [Integrations > Singular](https://app.adapty.io/integrations/singular) に移動し、トグルをオンにしてフィールドに入力します。 以下の認証情報が利用できます: - **Singular SDK Key**:必須。SingularアプリのプロダクションSDKキー。 - **Singular SDK Key (Sandbox)**:オプション。サンドボックス用SingularアプリのSDKキー。設定しない場合、サンドボックスイベントはSingularに送信されません。 両方のキーは、Singularダッシュボードの **Developer tools -> SDK Keys -> SDK Key(**SDKシークレットではありません**)** から確認できます: <img src="/assets/shared/img/4bc50d1-singular_sdk_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 認証情報の下には、AdaptyからSingularに送信できる3グループのイベントがあります。Adaptyが提供するイベントの完全なリストは[こちら](events)でご確認ください。 <img src="/assets/shared/img/e67de0c-singular_events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyが提供するデフォルトのイベント名を使用することをお勧めします。ただし、必要に応じてイベント名を変更することも可能です。 Adaptyはサーバー間連携を使用してサブスクリプションイベントをSingularに送信するため、Singularダッシュボードですべてのサブスクリプションイベントを確認し、獲得キャンペーンと紐付けることができます。 :::warning 連携を設定する前に作成されたプロファイルは、Singularにイベントを送信できません。 ::: ### アプリをSingularに接続する \{#connect-your-app-to-singular\} AdaptyとSingularの連携はサーバー間連携です。そのため、アプリケーションに追加のコードを記述する必要はありません。 ## イベント構造 \{#event-structure\} AdaptyはGETリクエストのクエリパラメーターを使用してSingularにイベントを送信します。各イベントの構造は次のとおりです: ```json { "n": "subscription_renewed", "a": "singular_sdk_key_123", "p": "iOS", "i": "com.example.app", "ip": "192.168.100.1", "idfa": "00000000-0000-0000-0000-000000000000", "idfv": "00000000-0000-0000-0000-000000000000", "ve": "17.0.1", "att_authorization_status": 3, "custom_user_id": "user_12345", "utime": 1709294400, "amt": 9.99, "cur": "USD", "purchase_product_id": "yearly.premium.6999", "purchase_transaction_id": "GPA.3383...", "e": "{\"is_revenue_event\":true,\"amt\":9.99,\"cur\":\"USD\",\"purchase_product_id\":\"yearly.premium.6999\",\"purchase_transaction_id\":\"GPA.3383...\"}" } ``` 各パラメーターの説明: | パラメーター | 型 | 説明 | |:---------------------------|:--------|:---------------------------------------------------------| | `n` | String | イベント名(Adaptyイベントからマッピングされたもの)。 | | `a` | String | Singular SDKキー。 | | `p` | String | プラットフォーム("iOS" または "Android")。 | | `i` | String | ストアアプリID(バンドルID)。 | | `ip` | String | ユーザーのIPアドレス。 | | `idfa` | String | **iOSのみ**。広告主向けID(大文字)。 | | `idfv` | String | **iOSのみ**。ベンダー向けID(大文字)。 | | `aifa` | String | **Androidのみ**。Google広告ID(小文字)。 | | `andi` | String | **Androidのみ**。Android ID(小文字)。 | | `asid` | String | **Androidのみ**。アプリセットID(小文字)。 | | `ve` | String | OSバージョン。 | | `att_authorization_status` | Integer | **iOSのみ**。ATTステータス(例:`3` は承認済み)。 | | `custom_user_id` | String | ユーザーのカスタマーユーザーID。 | | `utime` | Long | イベントのUNIXタイムスタンプ(秒単位)。 | | `amt` | Float | 収益金額。 | | `cur` | String | 通貨コード(例:"USD")。 | | `purchase_product_id` | String | ストアのプロダクトID。 | | `purchase_transaction_id` | String | 元のトランザクションID。 | | `e` | String | イベント詳細を含むJSONエンコード文字列(以下参照)。 | `e` パラメーター(カスタムイベントデータ)は、以下を含むJSONエンコード文字列です: | パラメーター | 型 | 説明 | |:--------------------------|:--------|:---------------------------------------| | `is_revenue_event` | Boolean | イベントに収益が含まれる場合は `true`。 | | `amt` | Float | 収益金額。 | | `cur` | String | 通貨コード。 | | `purchase_product_id` | String | ストアのプロダクトID。 | | `purchase_transaction_id` | String | 元のトランザクションID。 | --- # File: tenjin --- --- title: "Tenjin連携" description: "" --- Tenjinは、アプリ開発者やマーケター向けのモバイルアトリビューション・分析プラットフォームです。広告ネットワークやアプリストアのデータを集約し、ROIの分析、コンバージョンのトラッキング、主要なパフォーマンス指標のモニタリングを可能にします。透明性が高く柔軟なアプローチで、ユーザー獲得キャンペーンの計測と最適化を支援します。 [サブスクリプションイベント](events)をTenjinに転送することで、コンバージョンの発生源や最も価値をもたらすキャンペーンを、すべてのチャネル・プラットフォーム・デバイスにわたって正確に把握できます。TenjinのダッシュボードはマーケティングキャンペーンのA/Bテスト向け高度な分析機能を提供します。 TenjinのアトリビューションをAdaptyに転送することで、Adaptyのアナリティクスにコホート分析やコンバージョン分析で活用できる追加フィルタ条件を追加できます。 この連携は2つの方法で機能します: 1. **Tenjinからアトリビューションデータを受け取る** 連携後、AdaptyはTenjinからアトリビューションデータを収集します。この情報はAdapty Dashboardのユーザーのプロファイルページで確認できます。 2. **サブスクリプションイベントをTenjinに送信する** Adatyはリアルタイムで購入イベントをTenjinに送信します。これらのイベントを使って、Tenjinのダッシュボード内で広告キャンペーンの効果を直接評価できます。 | 連携の特性 | 説明 | | -------------------------- | ------------------------------------------------------------ | | スケジュール | リアルタイム | | データの方向 | <p>双方向転送:</p><ul><li> **Adaptyイベント**:AdaptyサーバーからTenjinサーバーへ</li><li> **Tenjinアトリビューション**:Tenjin SDKからAdaptyサーバーへ</li></ul> | | Adaptyの連携ポイント | <ul><li> モバイルアプリコード内のTenjinとAdapty SDK</li><li> Adaptyサーバー</li></ul> | ## 連携のセットアップ \{#set-up-integration\} ### AdaptyをTenjinに接続する \{#connect-adapty-to-tenjin\} 1. Adapty Dashboardの[**Integrations** -> **Tenjin**](https://app.adapty.io/integrations/tenjin)ページを開きます。 2. トグルを有効にして連携をアクティブにします。 <img src="/assets/shared/img/tenjin-toggle.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. [Tenjin Dashboard](https://tenjin.com/)にログインします。 4. ナビゲーションメニューで**Configuration** -> **Apps**に移動します。 <img src="/assets/shared/img/tenjin-apps.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. お使いのプラットフォーム(iOSまたはAndroid)のアプリを選択し、**App and SDK**タブに移動します。 6. **App and SDK**タブで、**SDK Key**列の**Copy**をクリックします。SDKキーがまだない場合は、**Generate SDK Key**ボタンをクリックして作成します。 <img src="/assets/shared/img/tenjin-copy-sdk-key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. Adapty Dashboardに戻り、コピーしたSDKキーを対応するプラットフォームのフィールドに貼り付けます: - iOSアプリの場合:**iOS SDK Key**または**iOS Sandbox SDK Key**フィールドに貼り付けます - Androidアプリの場合:**Android SDK Key**または**Android Sandbox SDK Key**フィールドに貼り付けます :::info Tenjinにはサーバー間連携向けの専用サンドボックスモードはありません。本番環境とサンドボックスイベントの両方に、別のTenjinアプリまたは同じキーを使用してください。 ::: <img src="/assets/shared/img/tenjin-keys.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. 両方のプラットフォームにアプリがある場合は、もう一方のプラットフォームについて手順5〜7を繰り返します。 9. (任意)必要に応じて**How the revenue data should be sent**セクションを調整します。設定の詳細については、[連携設定](configuration#integration-settings)を参照してください。 10. **Save**をクリックしてセットアップを完了します。 これでAdaptyはTenjinに購入イベントを送信し、アトリビューションデータを受信します。**Events names**セクションでイベントの共有を調整できます。 ### イベントとタグを設定する \{#configure-events-and-tags\} Tenjinは購入イベントと**Trial started**イベントのみを受け付けます。**Events names**セクションで、トラッキング目標に合わせてTenjinと共有するイベントを選択します。 <img src="/assets/shared/img/tenjin-events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### アプリをTenjinに接続する \{#connect-your-app-to-tenjin\} `Adapty.updateAttribution()` SDKメソッドを使用してTenjinからアトリビューションデータを取得し、Adaptyに渡します。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers func updateTenjinId() { guard let tenjinId = TenjinSDK.getAnalyticsInstallationId() else { return } do { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.tenjinAnalyticsInstallationId(tenjinId)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "tenjin_analytics_installation_id", value: tenjinId ) } catch { // handle the error } } func updateTenjinAttribution() { let instance = TenjinSDK.getInstance("<YOUR_TENJIN_API_TOKEN>") instance?.getAttributionInfo { info, _ in guard let info else { return } Task { do { // Adapty SDK 4.x try await Adapty.updateAttribution(info, source: .tenjin) // Adapty SDK 3.x try await Adapty.updateAttribution(info, source: "tenjin") } catch { // handle the error } } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("tenjin_analytics_installation_id", tenjinSdk.analyticsInstallationId) { error -> if (error != null) { // handle the error } } tenjinSdk.getAttributionInfo { attribution -> if (attribution == null) return@getAttributionInfo Adapty.updateAttribution(attribution, "tenjin") { error -> if (error != null) { // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.setIntegrationIdentifier("tenjin_analytics_installation_id", tenjinSdk.getAnalyticsInstallationId(), error -> { if (error != null) { // handle the error } }); tenjinSdk.getAttributionInfo(attribution -> { if (attribution == null) return; Adapty.updateAttribution(attribution, "tenjin", error -> { // handle the error }); }); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers try { final tenjinId = await TenjinSDK.instance.getAnalyticsInstallationId(); if (tenjinId != null) { await Adapty().setIntegrationIdentifier( key: 'tenjin_analytics_installation_id', value: tenjinId, ); } final attribution = await TenjinSDK.instance.getAttributionInfo(); if (attribution != null) { await Adapty().updateAttribution(attribution, source: 'tenjin'); } } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; using System.Linq; BaseTenjin instance = Tenjin.getInstance("<SDK_KEY>"); var tenjinId = instance.GetAnalyticsInstallationId(); Adapty.SetIntegrationIdentifier( "tenjin_analytics_installation_id", tenjinId, (error) => { // handle the error }); instance.GetAttributionInfo((attribution) => { var dynamicAttribution = attribution.ToDictionary( kvp => kvp.Key, kvp => (dynamic)kvp.Value ); Adapty.UpdateAttribution( dynamicAttribution, "tenjin", (error) => { // handle the error }); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // ... const posthog = usePostHog() // ... try { await adapty.setIntegrationIdentifier("tenjin_analytics_installation_id", await Tenjin.getAnalyticsInstallationId()); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## イベント構造 \{#event-structure\} Adatyは[**Tenjin Integration page**](https://app.adapty.io/integrations/tenjin)の**Events names**セクションで設定した選択済みイベントをTenjinに送信します。各イベントの構造は次のとおりです: ```json showLineNumbers title="Json" { "price": 99.0, "locale": "en-US", "country": "ME", "postcut": "false", "currency": "USD", "platform": "ios", "quantity": 1, "bundle_id": "com.adapty.adaptydemoapp", "ip_address": "127.0.0.1", "os_version": "18.1.1", "product_id": "month.premium.99", "app_version": "3.2.0", "sdk_version": "server", "device_model": "iPhone 13 Mini", "advertising_id": "00000000-0000-0000-0000-000000000000", "os_version_release": "18.1.1", "developer_device_id": "00000000-0000-0000-0000-000000000000", "analytics_installation_id": "00000000-0000-0000-0000-000000000000" } ``` 各パラメーターの説明: | **パラメーター** | **型** | **説明** | | ----------------------------- | ---------------- | ------------------------------------------------------------ | | **price** | Float | 購入アイテムの単価(通貨の標準単位。例:USDはドル単位で報告)。 | | **locale** | String | デバイスのロケール。Android:`Locale.getDefault().toString()`、iOS:`[[NSLocale currentLocale] localeIdentifier]`。 | | **country** | String | ISO標準の国コード(例:米国はUS)。 | | **postcut** | String (Boolean) | プラットフォームの手数料差し引き後に購入が送信されたかどうかを示します。trueの場合は1、falseの場合は0。 | | **currency** | String | ISO通貨コード(例:米ドルはUSD)。 | | **platform** | String | デバイスのプラットフォーム(例:ios、android、windows、amazon)。 | | **quantity** | Integer | 購入した数量。 | | **bundle_id** | String | アプリのバンドル識別子(例:`com.example.app`)。 | | **ip_address** | String (IPv4) | ユーザーのIPアドレス。国の検索に使用されます。 | | **os_version** | String | デバイスのOSバージョン。Android:`String.valueOf(Build.VERSION.SDK_INT)`、iOS:`[[UIDevice currentDevice] systemVersion]`。 | | **product_id** | String | 購入したプロダクトの一意識別子。 | | **app_version** | Float, Decimal | アプリのバージョン。Android:`context.getPackageManager().getPackageInfo()`、iOS:`[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]`。 | | **sdk_version** | String | 使用中のSDKバージョン。常に`server`に設定されます。 | | **device_model** | String | デバイスのモデル。Android:`Build.MODEL`、iOS:`sysctl("hw.machine")`。 | | **advertising_id** | UUID | デバイスの広告ID。Androidでは必須です。iOSでは空またはすべてゼロになることがあります。 | | **os_version_release** | String | OSバージョンのリリース情報。Android:`String.valueOf(Build.VERSION.RELEASE)`、iOS:`[[UIDevice currentDevice] systemVersion]`。 | | **developer_device_id** | UUID | ベンダー識別子(iOSのみ)。 | | **analytics_installation_id** | UUID | アナリティクスインストールID。詳細については、`https://docs.tenjin.com`のドキュメントを参照してください。 | --- # File: amplitude --- --- title: "Amplitude" description: "ユーザー行動をより深く把握するために、AmplitudeとAdaptyを連携しましょう。" --- [Amplitude](https://amplitude.com/) は強力なモバイル解析サービスです。Adaptyと組み合わせることで、イベントをAmplitudeに簡単に送信し、ユーザーの行動を把握して、的確な意思決定を行えます。 Adaptyは、ストアからの[サブスクリプションイベント](events)を一箇所で追跡できる完全なデータセットを提供し、Amplitudeアカウントに送信します。これにより、Amplitude上でユーザーの行動と課金履歴を紐付け、プロダクトの意思決定に役立てることができます。 ### Amplitude 連携のセットアップ方法 \{#how-to-set-up-amplitude-integration\} Adaptyでは、AppleまたはStripeサンドボックス環境、もしくはGoogleテストアカウントからの**本番**イベントと**テスト**イベントに対して、それぞれ個別のフローを設定できます。 - 本番イベントには、AmplitudeダッシュボードのプラットフォームごとのAPIキー(iOS、Android、Stripe各固有のキー)を **Production** フィールドに入力してください。 - テストイベントには、必要に応じて **Sandbox** フィールドを使用してください。 Amplitude連携をセットアップするには: 1. Adapty ダッシュボードで [**Integrations** -> **Amplitude**](https://app.adapty.io/integrations/amplitude) を開きます。 <img src="/assets/shared/img/3b50552-CleanShot_2023-08-15_at_16.47.102x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Amplitude integration** をオンに切り替えて有効化します。 3. 連携フィールドに入力します: | フィールド | 説明 | | ------------------------------------------ | ------------------------------------------------------------ | | **Amplitude iOS/ Android/ Stripe API key** | iOS / Android / Stripe用のAmplitude **API Key** をAdaptyに入力します。Amplitudeの **Project settings** から確認できます。詳しくは [Amplitude ドキュメント](https://amplitude.com/docs/apis/authentication) をご覧ください。まず **Sandbox** キーでテストを行い、成功したら **Production** キーに切り替えてください。 | <img src="/assets/shared/img/2297782-CleanShot_2023-08-15_at_16.53.512x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. さらに詳細なカスタマイズのためのオプション設定: | パラメータ | 説明 | | --------------------------------------- | ------------------------------------------------------------ | | **How the revenue data should be sent** | 総収益を送るか、税金と手数料控除後の収益を送るかを選択します。詳細は[ストア手数料と税金](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)をご覧ください。 | | **Exclude historical events** | Adapty SDK インストール以前のイベントを除外するか選択します。データの重複を防ぐことができます。たとえば、ユーザーが1月10日にサブスクリプションを開始し、3月6日にAdapty SDKをインストールした場合、Adaptyは3月6日以降のイベントのみを送信します。 | | **Send User Attributes** | 言語設定などのユーザー固有の属性を送信するにはこのオプションを選択します。 | | **Always populate user_id** | Adaptyは自動的に `device_id` を `amplitudeDeviceId` として送信します。`user_id` については、この設定で動作を定義します:<ul><li>**ON**:`amplitudeUserId` または `customer_user_id` が利用できない場合、Adaptyの `profile_id` を送信します。</li><li>**OFF**:いずれのIDも利用できない場合、`user_id` を空のままにします。</li></ul> | 5. 受信したいイベントを選択し、[イベント名をマッピング](amplitude#events-and-tags)します。 6. **Save** をクリックして変更を保存します。 **Save** をクリックすると、AdaptyはAmplitudeへのイベント送信を開始します。 イベントに加えて、Adaptyは[サブスクリプションステータス](subscription-status)とサブスクリプションのプロダクトIDを[Amplitudeユーザープロパティ](https://amplitude.com/docs/data/user-properties-and-events)に送信します。 ### イベントとタグ \{#events-and-tags\} 認証情報の下に、AdaptyからAmplitudeに送信できるイベントが3つのグループに分かれて表示されています。必要なものをオンにするだけで使えます。Adaptyが提供するイベントの全リストは[こちら](events)で確認できます。 <img src="/assets/shared/img/da67694-CleanShot_2023-08-15_at_16.52.352x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyが提供するデフォルトのイベント名を使用することをお勧めします。ただし、必要に応じてイベント名を変更することも可能です。Adaptyはサーバー間連携を使ってAmplitudeにサブスクリプションイベントを送信するため、Amplitudeダッシュボードですべてのサブスクリプションイベントを確認できます。 ### SDK の設定 \{#sdk-configuration\} `setIntegrationIdentifier()` メソッドを使用して `amplitude_device_id` パラメータを設定します。これは連携のセットアップに必須です。 ユーザー登録がある場合は、`amplitude_user_id` も合わせて渡すことができます。 :::note サードパーティSDKはユーザーIDを非同期で生成します。`Adapty.activate()` の実行時にIDがまだ準備できていない場合があります。**Customer User ID** がこれらのSDKのいずれかから取得される場合は、IDなしで `Adapty.activate()` を呼び出してください。IDが取得できたら、`setIntegrationIdentifier()` を呼び出し、次にCUIDで `identify()` を呼び出してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="Swift" label="iOS (Swift)" default> **amplitudeDeviceId の設定** ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "amplitude_device_id", value: Amplitude.instance().deviceId ) } catch { // handle the error } ``` **amplitudeUserId の設定** ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "amplitude_user_id", value: "YOUR_AMPLITUDE_USER_ID" ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> **amplitudeDeviceId の設定** ```kotlin showLineNumbers //for Amplitude maintenance SDK (obsolete) val amplitude = Amplitude.getInstance() val amplitudeDeviceId = amplitude.getDeviceId() val amplitudeUserId = amplitude.getUserId() //for actual Amplitude Kotlin SDK val amplitude = Amplitude( Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext ) ) val amplitudeDeviceId = amplitude.store.deviceId // Adapty.setIntegrationIdentifier("amplitude_device_id", amplitudeDeviceId) { error -> if (error != null) { // handle the error } } ``` **amplitudeUserId の設定** ```kotlin showLineNumbers //for Amplitude maintenance SDK (obsolete) val amplitude = Amplitude.getInstance() val amplitudeDeviceId = amplitude.getDeviceId() val amplitudeUserId = amplitude.getUserId() //for actual Amplitude Kotlin SDK val amplitude = Amplitude( Configuration( apiKey = AMPLITUDE_API_KEY, context = applicationContext ) ) val amplitudeUserId = amplitude.store.userId // Adapty.setIntegrationIdentifier("amplitude_user_id", amplitudeUserId) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="Flutter" label="Flutter (Dart)" default> **amplitudeDeviceId の設定** ```javascript showLineNumbers final Amplitude amplitude = Amplitude.getInstance(instanceName: "YOUR_INSTANCE_NAME"); try { await Adapty().setIntegrationIdentifier( key: "amplitude_device_id", value: amplitude.getDeviceId(), ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` **amplitudeUserId の設定** ```javascript showLineNumbers final Amplitude amplitude = Amplitude.getInstance(instanceName: "YOUR_INSTANCE_NAME"); try { await Adapty().setIntegrationIdentifier( key: "amplitude_user_id", value: "YOUR_AMPLITUDE_USER_ID", ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="Unity" label="Unity (C#)" default> **amplitudeDeviceId の設定** ```csharp showLineNumbers using AdaptySDK; Adapty.SetIntegrationIdentifier( "amplitude_device_id", amplitude.getDeviceId(), (error) => { // handle the error }); ``` **amplitudeUserId の設定** ```csharp showLineNumbers using AdaptySDK; Adapty.SetIntegrationIdentifier( "amplitude_user_id", "YOUR_AMPLITUDE_USER_ID", (error) => { // handle the error }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> **amplitudeDeviceId の設定** ```typescript showLineNumbers try { await adapty.setIntegrationIdentifier("amplitude_device_id", deviceId); } catch (error) { // handle `AdaptyError` } ``` **amplitudeUserId の設定** ```typescript showLineNumbers try { await adapty.setIntegrationIdentifier("amplitude_user_id", userId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## Amplitude イベント構造 \{#amplitude-event-structure\} AdaptyはHTTP API v2を介してAmplitudeにイベントを送信します。各イベントの構造は次のとおりです: ```json { "api_key": "your_amplitude_api_key", "events": [ { "partner_id": "adapty", "event_type": "subscription_renewed", "time": 1709294400000, "insert_id": "123e4567-e89b-12d3-a456-426614174000", "user_id": "user_12345", "device_id": "device_12345", "platform": "iOS", "os_name": "iOS", "productId": "yearly.premium.6999", "revenue": 9.99, "event_properties": { "vendor_product_id": "yearly.premium.6999", "original_transaction_id": "GPA.3383...", "currency": "USD", "environment": "Production", "store": "app_store" }, "user_properties": { "subscription_state": "subscribed", "subscription_product": "yearly.premium.6999" } } ] } ``` 各フィールドの説明: | パラメータ | 型 | 説明 | |:----------------------------|:-------|:---------------------------------------------------------------------| | `api_key` | String | Amplitude API キー。 | | `events` | Array | イベントオブジェクトのリスト(Adaptyは1件ずつ送信します)。 | | `events[].partner_id` | String | 常に "adapty"。 | | `events[].event_type` | String | イベント名(Adaptyイベントからマッピングされたもの)。 | | `events[].time` | Long | イベントのタイムスタンプ(ミリ秒)。 | | `events[].insert_id` | String | 一意のイベントID(UUID)。 | | `events[].user_id` | String | Amplitude ユーザーIDまたはカスタマーユーザーID。 | | `events[].device_id` | String | Amplitude デバイスID。 | | `events[].platform` | String | プラットフォーム(例:「iOS」、「Android」)。 | | `events[].os_name` | String | OS名。 | | `events[].productId` | String | ストアのプロダクトID。 | | `events[].revenue` | Float | 収益額。 | | `events[].event_properties` | Object | 詳細なイベント属性(利用可能な[イベントフィールド](webhook-event-types-and-fields#for-most-event-types)をすべて含む)。 | | `events[].user_properties` | Object | サブスクリプションステータスなどのユーザー属性。 | --- # File: appmetrica --- --- title: "AppMetrica" description: "AppMetricaをAdaptyと統合して、サブスクリプション分析を深化させましょう。" --- [AppMetrica](https://appmetrica.yandex.com/about) は、ユーザーの行動を追跡し、モバイルアプリのパフォーマンスをリアルタイムで分析できる無料の解析ツールです。AppMetricaをAdaptyと統合することで、サブスクリプション指標やユーザーエンゲージメントについてより深い洞察を得られます。 ## AppMetrica連携の設定方法 \{#how-to-set-up-appmetrica-integration\} AppMetrica連携の設定は、主に2つのステップで構成されます。 1. Adapty ダッシュボードで連携を設定する 2. アプリのコードに連携を実装する ### ダッシュボードの設定 \{#dashboard-configuration\} AppMetrica連携を設定するには: 1. [AppMetricaアプリ一覧](https://appmetrica.yandex.ru/application/list)を開く 2. トラッキングしたいアプリを選択する 3. **Settings > Main** に移動し、**Application ID** と **Post API key** をコピーする <img src="/assets/shared/img/appmetrica.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Adapty ダッシュボードの [Integrations > AppMetrica](https://app.adapty.io/integrations/appmetrica) に移動する 5. AppMetricaの認証情報を貼り付ける <img src="/assets/shared/img/appmetrica_creds.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### イベントとタグ \{#events-and-tags\} Adaptyでは、3つのグループのイベントをAppMetricaに送信できます。アプリのパフォーマンスを追跡するために必要なイベントを有効化してください。利用可能なイベントの完全なリストは、[イベントドキュメント](events)をご参照ください。 :::note AppMetricaは4時間ごとにイベントを同期するため、ダッシュボードにイベントが表示されるまで遅延が生じる場合があります。 ::: <img src="/assets/shared/img/6ed2d88-CleanShot_2023-08-18_at_14.59.042x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::tip 一貫性を保つためにAdaptyのデフォルトイベント名の使用を推奨しますが、既存のアナリティクス設定に合わせてカスタマイズすることも可能です。 ::: ### 収益の設定 \{#revenue-settings\} デフォルトでは、Adaptyは収益データをイベントのプロパティとして送信し、AppMetricaのEventsレポートに表示されます。この収益データの計算と表示方法を設定できます。 - **収益の計算方法**: 財務レポートのニーズに合わせて収益値の計算方法を選択します: - **総収益(Gross revenue)**: 控除前の総収益を表示します。顧客が支払う全額の追跡に役立ちます - **ストア手数料控除後の収益(Proceeds after store commission)**: App Store/Play Storeの手数料を差し引いた収益を表示します。実際の収益の追跡に役立ちます - **ストア手数料・税金控除後の収益(Proceeds after store commission and taxes)**: ストア手数料と適用される税金の両方を差し引いた純収益を表示します。最も正確な収益の把握ができます - **ユーザーの通貨で報告(Report user's currency)**: 有効にすると、売上がユーザーのローカル通貨で報告され、地域別の収益分析がしやすくなります。無効にすると、異なる市場間での一貫したレポートのためにすべての売上がUSDに変換されます。 - **収益イベントを送信(Send revenue events)**: このオプションを有効にすると、収益データがEventsレポートだけでなく、AppMetricaの[アプリ内・広告収益](https://appmetrica.yandex.com/docs/en/mobile-reports/revenue-report)レポートにも表示されます。収益の重複を避けるため、他の場所からすでに収益を送信していないことを確認してください。 - **過去のイベントを除外(Exclude historical events)**: 有効にすると、ユーザーがAdapty SDKを含むアプリをインストールする前に発生したイベントは送信されません。Adaptyを統合する前からアナリティクスにイベントを送信していた場合のデータ重複を防ぐのに役立ちます。 <img src="/assets/shared/img/appmetrica_revenue.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### SDKの設定 \{#sdk-configuration\} アプリでAppMetrica連携を有効にするには、2つの識別子を設定する必要があります。 1. `appmetrica_device_id`: 基本的な連携に必要 2. `appmetrica_profile_id`: 任意ですが、アプリにユーザー登録機能がある場合は推奨 これらの値を設定するには `setIntegrationIdentifier()` メソッドを使用します。各プラットフォームでの実装方法は以下のとおりです。 :::note サードパーティSDKはユーザーIDを非同期で生成します。`Adapty.activate()` の実行時にIDがまだ準備できていない場合があります。**Customer User ID** がこれらのSDKのいずれかから取得される場合は、IDなしで `Adapty.activate()` を呼び出してください。IDが取得できたら、`setIntegrationIdentifier()` を呼び出し、次にCUIDで `identify()` を呼び出してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="Swift" label="iOS (Swift)" default> **appmetrica_device_idの設定** ```swift showLineNumbers AppMetrica.requestStartupIdentifiers(on: nil) { ids, error in if let error { // handle AppMetrica error return } guard let deviceIDHash = ids?[.deviceIDHashKey] as? String else { // handle AppMetrica error return } Task { do { try await Adapty.setIntegrationIdentifier( key: "appmetrica_device_id", value: deviceIDHash ) } catch { // handle the error } } } ``` **appmetrica_profile_idの設定** ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "appmetrica_profile_id", value: "YOUR_APPMETRICA_PROFILE_ID" ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> **appmetrica_device_idの設定** ```kotlin showLineNumbers val startupParamsCallback = object: StartupParamsCallback { override fun onReceive(result: StartupParamsCallback.Result?) { val deviceIdHash = result?.deviceIdHash ?: return Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceIdHash) { error -> if (error != null) { // handle the error } } } override fun onRequestError( reason: StartupParamsCallback.Reason, result: StartupParamsCallback.Result? ) { //handle the error } } AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID_HASH)) ``` **appmetrica_profile_idの設定** ```kotlin showLineNumbers val startupParamsCallback = object: StartupParamsCallback { override fun onReceive(result: StartupParamsCallback.Result?) { val deviceIdHash = result?.deviceIdHash ?: return Adapty.setIntegrationIdentifier("appmetrica_device_id", deviceIdHash) { error -> if (error != null) { // handle the error } } Adapty.setIntegrationIdentifier("appmetrica_profile_id", "YOUR_ADAPTY_CUSTOMER_USER_ID") { error -> if (error != null) { // handle the error } } } override fun onRequestError( reason: StartupParamsCallback.Reason, result: StartupParamsCallback.Result? ) { //handle the error } } AppMetrica.requestStartupParams(context, startupParamsCallback, listOf(StartupParamsCallback.APPMETRICA_DEVICE_ID_HASH)) ``` </TabItem> <TabItem value="Flutter" label="Flutter (Dart)" default> **appmetrica_device_idの設定** ```javascript showLineNumbers final startupParams = await AppMetrica.requestStartupParams([AppMetricaStartupParams.deviceIdHashKey]); final deviceIdHash = startupParams.result?.deviceIdHash; if (deviceIdHash != null) { try { await Adapty().setIntegrationIdentifier( key: "appmetrica_device_id", value: deviceIdHash, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } } ``` **appmetrica_profile_idの設定** ```javascript showLineNumbers try { await Adapty().setIntegrationIdentifier( key: "appmetrica_profile_id", value: "YOUR_APPMETRICA_PROFILE_ID", ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="Unity" label="Unity (C#)" default> **appmetrica_device_idの設定** ```csharp showLineNumbers using AdaptySDK; using Io.AppMetrica; AppMetrica.RequestStartupParams( (result, errorReason) => { string deviceIdHash = result.DeviceIdHash; if (deviceIdHash != null) { Adapty.SetIntegrationIdentifier( "appmetrica_device_id", deviceIdHash, (error) => { // handle the error }); } }, new List<string>() { StartupParamsKey.AppMetricaDeviceIDHash } ); ``` **appmetrica_profile_idの設定** ```csharp showLineNumbers Adapty.SetIntegrationIdentifier( "appmetrica_profile_id", "YOUR_APPMETRICA_PROFILE_ID", (error) => { // handle the error }); ``` </TabItem> <TabItem value="RN" label="React Native (TS)" default> **appmetrica_device_idの設定** ```typescript showLineNumbers // ... const startupParamsCallback = async ( params?: StartupParams, reason?: StartupParamsReason ) => { const deviceIdHash = params?.deviceIdHash if (deviceIdHash) { try { await adapty.setIntegrationIdentifier("appmetrica_device_id", deviceIdHash); } catch (error) { // handle `AdaptyError` } } } AppMetrica.requestStartupParams(startupParamsCallback, [DEVICE_ID_HASH_KEY]) ``` **appmetrica_profile_idの設定** ```typescript showLineNumbers try { await adapty.setIntegrationIdentifier("appmetrica_profile_id", 'YOUR_ADAPTY_CUSTOMER_USER_ID'); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## AppMetricaのイベント構造 \{#appmetrica-event-structure\} AdaptyはPOSTリクエストを通じてAppMetricaにイベントを送信し、パラメーターはクエリパラメーターとして渡されます。Adaptyの各イベントに対して、AppMetricaは最大**2つの個別リクエスト**を受け取ります。 1. **プロファイルイベント**(常に送信): イベントのメタデータを含む 2. **収益イベント**(任意): Adapty ダッシュボードで「収益イベントを送信」オプションが有効な場合に収益データを含む ### プロファイルイベントリクエスト \{#profile-event-request\} 送信先: `https://api.appmetrica.yandex.ru/logs/v1/import/events` クエリパラメーター付きのURLの例: ``` POST https://api.appmetrica.yandex.ru/logs/v1/import/events?post_api_key=your_key&application_id=your_app_id&event_name=subscription_renewed&event_timestamp=1709294400&event_json=%7B%22vendor_product_id%22%3A%22yearly.premium%22...%7D&os_name=ios&ios_ifa=00000000-0000-0000-0000-000000000000&ios_ifv=12345678-1234-1234-1234-123456789012&profile_id=user_12345&session_type=foreground ``` クエリパラメーター: | パラメーター | 型 | 説明 | |:-----------------------|:-------|:----------------------------------------------------------------------------------------------------------------------------------------------------| | `post_api_key` | String | AppMetricaのPost APIキー | | `application_id` | String | AppMetricaのアプリケーションID | | `event_name` | String | イベント名(Adaptyのイベントからマッピング) | | `event_timestamp` | Long | イベントのUNIXタイムスタンプ(秒単位)。7日以上前の場合は直近7日以内に制限されます | | `event_json` | String | 利用可能な[イベントフィールド](webhook-event-types-and-fields#for-most-event-types)をすべて含むURLエンコードされたJSON文字列。nullでないフィールドのみ含まれます | | `os_name` | String | "ios" または "android" | | `profile_id` | String | AppMetricaのプロファイルID(設定されている場合)、それ以外はカスタマーユーザーID(利用可能な場合) | | `appmetrica_device_id` | String | AppMetricaのデバイスIDハッシュ。`profile_id` が利用できない場合のみ送信されます | | `session_type` | String | 常に "foreground" | | `ios_ifa` | String | **iOSのみ**。広告主向けID(IDFA) | | `ios_ifv` | String | **iOSのみ**。ベンダー向けID(IDFV) | | `google_aid` | String | **Androidのみ**。Google広告ID | ### 収益イベントリクエスト(任意) \{#revenue-event-request-optional\} 送信先: `https://api.appmetrica.yandex.ru/logs/v1/import/revenue` このリクエストは、Adapty ダッシュボードの連携設定で「収益イベントを送信」オプションが有効な場合にのみ送信されます。 クエリパラメーター付きのURLの例: ``` POST https://api.appmetrica.yandex.ru/logs/v1/import/revenue?post_api_key=your_key&application_id=your_app_id&revenue_event_type=subscription_renewed&price=9.99¤cy=USD&product_id=yearly.premium&quantity=1&transaction_id=GPA.3383...&payload=%7B%22vendor_product_id%22%3A%22yearly.premium%22...%7D&os_name=ios&ios_ifa=00000000-0000-0000-0000-000000000000&profile_id=user_12345&session_type=foreground ``` クエリパラメーター: | パラメーター | 型 | 説明 | |:---------------------|:--------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `post_api_key` | String | AppMetricaのPost APIキー | | `application_id` | String | AppMetricaのアプリケーションID | | `revenue_event_type` | String | 収益イベントのタイプ(例:"subscription_renewed"、"refund"、"intro_started")。[AppMetricaのイベントマッピング](#revenue-event-type-mapping)をご参照ください | | `price` | Float | 収益額(収益計算設定に基づく) | | `currency` | String | 通貨コード(例:"USD") | | `product_id` | String | ストアのプロダクトID | | `quantity` | Integer | 常に1 | | `transaction_id` | String | ストアのトランザクションID | | `payload` | String | イベントの詳細を含むURLエンコードされたJSON文字列。30KBを超える場合は、最も重要なデータを保持するために重要度の低いフィールドから順に削除されて自動的にトリミングされます | | `os_name` | String | "ios" または "android" | | `profile_id` | String | AppMetricaのプロファイルID(設定されている場合)、それ以外はカスタマーユーザーID(利用可能な場合) | | `appmetrica_device_id` | String | AppMetricaのデバイスIDハッシュ。`profile_id` が利用できない場合のみ送信されます | | `session_type` | String | 常に "foreground" | | `ios_ifa` | String | **iOSのみ**。広告主向けID(IDFA) | | `ios_ifv` | String | **iOSのみ**。ベンダー向けID(IDFV) | | `google_aid` | String | **Androidのみ**。Google広告ID | --- # File: firebase-and-google-analytics --- --- title: "FirebaseとGoogle Analytics" description: "AdaptyのサブスクリプションイベントをFirebaseとGoogle Analyticsに送信して、オーディエンス、リモートコンフィグ、Google広告アトリビューション、その他のFirebaseツールを活用しましょう。" --- Adaptyは、購入・更新・返金・トライアル開始などのサブスクリプションイベントをFirebaseとGoogle Analyticsに送信できます。1つの連携で両方にデータを届けられます。 :::warning Firebase プロジェクトと、それにリンクされた Google Analytics プロパティの両方が必要です。どちらか一方しか使わない場合でも同様です。Firebase と Google Analytics は、2つのコンソールで表示される同じデータです。 ::: 購入と返金のイベントは、収益、通貨、プロダクトの詳細を付加した状態で届きます。同じデータが Firebase のモバイルツール(Audiences、Remote Config など)と Google Analytics のレポートに反映されます。 これはアナリティクス連携であり、Google 広告のアトリビューションツールではありません。詳しくは[制限事項](#limitations)をご覧ください。 ## このインテグレーションでできること \{#what-you-can-do-with-this-integration\} Adapty はユーザーを `subscription_state`(`subscribed`、`active_trial`、`never_subscribed` など)でグループ化し、サブスクリプションのライフサイクルイベントを Firebase および Google Analytics に転送します。 - **オーディエンス**: Firebase と Google Analytics でサブスクライバーオーディエンスを作成し、外部チャネルに活用 — Google Ads リターゲティング、FCM キャンペーン、類似ユーザーモデリング。 - **Google Ads コンバージョン** *(Google Analytics)*: `purchase` および `refund` を Google Ads のコンバージョン目標として使用。 - **Firebase Remote Config**: アプリを更新せずに利用制限、コピー、機能フラグを変更 — サブスクリプション状態を条件として設定。(フロー/ペイウォールのコンテンツを設定する [Adapty リモートコンフィグ](customize-paywall-with-remote-config) とは異なります。) - **Cloud Messaging**: アプリが閉じているときに離脱したサブスクライバーへプッシュ通知を送信。 - **クロスデバイストラッキング** *(Google Analytics)*: Adapty が `customer_user_id` を Google Analytics に送信することで、Google Ads が同一ユーザーを複数デバイスにまたがって追跡可能に。 - **コンバージョンファネル** *(Google Analytics)*: ユーザーがコンバージョンまたはチャーンに至る前にアプリ内で何を行ったか確認。 - **予測**: 購入履歴を使ってチャーンや支出を予測。 - **A/B テスト**: サブスクライバーコホートを対象にアプリ機能をテスト — たとえば、トライアルユーザーに新しいナビゲーションパターンを展開してセッション長を計測。(ペイウォールのバリアントには [Adapty A/B テスト](ab-tests) を使用してください。) ## インテグレーションの仕組み \{#how-the-integration-works\} 1. ユーザーが初めてアプリを開くと、Firebase SDK はインストールに対して一意の識別子(**Firebase App Instance ID**)を生成します。Firebase と Google Analytics はこの ID を使って、各イベントの発生元となるインストールを特定します。 2. アプリは Firebase App Instance ID を Adapty の SDK に渡します。Adapty はユーザーのプロファイルをこの Firebase インストールに紐づけます。 3. ユーザーが購入を行うと、Adapty のサーバーは Firebase App Instance ID を付与したうえで、イベントを Firebase にサーバー間通信で転送します。このデータのやり取りはアプリの外部で行われます。 4. Firebase は購入をインストールと照合するため、ユーザーがアプリ内で行ったその他のアクティビティと並べて購入状況を確認できます。 :::note Firebase App Instance ID はデバイス固有の情報です。同じ Adapty ユーザーが別のデバイスでアプリを開くと、新しい Firebase ID が以前の ID を上書きします。デバイスをまたいでユーザーを特定し続けるには、[カスタマーユーザー ID](identifying-users) を使用してください。 ::: ### Stripe の購入 \{#stripe-purchases\} Stripe の購入が Firebase に届くのは、購入者がまず**モバイルアプリを起動した場合**に限られます。Stripe の購入が実行される**前に**、Firebase App Instance ID が設定されている必要があります。 App Store および Play Store の購入では、これは自動的に行われます。これらの購入はモバイルアプリ内から発生し、[`setIntegrationIdentifier`](#configure-your-app-code) の呼び出しと同時に行われます。購入が実行される時点で Firebase ID は既に存在しています。 Stripe の購入はアプリ外、つまりサーバー側で行われます。モバイルアプリは起動時に `setIntegrationIdentifier` を呼び出す必要があります — Stripe の購入が発生する前に。そうしないと、Adapty にアタッチする ID がなく、Stripe の購入が Firebase に届きません。 ### 制限事項 \{#limitations\} - **Google Ads アトリビューションツールではありません。** このインテグレーションは、Adapty のイベントを Firebase および Google Analytics に送信してアナリティクスに活用するものです。Google Ads キャンペーン(UAC / ユニバーサルアプリキャンペーン)へのアプリインストールのアトリビューションや、有料トラフィックとオーガニックトラフィックの区別には対応していません。インストールアトリビューションには、Adapty の組み込み機能である [Adapty アトリビューション](adapty-user-acquisition) をご利用ください。 - **過去データの遡及入力はできません。** Adapty は、インテグレーションを有効にした時点以降のイベントを転送します。過去の購入・更新・返金のデータが Firebase に届くことはありません。(過去のデータは Adapty の [S3](s3-exports) / [GCS](google-cloud-storage) エクスポートに保存されていますが、Firebase へのインポートはこのインテグレーションの対象外です。) - **Web 専用の購入者は Firebase に届きません。** Adapty は、モバイルアプリが設定した Firebase App Instance ID を使って購入データを Firebase に転送します。アプリをインストールしていない購入者には ID が存在しないため、その購入データは Firebase に届きません。詳細は上記の [Stripe 購入](#stripe-purchases) をご参照ください。Web トラッキングには [FunnelFox の Firebase インテグレーション](https://funnelfox.com/docs/integrations/subscription-management/adapty) または Google Analytics の Web データストリームの利用をご検討ください。 - **Paddle の購入は対象外です。** このインテグレーションは現時点で Paddle に対応していません。Paddle の購入は Adapty アナリティクス内に留まり、このパスを通じて Firebase に届くことはありません。 - **Stripe の購入には Stripe 固有の制限が適用されます。** 詳細は [Stripe インテグレーションの制限事項](stripe#current-limitations) をご確認ください。 ## セットアップ手順 \{#setup-instructions\} ### Firebase を設定する \{#configure-firebase\} 1. [Firebase Console](https://console.firebase.google.com/) を開き、プロジェクトを選択または作成します。サンドボックスイベントを本番のアナリティクスに混入させないために、開発ビルド用には別の Firebase プロジェクトを使用してください。 2. プロジェクトを Google Analytics プロパティにリンクします。Firebase ではプロジェクト作成時にリンクを促しますが、後から **Project settings** > **Integrations** > **Google Analytics** で追加することもできます。 3. **Project settings** > **General** > **Your apps** で、リリースするプラットフォーム(iOS / Android / Web)ごとにエントリを追加します。Stripe の場合は Web アプリのエントリを追加してください(Stripe 専用のネイティブアプリタイプはありません)。各エントリには固有の **Firebase App ID** が生成され、Google Analytics 上に対応するデータストリームが作成されます。この ID は、セットアップ時に Adapty の Firebase インテグレーション設定に貼り付けます。 ### Adapty を設定する \{#configure-adapty\} 1. Adapty ダッシュボードで [**Integrations** > **Firebase**](https://app.adapty.io/integrations/firebase) を開きます。 2. **Firebase integration** トグルを有効にします。 3. 対応している各プラットフォームの認証情報を入力します。Adapty は各プラットフォームに対して **Firebase App ID** と **Google Analytics secret** の両方が必要です。各値は iOS、Android、Stripe で異なります。 | Adapty ダッシュボード | Google Analytics | 確認場所 | | --- | --- | --- | | **Firebase App ID** | **App ID** | Firebase Console > **Project settings** > **General** > **Your apps** | | **Google Analytics secret** | **Measurement Protocol API secret** | Google Analytics > **Admin** > **Data streams** > **Measurement Protocol API secrets** > **Create** | 4. Adapty がどのように収益とユーザーデータを転送するかを設定します。4つのコントロールはダッシュボードの1行に並んでいます: - **Revenue definition** ドロップダウン: 総収益、ストア手数料控除後の収益、または[ストア手数料・税金控除後の収益](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)。 - **Send user properties** トグル: オンにすると、イベントに `subscription_state` と `subscription_product_id` が含まれます。レポートやオーディエンスでの活用方法は[レポートでサブスクリプションデータを使用する](#use-subscription-data-in-reports-and-audiences)をご覧ください。 - **Report user's currency** トグル: オンにすると、Adapty は各トランザクションの現地通貨をアカウントのレポート通貨に変換してから Google Analytics に送信します。 - **Send trial price** トグル: トライアル開始は重要です。多くの有料ユーザーはトライアルから始めることが多いからです。しかし Google 広告の入札最適化は、収益を伴うイベントのみを追跡対象として扱います。このトグルをオンにすると、各トライアルにダミーの価格が割り当てられ、Google がコンバージョンとして認識し、トライアル開始ユーザーの獲得に向けて広告費を最適化できます。オンにすると **Trial price percentage** フィールドが表示されます。Google が各トライアルの価値として扱うべき、フルサブスクリプション価格に対する割合を設定してください。例えば `50%` と設定すると、トライアル中はサブスクリプション価格の半額がレポートされます。 5. Adapty イベントを Firebase/Google Analytics のイベント名にマッピングします。Adapty では **iOS** と **Android** ごとに個別のイベントマップを用意しているため、プラットフォームごとに異なる名前を使用できます。**Stripe の購入には iOS のイベントマップが使用されます** — Stripe 専用のマップはありません。 Google Analytics は、Measurement Protocol に厳格な制限を設けています。イベント名は40文字、ユーザープロパティ名は24文字、値は36文字が上限です。これらの制限を超えるカスタムイベントは、Google Analytics によって警告なしに破棄されます。 :::warning 一部のイベントは、Firebase および Google Analytics の予約済みeコマース語彙(`purchase` および `refund`)を使用しています。Google 広告のコンバージョンインポート、Google Analytics の収益レポート、予測オーディエンスはこれらの正確な文字列に依存しています。これらの機能が不要な場合にのみ、デフォルト値を変更してください。 ::: 6. **Save** をクリックします。数分以内に Adapty が Firebase へのイベント転送を開始します。 ### アプリコードの設定 \{#configure-your-app-code\} :::tip アプリに <InlineTooltip tooltip="Firebase SDK">[iOS](https://firebase.google.com/docs/ios/setup)、[Android](https://firebase.google.com/docs/android/setup)、[Flutter](https://firebase.google.com/docs/flutter/setup)、[Unity](https://firebase.google.com/docs/unity/setup)、[React Native](https://rnfirebase.io/)、[Capacitor](https://github.com/capawesome-team/capacitor-firebase)</InlineTooltip> が含まれていることを確認してください。 ::: Adaptyが各イベントに**Firebase App Instance ID**を含める必要があります。これがないとFirebaseにデータが届きません(`MISSING_INTEGRATION_ID`)。 `FirebaseApp.configure()`と`Adapty.activate()`の後、Firebase SDKにApp Instance IDを問い合わせ、`setIntegrationIdentifier`経由でAdaptyに渡してください。この処理は購入フローの前に、アプリ起動ごとに1回実行してください。 :::note サードパーティSDKはユーザーIDを非同期で生成します。`Adapty.activate()` の実行時にIDがまだ準備できていない場合があります。**Customer User ID** がこれらのSDKのいずれかから取得される場合は、IDなしで `Adapty.activate()` を呼び出してください。IDが取得できたら、`setIntegrationIdentifier()` を呼び出し、次にCUIDで `identify()` を呼び出してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> <Tabs groupId="sdk-version" queryString> <TabItem value="v4" label="Adapty SDK v4+"> ```swift showLineNumbers FirebaseApp.configure() if let appInstanceId = Analytics.appInstanceID() { do { try await Adapty.setIntegrationIdentifier(.firebaseAppInstanceId(appInstanceId)) } catch { // handle the error } } ``` </TabItem> <TabItem value="v3" label="Adapty SDK v3" default> ```swift showLineNumbers FirebaseApp.configure() if let appInstanceId = Analytics.appInstanceID() { do { try await Adapty.setIntegrationIdentifier( key: "firebase_app_instance_id", value: appInstanceId ) } catch { // handle the error } } ``` </TabItem> </Tabs> </TabItem> <TabItem value="kotlin" label="Android (Kotlin)"> ```kotlin showLineNumbers // after Adapty.activate() FirebaseAnalytics.getInstance(context).appInstanceId.addOnSuccessListener { appInstanceId -> Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId) { error -> if (error != null) { // handle the error } } } ``` </TabItem> <TabItem value="java" label="Android (Java)"> ```java showLineNumbers // after Adapty.activate() FirebaseAnalytics.getInstance(context).getAppInstanceId().addOnSuccessListener(appInstanceId -> { Adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId, error -> { if (error != null) { // handle the error } }); }); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)"> ```dart showLineNumbers final appInstanceId = await FirebaseAnalytics.instance.appInstanceId; if (appInstanceId != null) { try { await Adapty().setIntegrationIdentifier( key: "firebase_app_instance_id", value: appInstanceId, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } } ``` </TabItem> <TabItem value="unity" label="Unity (C#)"> ```csharp showLineNumbers using AdaptySDK; using Firebase.Analytics; FirebaseAnalytics .GetAnalyticsInstanceIdAsync() .ContinueWithOnMainThread((task) => { if (!task.IsCompletedSuccessfully) { // handle the error return; } Adapty.SetIntegrationIdentifier( "firebase_app_instance_id", task.Result, (error) => { // handle the error } ); }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)"> ```typescript showLineNumbers try { const appInstanceId = await analytics().getAppInstanceId(); if (appInstanceId) { await adapty.setIntegrationIdentifier("firebase_app_instance_id", appInstanceId); } } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ### インテグレーションを確認する \{#verify-the-integration\} イベントが正しく流れているかを確認する最も手軽な方法は、Firebase DebugView です。 1. テストデバイスで、[Firebase デバッグモードを有効にした](https://firebase.google.com/docs/analytics/debugview#enable_debug_mode)状態でアプリを起動します。 2. サンドボックス購入、または Adapty ダッシュボードで有効にしたイベントをトリガーします。 3. Firebase Console > **Analytics** > **DebugView** を開きます。イベントはすべてのパラメーターとともに数秒以内に表示されます。 リアルタイム、レポート、オーディエンスなどの標準レポートは、レポートの種類に応じて数分〜24時間以内に反映されます。リアルタイムで確認できるのは DebugView だけです。 ## レポートやオーディエンスでサブスクリプションデータを活用する \{#use-subscription-data-in-reports-and-audiences\} **Send user properties** を Adapty ダッシュボードで有効にしてください([Adapty の設定](#configure-adapty)、手順 4)。これを有効にしないと、Adapty は `subscription_state` や `subscription_product_id` を転送しないため、このセクションの内容は機能しません。 デフォルトでは、FirebaseとGoogle Analyticsはユーザープロパティを公開しません。それぞれをカスタムディメンションとして登録することで、`subscription_state`と`subscription_product_id`がレポート、Explorations、オーディエンスで利用できるようになります。ディメンションはGoogle Analytics管理画面で設定します。FirebaseとGoogle Analyticsはバックエンドを共有しているため、両方でクエリを実行できます。 有料ユーザーのGoogle Adsオーディエンスを構築したり、予測モデルへのデータ供給に役立ちます。 設定が完了すると、Adaptyはそれ以降のイベントにこれらのプロパティを付与します。既存のイベントは更新されません。 1. Google Analytics で **Admin** > **Custom definitions** を開きます。 2. **Create custom dimensions** をクリックします。 3. 各プロパティに以下を設定します: - **Dimension name**:人間が読める任意の名前。例:「Subscription state」。 - **Scope**:**User**。 - **User property**:`subscription_state` または `subscription_product_id`。名前は完全に一致している必要があります。Google Analytics は大文字と小文字を区別します。 ## トラブルシューティング \{#troubleshooting\} ### Firebaseにイベントが表示されない \{#events-dont-appear-in-firebase\} - Firebaseアプリインスタンスの ID が、**最初の購入が行われる前**に設定されていることを確認してください。Firebase IDが設定されていないイベントはFirebaseに届かず、エラーが発生します。 - Firebase ConsoleでリンクされているGoogle Analyticsプロパティがデータストリームと一致していることを確認してください。 - Adaptyに設定した認証情報(IDとシークレット)がプラットフォームと一致していることを確認してください。 ### `access_level_updated` がイベントフィードで失敗と表示される \{#access_level_updated-shows-as-failed-in-the-event-feed\} `access_level_updated` は **Webhook 専用イベント**です。Adapty は Firebase へのこのイベントの配信を試みません。ただし、イベントフィードには配信失敗として表示されます。この行は無視してください。インテグレーションは正常です。このイベントを使用するには、[Webhook インテグレーション](webhook)を設定してください。 ### サンドボックスイベントが本番データを汚染する \{#sandbox-events-pollute-production-data\} Adapty はサンドボックスと本番のトランザクションを同じ Firebase プロジェクトに転送します。[Firebase の設定](#configure-firebase) を参照してください — 開発ビルド用に別の Firebase プロジェクトを使うことで、この問題を完全に回避できます。 ### StoreKit 2 アプリでは Firebase が収益を過小計上する \{#firebase-undercounts-revenue-for-storekit-2-apps\} Firebase は StoreKit 1 のすべての購入に対して `in_app_purchase` イベントを自動ログに記録します — コード不要です。StoreKit 2 は異なる API を使用しており、Firebase はそれらのトランザクションを認識できません。 その影響として、別の収益パイプラインを持たない SK2 中心のアプリでは、Firebase・Google Analytics・下流のすべての Google 広告キャンペーンで収益が半分以下に過小報告されます。入札の最適化は誤った数値に基づいて動作し、収益レポートには実態の半分しか表示されません。 修正方法:`firebase_app_instance_id` を Adapty に渡してください([アプリコードの設定](#configure-your-app-code)を参照)。Adapty は Measurement Protocol を通じて、収益・通貨・プロダクトを含むすべての購入データを転送します。 ### Adapty アナリティクスと Firebase の数値が一致しない \{#adapty-analytics-and-firebase-numbers-diverge\} - **StoreKit 2**: 最大の原因はこれです。[StoreKit 2 アプリにおける Firebase の収益過小計上](#firebase-undercounts-revenue-for-storekit-2-apps)をご覧ください。 - **SDK の普及率**: Firebase がイベントをカウントするのは、Firebase App Instance ID を送信しているアプリのユーザーのみです。古いバージョンのアプリはこの呼び出しを行いません。Adapty はそれらのユーザーもカウントしますが、Firebase はカウントしません。 - **サンドボックスイベント**: Adapty はサンドボックスのトランザクションも Firebase に転送します。開発ビルドとの混在を避けるために、開発用には別の Firebase プロジェクトを使用してください。 - **サンプリング**: Google Analytics のエクスプロレーションは大規模なデータセットをサンプリングします。サンプリングなしの数値を確認するには、リアルタイムビューまたは標準レポートを参照してください。 ### カスタムイベント名が Google Analytics に拒否される \{#custom-event-names-are-rejected-by-google-analytics\} Google Analytics のイベント名は、40文字以内、英数字とアンダースコアのみ、かつ先頭が英字である必要があります。これらの制限に違反するカスタム Adapty イベントは、ダッシュボードで名前を変更してください。 --- # File: mixpanel --- --- title: "Mixpanel" description: "Adapty と Mixpanel を連携して、強力なサブスクリプション分析を実現しましょう。" --- [Mixpanel](https://mixpanel.com/home/) は強力なプロダクト分析サービスです。イベントドリブンのトラッキングソリューションにより、プロダクトチームはさまざまなプラットフォームにおけるユーザー獲得・コンバージョン・リテンション戦略について深い知見を得ることができます。 この連携により、Adapty のすべてのイベントを Mixpanel に送信できます。その結果、サブスクリプションビジネスとユーザー行動をより包括的に把握できるようになります。Adapty はストアからの[サブスクリプションイベント](events)を一か所で追跡できる完全なデータセットを提供します。Adapty を使えば、サブスクライバーの行動を簡単に把握し、好みを理解し、その情報をもとにターゲットを絞った効果的なコミュニケーションを行えます。 ## Mixpanel 連携の設定方法 \{#how-to-set-up-mixpanel-integration\} 1. Adapty ダッシュボードで [Integrations -> Mixpanel](https://app.adapty.io/integrations/mixpanel) ページを開きます。 2. トグルを有効にして **Mixpanel Token** を入力します。すべてのプラットフォームに対してトークンを指定するか、特定のプラットフォームからのみデータを受け取りたい場合はプラットフォームを絞り込むこともできます。 3. **Mixpanel Data Residency** を Mixpanel プロジェクトに合わせて設定します。このフィールドは必須で、デフォルトは **US** です。`api.mixpanel.com` エンドポイントを使用する場合は **US** を、`api-eu.mixpanel.com` を使用する場合は **Europe** を選択してください。 :::warning Mixpanel プロジェクトが EU データレジデンシーを使用している場合、**Mixpanel Data Residency** を **Europe** に設定する必要があります。EU プロジェクトから US エンドポイントに送信されたイベントは Mixpanel によって破棄されます。 ::: <img src="/assets/shared/img/mixpanel.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Mixpanel トークンの確認方法 \{#finding-your-mixpanel-token\} **Mixpanel Token** を取得するには: 1. [Mixpanel ダッシュボード](https://mixpanel.com/settings/project/)にログインします。 2. **Settings** を開き、**Organization Settings** を選択します。 <img src="/assets/shared/img/mixpanel-settings.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 左サイドバーから **Projects** に移動し、プロジェクトを選択します。 <img src="/assets/shared/img/mixpanel-project-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 連携の仕組み \{#how-the-integration-works\} Adapty は、ユーザー ID や売上などの関連イベントプロパティを[Mixpanel ネイティブプロパティ](https://docs.mixpanel.com/docs/data-structure/user-profiles)に自動的にマッピングします。これにより、サブスクリプション関連イベントの正確なトラッキングとレポーティングが実現されます。 また、Adapty はユーザーごとに売上データを蓄積し、`subscription state` や `subscription product ID` などの[ユーザープロファイルプロパティ](https://docs.mixpanel.com/docs/data-structure/user-profiles)を更新します。イベントを受信すると、Mixpanel は対応するフィールドをリアルタイムで更新します。 ## イベントとタグ \{#events-and-tags\} 認証情報の下には、Adapty から Mixpanel に送信できるイベントが 3 つのグループに分かれています。必要なものをオンにするだけです。Adapty が提供するイベントの完全な一覧は[こちら](events)をご確認ください。 <img src="/assets/shared/img/mixpanel-events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty が提供するデフォルトのイベント名を使用することをお勧めします。ただし、必要に応じてイベント名を変更することも可能です。 ## SDK の設定 \{#sdk-configuration\} `.setIntegrationIdentifier()` メソッドを使用して `mixpanelUserId` を設定します。設定しない場合、Adapty はユーザー ID(`customerUserId`)を使用し、それが null の場合は Adapty ID を使用します。アプリから Mixpanel にデータを送信する際に使用するユーザー ID と、Adapty に送信するユーザー ID が同じであることを確認してください。 :::note サードパーティSDKはユーザーIDを非同期で生成します。`Adapty.activate()` の実行時にIDがまだ準備できていない場合があります。**Customer User ID** がこれらのSDKのいずれかから取得される場合は、IDなしで `Adapty.activate()` を呼び出してください。IDが取得できたら、`setIntegrationIdentifier()` を呼び出し、次にCUIDで `identify()` を呼び出してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "mixpanel_user_id", value: Mixpanel.mainInstance().distinctId ) } catch { // handle the error } ``` </TabItem> <TabItem value="swift-callback" label="iOS (Swift-Callback)" default> ```swift showLineNumbers let builder = AdaptyProfileParameters.Builder() .with(mixpanelUserId: Mixpanel.mainInstance().distinctId) Adapty.updateProfile(params: builder.build()) ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelAPI.distinctId) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers final mixpanel = await Mixpanel.init("Your Token", trackAutomaticEvents: true); final distinctId = await mixpanel.getDistinctId(); try { await Adapty().setIntegrationIdentifier( key: "mixpanel_user_id", value: distinctId, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; var distinctId = Mixpanel.DistinctId; if (distinctId != null) { Adapty.SetIntegrationIdentifier( "mixpanel_user_id", distinctId, (error) => { // handle the error }); } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // If you already have a shared Mixpanel instance in your app, use that instance instead. const trackAutomaticEvents = true; const mixpanel = new Mixpanel('YOUR_PROJECT_TOKEN', trackAutomaticEvents); await mixpanel.init(); // This is Mixpanel's current distinct_id (auto-generated, or set via mixpanel.identify(...)) const mixpanelUserId = await mixpanel.getDistinctId(); try { await adapty.setIntegrationIdentifier("mixpanel_user_id", mixpanelUserId); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> ## Mixpanel イベントの構造 \{#mixpanel-event-structure\} Adapty は `track` メソッドを使用して Mixpanel にイベントを送信します。イベントプロパティの構造は次のとおりです: ```json { "event": "subscription_renewed", "properties": { "ip": 0, "time": 1709294400, "$insert_id": "123e4567-e89b-12d3-a456-426614174000", "vendor_product_id": "yearly.premium.6999", "original_transaction_id": "GPA.3383...", "currency": "USD", "environment": "Production", "store": "app_store", "purchase_date": "2024-03-01T12:00:00.000000+0000" } } ``` 各パラメータの説明: | パラメータ | 型 | 説明 | |:-------------------------------------|:--------|:--------------------------------------------------| | `event` | String | イベント名(Adapty イベントからマッピング)。 | | `properties` | Object | イベントプロパティ。 | | `properties.ip` | Integer | IP アドレス(サーバー間通信では 0 として送信)。 | | `properties.time` | Long | イベントの UNIX タイムスタンプ(秒単位)。 | | `properties.$insert_id` | String | 重複排除用のユニークイベント ID(UUID)。 | | `properties.vendor_product_id` | String | ストアのプロダクト ID。 | | `properties.original_transaction_id` | String | 元のトランザクション ID。 | | `properties.currency` | String | 通貨コード。 | | `properties.store` | String | ストア名(例:「app_store」)。 | | `properties.environment` | String | 環境(「Sandbox」または「Production」)。 | ### ユーザープロファイルの更新 \{#user-profile-updates\} Adapty は `people_set` を使用して、以下のプロパティで Mixpanel ユーザープロファイルも更新します: | パラメータ | 型 | 説明 | |:--------------------------|:-------|:------------------------------------------------------| | `subscription_state` | String | 現在のサブスクリプション状態(例:「subscribed」)。 | | `subscription_product_id` | String | アクティブなサブスクリプションプロダクトの ID。 | --- # File: posthog --- --- title: "PostHog" description: "" --- PostHog は、ユーザー行動のトラッキング、プロダクト利用状況の可視化、リテンション分析などのツールを提供するアナリティクスプラットフォームです。イベントトラッキング、ユーザーフロー、フィーチャーフラグといった機能を備え、プロダクトをより深く理解して改善するために設計されています。 PostHog と Adapty を連携することで、トライアル開始・更新・解約といったサブスクリプション関連イベントをシームレスにトラッキングできます。これらのイベントを PostHog に送信することで、サブスクリプションの変化がユーザー行動に与える影響を分析したり、ペイウォールのパフォーマンスを評価したり、マネタイズ戦略に関するより深いインサイトを得たりできます — すべて既存のアナリティクスワークフロー内で完結します。 ## 連携の特性 \{#integration-characteristics\} | 連携の特性 | 説明 | | -------------------------- | ------------------------------------------------------------ | | スケジュール | リアルタイム。イベントが PostHog ダッシュボードにすぐ表示されない場合があります。 | | データの方向 | Adapty のイベントは Adapty サーバーから PostHog サーバーへ送信されます。 | | Adapty の連携ポイント | <ul><li>モバイルアプリのコード内の PostHog と Adapty SDK</li><li>Adapty サーバー</li></ul> | ## PostHog イベントの構造 \{#posthog-event-structure\} Adapty は、[PostHog 連携ページ](https://app.adapty.io/integrations/posthog)の **Events names** セクションで設定されたイベントを PostHog に送信します。各イベントの構造は以下のとおりです: ```json showLineNumbers { "distinct_id": "john.doe@example.com", "timestamp": "2025-01-08T11:06:12+00:00", "event": "subscription_started", "properties": { "$set": { "email": "user@example.com", "first_name": "John", "last_name": "Doe", "birthday": "1990-01-01", "gender": "male", "os": "iOS" }, "timezone": "America/New_York", "ip_address": "10.168.1.1", "*": "{{other_event_properties}}" } } ``` 各パラメーターの説明: | **パラメーター** | **型** | **説明** | | --------------- | -------------------- | ------------------------------------------------------------ | | **distinct_id** | String | ユーザーの一意識別子(例:`profile.posthog_distinct_user_id`、`customer_user_id`、または `profile_id`)。 | | **timestamp** | ISO 8601 日時 | イベントの日時。 | | **event** | String | [PostHog 設定](https://app.adapty.io/integrations/posthog)の Events names セクションで定義したイベント名。 | | **properties** | Object | [properties.$set](posthog#propertiesset-parameters) と [イベント固有のプロパティ](messaging#event-properties)をすべて含みます。各プロパティはオプションであり、値がない場合は PostHog に送信されません。 | ### properties.$set パラメーター \{#propertiesset-parameters\} `properties.$set` オブジェクトの各パラメーターはオプションであり、値がない場合は PostHog に送信されません。 | **パラメーター** | **型** | **説明** | | --------------- | -------------------- | ------------------------------------------------------------ | | **email** | String | ユーザーのメールアドレス。 | | **first_name** | String | ユーザーの名。 | | **last_name** | String | ユーザーの姓。 | | **birthday** | String (Date) | ユーザーの生年月日。 | | **gender** | String | ユーザーの性別。 | | **os** | String | ユーザーのデバイスのOS。 | ## PostHog 連携の設定 \{#setting-up-posthog-integration\} 1. Adapty ダッシュボードで [Integrations -> PostHog](https://app.adapty.io/integrations/posthog) ページを開き、トグルを有効にします。 <img src="/assets/shared/img/posthog-on.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. [PostHog ダッシュボード](https://posthog.com/)にログインします。 3. **Settings -> Project** に移動します。 <img src="/assets/shared/img/posthog-settings.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Project** ウィンドウで下にスクロールして **Project ID** セクションを表示し、**Project API key** をコピーします。 5. APIキーを Adapty ダッシュボードの **Project API key** フィールドに貼り付けます。PostHog にはサーバー間連携専用のサンドボックスモードはありません。 6. **PostHog Deployment** を選択します: | オプション | 説明 | | ------ | ------------------------------------------------------------ | | us/eu | PostHog がホストするデフォルトのデプロイメント。 | | Custom | セルフホスト環境向け。**PostHog Instance URL** フィールドにインスタンスのURLを入力します。 | 7. (任意)セルフホストの PostHog デプロイメントを使用している場合は、**PostHog Instance URL** フィールドにデプロイメントのアドレスを入力します。 8. (任意)**Reporting Proceeds**、**Exclude Historical Events**、**Report User's Currency**、**Send Trial Price** などの設定を調整します。これらのオプションの詳細は [Integration settings](configuration#integration-settings) を参照してください。 9. (任意)**Events names** セクションで PostHog に送信するイベントをカスタマイズすることもできます。不要なイベントを無効にしたり、名前を変更したりできます。 10. **Save** をクリックして設定を確定します。 ## SDK の設定 \{#sdk-configuration\} PostHog からアトリビューションデータを受け取るには、以下のように `distinctId` の値を Adapty に渡してください: :::note サードパーティSDKはユーザーIDを非同期で生成します。`Adapty.activate()` の実行時にIDがまだ準備できていない場合があります。**Customer User ID** がこれらのSDKのいずれかから取得される場合は、IDなしで `Adapty.activate()` を呼び出してください。IDが取得できたら、`setIntegrationIdentifier()` を呼び出し、次にCUIDで `identify()` を呼び出してください。 ::: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="Swift" default> ```swift showLineNumbers do { let distinctId = PostHogSDK.shared.getDistinctId() try await Adapty.setIntegrationIdentifier( key: "posthog_distinct_user_id", value: distinctId ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Kotlin" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("posthog_distinct_user_id", PostHog.distinctId()) { error -> if (error != null) { // handle the error } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers Adapty.setIntegrationIdentifier("posthog_distinct_user_id", PostHog.distinctId(), error -> { if (error != null) { // handle the error } }); ``` </TabItem> <TabItem value="flutter" label="Flutter" default> ```javascript showLineNumbers try { final distinctId = await Posthog().getDistinctId(); await Adapty().setIntegrationIdentifier( key: "posthog_distinct_user_id", value: distinctId, ); } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity" default> Unity 向けの公式 PostHog SDK はありません。 </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // ... const posthog = usePostHog(); // ... try { await adapty.setIntegrationIdentifier("posthog_distinct_user_id", posthog.getDistinctId()); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> Adapty は PostHog へのイベント送信とアトリビューションの受信を行えるようになりました。 --- # File: splitmetrics --- --- title: "SplitMetrics Acquire" description: "サブスクリプションの A/B テストと最適化のために SplitMetrics と Adapty を使用する。" --- [SplitMetrics Acquire](https://splitmetrics.com/acquire/) との連携により、Apple Search Ads でのサブスクリプション収益を正確に把握できます。また、数か月にわたってユーザーをトラッキングし、広告が長期的にどれだけ収益をもたらすかを確認できます。 さらに、Adapty は [サブスクリプションイベント](events) を SplitMetrics Acquire に送信するため、Apple Search Ads のアトリビューションをもとにカスタムダッシュボードや自動化を構築できます。 ASA から必要なアトリビューションデータはすでに直接取得しているため、Adapty 側にアトリビューションデータが追加されることはありません。 ## SplitMetrics Acquire 連携のセットアップ方法 \{#how-to-set-up-splitmetrics-acquire-integration\} SplitMetrics Acquire を連携するには、[Integrations > SplitMetrics Acquire](https://app.adapty.io/integrations/splitmetrics) に移動して認証情報を設定してください。 <img src="/assets/shared/img/8255349-CleanShot_2023-08-14_at_17.39.422x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> SplitMetrics Acquire のアカウントを開き、いずれかの MMP ロゴにカーソルを合わせて **Settings** ボタンをクリックします。ダイアログの項目 **5** に表示されている Client ID をコピーし、Adapty の **Client ID** フィールドに貼り付けてください。 <img src="/assets/shared/img/4d0b2b6-Adapty.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/4f8d0b8-AdaptyGuide.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 連携を使用するには Apple App ID の設定も必要です。App ID を確認するには、App Store Connect でアプリのページを開き、**General** セクションの **App Information** ページに移動して、画面左下の **Apple ID** を確認してください。 <img src="/assets/shared/img/61578ee-CleanShot_2022-04-20_at_17.55.03.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## イベントとタグ \{#events-and-tags\} 認証情報の下に、Adapty から SplitMetrics Acquire に送信できる 3 つのイベントグループがあります。必要なものをオンにするだけです。Adapty が提供するイベントの全一覧は[こちら](events)をご確認ください。 <img src="/assets/shared/img/1b0c777-CleanShot_2023-08-11_at_14.56.362x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty が提供するデフォルトのイベント名を使用することをおすすめします。ただし、必要に応じてイベント名を変更することも可能です。Adapty はサーバー間連携を使用してサブスクリプションイベントを SplitMetrics Acquire に送信するため、SplitMetrics ダッシュボードですべてのサブスクリプションイベントを確認できます。 ## SDK の設定 \{#sdk-configuration\} SDK 側での設定は不要ですが、精度向上のために `customerUserId` を Adapty に送信することをおすすめします。 :::warning [Apple Search Ads](apple-search-ads) を Adapty で設定し、[認証情報をアップロード](https://app.adapty.io/settings/apple-search-ads)していることを確認してください。これらがない場合、SplitMetrics Acquire は機能しません。 ::: ## トラブルシューティング \{#troubleshooting\} 正しく設定しているにもかかわらず SplitMetrics Acquire との連携が機能しない場合: - [App Settings -> Apple Search Ads タブ](https://app.adapty.io/settings/apple-search-ads) で **Receive Apple Search Ads attribution in Adapty** トグルが有効になっていること、Adapty で [Apple Search Ads](apple-search-ads) が設定されていること、および[認証情報がアップロード](https://app.adapty.io/settings/apple-search-ads)されていることを確認してください。これらがない場合、SplitMetrics は機能しません。 - プロファイルにオーガニックではない ASA アトリビューションが設定されていることを確認してください。詳細なオーガニックでない ASA アトリビューションを持つプロファイルのみ、イベントが Adapty に配信されます。 ## SplitMetrics Acquire のイベント構造 \{#splitmetrics-acquire-event-structure\} Adapty はクエリパラメーターを使用した GET リクエストで SplitMetrics Acquire にイベントを送信します。各イベントの構造は次のとおりです: ```json { "source": "Apple Search Ads", "app_id": "123456789", "name": "subscription_renewed", "type": "subscription_renewed", "revenue": 9.99, "currency": "USD", "tap_time": "2024-03-01 12:00:00", "open_time": "2024-03-01 12:05:00", "event_time": "2024-03-02 12:00:00", "adaccount_id": "123456", "campaign_id": "123456789", "adgroup_id": "123456789", "keyword_id": "123456789", "creative_set_id": "123456789", "Ad_id": "123456789", "country_or_region": "US", "conversion_type": "Download", "user_id": "user_12345", "att_status": "3", "device_type": "iphone", "app_version": "1.2.3", "sdk_version": "2.10.0", "ios_version": "17.2", "event_value": "{\"vendor_product_id\":\"yearly.premium.6999\",\"original_transaction_id\":\"GPA.3383...\"}", "event_id": "123e4567-e89b-12d3-a456-426614174000" } ``` 各パラメーターの説明: | パラメーター | 型 | 説明 | |:--------------------|:-------|:---------------------------------------------------------------------------------------------------------------| | `source` | String | 常に "Apple Search Ads"。 | | `app_id` | String | Apple App ID。 | | `name` | String | イベント名(Adapty イベントからマッピング)。 | | `type` | String | イベントタイプ(`name` と同じ)。 | | `revenue` | Float | 収益金額。 | | `currency` | String | 通貨コード。 | | `tap_time` | String | 広告タップの日時。 | | `open_time` | String | アプリを開いた(インストールした)日時。 | | `event_time` | String | イベントの日時。 | | `adaccount_id` | String | ASA 組織 ID。 | | `campaign_id` | String | ASA キャンペーン ID。 | | `adgroup_id` | String | ASA 広告グループ ID。 | | `keyword_id` | String | ASA キーワード ID。 | | `creative_set_id` | String | ASA クリエイティブセット ID。 | | `Ad_id` | String | ASA 広告 ID。 | | `country_or_region` | String | ストアの国または地域。 | | `conversion_type` | String | コンバージョンタイプ(例: "Download")。 | | `user_id` | String | カスタマーユーザー ID または Adapty プロファイル ID。 | | `att_status` | String | トラッキング使用状況ステータス(0〜3)。 | | `device_type` | String | デバイスタイプ(例: "iphone"、"ipad")。 | | `app_version` | String | アプリケーションバージョン。 | | `sdk_version` | String | Adapty SDK バージョン。 | | `ios_version` | String | iOS バージョン。 | | `event_value` | String | 利用可能なすべての[イベント詳細](webhook-event-types-and-fields#for-most-event-types)を含む JSON 文字列。 | | `event_id` | String | 一意のイベント ID(UUID)。 | --- # File: braze --- --- title: "Braze" description: "シームレスなカスタマーエンゲージメントとプッシュ通知のために、BrazeとAdaptyを統合します。" --- トップクラスのカスタマーエンゲージメントソリューションのひとつである [Braze](https://www.braze.com/) は、プッシュ通知、メール、SMS、アプリ内メッセージングなど幅広いツールを提供しています。AdaptyとBrazeを統合することで、すべてのサブスクリプションイベントを一箇所で確認でき、それらのイベントをもとに自動コミュニケーションをトリガーできます。 Adaptyは、すべてのストアからの[サブスクリプションイベント](events)を一元管理できる完全なデータセットを提供しており、Brazeのユーザープロファイルの更新に活用できます。Adaptyを使えば、サブスクライバーの行動を把握し、好みを把握して、ターゲットを絞った効果的なコミュニケーションに役立てることができます。この統合により、Brazeダッシュボードでサブスクリプションイベントを追跡し、[獲得キャンペーン](https://www.braze.com/product/journey-orchestration)と紐付けることが可能になります。 Adaptyはサブスクリプションイベントやユーザープロパティ、購入情報をBrazeに送信するため、以下に説明する簡単な統合を行うだけで、Brazeのプッシュ通知を使った顧客向けターゲットコミュニケーションを構築できます。 ## Braze統合のセットアップ方法 \{#how-to-set-up-braze-integration\} Brazeを統合するには、[Integrations → Braze](https://app.adapty.io/integrations/braze) に移動してトグルをオンにし、各フィールドを入力してください。 統合の最初のステップは、BrazeとAdaptyのプロファイルを接続するために必要な認証情報を提供することです。統合を正しく動作させるには、**REST API Key**、**Braze Instance ID**、そしてiOSとAndroidの**App ID**が必要です: <img src="/assets/shared/img/5f1e62c-adapty_braze.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. **REST API Key** は **Braze Dashboard** → **Settings** → **API Keys** で作成できます。作成時にキーに `users.track` 権限が付与されていることを確認してください: <img src="/assets/shared/img/b5fdf16-adapty_braze_create_api_key.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/1e5b4b8-adapty_braze_api_key_users_track.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Braze Instance ID** を取得するには、BrazeダッシュボードのURLを確認し、インスタンスIDが記載されている [Braze Docs](https://www.braze.com/docs/api/basics/#endpoints) のセクションを参照してください。US-03、EU-01などの地域形式になっています。 3. iOSおよびAndroidのApp IDは、Braze Dashboard → Settings → API Keys でも確認できます。こちらからコピーしてください: <img src="/assets/shared/img/1e6d21b-adapty_braze_app_ids.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## イベント、ユーザー属性、購入 \{#events-user-attributes-and-purchases\} 認証情報の下には、AdaptyからBrazeに送信できるイベントが3つのグループで表示されています。必要なものをオンにするだけです。Brazeへの送信に合わせてイベント名を変更することもできます。Adaptyが提供するイベントの完全なリストは[こちら](events)で確認できます: <img src="/assets/shared/img/702e628-adapty_braze_events_names.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyはサブスクリプションイベントとユーザー属性をサーバー間統合でBrazeに送信するため、Brazeダッシュボードで確認してキャンペーンを設定できます。 トライアル転換や更新など収益が発生するイベントについては、Adaptyはその情報を購入としてBrazeに送信します。 Brazeに送信されるイベントプロパティの完全な仕様は[こちら](messaging#event-properties)をご覧ください。 :::note 便利なユーザー属性 AdaptyはBraze統合のためにデフォルトでいくつかのユーザー属性を送信します。ニーズに最適なものを判断するために、以下のリストを参照してください。 ::: | ユーザー属性 | 型 | 値 | |--------------|----|-----| | `adapty_customer_user_id` | String | お客様が定義したユーザーの一意識別子の値を含みます。Adaptyの[ダッシュボード](profiles-crm)とBrazeの両方で確認できます。 | | `adapty_profile_id` | String | Adaptyのユーザープロファイルの一意識別子(Adapty User Profile ID)の値を含みます。Adaptyの[ダッシュボード](profiles-crm)で確認できます。 | | `environment` | String | <p>ユーザーがサンドボックス環境または本番環境のどちらで操作しているかを示します。</p><p></p><p>値は `Sandbox` または `Production` のいずれかです。</p> | | `store` | String | <p>購入に使用したストアの名前を含みます。</p><p></p><p>設定可能な値:</p><p>`app_store` または `play_store`</p> | | `vendor_product_id` | String | <p>Apple/GoogleストアのプロダクトIDの値を含みます。</p><p></p><p>例:org.locals.12345</p> | | `subscription_expires_at` | String | <p>最新のサブスクリプションの有効期限を含みます。</p><p></p><p>値のフォーマット:</p><p>YYYY-MM-DDTHH:mm:ss.SSS+TZ</p><p>例:2023-02-15T17:22:03.000+0000</p> | | `active_subscription` | String | 購入・更新イベント時に `true`、サブスクリプションが期限切れの場合は `false` に設定されます。 | | `period_type` | String | <p>購入または更新の最新の期間タイプを示します。</p><p></p><p>設定可能な値:</p><p>トライアル期間の場合は `trial`、それ以外は `normal`</p> | すべてのfloat値はintに丸められます。文字列はそのまま維持されます。 定義済みのタグリストに加えて、タグを使って[カスタム属性](segments#custom-attributes)を送信することも可能です。これにより、タグに含めるデータの種類の柔軟性が高まり、プロダクトやサービスに関連する特定の情報の追跡に役立ちます。すべてのカスタムユーザー属性は、ユーザーが[統合ページ](https://app.adapty.io/integrations/braze)の **Send user attributes** チェックボックスをオンにすることで、自動的にBrazeに送信されます。 ## SDK設定 \{#sdk-configuration\} AdaptyとBrazeのユーザープロファイルを紐付けるには、Braze SDKをAdaptyと同じカスタマーユーザーIDで設定するか、`.changeUser()` メソッドを使用する必要があります: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers let braze = Braze(configuration: configuration) braze.changeUser(userId: "adapty_customer_user_id") ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Braze.getInstance(context).changeUser("adapty_customer_user_id") ``` </TabItem> </Tabs> --- # File: onesignal --- --- title: "OneSignal" description: "Adapty と OneSignal を連携してプッシュ通知ベースのエンゲージメントを向上させましょう。" --- [OneSignal](https://onesignal.com/) は、プッシュ通知・メール・SMS・アプリ内メッセージングを提供する主要なカスタマーエンゲージメントプラットフォームです。Adapty と OneSignal を連携することで、すべてのサブスクリプションイベントを一か所で確認でき、それらのイベントをトリガーとした自動コミュニケーションを設定できます。 Adapty を使えば、複数のストアにわたる[サブスクリプションイベント](events)を追跡し、ユーザー行動を分析して、よりターゲットを絞ったコミュニケーションに活用できます。この連携により、OneSignal ダッシュボード内でサブスクリプションイベントを監視し、[獲得キャンペーン](https://documentation.onesignal.com/docs/en/automated-messages)にマッピングすることが可能です。 Adapty はサブスクリプションイベントに基づいて OneSignal のタグを更新するため、最小限の設定でパーソナライズされたプッシュ通知を配信できます。 **連携の特性** | 連携の特性 | 説明 | | :------------------------- | :----------------------------------------------------------- | | スケジュール | リアルタイム更新 | | データの方向 | 一方向:Adapty から OneSignal サーバーへ | | Adapty の連携ポイント | <ul><li>モバイルアプリのコード内の OneSignal と Adapty SDK</li><li>Adapty サーバー</li></ul>| ## OneSignal 連携の設定 \{#setting-up-one-signal-integration\} 連携を設定するには: 1. Adapty ダッシュボードの [Integrations → OneSignal](https://app.adapty.io/integrations/onesignal) を開きます。 <img src="/assets/shared/img/onesignal-on.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 連携トグルを有効にします。 3. **OneSignal App ID** を入力します。 OneSignal との連携を設定するには、Adapty ダッシュボードの [Integrations -> OneSignal](https://app.adapty.io/integrations/onesignal) に移動し、トグルをオンにして連携の認証情報を設定してください。 ## OneSignal App ID の取得 \{#retrieving-your-onesignal-app-id\} **OneSignal App ID** は [OneSignal ダッシュボード](https://dashboard.onesignal.com/login)で確認できます: 1. **Settings** → **Keys & IDs** に移動します。 <img src="/assets/shared/img/onesignal-dashboard.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **OneSignal App ID** をコピーして、Adapty ダッシュボードの **App ID** フィールドに貼り付けます。 <img src="/assets/shared/img/onesignal-id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> OneSignal ID の詳細については、[こちらのドキュメント](https://documentation.onesignal.com/docs/en/keys-and-ids)をご覧ください。 ### イベントの設定 \{#configuring-events\} Adapty では、3 つのグループのイベントを OneSignal に送信できます。Adapty ダッシュボードで必要なものをトグルでオンにしてください。利用可能なイベントの完全なリストと詳細な説明は[こちら](events)で確認できます。 <img src="/assets/shared/img/onesignal.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty はサーバー間連携を使用してサブスクリプションイベントを OneSignal に送信するため、OneSignal ですべてのサブスクリプション関連のアクティビティを追跡できます。 :::warning 2023 年 4 月 17 日より、OneSignal の無料プランではこの連携がサポートされなくなりました。**Growth**、**Professional**、およびそれ以上のプランでのみ利用可能です。詳細は [OneSignal Pricing](https://onesignal.com/pricing) をご覧ください。 ::: ## カスタムタグ \{#custom-tags\} この連携では、Adapty ユーザーのさまざまなプロパティをタグとして更新・付与し、OneSignal に送信します。以下のタグ一覧から、ニーズに合ったものをご確認ください。 :::warning OneSignal にはタグの上限があります。これには Adapty が生成するタグと OneSignal に既存するタグの両方が含まれます。上限を超えると、イベント送信時にエラーが発生する可能性があります。 ::: | タグ | 型 | 説明 | |---|----|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `adapty_customer_user_id` | String | アプリ内でのユーザーの一意の識別子。システム、Adapty、OneSignal 全体で一貫している必要があります。 | | `adapty_profile_id` | String | Adapty のユーザープロファイル ID。[Adapty ダッシュボード](profiles-crm)で確認できます。 | | `environment` | String | ユーザーの現在の環境を示す `Sandbox` または `Production`。 | | `store` | String | プロダクトが購入されたストア。選択肢:**app_store**、**play_store**、**stripe**、または[カスタムストア](custom-store)の名前。 | | `vendor_product_id` | String | アプリストアにおけるプロダクト ID(例:`org.locals.12345`)。 | | `subscription_expires_at` | String | 最新のサブスクリプションの有効期限(`YYYY-MM-DDTHH:MM:SS+0000`、例:`2023-02-10T17:22:03.000000+0000`)。 | | `last_event_type` | String | [Adapty イベントリスト](events)における最新のイベントタイプ。<br/> 注意点:<br/>- **Subscription expired** イベントの場合、Adapty は `last_event_type` プロパティを `subscription_cancelled` として送信します。<br/>- **Trial renew canceled** の場合は `auto_renew_off` として送信します。<br/>- **Subscription renew canceled** の場合は `auto_renew_off_subscription` として送信します。 | | `purchase_date` | String | 最後のトランザクション日時(`YYYY-MM-DDTHH:MM:SS+0000`、例:`2023-02-10T17:22:03.000000+0000`)。 | | `active_subscription` | String | ユーザーがアクティブなサブスクリプションを持つ場合は `true`、サブスクリプションが終了している場合は `false`。 | | `period_type` | String | 購入または更新における最新の期間タイプを示します。使用可能な値:試用期間の場合は `trial`、それ以外のすべての場合は `normal`。 | すべての float 値は整数に丸められます。文字列はそのまま変更されません。 事前定義されたタグに加えて、[カスタム属性](segments#custom-attributes)をタグとして送信することで、含めるデータの柔軟性を高めることができます。これは、プロダクトやサービスに関連する特定の詳細を追跡するのに役立ちます。 カスタムユーザー属性は、[連携ページ](https://app.adapty.io/integrations/onesignal)の **Send user attributes** チェックボックスが有効になっている場合、自動的に OneSignal に送信されます。チェックを外した場合、Adapty はちょうど 10 個のタグを送信します。チェックを入れると 10 個を超えるタグを送信でき、より多くのデータをキャプチャできます。 ## SDK の設定 \{#sdk-configuration\} OneSignal と Adapty を連携する方法は 2 つあります: 1. **レガシー(v5 以前):** `playerId` を使用します([OneSignal SDK v5](https://github.com/OneSignal/OneSignal-iOS-SDK/releases/tag/5.0.0) では非推奨)。 2. **現行(v5 以降):** `subscriptionId` を使用します。 :::warning Adapty に `playerId`(OneSignal SDK v5 以前の場合)または `subscriptionId`(OneSignal SDK v5 以降の場合)を必ず送信してください。これを行わないと、OneSignal のタグが更新されず、連携が正しく機能しません。 ::: <Tabs groupId="current-version" queryString> <TabItem value="v5+" label="OneSignal SDK v5+ (current)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers // SubscriptionID OneSignal.Notifications.requestPermission({ accepted in Task { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.oneSignalSubscriptionId(OneSignal.User.pushSubscription.id)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "one_signal_subscription_id", value: OneSignal.User.pushSubscription.id ) } }, fallbackToSettings: true) ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers // SubscriptionID val oneSignalSubscriptionObserver = object: IPushSubscriptionObserver { override fun onPushSubscriptionChange(state: PushSubscriptionChangedState) { Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.current.id) { error -> if (error != null) { // handle the error } } } } ``` </TabItem> <TabItem value="java" label="(Android) Java" default> ```java showLineNumbers // SubscriptionID IPushSubscriptionObserver oneSignalSubscriptionObserver = state -> { Adapty.setIntegrationIdentifier("one_signal_subscription_id", state.getCurrent().getId(), error -> { if (error != null) { // handle the error } }); }; ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers // 1. Since OneSignal.User.pushSubscription.id may return null if called too early, // OneSignal suggests to listen for the updates: OneSignal.User.pushSubscription.addObserver((state) { if (state.current.optedIn) { // now you can try to retrieve subscriptionId } }); // 2. Then you can push subscriptionId to Adapty: final subscriptionId = OneSignal.User.pushSubscription.id; if (subscriptionId != null) { await Adapty().setIntegrationIdentifier(key: "one_signal_subscription_id", value: subscriptionId); } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; using OneSignalSDK; var pushUserId = OneSignal.Default.PushSubscriptionState.userId; Adapty.SetIntegrationIdentifier( "one_signal_player_id", pushUserId, (error) => { // handle the error }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers OneSignal.User.pushSubscription.addEventListener('change', (subscription) => { const subscriptionId = subscription.current.id; if (subscriptionId) { adapty.setIntegrationIdentifier("one_signal_subscription_id", subscriptionId); } }); ``` </TabItem> </Tabs> </TabItem> <TabItem value="pre-v5" label="OneSignal SDK v. up to 4.x (legacy)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers // PlayerID // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { Task { // Adapty SDK 4.x try await Adapty.setIntegrationIdentifier(.oneSignalPlayerId(playerId)) // Adapty SDK 3.x try await Adapty.setIntegrationIdentifier( key: "one_signal_player_id", value: playerId ) } } } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers // PlayerID val osSubscriptionObserver = OSSubscriptionObserver { stateChanges -> stateChanges?.to?.userId?.let { playerId -> Adapty.setIntegrationIdentifier("one_signal_player_id", playerId) { error -> if (error != null) { // handle the error } } } } ``` </TabItem> <TabItem value="java" label="Java" default> ```java showLineNumbers // PlayerID OSSubscriptionObserver osSubscriptionObserver = stateChanges -> { OSSubscriptionState to = stateChanges != null ? stateChanges.getTo() : null; String playerId = to != null ? to.getUserId() : null; if (playerId != null) { Adapty.setIntegrationIdentifier("one_signal_player_id", playerId, error -> { if (error != null) { // handle the error } }); } }; ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers // PlayerID (pre-v5 OneSignal SDK) // in your OSSubscriptionObserver implementation func onOSSubscriptionChanged(_ stateChanges: OSSubscriptionStateChanges) { if let playerId = stateChanges.to.userId { Task { try await Adapty.setIntegrationIdentifier( key: "one_signal_player_id", value: playerId ) } } } ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers OneSignal.addSubscriptionObserver(event => { const playerId = event.to.userId; adapty.setIntegrationIdentifier("one_signal_player_id", playerId); }); ``` </TabItem> </Tabs> </TabItem> </Tabs> OneSignal ドキュメントの詳細はこちらをご覧ください: - [プッシュサブスクリプション ID](https://documentation.onesignal.com/docs/en/mobile-sdk-reference#user-pushsubscription-id) - [プッシュサブスクリプションの変更](https://documentation.onesignal.com/docs/en/mobile-sdk-reference#addobserver-push-subscription-changes) ## 複数デバイスへの対応 \{#dealing-with-multiple-devices\} ユーザーが複数のデバイスを持っている場合、購入イベントやサブスクリプションの追跡が難しくなることがあります。OneSignal では、[external user ID](https://documentation.onesignal.com/docs/en/users) を使ってこの問題に対処できます。 デバイス間でユーザーデータを一貫させるには: 1. **サーバーサイド**で異なるデバイスを照合し、そのデータを OneSignal に送信します。 2. Adapty の [customer_user_id](identifying-users) を OneSignal の [externalUserId](https://documentation.onesignal.com/docs/en/users#external-id) として使用します。アプリに登録システムがない場合は、ユーザーのデバイス間で一貫性を保つ別の一意の識別子の使用を検討してください。 すべてのデバイスでユーザー識別子の一貫性を維持し、ユーザーの ID が変わるたびに OneSignal を更新することが重要です。これにより、ユーザーのアクティビティとサブスクリプションの追跡が簡素化され、一貫したメッセージングが確保されるとともに、より正確な分析とより良いユーザー体験が実現できます。詳細については、OneSignal の [external user ID ドキュメント](https://documentation.onesignal.com/docs/en/users)をご覧ください。 --- # File: pushwoosh --- --- title: "Pushwoosh" description: "AdaptyとPushwooshを統合して、プッシュ通知のトラッキングをシームレスに実現しましょう。" --- Adaptyはサブスクリプションイベントを使用して[Pushwoosh](https://www.pushwoosh.com/)のプロファイルタグを更新します。以下に説明する簡単なインテグレーション設定を行うことで、プッシュ通知を活用した顧客へのターゲットコミュニケーションが可能になります。 ## Pushwoosh インテグレーションの設定方法 \{#how-to-set-up-pushwoosh-integration\} Pushwoosh との連携を設定するには、[**Integrations** -> **Pushwoosh**](https://app.adapty.io/integrations/pushwoosh) に移動してトグルをオンにし、各フィールドを入力してください。 まず、PushwooshとAdaptyのプロファイルを接続するための認証情報を設定します。 Pushwoosh のアプリIDと認証トークンが必要です。 <img src="/assets/shared/img/64e48a1-CleanShot_2023-08-18_at_11.13.212x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 1. **App ID** はPushwooshのダッシュボードで確認できます。 <img src="/assets/shared/img/ee27687-CleanShot_2023-08-18_at_14.37.442x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Auth token** はPushwoosh の設定画面にある「API Access」セクションで確認できます。 <img src="/assets/shared/img/50e634b-CleanShot_2023-08-18_at_14.35.022x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## イベントとタグ \{#events-and-tags\} 認証情報の下には、AdaptyからPushwooshに送信できるイベントのグループが3つあります。必要なものをオンにするだけです。Pushwooshに送信するイベント名は変更することもできます。Adaptyが提供するイベントの全リストは[こちら](events)でご確認ください。 <img src="/assets/shared/img/392dc31-screencapture-app-adapty-io-integrations-pushwoosh-2023-08-22-13_31_07.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyはサーバー間インテグレーションを使用してPushwooshにサブスクリプションイベントを送信するため、Pushwooshダッシュボードですべてのサブスクリプションイベントを確認できます。 :::note カスタムタグ AdaptyではPushwooshインテグレーションにカスタムタグを使用することもできます。以下のタグ一覧を参照して、用途に合ったタグをお選びください。 ::: | タグ | タイプ | 値 | |---|----|-----| | `adapty_customer_user_id` | String | Pushwoosh側で確認できるユーザーの一意の識別子の値を含みます。 | | `adapty_profile_id` | String | Adaptyの[ダッシュボード](profiles-crm)で確認できるユーザーのAdaptyプロファイルIDの値を含みます。 | | `environment` | String | <p>ユーザーがサンドボックス環境または本番環境のいずれで操作しているかを示します。</p><p></p><p>値は `Sandbox` または `Production` のいずれかです。</p> | | `store` | String | <p>購入に使用されたストアの名前を含みます。</p><p></p><p>設定可能な値:</p><p>`app_store` または `play_store`</p> | | `vendor_product_id` | String | <p>Apple/GoogleストアのプロダクトIDの値を含みます。</p><p></p><p>例:org.locals.12345</p> | | `subscription_expires_at` | String | <p>最新のサブスクリプションの有効期限日を含みます。</p><p></p><p>値の形式:</p><p>year-month dayThour:minute:second</p><p>例:2023-02-10T17:22:03.000000+0000</p> | | `last_event_type` | String | インテグレーションで有効化した標準の[Adaptyイベント](events)の中で、最後に受信したイベントの種類を示します。 | | `purchase_date` | String | <p>最後のトランザクション(初回購入または更新)の日付を含みます。</p><p></p><p>値の形式:</p><p>year-month dayThour:minute:second</p><p>例:2023-02-10T17:22:03.000000+0000</p> | | `original_purchase_date` | String | <p>トランザクションに基づく最初の購入日を含みます。</p><p></p><p>値の形式:</p><p>year-month dayThour:minute:second</p><p>例:2023-02-10T17:22:03.000000+0000</p> | | `active_subscription` | String | 購入または更新イベント時に `true`、サブスクリプションが期限切れの場合は `false` に設定されます。 | | `period_type` | String | <p>購入または更新の最新の期間タイプを示します。</p><p></p><p>設定可能な値:</p><p>トライアル期間の場合は `trial`、それ以外は `normal`</p> | すべての浮動小数点値は整数に丸められます。文字列はそのまま維持されます。 定義済みのタグ一覧に加えて、タグを使用して[カスタム属性](segments#custom-attributes)を送信することも可能です。これにより、タグに含めるデータの種類の柔軟性が高まり、プロダクトやサービスに関連する特定の情報のトラッキングに役立ちます。**Send user custom attributes** チェックボックスを[インテグレーションページ](https://app.adapty.io/integrations/pushwoosh)でオンにすると、すべてのカスタムユーザー属性が自動的にPushwooshに送信されます。 ## SDK の設定 \{#sdk-configuration\} AdaptyとPushwooshを連携するには、`HWID` の値を送信する必要があります: <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (Swift)" default> ```swift showLineNumbers do { try await Adapty.setIntegrationIdentifier( key: "pushwoosh_hwid", value: Pushwoosh.sharedInstance().getHWID() ) } catch { // handle the error } ``` </TabItem> <TabItem value="kotlin" label="Android (Kotlin)" default> ```kotlin showLineNumbers Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().hwid) { error -> if (error != null) { // handle the error } } ``` </TabItem> <TabItem value="java" label="Android (Java)" default> ```java showLineNumbers Adapty.setIntegrationIdentifier("pushwoosh_hwid", Pushwoosh.getInstance().getHwid(), error -> { if (error != null) { // handle the error } }); ``` </TabItem> <TabItem value="flutter" label="Flutter (Dart)" default> ```javascript showLineNumbers final hwid = await Pushwoosh.getInstance.getHWID; try { await Adapty().setIntegrationIdentifier( key: "pushwoosh_hwid", value: hwid, ); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="unity" label="Unity (C#)" default> ```csharp showLineNumbers using AdaptySDK; Adapty.SetIntegrationIdentifier( "pushwoosh_hwid", Pushwoosh.Instance.HWID, (error) => { // handle the error }); ``` </TabItem> <TabItem value="rn" label="React Native (TS)" default> ```typescript showLineNumbers // ... try { await adapty.setIntegrationIdentifier("pushwoosh_hwid", hwid); } catch (error) { // handle `AdaptyError` } ``` </TabItem> </Tabs> --- # File: slack --- --- title: "Slack" description: "Adapty と Slack を連携して、サブスクリプションイベントのリアルタイム通知を受け取りましょう。" --- [Slack](https://slack.com/) は、ビジネス向けメッセンジャー兼生産性プラットフォームです。説明不要でしょう。 この連携を使えば、Adapty が収益イベントを検知するたびに Slack で通知を受け取れるようになります。MRR が上がる瞬間を逃さず確認したい場合や、トライアルのキャンセル・請求エラー・返金などを素早く把握したい場合に特に便利です。 ## Slack 連携の設定方法 \{#how-to-set-up-slack-integration\} 以下の手順が必要です: - Slack ワークスペースにアプリを作成する - メッセージ投稿の権限を付与する - Adapty の [Integrations → Slack](https://app.adapty.io/integrations/slack) に必要な情報を入力する ### 1\. Slack でアプリを作成する \{#1-create-an-app-in-slack\} 1. [Slack API ダッシュボード](https://api.slack.com/apps)にアクセスし、次の手順でアプリを作成します: <img src="/assets/shared/img/f43aedc-CleanShot_2024-01-04_at_18.27.412x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/08fa9e6-CleanShot_2024-01-04_at_18.28.142x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 任意の名前(例:`Adapty`)を付け、ワークスペースに追加します: <img src="/assets/shared/img/5002bb1-CleanShot_2024-01-04_at_18.29.132x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 2\. 投稿権限を付与してトークンを取得する \{#2-give-permission-to-post-and-get-a-token-for-your-app\} アプリのページにリダイレクトされます。 1. 下にスクロールして **Permissions** をクリックします: <img src="/assets/shared/img/9750451-CleanShot_2024-01-04_at_18.48.072x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. リダイレクト後、**Scopes** までスクロールして **Add an OAuth Scope** をクリックします: <img src="/assets/shared/img/db5b5f4-CleanShot_2024-01-04_at_18.50.262x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. チャンネルへの投稿とメッセージのカスタマイズに必要な `chat:write`、`chat:write.public`、`chat:write.customize` の権限を付与します: <img src="/assets/shared/img/d97ccb9-CleanShot_2024-01-04_at_18.51.572x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. ページ上部に戻り、**Install to Workspace** をクリックします: <img src="/assets/shared/img/14608e3-CleanShot_2024-01-04_at_19.17.58.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Allow** をクリックします: <img src="/assets/shared/img/143967e-CleanShot_2024-01-04_at_18.53.292x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> この操作後、同じページにリダイレクトされますが、OAuth トークン(`xoxb-...`)が表示されます。これが設定完了に必要なトークンです: <img src="/assets/shared/img/59b33ee-CleanShot_2024-01-04_at_18.55.222x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 3\. Adapty で連携を設定する \{#3-configure-the-integration-in-adapty\} 1. [**Integrations** → **Slack**](https://app.adapty.io/integrations/slack) に移動します: <img src="/assets/shared/img/b4ffd71-CleanShot_2024-01-04_at_19.05.222x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 前のステップで取得した `xoxb-...` トークンを貼り付け、投稿先のチャンネルを選択します。本番環境のみ、サンドボックスのみ、または両方でイベントを受け取るよう設定できます。また、通知に使用する通貨(元の通貨または USD 換算)も選択できます。 :::note プライベートチャンネルに Adapty からメッセージを投稿したい場合は、Slack で作成した `Adapty` アプリをそのチャンネルに手動で追加する必要があります。追加しないと正常に動作しません。 ::: 3. 最後に、**Events** で受け取りたいイベントを選択します: <img src="/assets/shared/img/970a7bb-CleanShot_2024-01-04_at_19.09.472x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これで設定完了です! 指定したチャンネルにイベントが送信されます。該当する場合は収益も確認でき、Adapty でカスタマープロファイルを参照することもできます: <img src="/assets/shared/img/852b8c8-CleanShot_2024-01-04_at_19.11.332x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: s3-exports --- --- title: "Amazon S3" description: "高度な分析とレポートのためにサブスクリプションデータをS3にエクスポートします。" --- AdaptyのAmazon S3との連携により、イベントやペイウォール訪問データを一か所に安全に保存できます。[サブスクリプションイベント](events)をAmazon S3バケットに.csvファイルとして保存することが可能です。 この連携を設定するには、AWSコンソールとAdapty ダッシュボードでいくつかの手順を行う必要があります。 :::note スケジュール Adaptyはデータを毎日**24時間ごと**、UTC 4:00に送信します。 各ファイルには、UTC 基準で前日のカレンダー1日分に発生したイベントデータが含まれます。たとえば、3月8日の4:00 UTC に自動エクスポートされるデータには、3月7日の00:00:00〜23:59:59(UTC)に発生したすべてのイベントが含まれます。 ::: ## Amazon S3 インテグレーションの設定方法 \{#how-to-set-up-amazon-s3-integration\} データの受信を開始するには、以下の認証情報が必要です: 1. アクセスキー ID 2. シークレットアクセスキー 3. S3 バケット名 4. S3 バケット内のフォルダ名 :::note ネストされたディレクトリ Amazon S3 バケット名フィールドにネストされたディレクトリを指定できます(例:adapty-events/com.sample-app) ::: Amazon S3 のインテグレーションを設定するには、[**Integrations** -> **Amazon S3**](https://app.adapty.io/integrations/s3) に移動し、トグルをオフからオンに切り替えて、各フィールドに入力してください。 まず、Amazon S3 と Adapty プロファイルの接続を確立するための認証情報を設定します。 <img src="/assets/shared/img/2b1a6e3-CleanShot_2023-03-24_at_14.51.272x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty ダッシュボードでは、接続を設定するために以下のフィールドが必要です: | フィールド | 説明 | | :--------------------------- | :----------------------------------------------------------- | | **Access Key ID** | AWS サービスへのアクセスを認証するために使用される一意の識別子です。ダウンロードした [csv ファイル](s3-exports#how-to-create-amazon-s3-credentials) で確認できます。 | | **Secret Access Key** | Access Key ID と組み合わせて AWS サービスへのアクセスを認証するためのプライベートキーです。ダウンロードした [csv ファイル](s3-exports#how-to-create-amazon-s3-credentials) で確認できます。 | | **S3 Bucket Name** | AWS クラウド内の特定の S3 バケットを識別するグローバルに一意の名前です。S3 バケットはシンプルなストレージサービスで、ファイルや画像などのデータオブジェクトをクラウド上に保存・取得できます。 | | **Folder Inside the Bucker** | 選択した S3 バケット内に作成するフォルダーの名前です。S3 はオブジェクトキーのプレフィックス(実質的にフォルダー名)を使用してフォルダーを疑似的に表現している点にご注意ください。 | ## Amazon S3 認証情報の作成方法 \{#how-to-create-amazon-s3-credentials\} このガイドでは、AWS コンソールで必要な認証情報を作成する手順を説明します。 ### 1\. アクセスポリシーの作成 \{#1-create-access-policy\} まず、AWS コンソールの [IAM ポリシーダッシュボード](https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/policies) に移動し、**Create Policy** を選択します。 <img src="/assets/shared/img/7af075c-CleanShot_2023-03-21_at_10.52.002x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> In the Policy editor, paste the following JSON and change `adapty-s3-integration-test` to your bucket name: ```json showLineNumbers title="Json" { "Version": "2012-10-17", "Statement": [ { "Sid": "AllowListObjectsInBucket", "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::adapty-s3-integration-test" }, { "Sid": "AllowAllObjectActions", "Effect": "Allow", "Action": "s3:*Object", "Resource": [ "arn:aws:s3:::adapty-s3-integration-test/*", "arn:aws:s3:::adapty-s3-integration-test" ] }, { "Sid": "AllowBucketLocation", "Effect": "Allow", "Action": "s3:GetBucketLocation", "Resource": "arn:aws:s3:::adapty-s3-integration-test" } ] } ``` <img src="/assets/shared/img/d4e474a-CleanShot_2023-03-21_at_10.56.212x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ポリシーの設定が完了したら、タグを追加する(任意)かどうかを選択し、**Next** をクリックして最終ステップに進みます。このステップでポリシーに名前を付け、**Create policy** ボタンをクリックするだけで作成が完了します。 <img src="/assets/shared/img/7dcb02f-CleanShot_2023-03-21_at_11.03.372x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 2\. IAM ユーザーの作成 \{#2-create-iam-user\} Adapty がローデータレポートをバケットにアップロードできるようにするには、対象バケットへの書き込みアクセス権を持つユーザーの Access Key ID と Secret Access Key を提供する必要があります。 手順を進めるには、IAM コンソールにアクセスし、[Users セクション](https://console.aws.amazon.com/iamv2/home#/users)を選択してください。次に、**Add users** ボタンをクリックします。 <img src="/assets/shared/img/bb612c8-CleanShot_2023-03-21_at_11.12.392x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ユーザーに名前を付け、**Access key – Programmatic access** を選択して、権限の設定に進みます。 <img src="/assets/shared/img/467ee4d-j6aoX.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 次のステップでは、**Add user to group** オプションを選択し、**Create group** ボタンをクリックしてください。 <img src="/assets/shared/img/bfd0e80-CleanShot_2023-03-21_at_11.24.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 次に、User Group の名前を入力し、先ほど作成したポリシーを選択します。ポリシーを選択したら、**Create group** ボタンをクリックして完了です。 <img src="/assets/shared/img/df29c12-CleanShot_2023-03-21_at_11.28.052x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> グループの作成が完了したら、**それを選択**して次のステップに進んでください。 <img src="/assets/shared/img/1f3722e-CleanShot_2023-03-21_at_11.36.192x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このセクションの最後のステップなので、**Create User** ボタンをクリックして進んでください。 <img src="/assets/shared/img/ea43722-CleanShot_2023-03-21_at_11.40.462x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 最後に、認証情報を**.csv 形式でダウンロード**するか、ダッシュボードから直接コピー&ペーストすることができます。 <img src="/assets/shared/img/bcf35e1-S3created.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 手動データエクスポート \{#manual-data-export\} Amazon S3 への自動イベントデータエクスポートに加えて、Adapty では手動ファイルエクスポート機能も提供しています。この機能を使うと、エクスポートするイベントデータの期間を指定し、S3 バケットに手動でエクスポートできます。これにより、エクスポートするデータとそのタイミングをより細かく管理できます。 指定した日付範囲では、Date A の 00:00:00 UTC から Date B の 23:59:59 UTC までに作成されたイベントがエクスポートされます。 <img src="/assets/shared/img/466bd29-CleanShot_2023-03-21_at_12.35.252x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## テーブル構造 \{#table-structure\} AWS S3 連携では、Adapty はトランザクションイベントおよびペイウォール訪問の履歴データを保存するテーブルを提供します。このテーブルには、ユーザープロファイル、収益および収益額、元のストアなど、さまざまなデータが含まれています。基本的に、これらのテーブルはアプリが一定期間に生成したすべてのトランザクションを記録します。 :::warning この構造は今後拡張される可能性があります。新しいデータが Adapty または連携先のサードパーティによって追加されることがあります。この構造を処理するコードは、特定のフィールドに依存する形で実装し、構造全体に依存しないよう堅牢に設計してください。 ::: イベントのテーブル構造は以下の通りです: :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: | カラム | 説明 | |---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **profile_id** | Adapty ユーザー ID。 | | **event_type** | 小文字のイベント名。イベントの種類については [Events](events) セクションを参照してください。 | | **event_datetime** | ISO 8601 形式の日付。 | | **transaction_id** | 購入や更新などのトランザクションの一意の識別子。 | | **original_transaction_id** | 最初の購入のトランザクション識別子。 | | **subscription_expires_at** | サブスクリプションの有効期限。通常は未来の日時。 | | **environment** | Sandbox または Production。 | | **revenue_usd** | USD での売上。空の場合があります。 | | **proceeds_usd** | USD での収益。空の場合があります。 | | **net_revenue_usd** | USD での純収益(税引き後の収入)。空の場合があります。 | | **tax_amount_usd** | USD での税額。空の場合があります。 | | **revenue_local** | 現地通貨での売上。空の場合があります。 | | **proceeds_local** | 現地通貨での収益。空の場合があります。 | | **net_revenue_local** | 現地通貨での純収益(税引き後の収入)。空の場合があります。 | | **tax_amount_local** | 現地通貨での税額。空の場合があります。 | | **customer_user_id** | 開発者のユーザー ID。たとえば、ユーザーの UUID、メールアドレス、その他の ID を使用できます。設定していない場合は Null。 | | **store** | _app_store_ または _play_store_。 | | **product_id** | Apple App Store、Google Play Store、または Stripe でのプロダクト ID。 | | **base_plan_id** | Google Play Store での [ベースプラン ID](https://support.google.com/googleplay/android-developer/answer/12154973) または Stripe での [価格 ID](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices)。 | | **developer_id** | トランザクションが発生したペイウォールの開発者(SDK)ID。 | | **ab_test_name** | トランザクションが発生した A/B テストの名前。 | | **ab_test_revision** | トランザクションが発生した A/B テストのリビジョン。 | | **paywall_name** | トランザクションが発生したペイウォールの名前。 | | **paywall_revision** | トランザクションが発生したペイウォールのリビジョン。 | | **profile_county** | IP アドレスをもとに Adapty が判定したプロファイルの国。 | | **install_date** | インストールが行われた日付(ISO 8601 形式)。 | | **idfv** | iOS デバイスの [identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) | | **idfa** | iOS デバイスの [advertisingIdentifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) | | **advertising_id** | Android オペレーティングシステムが割り当てる一意のコードで、広告主がユーザーのデバイスを識別するために使用する広告 ID。 | | **ip_address** | デバイスの IP アドレス(IPv4 または IPv6。利用可能な場合は IPv4 を優先)。デバイスの IP が変わるたびに更新されます。 | | **cancellation_reason** | <p>ユーザーがサブスクリプションをキャンセルした理由。</p><p></p><p>以下の値が設定されます:</p><p>**iOS & Android** _voluntarily_cancelled_、_billing_error_、_refund_</p><p>**iOS** _price_increase_、_product_was_not_available_、_unknown_、_upgraded_</p><p>**Android** _new_subscription_replace_、_cancelled_by_developer_</p> | | **android_app_set_id** | [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId) — デバイスおよび開発者アカウントごとに一意で、ユーザーがリセット可能な、非収益化広告用途向けの ID。 | | **android_id** | Android 8.0(API レベル 26)以降では、アプリの署名キー、ユーザー、デバイスの組み合わせごとに一意な 64 ビットの数値(16 進数文字列で表現)。詳細は [Android 開発者ドキュメント](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID) を参照してください。 | | **device** | エンドユーザーに表示されるデバイスのモデル名。 | | **currency** | トランザクションの 3 文字の通貨コード(ISO-4217)。 | | **store_country** | Apple/Google ストアが判定したプロファイルの国。 | | **attribution_source** | アトリビューションソース。 | | **attribution_network_user_id** | アトリビューションソースがユーザーに割り当てた ID。 | | **attribution_status** | organic、non_organic、または unknown。 | | **attribution_channel** | マーケティングチャネル名。 | | **attribution_campaign** | マーケティングキャンペーン名。 | | **attribution_ad_group** | アトリビューションの広告グループ。 | | **attribution_ad_set** | アトリビューションの広告セット。 | | **attribution_creative** | アトリビューションのクリエイティブキーワード。 | | **attributes** | [カスタムユーザー属性](setting-user-attributes#custom-user-attributes) の JSON。モバイルアプリから送信するよう設定したカスタム属性が含まれます。送信するには、[Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook) ページで **Send User Attributes** オプションを有効にしてください。 | | **integration_ids** | プロファイルに関連付けられたすべてのインテグレーション ID。ディクショナリ形式。例: {'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | ここにペイウォール訪問数のテーブル構造を示します: | カラム | 説明 | | :-------------------- | :----------------------------------------------------------------------------------------------------------- | | **profile_id** | Adapty のユーザー ID。 | | **customer_user_id** | 開発者のユーザー ID。例えば、ユーザーの UUID、メールアドレス、その他の ID などを設定できます。未設定の場合は Null。 | | **profile_country** | Apple/Google ストアによって決定されるプロファイルの国。 | | **install_date** | インストールが行われた日時(ISO 8601 形式)。 | | **store** | _app_store_ または _play_store_ のいずれか。 | | **paywall_showed_at** | ペイウォールがユーザーに表示された日時。 | | **developer_id** | トランザクションが発生したペイウォールの開発者(SDK)ID。 | | **ab_test_name** | トランザクションが発生した A/B テストの名前。 | | **ab_test_revision** | トランザクションが発生した A/B テストのリビジョン。 | | **paywall_name** | トランザクションが発生したペイウォールの名前。 | | **paywall_revision** | トランザクションが発生したペイウォールのリビジョン。 | ## イベントとタグ \{#events-and-tags\} インテグレーションで通信するデータを管理できます。このインテグレーションでは、以下の設定オプションを利用できます。 | 設定 | 説明 | | :--------------------------------- | :----------------------------------------------------------- | | **Exclude Historical Events** | Adapty SDK を含むアプリをユーザーがインストールする前に発生したイベントを除外するかどうかを選択します。これにより、イベントの重複を防ぎ、正確なレポートを確保できます。たとえば、ユーザーが 1 月 10 日に月次サブスクリプションを有効化し、3 月 6 日に Adapty SDK を含むアプリにアップデートした場合、Adapty は 3 月 6 日より前のイベントを除外し、以降のイベントのみを保持します。 | | **Include events without profile** | Adapty のユーザープロファイルに紐付いていないトランザクションを含めるかどうかを選択します。これには、Adapty SDK のインストール前に行われた購入や、特定のユーザーにすぐに関連付けられないストアのサーバー通知から受信したトランザクションが含まれる場合があります。 | | **Send User Attributes** | 言語設定などのユーザー固有の属性を送信したい場合で、かつ OneSignal のプランが 10 個を超えるタグをサポートしている場合は、このオプションを選択します。有効にすると、デフォルトの 10 タグを超える追加情報を含めることができます。タグの上限を超えるとエラーが発生する可能性がある点に注意してください。 | <img src="/assets/shared/img/s3-settings.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> インテグレーション設定の下には、Adapty から Amazon S3 にエクスポート・送信・保存できるイベントが3つのグループに分かれています。必要なものをオンにするだけです。Adapty が提供するイベントの全一覧は[こちら](events)をご確認ください。 <img src="/assets/shared/img/fd5ccb9-CleanShot_2023-08-17_at_14.49.282x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: google-cloud-storage --- --- title: "Google Cloud Storage" description: "Adapty と Google Cloud Storage を統合してデータを安全に保存する方法。" --- Google Cloud Storage インテグレーションを有効にすると、[サブスクリプションイベント](events)と[ペイウォール訪問データ](paywall-metrics)を Google Cloud Storage バケットに一元的かつ安全に保存できます。 毎日UTC午前4時に、Adaptは前日のデータを含む.csvファイルをあなたのバケットにアップロードします。**イベント**データ、**ペイウォール訪問**データ、または**両方**を受信するかどうかを選択できます。また、任意の期間のデータを[手動](#manual-data-export)でエクスポートすることもできます。 インテグレーションを設定するには、Google CloudコンソールでBucketアクセスキーを[生成](#create-google-cloud-storage-credentials)し、それをAdaptyの設定に[追加](#set-up-google-cloud-storage-integration)します。 ## アップロードスケジュールと所要時間 \{#upload-schedule-and-duration\} AdapyはUTC 04:00に24時間ごとにGoogle Cloud Storageへデータをアップロードします。 ファイルには前の暦日(UTC)に作成されたイベントのデータが含まれます。3月8日にアップロードされるファイルには、3月7日の00:00:00〜23:59:59 UTCに作成されたすべてのイベントが含まれます。 キュー内のファイルの総数やご自身がリクエストしたデータ量によっては、処理に数時間かかる場合があります。初回アップロードに過去のデータが含まれる場合、以降の毎日のアップロードより時間がかかります。 ## Google Cloud Storage連携の設定 \{#set-up-google-cloud-storage-integration\} **書き込みアクセス権**を持つ有効なGoogle Cloudサービスアカウントキーが必要です。生成方法については、[認証情報の作成](#create-google-cloud-storage-credentials)セクションの手順に従ってください。 :::warning イベントとペイウォール訪問に対して、それぞれ異なるバケットと認証情報を使用できます。ただし、**いずれか**の認証情報が無効な場合、[**両方のアップロードが失敗します**](#troubleshooting)。 ::: [**Integrations** -> **Google Cloud Storage**](https://app.adapty.io/integrations/google-cloud-storage) に移動し、必要なタブ(**Events** または **Paywall visits**)を開きます。連携を有効にします。 **Google Cloudサービスアカウントキー**を含むファイルをアップロードします。対象の**バケット**と**フォルダー**を指定します。変更を保存します。 ### イベントデータのオプション設定 \{#optional-settings-for-event-data\} レポートに含めるイベントを指定したり、イベントにカスタム名を設定したりできます。利用可能なイベントの全一覧は[イベント](events)の記事をご覧ください。 | 名前 | デフォルト | 説明 | | ------------------------------ | ----------------- | ----------- | | Exclude historical events | true | AdaptySDKをアプリに統合する前に発生したイベントの情報を除外します。<br /> <br />アナリティクスプラットフォームがAdapty導入**前**にサブスクリプションイベントを受け取っていた場合、このオプションによって重複イベントの受信を防げます。<Details summary="実際の例"><p>ユーザーが1月10日に月次サブスクリプションを購入しました。3月1日のアプリアップデートが初めてAdapty SDKを含むものでした。<br /> <br /> この設定が**オン**の場合、レポートには1月の「サブスクリプション開始」イベントも2月の「サブスクリプション更新」イベントも含まれません。3月10日の「サブスクリプション更新」イベント**は**含まれます。</p> </Details> | | Include events without profile | false | ユーザープロファイルに紐付いていない、または特定ユーザーにすぐに関連付けられないトランザクションを含めます。Adapty SDK導入前の購入や、サーバー通知経由で受け取ったトランザクションが該当します。 | | Send user attributes | false | [カスタムユーザー属性](setting-user-attributes)(ユーザーデータやアプリ使用データなど)を含めます。OneSignalのプランが10個以上のタグをサポートしている場合にこのオプションを選択してください。タグ上限を超えるとエラーが発生する場合があります。 | ## Google Cloud Storageの認証情報の作成 \{#create-google-cloud-storage-credentials\} このガイドでは、Google Cloud Platform コンソールで必要な認証情報を作成する方法を説明します。 Adaptyが指定のバケットに生データレポートをアップロードするには、サービスアカウントのキーと、対応するバケットへの書き込みアクセス権が必要です。サービスアカウントのキーを提供してバケットへの書き込みアクセスを付与することで、AdaptyがプラットフォームからストレージEnvironmentへ生データレポートを安全かつ効率的に転送できるようになります。 :::warning サービスアカウントのHMACキー認証のみをサポートしています。Google Cloud Storageへの適切なアクセスを有効にするため、サービスアカウントのHMACキーに「Storage Object Viewer」「Storage Legacy Bucket Writer」「Storage Object Creator」のロールが追加されていることを確認してください。 ::: 1. まず、Google CloudアカウントのIAMセクション([IAM](https://console.cloud.google.com/projectselector2/iam-admin/serviceaccounts))に移動し、関連するプロジェクトを選択するか、新しいプロジェクトを作成します。 1. 次に、「+ CREATE SERVICE ACCOUNT」ボタンをクリックしてAdapty用の新しいサービスアカウントを作成します。 2. 最初のステップのフィールドに入力します(アクセス権は後の段階で付与されます)。このページの詳細については、[こちら](https://docs.cloud.google.com/iam/docs/service-accounts-create)のドキュメントをご覧ください。 3. [プライベートJSONキー](https://docs.cloud.google.com/iam/docs/keys-create-delete)を作成してダウンロードするには、KEYSセクションに移動し、「ADD KEY」ボタンをクリックします。 4. DETAILSセクションで、作成したサービスアカウントに紐付くEmail値を見つけてコピーします。この情報は、アカウントを認証してバケットへの書き込みを許可するための後続手順で必要になります。 5. 次に、Google Cloud Storageの[Buckets](https://console.cloud.google.com/storage/browser)ページに移動し、既存のバケットを選択するか、AdapyのイベントまたはVisitsデータレポートを保存するための新しいバケットを作成します。次にPERMISSIONSセクションに移動し、[GRANT ACCESS](https://docs.cloud.google.com/identity/docs/how-to?hl=en)オプションを選択します。 6. PERMISSIONSセクションで、手順5で取得したサービスアカウントのEmailを入力し、Storage Object Creatorロールを選択します。最後にSAVEをクリックして変更を適用します。 バケット名は後で使用するので控えておいてください。 ## 手動データエクスポート \{#manual-data-export\} Google Cloud Storageへの自動イベントデータエクスポートに加えて、Adaptyでは手動ファイルエクスポート機能も提供しています。この機能を使用すると、イベントデータの特定の時間範囲を選択して、GCSバケットに手動でエクスポートできます。エクスポートするデータとタイミングをより細かく制御できます。 指定した日付範囲は、日付A 00:00:00 UTCから日付B 23:59:59 UTCまでに作成されたイベントのエクスポートに使用されます。 ## データ構造 \{#data-structure\} Adaptyはデータを表形式でエクスポートするために`.csv`ファイルを使用します。 :::warning イベントの内容は、Adaptyまたは連携している3rd partyが新しいデータを追加することで増えることがあります。処理するコードは特定のフィールドに依存させ、構造全体に依存しないよう十分に堅牢にしてください。 ::: ### イベント \{#events\} レポートに含まれるイベントの一覧は[変更](#optional-settings-for-event-data)できます。 :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: | カラム | 説明 | |------|-----------| | **profile_id** | AdapyユーザーID。 | | **event_type** | 小文字のイベント名。イベントタイプについては[Events](events)セクションを参照してください。 | | **event_datetime** | ISO 8601形式の日時。 | | **transaction_id** | 購入や更新などのトランザクションの一意の識別子。 | | **original_transaction_id** | 元の購入のトランザクション識別子。 | | **subscription_expires_at** | サブスクリプションの有効期限。通常は未来の日時。 | | **environment** | SandboxまたはProductionのいずれか。 | | **revenue_usd** | USD換算の収益。空の場合があります。 | | **proceeds_usd** | USD換算の受取額。空の場合があります。 | | **net_revenue_usd** | USD換算の純収益(税引後の収入)。空の場合があります。 | | **tax_amount_usd** | USD換算の税金控除額。空の場合があります。 | | **revenue_local** | 現地通貨での収益。空の場合があります。 | | **proceeds_local** | 現地通貨での受取額。空の場合があります。 | | **net_revenue_local** | 現地通貨での純収益(税引後の収入)。空の場合があります。 | | **tax_amount_local** | 現地通貨での税金控除額。空の場合があります。 | | **customer_user_id** | 開発者のユーザーID。ユーザーのUUID、メールアドレス、その他のIDを設定できます。設定していない場合はNull。 | | **store** | *app_store*または*play_store*のいずれか。 | | **product_id** | Apple App Store、Google Play Store、またはStripeでのプロダクトID。 | | **base_plan_id** | Google Play Storeの[ベースプランID](https://support.google.com/googleplay/android-developer/answer/12154973)、またはStripeの[価格ID](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices)。 | | **developer_id** | トランザクションが発生したペイウォールの開発者(SDK)ID。 | | **ab_test_name** | トランザクションが発生したA/Bテストの名前。 | | **ab_test_revision** | トランザクションが発生したA/Bテストのリビジョン。 | | **paywall_name** | トランザクションが発生したペイウォールの名前。 | | **paywall_revision** | トランザクションが発生したペイウォールのリビジョン。 | | **profile_country** | IPアドレスに基づいてAdapyが判定したプロファイルの国。 | | **install_date** | インストールが発生したISO 8601形式の日時。 | | **idfv** | iOSデバイスの[identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor) | | **idfa** | iOSデバイスの[advertisingIdentifier](https://developer.apple.com/documentation/adsupport/asidentifiermanager/advertisingidentifier) | | **advertising_id** | Androidオペレーティングシステムが広告主向けに割り当てる、デバイスを一意に識別するための広告ID | | **ip_address** | デバイスのIPアドレス(IPv4またはIPv6、利用可能な場合はIPv4優先)。デバイスのIPが変わるたびに更新されます | | **cancellation_reason** | <p>ユーザーがサブスクリプションをキャンセルした理由。</p><p></p><p>使用可能な値:</p><p>**iOS & Android** — *voluntarily_cancelled*, *billing_error*, *refund*</p><p>**iOSのみ** — *price_increase*, *product_was_not_available*, *unknown*, *upgraded*</p><p>**Androidのみ** — *new_subscription_replace*, *cancelled_by_developer*</p> | | **android_app_set_id** | [AppSetId](https://developer.android.com/design-for-safety/privacy-sandbox/reference/adservices/appsetid/AppSetId) — 非収益化広告用途向けの、デバイスごと・開発者アカウントごとにリセット可能な一意のID。 | | **android_id** | Android 8.0(APIレベル26)以降では、アプリの署名キー、ユーザー、デバイスの組み合わせごとに一意な64ビットの数値(16進数文字列として表現)。詳細は[Androidデベロッパードキュメント](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID)を参照してください。 | | **device** | エンドユーザーに表示されるデバイスモデル名。 | | **currency** | トランザクションの3文字通貨コード(ISO-4217)。 | | **store_country** | Apple/Google Storeが判定したプロファイルの国。 | | **attribution_source** | アトリビューションソース。 | | **attribution_network_user_id** | アトリビューションソースがユーザーに割り当てたID。 | | **attribution_status** | organic、non_organic、unknownのいずれか。 | | **attribution_channel** | マーケティングチャネル名。 | | **attribution_campaign** | マーケティングキャンペーン名。 | | **attribution_ad_group** | アトリビューションの広告グループ。 | | **attribution_ad_set** | アトリビューションの広告セット。 | | **attribution_creative** | アトリビューションのクリエイティブキーワード。 | | **attributes** | [カスタムユーザー属性](setting-user-attributes#custom-user-attributes)のJSON。モバイルアプリから送信するよう設定したカスタム属性が含まれます。送信するには、[Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook)ページで**Send User Attributes**オプションを有効にしてください。 | | **integration_ids** | プロファイルに関連付けられたすべての連携ID。ディクショナリ形式。例:{'mixpanel_user_id': 'mixpanelUserId-test', 'facebook_anonymous_id': 'facebookAnonymousId-test'} | ### ペイウォール訪問 \{#paywall-visits\} | カラム | 説明 | | :-------------------- | :----------------------------------------------------------------------------------------------------------- | | **profile_id** | AdapyユーザーID。 | | **customer_user_id** | 開発者のユーザーID。ユーザーのUUID、メールアドレス、その他のIDを設定できます。設定していない場合はNull。 | | **profile_country** | Apple/Google Storeが判定したプロファイルの国。 | | **install_date** | インストールが発生したISO 8601形式の日時。 | | **store** | *app_store*または*play_store*のいずれか。 | | **paywall_showed_at** | ペイウォールが顧客に表示された日時。 | | **developer_id** | トランザクションが発生したペイウォールの開発者(SDK)ID。 | | **ab_test_name** | トランザクションが発生したA/Bテストの名前。 | | **ab_test_revision** | トランザクションが発生したA/Bテストのリビジョン。 | | **paywall_name** | トランザクションが発生したペイウォールの名前。 | | **paywall_revision** | トランザクションが発生したペイウォールのリビジョン。 | ## トラブルシューティング \{#troubleshooting\} Adaptyはアップロードを開始する**前に**アクセスキーの有効性を確認します。Google Cloud Storageのキーが1つでも無効な場合、Adaptyは**アップロードを中断**してエラーをスローします。 アップロードが中断されないよう、キーの有効期限が切れる前に更新してください。**イベント**のキーを更新した場合は、**ペイウォール訪問**のキーも忘れずに更新してください(逆も同様です)。 --- # File: webhook-event-types-and-fields --- --- title: "Webhookイベントの種類とフィールド" description: "" --- Adaptyはサブスクリプションイベントに応じてWebhookを送信します。このセクションでは、これらのイベントの種類と各Webhookに含まれるデータについて説明します。 ## Webhookイベントタイプ \{#webhook-event-types\} すべてのイベントタイプをWebhookに送信するか、一部のみを選択して送信できます。受信データの内容やビジネスロジックの構築方法については、[イベントフロー](event-flows)を参照してください。不要なイベントタイプは、[Webhook連携の設定](set-up-webhook-integration#configure-webhook-integration-in-the-adapty-dashboard)時に無効化できます。また、必要に応じてAdaptyのデフォルトイベントIDを独自のIDに置き換えることも可能です。 | イベント名 | 説明 | |:-----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | subscription_started | トライアル期間なしで有料サブスクリプションを開始したとき(つまり即座に課金されたとき)にトリガーされます。 | | subscription_renewed | サブスクリプションが更新され、ユーザーに課金されたときに発生します。このイベントはトライアルあり・なしを問わず、2回目以降の請求から記録されます。 | | subscription_renewal_cancelled | ユーザーがサブスクリプションの自動更新をオフにしました。有料サブスクリプション期間が終了するまでプレミアム機能へのアクセスは継続されます。 | | subscription_renewal_reactivated | ユーザーがサブスクリプションの自動更新を再度有効にしたときにトリガーされます。 | | subscription_expired | キャンセルされたサブスクリプションが完全に終了したときにトリガーされます。たとえば、12月12日にサブスクリプションをキャンセルしても12月31日まで有効な場合、イベントは12月31日に記録されます。 | | subscription_paused | ユーザーが[サブスクリプションの一時停止](https://developer.android.com/google/play/billing/lifecycle/subscriptions#pause)を有効にしたときに発生します(Android のみ)。 | | subscription_deferred | サブスクリプションの購入が[延期](https://adapty.io/glossary/subscription-purchase-deferral/)され、ユーザーが支払いを先送りしながらプレミアム機能へのアクセスを維持できる場合にトリガーされます。この機能は Google Play Developer API を通じて利用可能で、無料トライアルや支払いが困難なユーザーへの対応に活用できます。 | | non_subscription_purchase | 永続アクセスやゲーム内コインなどの消耗型アイテムといった、サブスクリプション以外のすべての購入。 | | trial_started | ユーザーがトライアルサブスクリプションを開始したときにトリガーされます。 | | trial_converted | トライアルが終了してユーザーに課金されたとき(初回購入)に発生します。たとえば、1月14日までトライアル期間があるにもかかわらず1月7日に課金された場合、イベントは1月7日に記録されます。 | | trial_renewal_cancelled | トライアル期間中にユーザーがサブスクリプションの自動更新をオフにしました。トライアルが終了するまでプレミアム機能へのアクセスは継続されますが、課金やサブスクリプションの開始は行われません。 | | trial_renewal_reactivated | トライアル期間中にユーザーがサブスクリプションの自動更新を再度有効にしたときに発生します。 | | trial_expired | サブスクリプションに転換されずにトライアルが終了したときにトリガーされます。 | | entered_grace_period | 支払い試行が失敗し、ユーザーがグレース期間(有効な場合)に入ったときに発生します。この期間中もユーザーはプレミアム機能にアクセスできます。 | | billing_issue_detected | 課金試行中に請求エラーが発生したとき(例:カード残高不足)にトリガーされます。 | | subscription_refunded | サブスクリプションが返金されたとき(例:Apple サポートによる返金)にトリガーされます。 | | non_subscription_purchase_refunded | サブスクリプション以外の購入が返金されたときにトリガーされます。 | | access_level_updated | ユーザーのアクセスレベルが更新されたときに発生します。 | :::note `subscription_renewal_reactivated` は、ユーザーがキャンセルした時点でアクティブだったプロダクト ID(**以前の**プロダクト ID)を保持します。これは、ユーザーが別のプロダクトを購入して再アクティブ化した場合でも同様です。Apple はキャンセル → 再アクティブ化の一連の流れを通じて同じ `original_transaction_id` を維持するため、このイベントは元のプロダクトを反映します。新しいプロダクトは、新しいプロダクトの課金が開始される次の `subscription_renewed` イベントで確認できます。 ::: ## Webhookイベントの構造 \{#webhook-event-structure\} Adaptyは、[Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook)ページの**Events names**セクションで選択したイベントのみを送信します。 Webhookイベントは JSON 形式でシリアライズされます。サーバーへの `POST` リクエストのボディには、以下の構造でラップされたシリアライズ済みイベントが含まれます。すべてのイベントは同じ構造に従いますが、フィールドの内容はイベントタイプ、ストア、および設定内容によって異なります。ユーザー属性は、設定した[カスタムユーザー属性](setting-user-attributes#custom-user-attributes)であるため、設定した内容が反映されます。アトリビューションデータのフィールドはすべてのイベントタイプで共通ですが、アトリビューションのリストはモバイルアプリで使用しているアトリビューションソースによって異なります。イベントの例を以下に示します: ```json title="Json" showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "idfv": "00000000-0000-0000-0000-000000000000", "idfa": "00000000-0000-0000-0000-000000000000", "advertising_id": "00000000-0000-0000-0000-000000000000", "profile_install_datetime": "2000-01-31T00:00:00.000000+0000", "user_agent": "ExampleUserAgent/1.0 (Device; OS Version) Browser/Engine", "email": "john.doe@company.com", "event_type": "subscription_started", "event_datetime": "2000-01-31T00:00:00.000000+0000", "event_properties": { "store": "play_store", "currency": "USD", "price_usd": 4.99, "profile_id": "00000000-0000-0000-0000-000000000000", "cohort_name": "All Users", "environment": "Production", "price_local": 4.99, "original_price_usd": 4.99, "original_price_local": 4.99, "discount_amount_usd": 0, "discount_amount_local": 0, "base_plan_id": "b1", "developer_id": "onboarding_placement", "ab_test_name": "onboarding_ab_test", "ab_test_revision": 1, "paywall_name": "UsedPaywall", "proceeds_usd": 4.2315, "variation_id": "00000000-0000-0000-0000-000000000000", "purchase_date": "2024-11-15T10:45:36.181000+0000", "store_country": "AR", "event_datetime": "2000-01-31T00:00:00.000000+0000", "proceeds_local": 4.2415, "tax_amount_usd": 0, "transaction_id": "0000000000000000", "net_revenue_usd": 4.2415, "profile_country": "AR", "paywall_revision": "1", "profile_event_id": "00000000-0000-0000-0000-000000000000", "tax_amount_local": 0, "net_revenue_local": 4.2415, "vendor_product_id": "onemonth_no_trial", "profile_ip_address": "10.10.1.1", "consecutive_payments": 1, "rate_after_first_year": false, "original_purchase_date": "2000-01-31T00:00:00.000000+0000", "original_transaction_id": "0000000000000000", "subscription_expires_at": "2000-01-31T00:00:00.000000+0000", "profile_has_access_level": true, "profile_total_revenue_usd": 4.99, "promotional_offer_id": null, "store_offer_category": null, "store_offer_discount_type": null }, "event_api_version": 1, "profiles_sharing_access_level": [{"profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem"}], "attributions": { "appsflyer": { "ad_set": "Keywords 1.12", "status": "non_organic", "channel": "Google Ads", "ad_group": null, "campaign": "Social media influencers - Rest of the world", "creative": null, "created_at": "2000-01-31T00:00:00.000000+0000" } }, "user_attributes": {"Favourite_color": "Violet", "Pet_name": "Fluffy"}, "integration_ids": {"firebase_app_instance_id": "val1", "branch_id": "val2", "one_signal_player_id": "val3"}, "play_store_purchase_token": { "product_id": "product_123", "purchase_token": "token_abc_123", "is_subscription": true } } ``` ### イベントフィールド \{#event-fields\} イベントパラメーターはすべてのイベントタイプで共通です。 | **フィールド** | **型** | **説明** | |---|---|---| | **advertising_id** | UUID | 広告ID(Android のみ)。 | | **attributions** | JSON | [アトリビューションデータ](webhook-event-types-and-fields#attributions)。[Webhook 設定](https://app.adapty.io/integrations/customwebhook)で **Send Attribution** が有効な場合に含まれます。 | | **customer_user_id** | String | [ユーザーの識別](ios-quickstart-identify)時にアプリコードで設定したアプリ側のユーザー ID(UUID、メールアドレス、その他の ID)。アプリコードでユーザーを識別していない場合、または該当ユーザーが匿名(未ログイン)の場合は `null` になります。 | | **email** | String | Adapty SDK の [`updateProfile`](setting-user-attributes) メソッド、またはサーバーサイド API でプロファイルを作成・更新する際に設定したユーザーのメールアドレス。`email` の値を SDK や API メソッドに渡していない場合は `null` になります。 | | **event_api_version** | Integer | Adapty API のバージョン(現在: `1`)。 | | **event_datetime** | ISO 8601 | イベントのビジネス上の有効時刻。購入イベントなら購入日時、有効期限イベントなら有効期限など、Adapty がイベントを受信・送信した時刻ではありません。[ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) 形式(例: `2020-07-10T15:00:00.000000+0000`)。順序については下記の注記を参照してください。 | | **event_properties** | JSON | [イベントプロパティ](webhook-event-types-and-fields#event-properties)。 | | **event_type** | String | Adapty 形式のイベント名。全リストは[Webhook イベントタイプ](webhook-event-types-and-fields#webhook-event-types)を参照してください。 | | **idfa** | UUID | 広告識別子(Apple のみ)。[Adapty ダッシュボード](https://app.adapty.io/profiles/users)のプロファイルに表示される **IDFA**。トラッキング制限、キッズモード、プライバシー設定により利用できない場合は `null` になる場合があります。 | | **idfv** | UUID | ベンダー識別子(IDFV)。開発者ごとに一意の値。[Adapty ダッシュボード](https://app.adapty.io/profiles/users)のプロファイルに表示される **IDFV**。 | | **integration_ids** | JSON | Adapty SDK の `setIntegrationIdentifier` メソッド、またはサーバーサイド API でプロファイルを作成・更新する際に設定したユーザーのインテグレーション ID。利用できない場合またはインテグレーションが無効な場合は `null`。 | | **play_store_purchase_token** | JSON | [Play Store 購入トークン](webhook-event-types-and-fields#play-store-purchase-token)。[Webhook 設定](https://app.adapty.io/integrations/customwebhook)で **Send Play Store purchase token** が有効な場合に含まれます。 | | **profile_id** | UUID | Adapty が各プロファイルに対して自動生成するプロファイル ID。ユーザーを識別しない場合やログイン前に購入を許可している場合、1 つの Apple/Google ID が異なるプロファイル ID と紐付く可能性があります。詳しくは[Adapty の親プロファイルと継承プロファイルの仕組み](how-profiles-work#parent-and-inheritor-profiles)を参照してください。 | | **profile_install_datetime** | ISO 8601 | [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) 形式のインストール日時(例: `2020-07-10T15:00:00.000000+0000`)。 | | **profiles_sharing_access_level** | JSON | 現在のユーザープロファイルを除く、[アクセスレベルを共有している](general#6-sharing-paid-access-between-user-accounts)ユーザーの一覧。アプリでアクセスレベルの共有が有効になっている場合、同じ Apple/Google ID で使用されている他のプロファイルが含まれます。<br/>形式: <ul><li>**profile_id**: (UUID)Adapty ID</li><li>**customer_user_id**: (String)設定されている場合のカスタマーユーザー ID</li></ul> | | **user_agent** | String | デバイスのブラウザユーザーエージェント。 | | **user_attributes** | JSON | アプリ固有の情報でユーザープロファイルを拡充するために設定できるカスタムデータ。ユーザーの設定(テーマ、言語など)や行動フラグ(オンボーディング完了、機能の使用状況)のトラッキングに主に使用します。<br/>キーが文字列、値が文字列または数値のキーバリューペアで表されます(例: `{"Favourite_color": "Violet", "Pet_name": "Fluffy"}`)。<br/>カスタム属性は、Adapty ダッシュボードで個別のプロファイルに対して手動で設定するか、Adapty SDK の `updateProfile` メソッドを使ってプログラムから設定するか、サーバーサイド API でプロファイルを作成・更新する際に設定できます。<br/>[Webhook 設定](https://app.adapty.io/integrations/customwebhook)で **Send User Attributes** が有効な場合に含まれます。 <p>モバイルアプリコードではカスタム属性値を float または文字列として設定できますが、サーバーサイド API や過去データのインポートで受け取った属性は異なる形式で届く場合があります。その場合、boolean と integer の値は float に変換されます。</p> | :::note `event_datetime` はサブスクリプションのライフサイクルでイベントが発生した日時を表しており、Adapty が処理または配信した日時ではありません。そのため、複数のイベントが同じ `event_datetime` を持つ場合や、時系列順とは異なる順序で届く場合があります。たとえば、`subscription_expired` イベントの `event_datetime` が、それより前に配信された `subscription_renewal_cancelled` イベントの `event_datetime` より早い場合があります。イベントの順序付けに `event_datetime` を使用しないでください。代わりに、受信時刻を基準にイベントを並べ替え、`profile_event_id` またはトランザクション ID を使って重複を排除してください。 ::: ### アトリビューション \{#attributions\} アトリビューションデータを送信するには、[Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook) ページで **Send Attribution** オプションを有効にしてください。アトリビューションデータの送信を有効にしており、[アトリビューション連携](attribution-integration)を設定済みの場合、以下のデータがすべてのソースのイベントに付与されて送信されます。同じアトリビューションデータはすべてのイベントタイプに送信されます。 ```json title="Json" showLineNumbers { "attributions": { "appsflyer": { "ad_set": "sample_ad_set_123", "status": "non_organic", "channel": "sample_channel", "ad_group": "sample_ad_group_456", "campaign": "sample_ios_campaign", "creative": "sample_creative_789", "created_at": "2000-01-31T00:00:00.000000+0000", "network_user_id": "0000000000000-0000000" } } } ``` | フィールド名 | フィールド型 | 説明 | | :------------------ | :------------ | :------------------------------------------------- | | **ad_set** | String | アトリビューションの広告セット。 | | **status** | String | `organic`、`non_organic,`、または `unknown` のいずれか。 | | **channel** | String | マーケティングチャネル名。 | | **ad_group** | String | アトリビューションの広告グループ。 | | **campaign** | String | マーケティングキャンペーン名。 | | **creative** | String | アトリビューションのクリエイティブキーワード。 | | **created_at** | ISO 8601 date | アトリビューションレコードの作成日時。 | | **network_user_id** | String | アトリビューションソースがユーザーに割り当てたID。 | ### インテグレーション ID \{#integration-ids\} 現在、イベントで使用されているインテグレーション ID は以下のとおりです: - `adjust_device_id` - `airbridge_device_id` - `amplitude_device_id` - `amplitude_user_id` - `appmetrica_device_id` - `appmetrica_profile_id` - `appsflyer_id` - `branch_id` - `facebook_anonymous_id` - `firebase_app_instance_id` - `mixpanel_user_id` - `pushwoosh_hwid` - `one_signal_player_id` - `one_signal_subscription_id` - `tenjin_analytics_installation_id` - `posthog_distinct_user_id` ### Play Store の購入トークン \{#play-store-purchase-token\} このフィールドには、必要に応じて購入を再検証するために必要なすべてのデータが含まれています。[Webhookインテグレーションの設定](https://app.adapty.io/integrations/customwebhook)で **Send Play Store purchase token** オプションが有効になっている場合にのみ送信されます。 | Field | Type | Description | | :------------------ | :------ | :----------------------------------------------------------- | | **product_id** | String | Play Store で購入したプロダクトの一意識別子(SKU)。 | | **purchase_token** | String | この購入トランザクションを一意に識別するために Google Play が生成するトークン。 | | **is_subscription** | Boolean | 購入したプロダクトがサブスクリプション(`true`)か買い切り購入(`false`)かを示します。 | ### イベントプロパティ \{#event-properties\} イベントプロパティは、イベントの種類によって、また同じ種類のイベント間でも異なる場合があります。たとえば、App Store から発生したイベントには、`base_plan_id` のような Android 固有のプロパティは含まれません。 [アクセスレベル更新](webhook-event-types-and-fields#for-access-level-updated-event)イベントには固有のプロパティがあるため、専用セクションを設けています。同様に、[追加の税・収益イベントプロパティ](webhook-event-types-and-fields#additional-tax-and-revenue-event-properties)も特定のイベントタイプのみに該当するため、別セクションに分けています。 #### ほとんどのイベントタイプに共通 \{#for-most-event-types\} ほとんどのイベントタイプのイベントプロパティは共通です(**Access Level Updated** イベントは除き、そちらは別セクションで説明しています)。以下の表は、各プロパティと、それが特定のイベントに属するかどうかをまとめたものです。 :::note Adapty は [currencylayer.com](https://currencylayer.com/) の為替レート(8時間ごとに更新)を使用して他の通貨を USD に変換します。レートは**取引時点で固定**されるため、その後の変動は変換結果に影響しません。 ::: | フィールド | 型 | 説明 | |:------------------------------|:--------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **ab_test_name** | String | トランザクションが発生した[Adapty A/B テスト](ab-tests)の名前。 | | **ab_test_revision** | Integer | トランザクションが発生した A/B テストのリビジョン。 | | **base_plan_id** | String | Google Play ストアの[ベースプラン ID](https://support.google.com/googleplay/android-developer/answer/12154973)、または Stripe の[価格 ID](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices)。 | | **cancellation_reason** | String | <p>キャンセルの理由として考えられる値: `voluntarily_cancelled`、`billing_error`、`price_increase`、`product_was_not_available`、`refund`、`cancelled_by_developer`、`new_subscription_replace`、`upgraded`、`unknown`、`adapty_revoked`。</p><p>以下のイベントタイプに含まれます:</p>`subscription_cancelled`、`subscription_refunded`、`trial_cancelled`。 | | **cohort_name** | String | ユーザーに表示するペイウォールを決定した[オーディエンス](audience)の名前。 | | **consecutive_payments** | Integer | ユーザーが中断なくサブスクリプションを継続している期間数。現在の期間を含みます。 | | **currency** | String | ローカル通貨。 | | **developer_id** | String | トランザクションが発生した[プレースメント](placements)の ID。 | | **discount_amount_local** | Float | トランザクションに適用された割引額: Apple/Google の手数料を差し引く前の、標準価格と実際に請求された金額の差(ローカル通貨)。通常価格での購入の場合は `0`。無料トライアルの場合は何も請求されないため、標準価格の全額(`original_price_local`)と等しくなります。オファーが適用されたが標準価格が不明な場合は `null`(`original_price_local` を参照)。App Store の前払いオファーでは常に `null`: 単一の前払い請求が複数の請求期間をカバーするため、期間ごとの標準価格と比較できません。 | | **discount_amount_usd** | Float | `discount_amount_local` の USD 換算値。 | | **environment** | String | 可能な値は `Sandbox` または `Production`。 | | **event_datetime** | ISO 8601 date | イベントの日時。イベントのルートレベルの値と同じです。 | | **original_price_local** | Float | Apple/Google の手数料を差し引く前の、プロダクトの標準(非割引)価格(ローカル通貨)。サブスクリプションの場合は更新時の価格です。通常価格での購入では `price_local` と等しく、買い切り購入では常に `price_local` と等しくなります(ストアが別途標準価格を報告しないため)。割引購入でストアが信頼できる標準価格を報告しない場合は `null`(例: 自動更新がオフ、更新にオファーが適用されている、またはプロダクト変更が保留中の場合)。 | | **original_price_usd** | Float | `original_price_local` の USD 換算値。 | | **original_purchase_date** | ISO 8601 date | 継続サブスクリプションの場合、初回購入とは更新チェーンの最初のトランザクションであり、そのIDはオリジナルトランザクションIDと呼ばれ、更新チェーンをつなぐものです。以降のトランザクションはその延長です。初回購入日は、この最初のトランザクションの日時です。 | | **original_transaction_id** | String | <p>継続サブスクリプションの場合、これは更新チェーンをつなぐオリジナルトランザクション ID です。オリジナルトランザクションはチェーンの最初のものであり、以降のトランザクションはその延長です。</p><p>延長がない場合、`original_transaction_id` は store_transaction_id と一致します。</p> | | **paywall_name** | String | トランザクションが発生したペイウォールの名前。 | | **paywall_revision** | String | トランザクションが発生したペイウォールのリビジョン。デフォルト値は 1。 | | **price_local** | Float | Apple/Google の手数料を差し引く前の、トランザクションで請求された金額(ローカル通貨)。無料トライアルは何も請求されないため `null`。 | | **price_usd** | Float | Apple/Google の手数料を差し引く前の、トランザクションで請求された金額(USD)。無料トライアルは何も請求されないため `null`。 | | **profile_country** | String | プロファイルの IP を基に Adapty が判定した国。 | | **profile_event_id** | UUID | 重複排除に使用できる一意のイベント ID。 | | **profile_has_access_level** | Boolean | プロファイルにアクティブなアクセスレベルがあるかどうかを示すブール値。 | | **profile_id** | UUID | Adapty が生成したプロファイル ID。イベントのルートレベルの値と同じです。 | | **profile_ip_address** | String | プロファイルの IP アドレス(IPv4 または IPv6。利用可能な場合は IPv4 が優先されます)。[アプリ設定](https://app.adapty.io/settings/general)で **Collect users' IP addresses** が無効になっている場合は `null`。 | | **profile_total_revenue_usd** | Float | 返金を差し引いたプロファイルの総収益(USD)。 | | **promotional_offer_id** | String | 使用された[プロモーションオファー](offers)の Adapty ID。ダッシュボードでオファーを作成する際にこの ID を設定します。 | | **purchase_date** | ISO 8601 date | プロダクトが購入された日時。 | | **rate_after_first_year** | Boolean | サブスクリプションが 1 年間継続更新した後に手数料の軽減(通常 15%)の対象となるかどうかを示すブール値。手数料率はプログラムの適格性や国によって異なります。詳細は[ストア手数料と税金](controls-filters-grouping-compare-proceeds#display-gross-or-net-revenue)を参照してください。 | | **store** | String | プロダクトが購入されたストア。標準値: **app_store**、**play_store**、**stripe**、**paddle**。<br/>サーバーサイド API を使用して[カスタムストアトランザクション](api-adapty/operations/setTransaction)を設定した場合、**store** パラメーターの値が使用されます。 | | **store_country** | String | アプリストアから送信された国情報。 | | **store_offer_category** | String | 適用されたオファーのカテゴリ。可能な値は `introductory`、`promotional`、`winback`。 | | **store_offer_discount_type** | String | 適用されたオファーのタイプ。可能な値は `free_trial`、`pay_as_you_go`、`pay_up_front`。 | | **store_offer_number_of_periods** | Integer | オファーが割引を適用するベース請求期間の数(1 以上)。オファーが適用されている場合のみ含まれます。App Store の前払いオファー、またはストアがオファー期間を報告しない場合は `null`。 | | **subscription_expires_at** | ISO 8601 date | サブスクリプションの有効期限。通常は将来の日時。 | | **transaction_id** | String | トランザクションの一意の識別子。 | | **trial_duration** | String | トライアル期間の日数。"{} days" の形式で送信されます(例: "7 days")。トライアル関連のイベントタイプ(`trial_started`、`trial_converted`、`trial_cancelled`)にのみ含まれます。 | | **variation_id** | UUID | 購入が行われたペイウォールの一意の ID。 | | **vendor_product_id** | String | <p>Apple App Store、Google Play ストア、または Stripe におけるプロダクト ID。</p><p>実際のストアトランザクションなしでアクセスが付与された場合、`vendor_product_id` は以下のいずれかになります:</p><ul><li>`adapty_server_side_product` — [サーバーサイド API](api-adapty/operations/grantAccessLevel) 経由で付与された場合。</li><li>`adapty_dashboard_product` — Adapty ダッシュボードで[手動付与](give-access-level-to-specific-customer)された場合。</li><li>`adapty_promotion` — レガシー。</li></ul> | #### 税金と収益に関する追加イベントプロパティ \{#additional-tax-and-revenue-event-properties\} 以下の税金と収益に関するイベントプロパティは、特定のイベントタイプにのみ適用される追加フィールドです。つまり、ここに列挙されているイベントタイプには、[ほとんどのイベントタイプ共通のイベントプロパティ](webhook-event-types-and-fields#for-most-event-types)に加えて、以下の追加フィールドが含まれます。 税金と収益に関するイベントプロパティを持つイベントタイプ: - `subscription_renewed` - `subscription_initial_purchase`(`subscription_started` とも呼ばれる — 同じイベント) - `subscription_refunded` - `non_subscription_purchase` | フィールド | 型 | 説明 | | :-------------------- | :---- | :----------------------------------------------------------- | | **net_revenue_local** | Float | ローカル通貨でのネット収益(Apple/Google の手数料および税金控除後の収入)。 | | **net_revenue_usd** | Float | USD でのネット収益(Apple/Google の手数料および税金控除後の収入)。 | | **proceeds_local** | Float | ローカル通貨での Apple/Google 手数料控除後のプロダクト価格。 | | **proceeds_usd** | Float | Apple/Google 手数料控除後のプロダクト価格(USD)。 | | **tax_amount_local** | Float | ローカル通貨での控除税額。 | | **tax_amount_usd** | Float | USD での控除税額。 | #### `non_subscription_purchase` のペイロード例 \{#non-subscription-purchase-example-payload\} `non_subscription_purchase` はサブスクリプションイベントと同じ構造に従いますが、買い切り購入または消耗型アイテムの購入を反映します。サブスクリプション専用フィールドは適用されません。`cancellation_reason`、`will_renew`、`is_in_grace_period`、`is_refund`、`is_lifetime`、`trial_duration` は存在しません。`subscription_expires_at` は含まれますが `null` になります。税金および収益フィールド(`net_revenue_*`、`proceeds_*`、`tax_amount_*`)は含まれます。 <details> <summary>ペイロード例(クリックして展開)</summary> ```json title="Json" showLineNumbers { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "event_type": "non_subscription_purchase", "event_datetime": "2000-01-31T00:00:00.000000+0000", "event_properties": { "store": "app_store", "currency": "USD", "price_usd": 4.99, "price_local": 4.99, "original_price_usd": 4.99, "original_price_local": 4.99, "discount_amount_usd": 0, "discount_amount_local": 0, "proceeds_usd": 4.2415, "proceeds_local": 4.2415, "net_revenue_usd": 4.2415, "net_revenue_local": 4.2415, "tax_amount_usd": 0, "tax_amount_local": 0, "profile_id": "00000000-0000-0000-0000-000000000000", "environment": "Production", "vendor_product_id": "100coins", "transaction_id": "0000000000000000", "original_transaction_id": "0000000000000000", "purchase_date": "2024-11-15T10:45:36.181000+0000", "original_purchase_date": "2024-11-15T10:45:36.181000+0000", "subscription_expires_at": null, "store_country": "US", "profile_country": "US", "profile_ip_address": "10.10.1.1", "profile_has_access_level": false, "profile_total_revenue_usd": 4.99, "consecutive_payments": 1, "rate_after_first_year": false, "profile_event_id": "00000000-0000-0000-0000-000000000000" }, "event_api_version": 1 } ``` </details> #### アクセスレベル更新イベントについて \{#for-access-level-updated-event\} **Access Level Updated** イベントは、Webhook インテグレーションが有効であり、このイベントタイプが有効になっている場合にのみ生成される特定の Webhook イベントです。有効になっている場合、設定済みの Webhook に送信され、**Event Feed** に表示されます。有効になっていない場合、イベントは作成されません。 [アクセスレベルの共有](general#6-sharing-paid-access-between-user-accounts)を有効にしている場合、**access level updated** イベントはアクセスレベルを共有しているすべてのプロファイルに対して送信されます。 :::tip このイベントを使用して、データベース内のユーザーのアクセスレベルを更新し、バックエンドでプレミアム機能を付与または取り消し、デバイスやプラットフォーム間でアクセスを同期させましょう。 ::: | プロパティ | タイプ | 説明 | | ---------------------------------- | ------------- | ------------------------------------------------------------ | | **ab_test_name** | String | トランザクションが発生した A/B テストの名前。 | | **access_level_id** | String | アクセスレベルの ID。 | | **activated_at** | ISO 8601 date | アクセスが最後にアクティブ化された日時。 | | **active_introductory_offer_type** | String | 適用された初回オファーのタイプ。指定可能な値は `free_trial`、`pay_as_you_go`、`pay_up_front`。 | | **active_promotional_offer_id** | String | Adapty ダッシュボードの Product セクションに記載されたプロモーションオファーの ID。 | | **active_promotional_offer_type** | String | 適用されたプロモーションオファーのタイプ。指定可能な値は `free_trial`、`pay_as_you_go`、`pay_up_front`。 | | **base_plan_id** | String | Google Play ストアの[ベースプラン ID](https://support.google.com/googleplay/android-developer/answer/12154973)、または Stripe の[価格 ID](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices)。 | | **billing_issue_detected_at** | ISO 8601 date | 請求問題が発生した日時。 | | **cancellation_reason** | String | キャンセル理由として考えられる値: `voluntarily_cancelled`、`billing_error`、`price_increase`、`product_was_not_available`、`refund`、`cancelled_by_developer`、`new_subscription_replace`、`upgraded`、`unknown`、`adapty_revoked`。 | | **cohort_name** | String | プロファイルが属するオーディエンスの名前。 | | **currency** | String | ローカル通貨(デフォルトは USD)。 | | **developer_id** | String | トランザクションが発生したプレースメントの ID。 | | **environment** | String | 指定可能な値は `Sandbox` または `Production`。 | | **event_datetime** | ISO 8601 date | イベントの日時。 | | **expires_at** | ISO 8601 date | アクセスが失効する日時。 | | **is_active** | Boolean | アクセスレベルがアクティブかどうかを示す Boolean 値。 | | **is_in_grace_period** | Boolean | プロファイルがグレース期間中かどうかを示す Boolean 値。 | | **is_lifetime** | Boolean | アクセスレベルが永続アクセスかどうかを示す Boolean 値。 | | **is_refund** | Boolean | トランザクションが返金かどうかを示す Boolean 値。 | | **original_purchase_date** | ISO 8601 date | 自動更新サブスクリプションの場合、最初のトランザクションが「オリジナル購入」となり、その ID(オリジナルトランザクション ID)が以降の更新トランザクションのチェーンをつなぐ。以降のトランザクションはこの最初のトランザクションの延長である。オリジナル購入日はこの最初のトランザクションの日時。 | | **original_transaction_id** | String | <p>自動更新サブスクリプションの場合、更新チェーンをつなぐオリジナルトランザクション ID。オリジナルトランザクションはチェーンの最初のもので、以降のトランザクションはその延長である。</p><p>延長がない場合、`original_transaction_id` は store_transaction_id と一致する。</p>最初の購入のトランザクション識別子。 | | **paywall_name** | String | トランザクションが発生したペイウォールの名前。 | | **paywall_revision** | String | トランザクションが発生したペイウォールのリビジョン。デフォルト値は 1。 | | **profile_country** | String | プロファイルの IP を基に Adapty が判定した国。 | | **profile_event_id** | UUID | 重複排除に使用できる一意のイベント ID。 | | **profile_has_access_level** | Boolean | プロファイルにアクティブなアクセスレベルがあるかどうかを示す Boolean 値。 | | **profile_id** | UUID | Adapty の内部ユーザープロファイル ID。 | | **profile_ip_address** | String | プロファイルの IP アドレス(IPv4 または IPv6。利用可能な場合は IPv4 が優先される)。[アプリ設定](https://app.adapty.io/settings/general)で **Collect users' IP addresses** が無効になっている場合は `null`。 | | **profile_total_revenue_usd** | Float | プロファイルの累計収益(返金を含む)。 | | **purchase_date** | ISO 8601 date | プロダクトを購入した日時。 | | **renewed_at** | ISO 8601 date | アクセスが更新される日時。 | | **starts_at** | ISO 8601 date | アクセスレベルが開始する日時。 | | **store** | String | プロダクトを購入したストア。標準値: **app_store**、**play_store**、**stripe**、**paddle**。<br/>サーバーサイド API で[カスタムストアトランザクション](api-adapty/operations/setTransaction)を設定した場合は、**store** パラメータの値が使用される。 | | **store_country** | String | アプリストアから Adapty に送信された国。 | | **subscription_expires_at** | ISO 8601 date | サブスクリプションの有効期限。 | | **transaction_id** | String | トランザクションの一意の識別子。 | | **trial_duration** | String | トライアル期間の日数(例:「7 days」)。 | | **variation_id** | UUID | バリアントの識別子。購入をこのペイウォールに紐付けるために使用される。 | | **vendor_product_id** | String | <p>ストア(Apple / Google / Stripe)内のプロダクト ID。</p><p>実際のストアトランザクションなしでアクセスが付与された場合、`vendor_product_id` は以下のいずれかになる:</p><ul><li>`adapty_server_side_product` — [サーバーサイド API](api-adapty/operations/grantAccessLevel) 経由で付与された。</li><li>`adapty_dashboard_product` — Adapty ダッシュボードで[手動付与](give-access-level-to-specific-customer)された。</li><li>`adapty_promotion` — レガシー。</li></ul> | | **will_renew** | Boolean | 有料アクセスレベルが更新されるかどうかを示す値。 | :::warning この構造は、私たちまたは連携するサードパーティによって新しいデータが追加されることで、今後拡張される可能性があります。この構造を処理するコードは、構造全体ではなく特定のフィールドに依存するよう、十分に堅牢に実装してください。 ::: --- # File: set-up-webhook-integration --- --- title: "Webhook連携の設定" description: "AdaptyでWebhook連携を設定してイベントトラッキングを自動化します。" --- Adaptyの[webhook連携](webhook)は、以下のステップで構成されています。 <img src="/assets/shared/img/webhook-setup.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> 1. **エンドポイントを設定する:** 1. サーバーが **Content-Type** ヘッダーを `application/json` に設定したAdaptyリクエストを処理できることを確認します。 2. サーバーがAdaptyの検証リクエストを受信し、任意の `2xx` ステータスとJSONボディで応答するよう設定します。 3. 接続が確認されたら、[サブスクリプションイベントを処理します](#subscription-events)。 2. **[Adapty ダッシュボード](#configure-webhook-integration-in-the-adapty-dashboard)でwebhook連携を設定して有効化します。** [Adaptyのイベントをカスタムイベント名にマッピング](#configure-webhook-integration-in-the-adapty-dashboard)することもできます。本番環境に切り替える前に、**Sandbox環境**でテストすることをおすすめします。 3. **Adaptyがサーバーに検証リクエストを送信します。** 4. **サーバーが** `2XX` ステータスとJSONボディで**応答します。** 5. **Adaptyが有効なレスポンスを受信すると、サブスクリプションイベントの送信を開始します。** ## Adaptyリクエストを処理するサーバーを設定する \{#set-up-your-server-to-process-adapty-requests\} AdaptyはWebhookエンドポイントに2種類のリクエストを送信します。 1. [検証リクエスト](#verification-request): 接続が正しく設定されているか確認するための初回リクエストです。このリクエストにはイベントは含まれず、Adapty ダッシュボードのWebhook連携で **Save** ボタンをクリックした瞬間に送信されます。エンドポイントが検証リクエストを正常に受信したことを確認するため、エンドポイントは検証レスポンスを返す必要があります。 2. [サブスクリプションイベント](#subscription-events): Adaptyサーバーでイベントが作成されるたびに送信される標準リクエストです。サーバーは特定のレスポンスを返す必要はありません。Adaptyサーバーが必要とするのは、メッセージを正常に受信した場合に標準の200コードHTTPレスポンスを受け取ることだけです。 ### 検証リクエスト \{#verification-request\} Adapty ダッシュボードでwebhook連携を有効にすると、Adaptyは空のJSONオブジェクト `{}` をボディとして含むPOST検証リクエストを送信します。 エンドポイントの **Content-Typeヘッダー** が `application/json` になるよう設定してください。つまり、サーバーのエンドポイントは受信するWebhookリクエストのペイロードがJSON形式でフォーマットされることを想定している必要があります。 サーバーは2xxステータスコードで応答し、以下のような有効なJSONレスポンスを返す必要があります。 ```json title="Json" {} ``` Adaptyが正しい形式かつ2xxステータスコードの検証レスポンスを受信すると、AdaptyのWebhook連携は完全に設定された状態になります。 ### サブスクリプションイベント \{#subscription-events\} サブスクリプションイベントは **Content-Type** ヘッダーが `application/json` に設定された状態で送信され、JSON形式のイベントデータが含まれます。可能なイベントタイプとリクエスト構造については、[Webhookイベントの種類とフィールド](webhook-event-types-and-fields)を参照してください。 ## Adapty ダッシュボードでWebhook連携を設定する \{#configure-webhook-integration-in-the-adapty-dashboard\} Adaptyでは、本番イベントとApple・Sandbox環境またはGoogleテストアカウントから受信するテストイベントに対して、別々のフローを設定できます。 :::tip Adaptyは環境(本番とサンドボックス)ごとに1つのWebhook URLをサポートしています。複数のサービスにイベントを配信するには、Webhookを自分のバックエンドに向けてそこからファンアウトしてください。 ::: 本番イベントには、コールバックの送信先URLを指定する **Production endpoint URL** フィールドを使用します。また、**Authorization header value for production endpoint** フィールドも設定してください。これはサーバーがAdaptyイベントを認証するためのヘッダーです。**Authorization header value for production endpoint** フィールドに指定した値は、変更や追加なしにそのまま `Authorization` ヘッダーとして使用されることにご注意ください。 テストイベントには、**Sandbox endpoint URL** と **Authorization header value for sandbox endpoint** フィールドをそれぞれ使用します。 Webhook連携を設定するには: 1. Adapty ダッシュボードで [Integrations -> Webhook](https://app.adapty.io/integrations/customwebhook) を開きます。 <img src="/assets/shared/img/webhook_integration.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. トグルをオンにして連携を開始します。 4. 連携フィールドに入力します。 | フィールド | 説明 | | ------------------------------------------------------ | ------------------------------------------------------------ | | **Production endpoint URL** | AdaptyがHTTP POSTリクエストを本番環境のイベントとして送信するURL。 | | **Authorization header value for production endpoint** | <p>本番環境でサーバーがAdaptyからのリクエストを認証するためのヘッダー。このフィールドに指定した値は、変更や追加なしにそのまま `Authorization` ヘッダーとして使用されることにご注意ください。</p><p></p><p>必須ではありませんが、セキュリティ強化のために強くお勧めします。</p> | サンドボックス環境でのテスト用に、さらに2つのフィールドが利用可能です。 | テストフィールド | 説明 | | --------------------------------------------------- | ------------------------------------------------------------ | | **Sandbox endpoint URL** | AdaptyがサンドボックスHTTP POSTリクエストを送信するURL。 | | **Authorization header value for sandbox endpoint** | <p>サンドボックス環境でのテスト中にサーバーがAdaptyからのリクエストを認証するためのヘッダー。このフィールドに指定した値は、変更や追加なしにそのまま `Authorization` ヘッダーとして使用されることにご注意ください。</p><p></p><p>必須ではありませんが、セキュリティ強化のために強くお勧めします。</p> | 4. (任意)受信するイベントを選択して名前をマッピングします。様々な状況でどのイベントが発生するかは、[イベントフロー](event-flows)をご確認ください。 イベントIDがAdaptyで使用されているものと異なる場合は、システム内のIDをそのまま維持し、[Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook) ページの **Events names** セクションでデフォルトのAdaptyイベントIDをご自身のIDに置き換えてください。 イベントIDには任意の文字列を使用できます。Webhookを処理するサーバーのイベントIDと、Adapty ダッシュボードに入力したIDが一致していることを確認してください。有効なイベントのイベントIDを空のままにすることはできません。 <img src="/assets/shared/img/86942b8-event_names_renaming.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. その他のフィールドや設定は任意です。必要に応じて使用してください。 | 設定 | 説明 | | :--------------------------------- | :----------------------------------------------------------- | | **Send Trial Price** | 有効にすると、Adaptyは **Trial Started** イベントの `price_local` と `price_usd` フィールドにサブスクリプション価格を含めます。 | | **Exclude Historical Events** | ユーザーがAdapty SDKを含むアプリをインストールする前に発生したイベントを除外するオプションです。これによりイベントの重複を防ぎ、正確なレポートを確保します。例えば、ユーザーが1月10日に月次サブスクリプションを有効化し、3月6日にAdapty SDK付きのアプリにアップデートした場合、Adaptyは3月6日より前のイベントを省略し、以降のイベントを保持します。 | | **Send user attributes** | このオプションを有効にすると、言語設定などのユーザー固有の属性が送信されます。これらの属性は `user_attributes` フィールドに表示されます。詳細については、[イベントフィールド](webhook-event-types-and-fields#event-fields)を参照してください。 | | **Send attribution** | このオプションをオンにすると、`attributions` フィールドにアトリビューション情報(AppsFlierデータなど)が含まれます。詳細は[アトリビューションデータ](webhook-event-types-and-fields#attributions)セクションを参照してください。 | | **Send Play Store purchase token** | このオプションをオンにすると、必要に応じて購入の再検証に必要なPlay Storeトークンを受け取れます。有効にすると、イベントに `play_store_purchase_token` パラメータが追加されます。その内容の詳細については、[Play Store購入トークン](webhook-event-types-and-fields#play-store-purchase-token)セクションを参照してください。 | 6. **Save** ボタンをクリックして変更を確定することを忘れないでください。 **Save** ボタンをクリックした瞬間、Adaptyは検証リクエストを送信し、サーバーからの検証レスポンスを待ちます。 ### 送信するイベントを選択してイベント名をマッピングする \{#choose-events-to-send-and-map-event-names\} 受信したいイベントの横にあるトグルを有効にして、サーバーで受信するイベントを選択します。Adaptyで使用されているイベント名と異なる名前を使用していて、そのままの名前を維持したい場合は、[Integrations -> Webhooks](https://app.adapty.io/integrations/customwebhook) ページの **Events names** セクションでデフォルトのAdaptyイベント名をご自身のものに置き換えてマッピングを設定できます。 <img src="/assets/shared/img/86942b8-event_names_renaming.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> イベント名には任意の文字列を使用できます。有効なイベントのフィールドを空のままにすることはできません。誤ってAdaptyのイベント名を削除してしまった場合は、[サードパーティ連携に送信するイベント](events)のトピックからいつでも名前をコピーできます。 ## Webhookイベントを処理する \{#handle-webhook-events\} Webhookは通常、イベント発生後5〜60秒以内に配信されます。ただし、キャンセルイベントはユーザーがサブスクリプションをキャンセルしてから最大2時間後に配信される場合があります。 サーバーのレスポンスステータスコードが200〜404の範囲外の場合、Adaptyは指数バックオフで再送を試みます。最初の再試行は初回の失敗からおよそ**1分後**に行われ、その後は試行ごとに間隔が倍になり、最大9回の再試行が24時間にわたって行われます。Adaptyが応答する前にイベントボディの基本的な検証のみを行うようWebhookを設定することをお勧めします。サーバーがイベントを処理できず、Adaptyに再試行させたくない場合は、200〜404の範囲内のステータスコードを使用してください。また、時間のかかるタスクは非同期で処理し、Adaptyに素早く応答するようにしてください。Adaptyが10秒以内にレスポンスを受信しない場合、その試行は失敗とみなされ、再試行が行われます。 --- # File: test-webhook --- --- title: "Webhookインテグレーションのテスト" description: "AdaptyでWebhookインテグレーションをテストし、サブスクリプションイベントの追跡を自動化します。" --- インテグレーションを設定したら、次はテストを行いましょう。サンドボックスと本番のどちらのインテグレーションもテストできます。まずサンドボックスから始めて、以下の項目を十分に検証することをおすすめします: - イベントが送信され、正常に配信されること。 - 過去のイベント、**Trial started** イベントのサブスクリプション価格、アトリビューション、ユーザー属性、Google Play ストアの購入トークンについて、送信・非送信のオプションが正しく設定されていること。 - イベント名が正しくマッピングされており、サーバーで処理できること。 ## テスト方法 \{#how-to-test\} インテグレーションのテストを始める前に、以下が完了していることを確認してください: 1. [Webhookインテグレーションの設定](set-up-webhook-integration)のトピックに従ってWebhookインテグレーションを設定済みであること。 2. [Apple App StoreでのIn-App Purchaseのテスト](test-purchases-in-sandbox)および[Google Play StoreでのIn-App Purchaseのテスト](testing-on-android)のトピックに従って環境を設定済みであること。テストアプリが本番環境ではなくサンドボックス環境でビルドされていることを確認してください。 3. Webhookに送信するよう選択したイベントを発生させる購入・トライアル開始・返金などを実行済みであること。例えば、**Subscription started** イベントを取得するには、新しいサブスクリプションを購入します。 ## 結果の検証 \{#validation-of-the-result\} ### イベント送信成功時の結果 \{#successful-sending-events-result\} インテグレーションが正常に機能した場合、イベントはインテグレーションの **Last sent events** セクションに表示され、**Success** ステータスになります。 <img src="/assets/shared/img/6ccc3bb-webhook_integration_success.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### イベント送信失敗時の結果 \{#unsuccessful-sending-events-result\} | 問題 | 解決策 | |-----|--------| | イベントが表示されない | 購入が完了しなかったため、イベントが作成されませんでした。解決策については[テスト購入のトラブルシューティング](troubleshooting-test-purchases)のトピックを参照してください。 | | イベントが表示され、**Sending failed** ステータスになっている | <p>配信可否はHTTPステータスに基づいて判定し、**200〜399の範囲外**はすべて失敗とみなします。</p><p>詳しい原因を確認するには、以下に示すように失敗したイベントの **Sending failed** ステータスにマウスを重ねてください。</p> | <img src="/assets/shared/img/12ff189-hover_sending_failed.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: handle-integration-errors --- --- title: "インテグレーションのエラーを処理する" description: "インテグレーションのエラーを処理する" --- アトリビューション、メッセージング、またはアナリティクスのインテグレーションを使用する際に、いくつかの一般的なエラーが発生することがあります。トラブルシューティングのケースについては、このガイドを参照してください。 ## データの不一致 \{#data-discrepancy\} **原因**: Adapty SDK が含まれているアプリバージョンを使用していないユーザーが存在するために発生する可能性があります。 **解決策**: データの一貫性を確保するために、ユーザーに Adapty SDK が含まれているバージョンへのアップデートを促すことができます。 ## ネットワークエラー \{#network-errors\} **原因**: Adapty サーバーとインテグレーションサーバー間のインターネット接続が途切れた可能性が高いです。 **解決策**: このような問題は通常長く続かず、影響を受けるイベントの数もごく少数です。 ## インテグレーションサーバーがイベントの処理に失敗した \{#integration-server-failed-to-process-the-event\} **原因**: インテグレーションが正しく設定されていません。 **解決策**: ドキュメントのインテグレーションに関する記事を参照してください。Adapty ダッシュボード、サードパーティツール側、およびアプリコードの両方で、すべてのセットアップ手順を完了していることを確認してください。 ## インテグレーションデータが不足している \{#missing-integration-data\} **原因**: プロファイルにインテグレーション固有の ID が含まれていません。これはアプリコードでインテグレーションが正しく設定されていない場合に発生することがあります。 **解決策**: ドキュメントのインテグレーションに関する記事を参照してください。アプリコードにコードスニペットのメソッドを実装し、それらのメソッドが実際にユーザープロファイルと連携していることを確認してください。 ## インテグレーションの認証情報が不足している \{#missing-integration-credentials\} **原因**: インテグレーションの一部の認証情報が不足しているか、正しくありません。 **解決策**: Adapty ダッシュボードでそのインテグレーションの認証情報をすべて確認してください。バージョンまたは環境の不一致が原因で問題が発生することがあります。 ## イベントの有効期限が切れた \{#the-event-has-expired\} **原因**: インテグレーション設定で **Exclude historical events** オプションが有効になっており、イベントの作成日がシステム内のプロファイル作成日より前になっています。 これは、数年前に開始されたトランザクションのチェーンが、最近作成されたプロファイルのレシート検証を通じて Adapty に届いた場合に発生することがあります。 **解決策**: 新しいイベントでこれが発生しないようにしてください。過去のイベントをインテグレーションに送信したい場合は、**Exclude historical events** を無効にしてください。 ## 無効/未対応のイベントタイプ \{#disabledunsupported-event-type\} **原因**: このインテグレーションでイベントがサポートされていないか、インテグレーションのセットアップ時に無効にされています。たとえば、`access_level_updated` イベントはほとんどのインテグレーションでサポートされていません。 **解決策**: インテグレーションのドキュメントで、そのインテグレーションがこのイベントタイプをサポートしているか確認してください。サポートされている場合は、Adapty ダッシュボードでそのイベントタイプがインテグレーション設定で有効になっていることを確認してください。 --- # File: manage-adapty-with-ai --- --- title: "AIエージェントとコーディングツールでAdaptyを管理する" description: "AdaptyをAIと組み合わせるすべての方法 — コーディングエージェントでSDKを統合したり、LLMでアナリティクスを取得したり、AIツールにAdaptyのドキュメントを提供したりできます。" --- AdaptyはAIコーディングツールやエージェントと連携できます。SDKの統合、アナリティクスへの質問、エディタを離れずにAdaptyのドキュメントを検索するなど、さまざまな用途に活用できます。このページでは利用可能なツールと、それぞれの対象ユーザーを紹介します。 ## AIでAdapty SDKを統合する \{#integrate-the-adapty-sdk-with-ai\} AIコーディングツールを使ってAdapty SDKをアプリに追加する方法は2つあります。どちらもCursor、Claude、その他のAIアシスタントで動作します。 ### スキルベースの統合 \{#skill-based-integration\} Adapty SDK統合スキルは、AIコーディングツールからワンコマンドで統合全体を実行します。ガイド付きの自動セットアップが必要な場合に使用してください。 プラットフォームを選択してください: [iOS](adapty-sdk-integration-skill) · [Android](adapty-sdk-integration-skill-android) · [React Native](adapty-sdk-integration-skill-react-native) · [Flutter](adapty-sdk-integration-skill-flutter) · [Unity](adapty-sdk-integration-skill-unity) · [Kotlin Multiplatform](adapty-sdk-integration-skill-kmp) · [Capacitor](adapty-sdk-integration-skill-capacitor) ### ステップバイステップの統合 \{#step-by-step-integration\} 適切なドキュメントを順番に提供しながら、AIツールを統合の各段階でガイドします。各ステップを確認しながら進めたい場合に使用してください。 プラットフォームを選択してください: [iOS](adapty-cursor) · [Android](adapty-cursor-android) · [React Native](adapty-cursor-react-native) · [Flutter](adapty-cursor-flutter) · [Unity](adapty-cursor-unity) · [Kotlin Multiplatform](adapty-cursor-kmp) · [Capacitor](adapty-cursor-capacitor) ## コマンドラインからAdaptyを管理する \{#manage-adapty-from-the-command-line\} [Adapty Developer CLI](developer-cli-quickstart)を使用すると、ダッシュボードを開かずにターミナルからAdaptyのエンティティ(アプリ、アクセスレベル、プロダクト、ペイウォール、プレースメント)を管理できます。コマンドラインツールなので、AIコーディングエージェントから直接実行できます。 ## データについて質問する \{#ask-about-your-data\} AIコーディングエージェントをExport Analytics APIに向けると、収益、リテンション、LTVなどの指標を自然言語でクエリできます。MCPサーバーは不要です。 [AIにアナリティクスデータについて質問する](export-analytics-with-ai) ## AIツールにAdaptyのドキュメントを提供する \{#give-your-ai-tool-the-adapty-docs\} ### プレーンテキストのドキュメント \{#plain-text-docs\} すべてのAdaptyドキュメントはMarkdown形式で利用できます。ページURLに`.md`を追加するか、タイトルの下にある **Copy for LLM** をクリックしてください。より広いコンテキストを提供するには、[`llms.txt`](https://adapty.io/docs/ja/llms.txt)インデックスや[`ios-llms.txt`](https://adapty.io/docs/ja/ios-llms.txt)などのプラットフォーム別サブセットをツールに渡してください。 ### Context7 \{#context7\} [Context7](https://context7.com/adaptyteam/adapty-docs)はAdaptyのドキュメントをAIツールに提供するMCPサーバーですが、コードスニペットのみをインデックスし、散文全体はインデックスしません。簡単なコード例を調べる場合に使用してください。完全なガイダンスが必要な場合は、上記のプレーンテキストのドキュメントをツールに提供してください。Context7はCursor、Claude Code、Windsurf、その他のMCP対応ツールで動作します。 --- # File: export-analytics-with-ai --- --- title: "AI にアナリティクスデータについて質問する" description: "Export Analytics API を使用して、AIコーディングエージェントで Adapty アナリティクスを自然言語でクエリします。" --- Ask an AI coding agent about your Adapty analytics in plain language — revenue, conversions, retention, LTV — and let it pull the numbers for you. Point a tool that can make API calls at the [Export Analytics API](https://adapty.io/docs/ja/export-analytics-api.md), and it queries your metrics on demand. ## 質問できる内容 \{#what-you-can-ask-about\} Export Analytics API は、Adapty ダッシュボードのチャートで確認できる指標と同じものを返します。各指標には固有のオペレーションがあります。 | 指標 | カバー範囲 | オペレーション | | --- | --- | --- | | Revenue、MRR、ARR、ARPU | 期間・国・キャンペーン別にグループ化された収益 | [retrieveAnalyticsData](https://adapty.io/docs/ja/api-export-analytics/operations/retrieveAnalyticsData.md) | | コホートリテンション | 特定のコホートのサブスクライバーが支払いを継続する期間 | [retrieveCohortData](https://adapty.io/docs/ja/api-export-analytics/operations/retrieveCohortData.md) | | コンバージョン率 | あるステップやチャネルから次のステップに進むユーザー数 | [retrieveConversionData](https://adapty.io/docs/ja/api-export-analytics/operations/retrieveConversionData.md) | | チャーンとファネル | ユーザーが離脱する箇所と解約スピード | [retrieveFunnelData](https://adapty.io/docs/ja/api-export-analytics/operations/retrieveFunnelData.md) | | ライフタイムバリュー(LTV) | 時間経過によるユーザーセグメントあたりの平均収益 | [retrieveLTVData](https://adapty.io/docs/ja/api-export-analytics/operations/retrieveLTVData.md) | | リテンション | 一定日数後もアクティブなユーザーの割合 | [retrieveRetentionData](https://adapty.io/docs/ja/api-export-analytics/operations/retrieveRetentionData.md) | APIパラメーターとフィルターの全一覧については、[APIリファレンス](https://adapty.io/docs/ja/api-export-analytics.md)をご覧ください。 ## 始める前に \{#before-you-start\} 次の3つが必要です: - **データのある Adapty アカウント**: この API はダッシュボードのチャートと同じ指標を返すため、アプリがすでにアナリティクスを収集している必要があります。 - **シークレット API キー**: [App settings → General](https://app.adapty.io/settings/general) の **Secret key** フィールドで確認できます。キーはアプリごとに異なるため、アプリごとに別々のキーを使用してください。エージェントがチャットに貼り付けずに読み取れるよう、環境変数(例: `ADAPTY_SECRET_KEY`)に保存してください。 - **API を呼び出せる AI ツール**: Claude Code、Cursor、またはフェッチツールを備えた Claude Desktop などが使えます。claude.ai や ChatGPT のような通常のチャットツールは直接 API を呼び出せません。 ## エージェントにAPI仕様を提供する \{#give-your-agent-the-api-spec\} [OpenAPI仕様](https://adapty.io/docs/ja/api-specs/export-analytics-api.yaml)には、すべてのエンドポイント、認証ヘッダー、リクエストボディ、レスポンス例が記載されています。エージェントがこの仕様を参照することで、コードを書かなくても正しいリクエストを構築できます。 エージェントにURLで仕様を渡す: - **URLを貼り付ける**: エージェントがURLを取得できる場合は、`https://adapty.io/docs/ja/api-specs/export-analytics-api.yaml` を渡して仕様を読むよう指示してください。 - **フェッチツールを使用する**: エージェントにURLを取得するツール(例:MCP フェッチサーバー)がある場合は、同じURLを指定してください。 仕様にはベースURLとして `https://api-admin.adapty.io` が設定されているため、キーが環境に設定されていれば、エージェントは必要なものをすべて揃えています。 ## データについて質問する \{#ask-about-your-data\} スペックを読み込み、APIキーを環境変数に設定したら、取得したい指標を平易な言葉で説明してください。 プロンプトの例: ``` What was my MRR at the end of each month this year, and how does it compare to last year? Show my trial-to-paid conversion rate for the last 90 days, broken down by product. Which countries drive the most revenue from my yearly subscription? Top 10. How is week-1 retention trending for subscribers who started in the last 6 months? What's the refund rate on my annual plan since launch, by month? Compare LTV for paid-campaign users vs. organic over the last year, and export it as CSV. ``` エージェントはリクエストを適切なオペレーションにマッピングし、環境変数からキーを読み取ってデータを返します。レスポンスはデフォルトでJSONです。スプレッドシートに適したファイルが必要な場合はCSVをリクエストしてください — エージェントはリクエストボディの `format` を `csv` に設定します。 :::warning シークレットキーは環境変数に保存してください — チャットに貼り付けたり、ルールファイルにコミットしたりしないでください。キーはアプリ固有のため、漏洩した場合は **Settings → General** でローテーションしてください。[APIキーのローテーション](https://adapty.io/docs/ja/export-analytics-api-authorization.md)を参照してください。 ::: ## セッションをまたいで再利用するための初期設定 \{#set-up-once-for-repeated-use\} 毎回セットアップを繰り返さなくて済むよう、エージェントが再利用できる場所にスペックとキーを保存しておきましょう。 - **スペックリンクを保存する**: スペックのURLをエージェントのルールやメモリファイル(例:`CLAUDE.md`やCursorのルールファイル)に追加しておくと、毎セッションで自動的に読み込まれます。 - **キーを環境変数に保存する**: `ADAPTY_SECRET_KEY`をシェルプロファイルやツールのシークレットストアに保存しておけば、二度と貼り付ける手間がかかりません。 - **よく使うプロンプトを保存するか、カスタムスキルを作成する**: よく使う質問を保存済みプロンプトとして管理するか、カスタムスキルやスラッシュコマンドとしてまとめておくと、オンデマンドでレポートを実行できます。 ## 制限事項 \{#limits\} 以下の制約に注意してください。 - **レート制限**: APIはAPIキーごとに1秒あたり2リクエストまで許可されています。超過すると`429 Too Many Requests`エラーが返ります。`429`が返ったときは待ってからリトライするようエージェントに伝えてください。 - **アプリごとのキー**: 各キーは1つのアプリにのみ有効です。複数アプリのデータを取得する場合は、アプリごとに対応するキーを提供してください。 - **出力フォーマット**: レスポンスはデフォルトでJSON形式です。CSVでエクスポートするには、リクエストボディで`format`を`csv`に設定してください。 認証とリクエストのルールの詳細は、[認証とリクエスト形式](export-analytics-api-authorization)を参照してください。 --- # File: handle-webhooks-with-ai --- --- title: "ウェブフックでAdaptyのサブスクリプションイベントを処理する" description: "ウェブフックを使ってサーバーでAdaptyのサブスクリプションイベントを受信・処理する方法 — エンドポイントの設定、認証、ペイロード、テストを1ページで解説。" --- Webhookを使うと、サーバーがAdaptyのサブスクリプションイベント(購入、更新、キャンセル、請求エラー、返金)をリアルタイムで受信できます。アクセス権の付与、バックエンドとの同期、ワークフローのトリガーなどに活用できます。このガイドでは、エンドポイントの設定から検証済みの統合テストまでを1ページで説明し、AIコーディングエージェントを使ってハンドラーを自動生成する方法も紹介します。 :::tip AIコーディングエージェントを使っていますか?タイトル下の **Copy for LLM** をクリックして、このページ全体をエージェントに貼り付けてください。セットアップ、ペイロード、ハンドラーロジックがすべて含まれています。 ::: ## Adapty ウェブフックの仕組み \{#how-adapty-webhooks-work\} - **一方向かつリアルタイム**: イベントが発生すると、Adapty がサーバーに HTTP `POST` を送信します。ポーリング不要です。 - **2 種類のリクエスト**: インテグレーション保存時に送信される一回限りの確認リクエストと、継続的なサブスクリプションイベントの 2 種類があります。 - **環境ごとに 1 つの URL**: 本番環境とサンドボックス環境それぞれに別々のエンドポイントを設定します。 - **各リクエストへの応答が必要**: `2xx` ステータスをすばやく返してください。失敗した場合、Adapty はリトライします。 ## エンドポイントを構築する \{#build-your-endpoint\} 2種類のリクエストを処理する公開HTTPSエンドポイントを作成します。 - **確認リクエスト**: インテグレーションを保存したときに1回送信されます。JSONボディは空(`{}`)です。`2xx` ステータスとJSONボディを返してください。 - **サブスクリプションイベント**: イベントをボディに含む継続的な `POST` リクエストです。10秒以内に `200` を返し、重い処理は非同期で行ってください。 シークレット文字列を選んで環境変数(例:`ADAPTY_WEBHOOK_SECRET`)として保存してください。リクエストのたびに `Authorization` ヘッダーがその値と一致するか検証し、一致しない場合はリクエストを拒否します。この同じシークレットを、次のステップでダッシュボードに入力します。 ```javascript title="webhook.js" const app = express(); app.use(express.json()); const WEBHOOK_SECRET = process.env.ADAPTY_WEBHOOK_SECRET; app.post("/adapty/webhook", (req, res) => { // 1. Verify the shared secret Adapty echoes back. if (req.get("Authorization") !== WEBHOOK_SECRET) { return res.sendStatus(401); } // 2. Acknowledge fast, then process asynchronously. res.status(200).json({}); // 3. The verification request has an empty body — nothing to handle. const event = req.body; if (!event.event_type) return; switch (event.event_type) { case "subscription_started": case "subscription_renewed": case "trial_converted": // Grant or extend access. break; case "subscription_expired": case "subscription_refunded": // Revoke access. break; default: break; } }); app.listen(3000); ``` Adaptyはエンドポイントを保存した瞬間に検証リクエストを送信するため、インテグレーションを設定する前にエンドポイントをパブリックなHTTPS URLにデプロイしておいてください。 ### 主なイベントとペイロード \{#key-events-and-the-payload\} すべてのイベントは同じエンベロープを共有しています。フィールドはイベントタイプ、ストア、有効にしたオプションによって異なります。以下は `subscription_started` イベントの簡略版です。 ```json title="Example event" { "profile_id": "00000000-0000-0000-0000-000000000000", "customer_user_id": "UserIdInYourSystem", "event_type": "subscription_started", "event_datetime": "2024-11-15T10:45:36.181000+0000", "event_properties": { "store": "play_store", "currency": "USD", "price_usd": 4.99, "vendor_product_id": "onemonth_no_trial", "transaction_id": "0000000000000000", "original_transaction_id": "0000000000000000", "subscription_expires_at": "2024-12-15T10:45:36.181000+0000", "profile_event_id": "00000000-0000-0000-0000-000000000000" }, "event_api_version": 1 } ``` 最もよく扱うイベント: | イベントタイプ | 発火タイミング | | --- | --- | | `subscription_started` | ユーザーが有料サブスクリプションを開始したとき | | `subscription_renewed` | サブスクリプションが正常に更新・課金されたとき | | `subscription_renewal_cancelled` | ユーザーが自動更新をオフにしたとき(アクセスは有効期限まで継続) | | `subscription_expired` | 更新されなかったサブスクリプションの有効期限が切れてアクセスが終了したとき | | `trial_started` | ユーザーが無料トライアルを開始したとき | | `trial_converted` | トライアルが有料サブスクリプションに転換したとき | | `billing_issue_detected` | 更新時の支払いが失敗したとき | | `subscription_refunded` | サブスクリプションの購入が返金されたとき | 全イベントの一覧とフィールドの詳細については、[Webhookイベントのタイプとフィールド](https://adapty.io/docs/ja/webhook-event-types-and-fields.md)を参照してください。 :::warning `event_datetime` でイベントを並べないでください。これはイベントのビジネス上の発生時刻であるため、イベントが順序どおりに届かなかったり、同じタイムスタンプを持つ場合があります。並べ替えには自分の受信時刻を使用し、`profile_event_id` またはトランザクションIDを使って重複を排除してください。 ::: ## Adapty でウェブフックを設定する \{#configure-the-webhook-in-adapty\} 1. Adapty ダッシュボードで [Integrations → Webhook](https://app.adapty.io/integrations/customwebhook) を開きます。 2. インテグレーションをオンにします。 3. **Production endpoint URL** に、デプロイしたエンドポイントの HTTPS URL を入力します。 4. **Authorization header value for production endpoint** に、エンドポイントが検証に使用するシークレットと同じ値を入力します。Adapty はすべてのリクエストの `Authorization` ヘッダーにこの値を付与して送信します。省略可能ですが、強く推奨されます。 5. 先にサンドボックスでテストする場合は、**Sandbox endpoint URL** とその **Authorization header value** も入力します。 6. **Save** をクリックします。Adapty はすぐにエンドポイントへ検証リクエストを送信し、エンドポイントが `2xx` を返すとセットアップが完了します。 送信するイベントの選択、イベント名のマッピング、オプションフィールド(トライアル価格、過去のイベント、アトリビューション、ユーザー属性、Play Store トークン)の有効化については、[Webhook インテグレーションの設定](https://adapty.io/docs/ja/set-up-webhook-integration.md)をご参照ください。 ## AIコーディングエージェントで構築する \{#build-it-with-your-ai-coding-agent\} このガイドとリファレンスドキュメントをMarkdown形式(任意のページURLに`.md`を追加)でAIコーディングエージェントに渡し、使用しているスタックを伝えて、ハンドラーのひな形を生成させましょう。 - [Webhookイベントの種類とフィールド](https://adapty.io/docs/ja/webhook-event-types-and-fields.md) - [Webhook連携のセットアップ](https://adapty.io/docs/ja/set-up-webhook-integration.md) プロンプトの例: ``` Read these Adapty webhook docs, then write a webhook handler for my Express app: verify the Authorization header against ADAPTY_WEBHOOK_SECRET, answer the verification request, acknowledge events with 200, and grant or revoke access based on event_type. ``` The agent writes the handler code, but it can't deploy your endpoint or configure the dashboard — host the endpoint yourself and set the URL and secret in **Integrations → Webhook**. ## Webhookをテストする \{#test-your-webhook\} 本番環境に移行する前に、サンドボックスでテストしましょう: 1. 上記の手順に従って、サンドボックス用のエンドポイントとシークレットを設定します。 2. サンドボックスアプリで、購入・トライアル開始・返金などを行い、イベントをトリガーします。 3. インテグレーションの **Last sent events** セクションを開きます。正常に配信されたイベントには **Success** ステータスが表示されます。 **Sending failed** と表示されている場合、サーバーが200〜399の範囲外のステータスを返しています。ステータスにカーソルを合わせると詳細を確認できます。テストの詳細な手順については、[Webhookインテグレーションのテスト](https://adapty.io/docs/ja/test-webhook.md)をご覧ください。 ## 制限事項 \{#limits\} - **10秒以内に応答すること**: 時間内にレスポンスが返らない場合、Adapty はその試みを失敗とみなして再試行します。 - **再試行**: ステータスが 200〜404 の範囲外の場合、Adapty は指数バックオフで再試行します — 24時間以内に最大 9 回まで。 - **キャンセルの遅延**: キャンセルイベントは届くまで最大 2 時間かかる場合があります。 - **環境ごとに URL は 1 つ**: 複数のサービスにイベントを配信したい場合は、自分のバックエンドに Webhook を向け、そこからファンアウトしてください。 --- # File: server-side-api-with-ai --- --- title: "バックエンドからサブスクリプションアクセスを確認・付与する" description: "Adapty のサーバーサイド API を使って、ユーザーのサブスクリプションがアクティブかどうかを確認し、手動でアクセスを付与する方法を AI コーディングエージェントとともに解説します。" --- バックエンドから Adapty のサーバーサイド API を使って、ユーザーのアクティブなサブスクリプションを確認したり、アクセスを手動で付与したりできます。このガイドでは、最もよく使われる 2 つの呼び出し — `getProfile` と `grantAccessLevel` — を取り上げ、AI コーディングエージェントを使って自分のスタック向けに統合を実装する方法を説明します。 :::tip AI コーディングエージェントを使っていますか?タイトル下の **Copy for LLM** をクリックして、このページ全体をエージェントに貼り付けてください。必要な呼び出し、フィールド、注意点がすべて含まれています。 ::: ## 始める前に \{#before-you-start\} - **シークレット API キー**: [App settings → General](https://app.adapty.io/settings/general) の **Secret key** フィールドで確認できます。キーはアプリごとに異なります。環境変数(例: `ADAPTY_SECRET_KEY`)に保存し、`Authorization: Api-Key {key}` の形式で送信してください。 - **ベース URL**: すべてのリクエストは `https://api.adapty.io` に送信します。 - **ユーザーの識別方法**: `adapty-customer-user-id`(独自のユーザー ID — アプリでユーザーを識別している場合のみ使用可能)または `adapty-profile-id`(Adapty のプロファイル ID)のいずれかを送信します。どちらも同じように使えるので、どちらか一方を使用してください。 ## サブスクリプションを確認する \{#check-a-subscription\} ステータスを確認するには、`getProfile` を `GET` で呼び出し、ユーザー識別子をヘッダーとして渡します。リクエストボディは不要です。 ```javascript title="check-access.js" const res = await fetch("https://api.adapty.io/api/v2/server-side-api/profile/", { headers: { "Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`, "adapty-customer-user-id": userId, }, }); const { data } = await res.json(); function hasActiveAccess(profile, accessLevelId = "premium") { const level = profile.access_levels?.find(a => a.access_level_id === accessLevelId); if (!level) return false; if (level.is_in_grace_period) return true; if (!level.expires_at) return true; // lifetime / non-expiring return new Date(level.expires_at) > new Date(); // not expired yet } if (hasActiveAccess(data)) { // unlock premium features } ``` SDKのプロファイルとは異なり、サーバーサイドのレスポンスには **`is_active` フィールドがありません**。ステータスは `access_levels[].expires_at` から自分で判定してください。`null` の場合は永続アクセス、未来の日付の場合はアクティブ、過去の日付の場合は期限切れです。`is_in_grace_period` はアクティブとして扱ってください。プロファイルおよびアクセスレベルのフィールドの詳細については、[getProfile](https://adapty.io/docs/ja/api-adapty/operations/getProfile.md) を参照してください。 ## アクセスレベルを手動で付与する \{#grant-access-manually\} 購入なしで有料機能を解放したい場合(プロモーションコード、投資家・ベータアクセス、サポート対応など)は、`grantAccessLevel` を `POST` で呼び出します。 ```javascript title="grant-access.js" await fetch("https://api.adapty.io/api/v2/server-side-api/purchase/profile/grant/access-level/", { method: "POST", headers: { "Authorization": `Api-Key ${process.env.ADAPTY_SECRET_KEY}`, "adapty-customer-user-id": userId, "Content-Type": "application/json", }, body: JSON.stringify({ access_level_id: "premium" }), // 一時的なアクセスには "expires_at" を追加 }); ``` - **アクセスレベルはダッシュボード(**Access levels**)に事前に存在している必要があります** — `access_level_id` はその識別子であり、新しい名前ではありません。 - **手動付与はアナリティクスに表示されません**。Webhook インテグレーションと Event Feed にのみ配信されるため、収益やコンバージョンのチャートには反映されません。 リクエストとレスポンスの詳細については、[grantAccessLevel](https://adapty.io/docs/ja/api-adapty/operations/grantAccessLevel.md) を参照してください。 ## AIコーディングエージェントで構築する \{#build-it-with-your-ai-coding-agent\} このガイドとAPIスペックをMarkdown形式(任意のページURLに`.md`を追加)でAIコーディングエージェントに渡し、使用するスタックを伝えれば、あとはエージェントがAPIコールを書いてくれます: - [OpenAPI仕様](https://adapty.io/docs/ja/api-specs/adapty-api.yaml) - [getProfile](https://adapty.io/docs/ja/api-adapty/operations/getProfile.md) - [grantAccessLevel](https://adapty.io/docs/ja/api-adapty/operations/grantAccessLevel.md) プロンプト例: ``` Using the Adapty server-side API spec, write backend functions to check whether a user has an active "premium" access level (GET /profile/, derive status from expires_at — there's no is_active field) and to grant it (grantAccessLevel). Authenticate with ADAPTY_SECRET_KEY and identify users by adapty-customer-user-id. ``` The agent writes the code, but it can't run your backend or set your keys — you provide the secret key and the user identifiers. ## 制限 \{#limits\} - **レート制限**: アプリごとに1分あたり最大40,000リクエスト。 - **アプリ固有のキー**: 各キーは1つのアプリにのみ使用可能です。アプリごとに対応するキーを使用してください。 - **識別子の必須指定**: すべてのリクエストには `adapty-customer-user-id` または `adapty-profile-id` が必要です。 --- # File: test-purchases-in-sandbox --- --- title: "サンドボックステスト" description: "サンドボックス環境で購入をテストして、スムーズなトランザクションを確認しましょう。" --- Adapty ダッシュボードとモバイルアプリの設定が完了したら、アプリ内課金のテストを実施しましょう。 **注意:** テストツールはいずれも、プロダクトの購入テスト時にユーザーへの課金は行いません。App Store はテスト環境での購入や返金に関するメールを送信しません。 :::note **サンドボックスのトランザクションはすべてのアナリティクスチャートから除外されます。** 個々のプロファイルページやイベントフィードには引き続き表示されます。 ::: :::info アプリ内課金テストを進めるにあたり、以下を確認してください。 - ストア連携、プロダクトの追加、Adapty SDK の連携に関する[クイックスタート](quickstart)ガイドが完了していること。 - プロダクトが App Store Connect で [**Ready to submit**](InvalidProductIdentifiers#step-2-check-products) としてマークされていること。 ::: ## サンドボックステスト \{#sandbox-testing\} <div style={{ maxWidth: '560px', margin: '0 auto 2rem', position: 'relative', aspectRatio: '16/9', width: '100%' }}> <iframe style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%' }} src="https://www.youtube.com/embed/hq4PRU-vuik?si=m5F5Sj6iLEJ-2q6n" title="YouTube video player" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerPolicy="strict-origin-when-cross-origin" allowFullScreen /> </div> :::info アプリ内課金のテストは実機で行うことをお勧めします。サンドボックス購入はシミュレーターでも実行できますが、支払いダイアログや生体認証プロンプトを含むすべてのフローを完全にテストするには実機が必要です。 ::: アプリ内課金のテスト方法は主に 2 つあります。 - **Xcode でビルドしてテストデバイスで実行する**: 開発者や QA エンジニアに適しています。 - **TestFlight でサンドボックステストアカウントを使用する**: その他の方に適しています。 どちらの方法も以下のガイドで説明しています。 ### ステップ 1. App Store Connect でサンドボックステストアカウントを作成する \{#step-1-create-sandbox-test-account-in-app-store-connect\} :::warning 購入履歴をクリーンな状態に保つため、新しいサンドボックステストアカウントを作成してください。既存のアカウントを再利用すると、以前に購入したプロダクトが引き続き利用可能なため、それらのプロダクトの購入テストが行えません。 ::: 新しいサンドボックステストアカウントは数クリックで作成できます。 1. App Store Connect の [**Users and Access** > **Sandbox** > **Test Accounts**](https://appstoreconnect.apple.com/access/users/sandbox) に移動し、**+** をクリックします。 <img src="/assets/shared/img/add-sandbox-user.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. テストユーザーの詳細を入力します。テストする **Country or Region** を必ず設定してください。これはリージョンのプロダクト利用可否や購入通貨に影響します。 :::tip - Gmail や iCloud をお使いの場合は、[プラス記号サブアドレッシング](https://www.wikihow.com/Use-Plus-Addressing-in-Gmail)を使って既存のメールアドレスを再利用できます。 - 実際には存在しないランダムなメールアドレスも使用できますが、後でテストデバイスにサインインする際に 2 段階認証(2FA)を拒否するようにしてください。 ::: <img src="/assets/shared/img/57c3a7c-apple_new_test_account.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Create** をクリックします。 ### ステップ 2. デベロッパーモードを有効にする \{#step-2-enable-the-developer-mode\} :::note テストデバイスでデベロッパーモードが**すでに有効になっている**場合、または **Mac デバイスをお持ちでない**場合は、このステップをスキップしてください。 ::: Xcode がインストールされた Mac とテストデバイスのケーブルが必要です。 1. Mac で Xcode を開きます。TestFlight でアプリ内課金をテストする場合は、Xcode がインストールされていれば十分で、アプリを開く必要はありません。 2. ケーブルを使ってテストデバイスを Mac に接続します。 3. テストデバイスで **Settings > Privacy & Security > Developer Mode** に移動し、**Developer Mode** をオンにします。 ### ステップ 3. TestFlight からアプリをダウンロードする \{#step-3-download-the-app-from-testflight\} :::info このステップは TestFlight でテストする場合にのみ適用されます。Xcode でアプリをビルドする場合はスキップしてください。 ::: TestFlight へのアプリの提出については、[Apple のドキュメント](https://developer.apple.com/documentation/StoreKit/testing-in-app-purchases-with-sandbox#Prepare-for-sandbox-testing)を参照してください。 TestFlight アプリをダウンロードする前に、テストデバイスで本番の Apple アカウントにサインインしていることを確認してください。その後、TestFlight からテストするアプリをダウンロードします。 :::danger ダウンロードしたらアプリを開かないでください。次のステップに進んでください。 誤って開いてしまった場合は、テストデバイスからアプリを削除して再度ダウンロードしてください。そうしないと購入履歴がクリーンな状態にならず、アプリ内課金のテストでエラーが発生する可能性があります。 ::: ### ステップ 4. サンドボックステストアカウントに切り替える \{#step-4-switch-to-sandbox-test-account\} <Details> <summary>Mac をお使いでない方へ</summary> macOS をお使いでない場合、Xcode を使ってサンドボックスアカウントに切り替えることはできません。ただし、テストデバイス上で直接切り替えることができます。 1. テストデバイスで **Settings > Your Apple Account > Media & Purchases** に移動します。 2. ポップアップメニューから **Sign Out** を選択します。 3. TestFlight からダウンロードしたアプリを開き、プロダクトを購入しようとします。 4. サインインを求められたら、サンドボックスアカウントの認証情報を入力してサンドボックス環境に切り替えます。 </Details> サンドボックスアカウントに切り替えるには: 1. テストデバイスで **Settings > Your Apple Account > Media & Purchases** に移動します。 2. ポップアップメニューから **Sign Out** を選択します。 3. **Settings > Developer** に移動します。**Developer** オプションが表示されない場合は、[ステップ 2 で有効にしているか](#step-2-enable-the-developer-mode)確認してください。 <img src="/assets/shared/img/devmode.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Sandbox Apple Account** セクションまでスクロールし、**Sign In** をタップします。 <img src="/assets/shared/img/sandbox-acc.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. サンドボックス Apple アカウントの認証情報でサインインします。 ### ステップ 5. 購入履歴をクリアする \{#step-5-clear-purchase-history\} 新しいサンドボックステストアカウントを作成して切り替えたばかりの場合は、このステップをスキップできます。このステップは同じサンドボックステストアカウントを使って繰り返しテストする場合にのみ適用されます。 1. テストデバイスで **Settings > Developer > Sandbox Apple Account** に移動します。 2. ポップアップメニューから **Manage** を選択します。 3. **Account Settings** に移動し、**Clear Purchase History** をタップします。 :::danger このステップは同じサンドボックステストアカウントを使ってテストを繰り返すたびに必要です。この場合、[サンドボックステストアカウントからサインアウト](#step-4-switch-to-sandbox-test-account)した後、再度サインインしてテストデバイス上の購入履歴キャッシュをクリアする必要があります。 ::: ### ステップ 6. Xcode でビルドして実行する \{#step-6-build-in-xcode-and-run\} :::info このステップは Xcode ビルドでテストする場合にのみ適用されます。TestFlight を使用する場合はスキップしてください。 ::: 1. テストデバイスを Mac に接続します。 2. Xcode を開きます。 3. ツールバーの **Run** をクリックするか、**Product > Run** を選択して、接続されたデバイスでアプリをビルドして実行します。 ビルドが成功すると、Xcode はデバイス上でアプリを起動し、デバッグエリアにデバッグセッションを開きます。 これでデバイス上でのテストの準備が整いました。 ### ステップ 7. テスト購入を行う \{#step-7-make-test-purchase\} アプリを開き、ペイウォールからテスト購入を行います。 完了したら、[テスト購入の検証](validate-test-purchases)の記事で結果を確認してください。 ### ステップ 8. テストを続ける \{#step-8-keep-testing\} テスト環境の準備が整いました。再度テストしたい場合は、[サンドボックスアカウントの購入履歴をクリア](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings/)してください。 ## テストに関する問題 \{#testing-issues\} 以下はアプリテスト時によく発生する問題です。 ### TestFlight の問題 \{#testflight-issues\} **サンドボックステストアカウントなしで TestFlight を使用している場合**は購入履歴をクリアできないため、さまざまな問題や誤ったテスト結果が生じます。 誤って[サンドボックステストアカウントへの切り替え](#step-4-switch-to-sandbox-test-account)を忘れてアプリを一度でも開いてしまうと、TestFlight は購入履歴を本番の Apple アカウントに紐付けてしまい、予期せぬ問題が発生します。 修正するには、以下の手順に従ってください。 1. テストデバイスからアプリを削除します。 2. [サンドボックステスト](#sandbox-testing)の手順に従います。 :::note アプリを再インストールするだけでなく、サンドボックステストアカウントに切り替え、購入履歴をクリアし、サンドボックステストアカウントを使ってアプリを起動することが重要です。 ::: ### 共有アクセスレベルの問題 \{#shared-access-levels-issues\} 同じサンドボックステストアカウントを使って繰り返しテストすると、テストユーザーの[共有アクセスレベル](sharing-paid-access-between-user-accounts)で予期しない動作が発生することがあります。 ユーザーが継承されたアクセスレベルを持っているか確認するには、Adapty ダッシュボードの [Profiles & Segments](https://app.adapty.io/profiles/users) からユーザーのプロファイルを開いてください。 <img src="/assets/shared/img/profile-access-level-origin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ユーザーが継承されたアクセスレベルを持っている場合は、正確なテスト結果を得るために以下の手順に従ってください。 1. 親プロファイルを削除します。 2. テストデバイスからアプリを削除します。 3. [TestFlight からアプリをダウンロードします](#step-3-download-the-app-from-testflight)。 4. [サンドボックステストアカウントに切り替えます](#step-4-switch-to-sandbox-test-account)。 5. [購入履歴をクリアします](#step-5-clear-purchase-history)。 6. [アプリを開いてテスト購入を行います](#step-6-make-test-purchase)。 :::note 購入履歴のクリアがストア側の購入をリセットします。親プロファイルの削除は Adapty 側の記録を削除するだけです。再利用したアカウントがアクセスを保持し続ける理由と、実際に機能するリセット方法については、[テスターのサブスクリプションのリセット](#resetting-a-testers-subscription)を参照してください。 ::: ### TestFlight でのアプリの更新 \{#updating-app-in-testflight\} TestFlight アプリが更新された場合: 1. テストデバイスからアプリを削除します。 2. [TestFlight からアプリをダウンロードします](#step-3-download-the-app-from-testflight)。 3. [サンドボックステストアカウントに切り替えます](#step-4-switch-to-sandbox-test-account)。 4. [購入履歴をクリアします](#step-5-clear-purchase-history)。 5. [アプリを開いてテスト購入を行います](#step-6-make-test-purchase)。 ## テスターのサブスクリプションのリセット \{#resetting-a-testers-subscription\} サンドボックス環境では、購入は Adapty プロファイルではなく **Apple サンドボックスアカウント**に紐付けられます。プロファイルに対して行う操作(削除やアクセスレベルの編集)は、ストアアカウントから購入を削除しません。次回の再インストールや同期時に、SDK は同じトランザクションを再紐付けし、テスターは再びアクセスを得ます。 以下の表は、各リセット操作が何を変更するか、またその後テスターがどうなるかを示しています。 | 操作 | Adapty プロファイル | Apple サンドボックスアカウント | テスターのその後のアクセス | | :--- | :--- | :--- | :--- | | Adapty ダッシュボードでプロファイルを削除 | 削除済み | 変更なし | **復元される** — 再インストール時に新しいプロファイルが同じトランザクションチェーンを再紐付け | | [Delete profile API](api-adapty/operations/deleteProfile) でプロファイルを削除 | 削除済み | 変更なし | **復元される** — ダッシュボードでの削除と同じ | | **Add access level** で過去の有効期限を追加 | 次の同期時に上書き | 変更なし | 次の更新時に**復元される** — 有効なサブスクリプションが将来の有効期限を再適用 | | [Revoke access level API](api-adapty/operations/revokeAccessLevel) を呼び出す | 即時失効、`access_level_updated`(`is_active=false`)が発火 | 変更なし | 次の更新や再インストール時に**復元される** — サンドボックスのリセットとして信頼性が低い | | サンドボックスアカウントでサブスクリプションをキャンセル | 直接変更なし | サブスクリプションキャンセル済み | 更新が停止し、現在の期間が終了するとアクセスが終了。テスターは再度プロダクトを購入可能 | | 新しい Apple サンドボックスアカウントでサインイン | 新しいプロファイル | 新しい空のアカウント | **クリーン** — 繰り返しテストに推奨 | ### テスターをクリーンな状態にリセットする \{#reset-a-tester-to-a-clean-state\} 購入フローの繰り返しテストには、テストごとに新しい Apple サンドボックスアカウントを使用してください。アカウントの作成は[ステップ 1](#step-1-create-sandbox-test-account-in-app-store-connect)、デバイスでの切り替えは[ステップ 4](#step-4-switch-to-sandbox-test-account) に従ってください。既存のサンドボックスアカウントを再利用する場合は、先に[購入履歴をクリア](#step-5-clear-purchase-history)してください。Adapty プロファイルを削除してもクリアされません。 ### 既存テスターのアクセスを削除する \{#remove-access-from-an-existing-tester\} テスターのアクセスを削除するには、有効期限を過去に設定したり Revoke access level API を呼び出したりしないでください。サンドボックスでは、サブスクリプションは数分ごとに自動更新されます。更新のたびに同じトランザクションチェーンに将来の有効期限が復元されるため、アクセスは自動的に復活します。Revoke access level API は `access_level_updated`(`is_active=false`)イベントを発火しますが、次の更新でそれが上書きされます。 アクセスを実際に停止するには、ストア側でサブスクリプションをキャンセルしてください。テストデバイスで **Settings > Developer > Sandbox Apple Account** に移動し、**Manage** を選択して、サブスクリプションをキャンセルします。更新が停止し、現在の期間が終了するとアクセスが終了します。 ### プロファイルを削除するとアクセスが復活する理由 \{#why-deleting-the-profile-brings-access-back\} テスターがアプリを再インストールすると、Adapty はサンドボックスアカウントの購入履歴を受け取り、新しいインストールを既存の購入に紐付けます。購入は削除したプロファイルではなく、ストアアカウントに紐付いています。 - **匿名プロファイル**: `customer_user_id` なしで再インストールすると、[有料アクセス共有](sharing-paid-access-between-user-accounts)の設定に関わらず、常にストアアカウントのアクセスレベルを継承します。 - **識別済みプロファイル**: アクセスが新しい `customer_user_id` に引き継がれるかどうかは、有料アクセス共有の設定によります。 Adapty がこれらのプロファイルをチェーンとして紐付ける仕組みについては、[プロファイルの仕組み](how-profiles-work#parent-and-inheritor-profiles)を参照してください。 ## テストサブスクリプション \{#test-subscriptions\} サンドボックステストアカウントを使ってアプリをテストする際、サンドボックス内の各テスターのサブスクリプション更新レートを設定できます。サブスクリプション更新レートの編集について詳しくは、[Apple の公式ドキュメント](https://developer.apple.com/help/app-store-connect/test-in-app-purchases/manage-sandbox-apple-account-settings)を参照してください。 デフォルトでは、サブスクリプションは停止するまで最大 12 回更新されます。スケジュールは以下の通りです。 | サブスクリプション期間 | 1 週間 | 1 ヶ月 | 2 ヶ月 | 3 ヶ月 | 6 ヶ月 | 1 年 | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | | サブスクリプション更新速度 | 3 分 | 5 分 | 10 分 | 15 分 | 30 分 | 1 時間 | | 請求リトライ期間 | 10 分 | 10 分 | 10 分 | 10 分 | 10 分 | 10 分 | | 請求グレース期間 | 3 分 | 5 分 | 5 分 | 5 分 | 5 分 | 5 分 | :::note テストトランザクションが [Event feed](validate-test-purchases) に表示されるまで最大 10 分かかることに注意してください。 ::: サンドボックスは、更新・請求リトライ・グレース期間のアプリとバックエンドの処理を確認するために使用してください。本番環境の更新タイミングを予測するためのものではありません。上記の加速・上限付きスケジュールは本番環境とは異なります。バックエンドテスト用にサーバーでトランザクションを再実行するには、[Set transaction API](api-adapty/operations/setTransaction) を使用してください。 ## テストオファー \{#test-offers\} オファーのテストでは、適格性が正しく機能するために、すべてのユーザーレシートを削除する必要があります。 オファーをテストする最も確実な方法は、まったく新しい[サンドボックステストアカウント](#step-1-create-sandbox-test-account-in-app-store-connect)を使用することです。同じサンドボックステストアカウントを使って繰り返しテストすると、予期しない動作が発生する可能性があります。 :::danger 同じサンドボックステストアカウントを使って繰り返しテストする場合は、適格性関連の問題を避けるため、必ず[購入履歴をクリア](#step-5-clear-purchase-history)してください。 ::: --- # File: local-sk-files --- --- title: "XcodeでのStoreKitテスト" description: "サンドボックス環境でアプリ内課金をテストして、スムーズなトランザクションを確認しましょう。" --- XcodeでのStoreKitテストを使用すると、サンドボックスアカウントを設定することなく、アプリ内課金をローカルでテストできます。 このテストを行うには、次の手順が必要です: 1. [Adaptyでプロダクトを作成し](quickstart-products)、**App Store product ID** を割り当てます。 2. Xcodeで、ローカルの [StoreKit設定ファイル](https://developer.apple.com/documentation/xcode/setting-up-storekit-testing-in-xcode) を作成し、プロダクトを追加します。プロダクトIDは、AdaptyのApp Store product IDと同じである必要があります。 3. StoreKit設定ファイルをビルドスキーマに追加し、アプリをビルドします。エミュレータまたはデバイスで起動してください。 ## XcodeでのStoreKitテストを使うべきか? \{#should-i-use-storekit-testing-in-xcode\} このテスト方法は、ビルドをその場でテストしたい、またはXcodeの機能を使ってさまざまな購入シナリオをテストしたいアプリ開発者に最も便利です。 ただし、このテストはローカルで行われるため、Adaptyダッシュボードには変更が表示されないことを覚えておいてください。本番環境でアプリを公開する前に、[サンドボックス環境](test-purchases-in-sandbox)を使用して[プロファイルの操作](ios-quickstart-identify)をテストすることをおすすめします。 StoreKitテストを**使うべき**場合: - 購入ロジックをテストしたい - Xcodeのツールを使ってさまざまな購入シナリオを再現したい(例:キャンセルされた支払いや返金) - エミュレータを使ってテストしたい StoreKitテストを**使うべきでない**場合: - プロファイル関連のロジックをテストしたい - アプリ内での操作がAdaptyダッシュボードに反映されるか確認したい - 開発チーム以外とアプリを共有してテストしたい ## ステップ1. StoreKit設定ファイルを作成する \{#step-1-create-a-storekit-configuration-file\} StoreKit設定ファイルを作成するには、Xcodeで以下の手順を実行します: 1. **File > New > File from template** をクリックします。次に、**StoreKit Configuration File** を選択して **Next** をクリックします。 2. ファイル名を入力します。次に、App Store Connectにすでにプロダクトがあるかどうかに応じて: - **Sync this file with an app in App Store Connect** を選択:App Store Connectのすべてのプロダクトを含む設定ファイルを作成し、ローカルでテストできるようにします。 - **Sync this file with an app in App Store Connect** を選択しない:空の設定ファイルを作成し、プロダクトを手動で追加する必要があります。 **Next** をクリックします。 3. アプリをターゲットとして追加しないでください。そのまま進んでください。App Store Connectから同期されたプロダクトを使用している場合は、[ステップ2](#step-2-add-the-configuration-file-to-the-build-scheme)に進んでください。 4. App Store Connectからプロダクトを同期していない場合は、左下の **+** をクリックして、プロダクトタイプを選択します。 5. サブスクリプショングループ名を入力し、**Next** をクリックします。 6. 参照名を入力します。**Product ID** フィールドに、AdaptyのプロダクトのApp Store product IDを入力します。 7. 設定ファイルで価格、オファー、その他のプロダクト設定を構成します。または、さらにプロダクトを追加します。 ## ステップ2. 設定ファイルをビルドスキームに追加する \{#step-2-add-the-configuration-file-to-the-build-scheme\} この設定ファイルを使ってアプリをビルドするには、ビルドスキームに追加する必要があります。テスト用と本番用のスキームを分けるのがベストプラクティスなので、テスト用に新しいスキームを作成することをおすすめします: 1. 上部のアプリ名をクリックして、**New scheme** を選択します。 2. スキームの名前を入力し、**OK** をクリックします。 3. アプリ名を再度クリックし、**Edit scheme** を選択します。**StoreKit configuration** でローカルの設定ファイルを選択すると、ビルド時に使用されます。 ## ステップ3. ビルドとテスト \{#step-3-build--test\} これで、App Storeバックエンドに接続することなくアプリをビルドし、アプリ内課金をテストできます。プロダクトを購入し、ローカルでアクセスレベルを取得できます。これらの変更はAdaptyダッシュボードには反映されませんが、有料機能のアンロックをローカルでテストすることは引き続き可能です。 XcodeでのStoreKitテストで利用できる他の機能については、[こちら](https://developer.apple.com/documentation/xcode/testing-in-app-purchases-with-storekit-transaction-manager-in-code)をご覧ください。 --- # File: testing-on-android --- --- title: "Google Play StoreでのIn-App Purchaseのテスト" description: "AdaptyでAndroidのサブスクリプション購入をテストする方法。" --- AndroidアプリのIn-App Purchase(IAP)テストは、アプリを一般公開する前の重要なステップです。サンドボックステストは、ユーザーに実際の料金を請求することなく、IAPを安全かつ効率的にテストできる方法です。このガイドでは、Google Play StoreでAndroid向けにIAPのサンドボックステストを行う手順を説明します。 :::note **サンドボックスのトランザクションはすべてのアナリティクスチャートから除外されます。** 個々のプロファイルページやイベントフィードには引き続き表示されます。 ::: ## テスト環境 \{#testing-environment\} Androidアプリの最適なパフォーマンスを確認するには、エミュレーターではなく実機でテストすることを推奨します。エミュレーターでのテストに成功した実績もありますが、Googleは実機の使用を推奨しています。 エミュレーターを使用する場合は、Google Playがインストールされていることを確認してください。これにより、アプリが正常に動作しているかどうかを確認しやすくなります。 ## 1. アプリテスト用のテストアカウントを設定する \{#1-set-up-test-account-for-app-testing\} 開発の後半段階でスムーズにテストを行うため、アプリ内課金テスト用のテストユーザーを事前に設定しておく必要があります。このユーザーは、Androidテストデバイスで最初にログインするアカウントになります。 Androidデバイスのプライマリアカウントは、端末の初期化(すべてのデータが消去されます)を行わないと変更できません。そのため、初期化が必要にならないよう、テストユーザーアカウントを適切に設定することが重要です。 :::important テストアカウントの設定方法は、使用するデバイスによって異なります。 - テスト専用デバイスがある場合は、**別のテストアカウント(新しいGmailアカウント)**を作成してください。 - テスト専用デバイスがない場合は、**個人アカウント**を使用し、一時的に**ライセンステスト**を有効にすることができます。 - Androidデバイスをまったく持っていない場合は、**別のテストアカウントを作成してエミュレーターで使用**できます。ただし、この方法では実機固有の問題をすべて検出できるわけではないため、推奨はしません。 ::: ## 2. ライセンステストを有効にする \{#2-enable-license-testing\} テストユーザーアカウントを設定したら、アプリのライセンステストを設定する必要があります。以下の手順に従ってください。 1. Google Play Consoleのサイドバーで **Settings** に移動し、**Monetization** セクションの **License testing** を選択します。 <img src="/assets/shared/img/android-license-testing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 既存のライセンステスターリストを選択するか、新しいリストを作成します。 <img src="/assets/shared/img/android-testers.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. テストに使用するアカウントをリストに追加して変更を保存します。チームメンバーもテストを行う場合は、メールアドレスをリストに追加することでグループ全体にアクセスを付与できます。 <img src="/assets/shared/img/android-list.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 3. クローズドトラックを作成してテストアカウントを追加する \{#3-create-closed-track-and-add-test-account-to-it\} テストを開始するには、署名済みバージョンのアプリをクローズドトラックに公開する必要があります。 1. アプリを開き、メニューから **Test and release > Testing > Closed testing** を選択します。そこで **Create track** をクリックします。 <img src="/assets/shared/img/android-closed-testing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. クローズドテストトラック名を入力し、**Create track** をクリックします。 3. テスタリストをトラックに追加します。 4. **How testers join your test** セクションからリンクをコピーし、テストアカウントでログインしているデバイスに送信します。テストデバイスでリンクを開き、そのユーザーをテスターとして登録します。 <img src="/assets/shared/img/android-link.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning テストを正常に行うために、以下の点に注意してください。 - オプトインURLを開くと、Playアカウントがテストモードとしてマークされます。この手順を完了しないと、プロダクトが読み込まれません。 - 開発者がテストビルドに異なるアプリケーションIDを使用することがよくありますが、Google Play ServicesはアプリケーションIDを使用してアプリ内課金を検索するため、問題が発生します。 - テストデバイスにPINが設定されていない場合、テストユーザーが消耗型アイテムを購入できるにもかかわらず、サブスクリプションを購入できないケースがあります。この場合、「Something went wrong」という不明なメッセージが表示されることがあります。テストデバイスにPINが設定されており、Google Play Storeにログインしていることを確認してください。 ::: ## 4. 署名済みAPKをクローズドトラックにアップロードする \{#4-upload-a-signed-apk-to-the-closed-track\} 署名済みAPKを生成するか、Android App Bundleを使用して、先ほど作成したクローズドトラックに署名済みAPKをアップロードします。リリースをロールアウトする必要はありません。APKをアップロードするだけです。詳細については、[こちら](https://support.google.com/googleplay/android-developer/answer/9859348?visit_id=638929100639477968-3849460621&rd=1)のサポート記事を参照してください。 :::important アプリが新しい場合は、自分の国や地域でアプリを利用可能にする必要があるかもしれません。そのためには、**Testing > Closed testing** に移動し、テストトラックをクリックして、**Countries/regions** で希望する国や地域を追加してください。 ::: ## 5. アプリ内課金をテストする \{#5-test-in-app-purchases\} APKをアップロードしたら、リリースの処理が完了するまで数分お待ちください。その後、テストデバイスを開き、テスタリストに追加したメールアカウントでサインインします。本番アプリと同様にアプリ内課金をテストできます。 <img src="/assets/shared/img/a8d2da9-image.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 関連情報 \{#read-more\} AndroidアプリのIn-App Purchaseテストについて詳しく知るには、以下のリソースをご覧ください。 - [サンドボックスでの更新期間](https://developer.android.com/google/play/billing/test#subs) - [買い切り購入のテスト](https://developer.android.com/google/play/billing/test#one-time) --- # File: validate-test-purchases --- --- title: "テスト購入の検証" description: "Adaptyでテスト購入を検証し、スムーズなトランザクションを確保しましょう。" --- モバイルアプリを本番環境にリリースする前に、アプリ内課金を十分にテストすることが重要です。詳しいテスト手順については、[Apple App Storeでのアプリ内課金のテスト](test-purchases-in-sandbox)および[Google Play Storeでのアプリ内課金のテスト](testing-on-android)をご参照ください。テストを開始したら、テスト購入が成功しているかどうかを確認する必要があります。 モバイルデバイスでテスト購入を行うたびに、Adapty ダッシュボードの[**Event Feed**](https://app.adapty.io/event-feed)で対応するトランザクションを確認してください。購入が **Event Feed** に表示されない場合、Adaptyによってトラッキングされていません。 ## テスト購入が成功した場合 \{#test-purchase-is-successful\} テスト購入が成功すると、そのトランザクションイベントが **Event Feed** に表示されます。 <img src="/assets/shared/img/9ade2d5-event_feed_sandbox.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> トランザクションが期待どおりに動作している場合は、[リリースチェックリスト](release-checklist)に進み、その後アプリのリリースを行ってください。 ## テスト購入が成功しなかった場合 \{#test-purchase-is-not-successful\} 10分以内にトランザクションイベントが表示されない場合や、モバイルアプリでエラーが発生した場合は、[トラブルシューティング](troubleshooting-test-purchases)およびエラーハンドリングに関する記事([iOS向け](ios-sdk-error-handling)、[Android向け](android-sdk-error-handling)、[React Native向け](react-native-handle-errors)、[Flutter向け](error-handling-on-flutter-react-native-unity)、[Unity向け](unity-handle-errors)、[Kotlin Multiplatform向け](kmp-handle-errors))を参照して、解決策を探してください。 <img src="/assets/shared/img/31a79b2-no_events.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: troubleshooting-test-purchases --- --- title: "テスト購入のトラブルシューティング" description: "Adaptyでのテスト購入をトラブルシューティングし、アプリ内トランザクションに関する一般的な問題を解決する方法を解説します。" --- トランザクションの問題が発生した場合は、まず[リリースチェックリスト](release-checklist)に記載されているすべての手順を完了しているかご確認ください。すべての手順を完了しても問題が解決しない場合は、以下のガイダンスに従って対処してください。 ## モバイルアプリでエラーが返される \{#an-error-is-returned-in-the-mobile-app\} お使いのプラットフォームのエラーリストをご参照ください: [iOS向け](ios-sdk-error-handling)、[Android向け](android-sdk-error-handling)、[React Native向け](react-native-troubleshoot-purchases)、[Flutter](error-handling-on-flutter-react-native-unity)、[Unity](unity-troubleshoot-purchases)。記載の推奨事項に従って問題を解決してください。 ## モバイルアプリでエラーが返されないのにイベントフィードにトランザクションが表示されない \{#transaction-is-absent-from-the-event-feed-although-no-error-is-returned-in-the-mobile-app\} この問題を解決するには、以下の点をご確認ください。 1. **iOS の場合**: シミュレーターではなく実機を使用していることを確認してください。 2. アプリの `Bundle ID`/`Package name` が [**App settings**](https://app.adapty.io/settings/general) に設定されているものと一致していることを確認してください。 3. アプリ内の `PUBLIC_SDK_KEY` が Adapty ダッシュボードの **Public SDK key** と一致していることを確認してください: [**App settings** -> **General** タブ -> **API keys** セクション](https://app.adapty.io/settings/general)。 4. サンドボックスアカウントを使用していることを確認してください([ローカル StoreKit 設定ファイル](local-sk-files)ではなく)。以前にローカル StoreKit 設定ファイルをテストに使用していた場合は、現在のビルドでそれを使用していないことを確認してください。 ## テスト用プロファイルにイベントが表示されない \{#no-event-is-present-in-my-testing-profile\} これは正常な動作です。新しいユーザープロファイルレコードは、以下のタイミングで Adapty に自動作成されます。 - ユーザーが初めてアプリを起動したとき - ユーザーがアプリからログアウトしたとき **この動作の理由:** すべてのトランザクションとイベントは、最初のトランザクションを生成したプロファイルに紐付けられます。これにより、トランザクション履歴全体(トライアル、購入、更新)が同じプロファイルにリンクされ続けます。 **表示される内容:** 新しいプロファイルレコード(「非オリジナルプロファイル」と呼ばれます)はイベントなしで表示されることがありますが、アクセスレベルは保持されます。`access_level_updated` イベントが表示される場合があります。これは期待される動作です。 **テスト時の注意:** 複数のプロファイルが作成されないようにするため、アプリを再インストールするたびに新しいテストアカウント(サンドボックス Apple ID)を作成してください。 詳細については、[プロファイルの作成](how-profiles-work#profile-creation)をご覧ください。 以下は非オリジナルプロファイルの例です。**User history** にイベントがなく、アクセスレベルが設定されていることに注目してください。 <img src="/assets/shared/img/98d0dad-non-original_profile.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## App Store Connect で設定した実際の価格が反映されない \{#prices-do-not-reflect-the-actual-prices-set-in-app-store-connect\} サンドボックスおよびアプリ内課金にサンドボックス環境を使用する TestFlight では、価格の正確さよりも購入フローが正しく機能しているかどうかを確認することが重要です。Apple の API は、デバイスやアカウントに異なる地域が設定されている場合など、不正確なデータを返すことがあります。価格はストアから直接取得されるものであり、Adapty のバックエンドは購入価格に一切影響を与えないため、Adapty を通じた購入テスト中の価格の不正確さは無視していただいて構いません。 そのため、価格の正確さよりも購入フロー自体のテストを優先し、意図した通りに機能していることを確認してください。 ## イベントフィードのトランザクション時刻が正しくない \{#the-transaction-time-in-the-event-feed-is-incorrect\} **Event Feed** は **App Settings** で設定されたタイムゾーンを使用します。イベントのタイムゾーンをローカル時刻に合わせるには、[**App settings** -> **General** タブ](https://app.adapty.io/settings/general)で **Reporting timezone** を変更してください。 ## ペイウォールとプロダクトの読み込みに時間がかかる \{#paywalls-and-products-take-a-long-time-to-load\} この問題は、テストアカウントのトランザクション履歴が長い場合に発生することがあります。[App Store Connect でサンドボックステストアカウント(サンドボックス Apple ID)を作成する](test-purchases-in-sandbox#step-1-create-sandbox-test-account-in-app-store-connect)セクションに記載の通り、毎回新しいテストアカウントを作成することを強くお勧めします。 新しいアカウントを作成できない場合は、iOS デバイスで以下の手順に従って現在のアカウントのトランザクション履歴を消去できます。 1. **設定**を開き、**App Store** をタップします。 2. **サンドボックス Apple ID** をタップします。 3. ポップアップで **管理** を選択します。 4. **アカウント設定**ページで **購入履歴を消去** をタップします。 詳細については、[Apple Developer ドキュメント](https://developer.apple.com/documentation/storekit/testing-in-app-purchases-with-sandbox)をご覧ください。 --- # File: test-devices --- --- title: "テストデバイス" description: "Adaptyでテストデバイスを管理し、アプリのテストを効率化する方法を学びましょう。" --- テスト目的で、自分のデバイスをテストデバイスとして登録できます。これによりキャッシュが無効化され、変更がすぐに反映されるようになります。 :::note テストデバイスは以下の SDK バージョン以降でサポートされています。 - iOS: 2.11.1 - Android: 2.11.3 - React Native: 2.11.1 Flutter および Unity のサポートは後日追加される予定です。 ::: ## デバイスをテストデバイスとして登録する \{#mark-your-device-as-test\} 1. Adapty ダッシュボードで [**App settings**](https://app.adapty.io/settings/general) を開きます。 2. **General** タブの **Test devices** セクションまでスクロールします。 <img src="/assets/shared/img/14c581d-test_device_add.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Add test device** ボタンをクリックします。 <img src="/assets/shared/img/f86d5e2-test_users_add_device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Add test device** ウィンドウで以下を入力します。 | フィールド | 説明 | |:-----------------------------------------| :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Test device name** | 参照用のテストデバイス名。 | | **ID used to identify this test device** | テストデバイスの識別に使用する識別子の種類を選択します。最適な選択肢については、下記の [使用すべき識別子](test-devices#which-identifier-you-should-use) セクションの推奨事項を参照してください。 | | **ID value** | 識別子の値を入力します。 | 5. **Add test device** ボタンをクリックして変更を保存することを忘れないでください。 ## 使用すべき識別子 \{#which-identifier-you-should-use\} デバイスの識別には複数の識別子を使用できます。以下の方法を推奨します。 - <InlineTooltip tooltip="Adapty でユーザーを識別する">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip> の場合、iOS・Android どちらのデバイスでも **Customer User ID** が最適です。特に 1 つのアカウントに対して複数のテストデバイスを使用している場合に適しています。**ID used to identify this test device** として Customer User ID を使用すると、そのアカウントに紐づくすべてのデバイスがテストデバイスとしてマークされます。 - **IDFA(iOS)** および **Advertising ID(Android)**:これらの広告識別子は、ユーザーへの同意リクエストをすでに行っている場合に、それぞれ iOS・Android デバイスに最適な選択肢です。Customer User ID があっても、テスト中にアプリ内でアカウントを切り替える場合は広告識別子が便利です。また、同じアカウントにテスト用デバイスと個人用デバイスの両方があり、個人用デバイスをテストデバイスとしてマークしたくない場合にも有効です。 Adapty Profile ID、IDFV、Android ID などのオプションもあります。これらは利便性では劣りますが、Customer User ID・IDFA・Advertising ID が使えない場合に利用できます。 以下では、すべての選択肢を詳しく説明します。 ### すべてのプラットフォームで使用できる識別子 \{#identifiers-for-all-platforms\} | 識別子 | 使用方法 | |----------|-----| | Customer User ID | <p>ユーザーをシステム内で識別するために設定する一意の識別子。メールアドレス、内部 ID、その他の文字列などが使えます。このオプションを使用するには、<InlineTooltip tooltip="Adapty でユーザーを識別する">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip> でユーザーを識別している必要があります。</p><p></p><p>特に同じアカウントで複数のデバイスを使用している場合に、テストデバイスの識別として最適な選択肢です。このアカウントを持つすべてのデバイスがテスト用とみなされます。</p> | | Adapty profile ID | <p>Adapty における[ユーザープロファイル](profiles-crm)の一意の識別子。</p><p></p><p>Customer User ID・iOS の IDFA・Android の Advertising ID が使用できない場合にご利用ください。なお、アプリを再インストールしたり再ログインしたりすると Adapty Profile ID が変わる場合があります。</p> | #### Customer User ID と Adapty Profile ID の取得方法 \{#how-to-obtain-customer-user-id-and-adapty-profile-id\} どちらの識別子も Adapty ダッシュボードの **Profile** 詳細から取得できます。 1. [**Adapty Profiles** -> **Event feed** タブ](https://app.adapty.io/event-feed)でユーザーのプロファイルを見つけます。 :::note 正確なプロファイルを見つけるには、珍しい種類のトランザクションを実行してください。そうすることで、[**Event Feed**](https://app.adapty.io/event-feed) にトランザクションが表示されたときにすぐに特定できます。 ::: 2. プロファイル詳細の **Customer user ID** と **Adapty ID** フィールドの値をコピーします。 <img src="/assets/shared/img/345d308-test_users_CUID_adapty_ID.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Apple の識別子 \{#apple-identifiers\} | 識別子 | 使用方法 | |----------|-----| | IDFA | <p>IDFA(Identifier for Advertisers)は、Apple がユーザーのデバイスに割り当てる一意のデバイス識別子です。</p><p></p><p>自動的に変わることがないため(手動でリセットは可能)、iOS デバイスに最適です。</p><p>**注意**:iOS 14.5 以降、広告主は IDFA にアクセスするためにユーザーの同意を求める必要があります。アプリ内で同意を求めていること、テストデバイスで同意を付与済みであることを確認してください。</p> | | IDFV | IDFV(Identifier for Vendors)は、同一パブリッシャー/ベンダーの全アプリに対して Apple が 1 つのデバイスに割り当てる一意の英数字識別子です。アプリを再インストールまたはアップデートすると変わる場合があります。 | #### IDFA の取得方法 \{#how-to-obtain-the-idfa\} Apple はデフォルトで IDFA を提供していません。Adapty ダッシュボードのプロファイルのアトリビューションから取得してください。 1. [**Adapty Profiles** -> **Event feed** タブ](https://app.adapty.io/event-feed)でユーザーのプロファイルを見つけます。 :::note 正確なプロファイルを見つけるには、珍しい種類のトランザクションを実行してください。そうすることで、[**Event Feed**](https://app.adapty.io/event-feed) にトランザクションが表示されたときにすぐに特定できます。 ::: 2. プロファイル詳細を開き、**Attributes** セクションの **IDFA** フィールドの値をコピーします。 <img src="/assets/shared/img/ce4a63f-test_users_idfa.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> または、[App Store で IDFA を表示してくれるアプリを探す](https://www.apple.com/us/search/idfa?src=globalnav)こともできます。 #### Identifier for Vendors(IDFV)の取得方法 \{#how-to-obtain-the-identifier-for-vendors-idfv\} IDFV を取得するには、開発者に以下のメソッドを使ってアプリ内でリクエストし、取得した識別子をログまたはデバッグパネルに表示するよう依頼してください。 ```swift showLineNumbers title="Swift" UIDevice.current.identifierForVendor ``` ### Google の識別子 \{#google-identifiers\} | 識別子 | 使用方法 | |----------|-----| | Advertising ID | <p>Advertising ID は、Google がユーザーのデバイスに割り当てる一意のデバイス識別子です。</p><p>自動的に変わることがないため(手動でリセットは可能)、Android デバイスに最適です。</p><p>**注意**:使用するには、Android 12 以上の場合、**Ads** 設定の **Opt out of Ads Personalization** をオフにしてください。</p>| | Android ID | Android ID は、アプリの署名キー・ユーザー・デバイスの組み合わせごとに固有の識別子です。Android 8.0 以上で利用できます。 | #### Advertising ID の取得方法 \{#how-to-obtain-advertising-id\} デバイスの Advertising ID を確認するには: 1. Android デバイスで **Settings** アプリを開きます。 2. **Google** をタップします。 3. **Services** の下にある **Ads** を選択します。画面下部に Advertising ID が表示されます。 #### Android ID の取得方法 \{#how-to-obtain-android-id\} Android ID を取得するには、開発者に以下のメソッドを使って [ANDROID_ID](https://developer.android.com/reference/android/provider/Settings.Secure#ANDROID_ID) をアプリ内でリクエストし、取得した識別子をログまたはデバッグパネルに表示するよう依頼してください。 ```kotlin showLineNumbers title="Kotlin/Java" android.provider.Settings.Secure.getString(contentResolver, android.provider.Settings.Secure.ANDROID_ID); ``` --- # File: release-checklist --- --- title: "リリースチェックリスト" description: "Adaptyのリリースチェックリストに従って、スムーズなアプリのアップデートプロセスを確保しましょう。" --- Adaptyをご利用いただきありがとうございます!実装がうまくいったことを願っています。このガイドでは、アプリをストアに公開する準備が整っているか確認するための手順を説明します。これにより、マネタイゼーションフローが正しく機能していることを安心して確認できます。 ## 事前確認事項 \{#pre-flight-essentials\} バリデーションを始める前に必要なもの: - サンドボックスアカウントを持つ実機デバイス - Adapty ダッシュボードへのアクセス - App Store Connect / Google Play Console へのアクセス :::note サンドボックス購入はシミュレーターでも実行できますが、支払いダイアログや生体認証プロンプトを含むすべてのフローを完全にテストするには実機デバイスが必要です。 ::: <Button id="test-purchases-in-sandbox"> App Store向けテストガイド </Button> <Button id="testing-on-android"> Google Play向けテストガイド </Button> ## 共通バリデーション \{#universal-validations\} - [ ] **ストア接続**: AdaptyをApp StoreおよびGoogle Playに接続していることを確認してください: - [ ] [App Store](initial_ios) - [ ] [Google Play](initial-android) - [ ] **サブスクリプションイベントの配信**: サーバー通知が設定されていることを確認してください: - [ ] [App Serverサーバー通知](enable-app-store-server-notifications) - [ ] [リアルタイム開発者通知(RTDN)](enable-real-time-developer-notifications-rtdn) - [ ] **プロファイルの識別**: ユーザー識別ロジックを検証し、購入が正しいプロファイルに紐付けられていることを確認してください: - [ ] [アプリコードの識別ロジックがユースケースに合っているか確認する](ios-quickstart-identify) - [ ] [ユーザープロファイル間で有料アクセスを共有するための親/継承ロジックを理解しているか確認する](sharing-paid-access-between-user-accounts) - [ ] **オファー**: アプリにApp Storeのプロモーションオファーがある場合、[アプリ内購入キー](app-store-connection-configuration#step-4-for-trials-and-special-offers--set-up-promotional-offers)をメインフィールドと **App Store promotional offers** セクションの両方に追加していることを確認してください。 - [ ] **データ収集**: プライバシーへの準拠を確保してください: - [ ] GDPRやCCPAなどのプライバシー規制に準拠する必要がある場合、またはアプリが子供向けの場合は、[IDFAおよびIPの収集と共有を有効にするかどうか](sdk-installation-ios#data-policies)を制御してください。 - [ ] アプリがAppTrackingTransparencyを使用している場合は、[認証ステータスをAdaptyに送信](ios-deal-with-att)していることを確認してください。 - [ ] **プライバシーラベル**: Adaptyが収集するデータとレビューに必要なフラグについては、[詳細はこちら](apple-app-privacy)をご覧ください。 ## 購入バリデーション \{#purchase-validations\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: 公開前に、アプリ内購入が正しく機能し、ペイウォールがストアレビューの準備ができていることを確認してください。 アプリ内購入のバリデーション方法は、実装方法によって異なります: - Adapty ペイウォールビルダーで作成したペイウォールを表示する - 独自のペイウォールを実装し、その中で `makePurchase` メソッドを使用して購入を処理する - オブザーバーモードでAdaptyを使用する(Adapty ペイウォールビルダーまたはカスタムペイウォールのどちらでも) <Tabs groupId="paywall" queryString> <TabItem value="builder" label="Adapty Paywall Builder" default> **目標**: Adaptyがペイウォールをレンダリングし、ユーザーがプロダクトを購入でき、アクセスがアンロックされ、購入復元フローが機能すること。 - [ ] アプリが[ペイウォールを表示する](ios-present-paywalls)際、実際にリリースするのと同じプレースメントを使用している。 - [ ] ペイウォールが画面に表示される。読み込みに時間がかかりすぎる場合(不安定なインターネット環境など)は、[フェッチポリシーの調整](get-pb-paywalls#fetch-paywall-designed-with-paywall-builder)を検討してください。 - [ ] ペイウォールが期待するバリアント(該当する場合はオーディエンス/ロケール)と一致している。必要に応じて[オーディエンスの優先順位を変更](change-audience-priority)できます。 - [ ] プロダクトと価格がペイウォールに表示される。テスト中(特に異なるリージョン設定の場合)にAppleのAPIが不正確な価格を提供することがあります。AdaptyはStoreの価格に影響を与えないため、価格の正確さよりも購入フローの機能テストを優先してください。 - [ ] サンドボックス購入が正常に完了する。購入成功のコールバックが受信される。 - [ ] アクセスがアンロックされ、維持される。[現在のAdaptyプロファイルに基づいて有料アクセスが付与されていること](ios-check-subscription-status#connect-profile-with-paywall-logic)を確認する。 - [ ] 購入後、Adaptyプロファイルにアクティブなアクセスレベルがある。 - [ ] プロファイルにそのアクセスレベルが含まれている場合に有料機能がアンロックされる(購入コールバックだけでなく)。 - [ ] 購入の復元が機能する。アプリを再インストールするか新しいデバイスにインストールした場合、[有料アクセスの共有](sharing-paid-access-between-user-accounts)設定に従って購入の自動復元が機能する。バックエンド認証がない場合は、設定に関係なく購入が自動的に復元される。それ以外の場合は、アプリの再インストール後にユーザーが購入を復元できることを確認する。 - [ ] ストアレビュー要件: - [ ] **Restore purchases** ボタンがペイウォールに表示されている。ペイウォールビルダーで追加でき、タップ時に購入復元を自動的に処理します。 - [ ] 利用規約とプライバシーポリシーがペイウォール画面からアクセスでき、これらのリンクをクリックするとブラウザで開く。 </TabItem> <TabItem value="makepurchase" label="カスタムペイウォール(makePurchase)" default> **目標**: UIをレンダリングし、AdaptyがPurchase処理、プロファイル更新、および復元を担当する。 - [ ] プロダクトIDがアプリコードにハードコードされていない。ハードコードするのは[プレースメント](placements)IDのみ。 - [ ] アプリが[プロダクトを取得する](fetch-paywalls-and-products)際、実際にリリースするのと同じプレースメントを使用している。 - [ ] プロダクトリストが正常に読み込まれる。読み込みに時間がかかりすぎる場合(不安定なインターネット環境など)は、[フェッチポリシーの調整](fetch-paywalls-and-products#fetch-paywall-information)を検討してください。 - [ ] 取得したプロダクトが期待するバリアント(該当する場合はオーディエンス/ロケール)と一致している。必要に応じて[オーディエンスの優先順位を変更](change-audience-priority)できます。 - [ ] プロダクトと価格がペイウォールに表示される。テスト中(特に異なるリージョン設定の場合)にAppleのAPIが不正確な価格を提供することがあります。AdaptyはStoreの価格に影響を与えないため、価格の正確さよりも購入フローの機能テストを優先してください。 - [ ] [makePurchase](making-purchases)を使用したサンドボックス購入が正常に完了する: - [ ] 購入成功の結果が処理される。 - [ ] 保留中/失敗/キャンセルの結果が適切に処理される。 - [ ] [リモートコンフィグを使用する](present-remote-config-paywalls)場合、その値がペイウォールに正しく反映されている。 - [ ] ペイウォールが表示されたとき、[`logShowFlow`(iOS SDK v4+)/ `logShowPaywall` メソッド](present-remote-config-paywalls#track-paywall-view-events)が呼び出される。 - [ ] サンドボックス購入が正常に完了する。購入成功のコールバックが受信される。 - [ ] アクセスがアンロックされ、維持される。[現在のAdaptyプロファイルに基づいて有料アクセスが付与されていること](ios-check-subscription-status#connect-profile-with-paywall-logic)を確認する。 - [ ] 購入後、Adaptyプロファイルにアクティブなアクセスレベルがある。 - [ ] プロファイルにそのアクセスレベルが含まれている場合に有料機能がアンロックされる(購入コールバックだけでなく)。 - [ ] 購入の復元が機能する。アプリを再インストールするか新しいデバイスにインストールした場合、[有料アクセスの共有](sharing-paid-access-between-user-accounts)設定に従って購入の自動復元が機能する。バックエンド認証がない場合は、設定に関係なく購入が自動的に復元される。それ以外の場合は、アプリの再インストール後にユーザーが購入を復元できることを確認する。 - [ ] ストアレビュー要件: - [ ] **Restore purchases** ボタンがアクセス可能で、[購入復元を処理](restore-purchase)している。 - [ ] 利用規約とプライバシーポリシーがペイウォール画面からアクセスでき、これらのリンクをクリックするとブラウザで開く。 </TabItem> <TabItem value="observer" label="オブザーバーモード"> **目標**: 購入処理、プロファイル更新、復元を自身で行い、Adaptyがトランザクションレポートを受け取る。 - [ ] **アプリが独自の購入フロー(StoreKit / BillingClient / バックエンド)を使用して購入を完了する**: - [ ] サンドボックス購入がストアUIで成功する。 - [ ] 保留中/失敗/キャンセルの結果がアプリ内で適切に処理される。 - [ ] **トランザクションがAdaptyに報告される**。 - [ ] オブザーバーモードが[アプリコードで有効になっている](implement-observer-mode)。 - [ ] 購入がAdaptyのイベントフィードに表示される。 - [ ] 更新、キャンセル、返金が時間の経過とともに反映される(該当する場合)。 - [ ] **ペイウォールビューが追跡される**。ペイウォールが表示されたとき、[`logShowFlow`(iOS SDK v4+)/ `logShowPaywall` メソッド](present-remote-config-paywalls#track-paywall-view-events)が呼び出される。 - [ ] **実装に合わせた購入復元が機能する**。アプリの再インストールやデバイスの切り替えで、アクセスが正しく復元される。 - [ ] **ストアレビュー要件**: - [ ] **Restore purchases** アクションがアクセス可能で、独自の復元フローがトリガーされる。 - [ ] 利用規約とプライバシーポリシーがペイウォールまたは購入画面からアクセスでき、ブラウザで開く。 </TabItem> </Tabs> Adapty SDKの統合についてご不明な点がある場合は、右下のAIチャットボットをご利用いただくか、[support@adapty.io](mailto:support@adapty.io)までお問い合わせください。 --- # File: submit-app-to-app-store --- --- title: "iOSアプリをApp Storeに申請する" description: "ビルドをApp Store Connectにアップロードし、iOSサブスクリプションアプリをAppleのレビューに申請します。" --- Adaptyのインテグレーションのテストができたら、ビルドをApp Store Connectにアップロードして、アプリをAppleのレビューに申請しましょう。 :::tip 申請前に、[リリースチェックリスト](release-checklist)を確認して、Adaptyインテグレーション、購入フロー、ストアのレビュー要件を検証してください。 ::: ## ビルドをApp Store Connectにアップロードする \{#upload-your-build-to-app-store-connect\} ### ステップ1. XcodeでアプリをアーカイブしてApp Store Connectにアップロードする \{#step-1-archive-your-app-in-xcode-and-upload-it-to-app-store-connect\} 1. Xcodeで、ビルド先を **Any iOS Device (arm64)** に設定します。 <img src="/assets/shared/img/build-target.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 2. メニューバーから **Product** > **Archive** を選択します。 <img src="/assets/shared/img/xcode-archive.webp" style={{ border: '1px solid #727272', width: '500px', display: 'block', margin: '0 auto' }} /> 3. アーカイブ処理が完了するまで待ちます。**Organizer** ウィンドウが自動的に開きます。アーカイブを選択して **Distribute App** をクリックします。 <img src="/assets/shared/img/distribute-app.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 4. 配布方法として **App Store Connect** を選択します。画面の指示に従ってアップロードを完了させます。 :::note アプリアイコンや起動画面など、必要なアセットが不足している場合はアップロードが失敗することがあります。Xcodeのエラーログで詳細を確認してください。 ::: <img src="/assets/shared/img/distribution-method.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> ### ステップ2. App Store Connectでビルドを確認する \{#step-2-check-the-build-in-app-store-connect\} 1. [App Store Connect](https://appstoreconnect.apple.com) にアクセスしてアプリを開きます。 2. **Build** セクションまでスクロールし、アップロードしたビルドが表示されていることを確認します。 :::note アップロード後、ビルドがApp Store Connectに表示されるまで数分かかる場合があります。 ::: <img src="/assets/shared/img/app-store-build.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> ## アプリとプロダクトをレビューに申請する \{#submit-your-app-and-products-for-review\} **Build** セクションにビルドが表示されたら、アプリ内サブスクリプションを添付してAppleのレビューに申請します。 ### ステップ1. 申請にプロダクトを添付する \{#step-1-attach-products-to-the-submission\} 各サブスクリプションは、添付できるようになる前にApp Store Connectで **Ready to Submit** ステータスになっている必要があります。サブスクリプションがドラフト状態だったりメタデータが不足していたりすると、リストに表示されません。 1. 同じページで、**In-App Purchases and Subscriptions** セクションまでスクロールします。 2. **Select in-app purchases or subscriptions** をクリックします。 <img src="/assets/shared/img/app-store-select-products.webp" style={{ border: '1px solid #727272', width: '700px', display: 'block', margin: '0 auto' }} /> 3. この申請に含めたいプロダクトをすべて選択して **Done** をクリックします。 ### ステップ2. レビューに申請する \{#step-2-submit-for-review\} 1. ページ上の必須項目(説明文、スクリーンショット、キーワードなど)をすべて入力します。 2. **App Store Version Release** セクションで、承認後にアプリを自動リリースするか、手動でリリースするか、スケジュール設定でリリースするかを選択します。 3. **Add for Review** をクリックし、次に **Submit to App Review** をクリックします。 Appleのレビューは通常1〜2日以内に完了しますが、レビュー期間は変動することがあります。 ## 本番環境でアプリを確認する \{#verify-your-app-in-production\} Appleがアプリを承認したら: 1. 実際に購入を行います(または最初のユーザーが購入するのを待ちます)。 2. Adapty ダッシュボードの [**Event Feed**](https://app.adapty.io/event-feed) を開き、本番トランザクションイベントが表示されていることを確認します。 3. サブスクリプションイベント(更新、キャンセル)が正しく流れているか確認します。これには[App Storeサーバー通知](enable-app-store-server-notifications)の設定が必要です。 本番イベントが表示されない場合は、[App Store接続設定](app-store-connection-configuration)を確認してください。 ## 次のステップ \{#next-steps\} アプリが公開されました。サブスクリプション収益を伸ばしていきましょう: - **[A/B テスト](ab-tests)**:異なるペイウォールを試して、最もコンバージョンが高いものを見つけましょう。 - **[アナリティクス](charts)**:MRR、チャーン、コンバージョンなどのサブスクリプション指標を追跡しましょう。 - **インテグレーション**:サブスクリプションイベントを[アナリティクス](analytics-integration)や[アトリビューション](attribution-integration)プラットフォームに送信しましょう。 --- # File: general --- --- title: "App settings" description: "Adaptyのシームレスな利用に向けた一般設定と構成についてご説明します。" --- **App Settings** ページの **General** タブから、アプリの動作・外観・収益共有の設定を管理できます。ここでは、アプリ名やアイコンのカスタマイズ、Adapty SDK および API キーの管理、スモールビジネスプログラムのステータス設定、アナリティクスやチャートのタイムゾーン選択などが行えます。 ## 1. アプリの詳細 \{#1-app-details\} <img src="/assets/shared/img/8fa2929-CleanShot_2023-04-21_at_15.16.222x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty インターフェース上でアプリを識別するための一意の名前とアイコンを設定してください。なお、ここで設定するアプリ名とアイコンは、App Store や Google Play 上のアプリ名・アイコンには影響しません。また、アプリの目的やコンテンツを正確に反映した適切なアプリカテゴリを選択してください。これにより、ユーザーがアプリを見つけやすくなり、適切なストアカテゴリに表示されるようになります。 ## 2. スモールビジネスプログラムへの参加と手数料優遇 \{#2-member-of-small-business-program-and-reduced-service-fee\} <img src="/assets/shared/img/825e2be-CleanShot_2023-04-19_at_13.43.292x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Apple の [Small Business Program](app-store-small-business-program) または Google の [Reduced Service Fee プログラム](google-reduced-service-fee) に登録している場合、ストアの手数料が優遇されます。 アプリが手数料優遇プログラムに登録されている場合は、Adapty に通知してください。正確な計算のために、「Reduced Store Fee」セクションでプログラムのステータスを指定してください。 手数料優遇の設定は、今後の取引にのみ適用されます。ステータスが変更される**前に**設定を更新しておくと、Adapty が手数料率を自動的に調整します。 :::warning * 手数料優遇プログラムの参加期間を延長した場合は、**適用期間を追加してください**。 * プログラムの資格を失った場合は、現在の適用期間の**終了日を変更してください**。 ::: 詳細については以下の記事をご覧ください: * [App Store Small Business Program](app-store-small-business-program) * [Google Reduced Service Fee](google-reduced-service-fee) ## 3. レポートのタイムゾーン \{#3-reporting-timezone\} <img src="/assets/shared/img/47227f9-CleanShot_2023-04-19_at_13.45.302x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 拠点となる場所、またはアプリのアナリティクスやチャートに最も適したタイムゾーンを選択してください。一貫性を保つために、App Store Connect または Google Play Console のアカウントと同じタイムゾーンを使用することをおすすめします。なお、このタイムゾーン設定は、UTC タイムゾーンを使用する Adapty のサードパーティ連携には影響しません。 タイムゾーン設定は、**App Settings** ページの **General** タブにある **Reported timezone** セクションから行えます。また、Adapty アカウント内のすべてのアプリに同じタイムゾーンを設定するチェックボックスもあります。 ## 4. アナリティクスにおけるインストールの定義 \{#4-installs-definition-for-analytics\} アナリティクスにおける新規インストールイベントの定義を選択してください: | 基準 | 説明 | |------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | New device_ids | <p>(推奨)ストアからデバイスにアプリをインストールするたびに、新規インストールとしてカウントされます。初回インストールと再インストールの両方が含まれます。</p><p>インストールはデバイス ID 単位でカウントされ、ユーザー認証の影響を受けません。プロファイルの作成(SDK 起動時またはログアウト時)、ログイン、アプリのアップグレードでは追加のインストールイベントは発生しません。</p><p>例えば、同じアプリが 5 台の異なるデバイスにインストールされた場合、アナリティクスには 5 インストールと表示されます。</p> | | New customer_user_ids | <p>このオプションは、Adapty で <InlineTooltip tooltip="Adapty でユーザーを識別する">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)、[Kotlin Multiplatform](kmp-quickstart-identify)、[Capacitor](capacitor-quickstart-identify)</InlineTooltip> ユーザーを識別するアプリ向けです。</p><p>ログイン済みユーザーの場合、顧客ユーザー ID に関連付けられた最初のインストールのみが新規インストールとしてカウントされます。追加デバイスへのインストールは新規インストールとしてカウントされません。</p><p>匿名ユーザー(ログインしていないユーザー)はアナリティクスでカウントされません。</p><p>アプリの再インストールや再ログインでは追加のインストールは発生しません。</p><p>App Store Connect、Google Play Console、AppsFlyer などのアプリストアやアトリビューションプラットフォームは、デバイスベースでインストールをカウントします。Adapty で顧客ユーザー ID によるインストールカウントを使用した場合、これらの外部サービスの数値と異なる場合があります。</p><p>⚠️ Adapty でユーザーを識別していない場合、このオプションを有効にするとインストールはカウントされません。</p> | | New profiles in Adapty | (レガシー)すべてのアプリインストール、再インストール、およびログアウト時に作成された匿名プロファイルが新規インストールとしてカウントされます。 | このオプションは [**Analytics**](https://app.adapty.io/analytics) ページにのみ影響し、別途ビューを設定できる [**Overview**](https://app.adapty.io/overview) ページには影響しない点に注意してください。 ## 5. App Store の価格値上げロジック \{#5-app-store-price-increase-logic\} Adapty アナリティクスと App Store Connect の結果の間に不整合が生じないよう、App Store Connect で価格値上げに関する設定を変更する際は、適切なオプションを選択することが重要です。 Adapty でサブスクリプションの価格値上げに適用するロジックを選択できます: <img src="/assets/shared/img/b766c8b-CleanShot_2023-07-18_at_19.28.18_22x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **既存ユーザーのサブスクリプション価格を維持する:** このオプションを選択すると、App Store Connect で価格を変更しても、既存のサブスクライバーには元の価格が適用され続けます。つまり、既存のサブスクライバーは引き続き元のサブスクリプション価格で請求されます。 - **App Store Connect でサブスクリプション価格が変更された場合、既存のサブスクライバーにも適用される:** このオプションを選択すると、App Store Connect で行った価格変更が既存のサブスクライバーにも適用されます。つまり、既存のサブスクライバーは App Store Connect に設定された新しい価格で請求されます。 :::warning 選択したオプションは、Adapty のアナリティクスだけでなく、連携機能やトランザクション処理全体にも影響することをご注意ください。 ::: 既存のサブスクライバーに対するサブスクリプション価格の取り扱い方針に合ったオプションを選択してください。これにより、Adapty アナリティクスと App Store Connect の結果の正確なデータと同期を維持できます。 ## 6. ユーザーアカウント間でのアクセスレベルの共有 \{#6-sharing-paid-access-between-user-accounts\} :::link メイン記事:[ユーザーアカウント間でのアクセスレベルの共有](sharing-paid-access-between-user-accounts) ::: **Sharing paid access between user accounts** 設定は、複数の[ユーザープロファイル](identifying-users)が同じ購入にアクセスしようとした場合に Adapty がどう処理するかを決定します。[サンドボックス環境](test-purchases-in-sandbox)に対して個別のアクセス共有設定を指定することもできます。 **有効(デフォルト)** 識別済みユーザー([Customer User ID](identifying-users#set-customer-user-id-on-configuration)が設定されているユーザー)は、同じApple/Google IDでサインインしているデバイスであれば、Adaptyが提供する同じ[アクセスレベル](access-level)を共有できます。これは、ユーザーがアプリを再インストールして別のメールアドレスでログインした場合でも、以前の購入へのアクセスを維持できるため便利です。このオプションでは、複数の識別済みユーザーが同じアクセスレベルを共有できます。 アクセスレベルは共有されますが、過去および将来のすべてのトランザクションは、一貫したアナリティクスを維持し完全なトランザクション履歴(トライアル期間、サブスクリプション購入、更新など)を同じプロファイルに紐付けるため、元のCustomer User IDのイベントとして記録されます。 **新しいユーザーへアクセスを移譲** 識別済みユーザーは、デバイスが同じApple/Google IDでサインインしている限り、別の[Customer User ID](identifying-users#set-customer-user-id-on-configuration)でログインしたりアプリを再インストールしたりしても、Adaptyが提供する[アクセスレベル](access-level)を引き続き利用できます。 前のオプションとは異なり、Adaptyは識別済みユーザー間で購入を移譲します。これにより購入済みコンテンツへのアクセスが保証されますが、一度にアクセスできるのは1人のユーザーのみです。たとえば、UserAがサブスクリプションを購入し、同じデバイスでUserBがログインしてトランザクションをリストアした場合、UserBがサブスクリプションへのアクセスを取得し、UserAからはアクセスが取り消されます。 いずれかのユーザー(新しいユーザーまたは古いユーザー)が識別されていない場合でも、Adapty内でそれらのプロファイル間でアクセスレベルは共有されます。 アクセスレベルは移譲されますが、過去および将来のすべてのトランザクションは、一貫したアナリティクスを維持し完全なトランザクション履歴(トライアル期間、サブスクリプション購入、更新など)を同じプロファイルに紐付けるため、元のCustomer User IDのイベントとして記録されます。 **新しいユーザーへアクセスを移譲**に切り替えた後、アクセスレベルはすぐにはプロファイル間で移譲されません。特定のアクセスレベルの移譲プロセスは、サブスクリプションの更新、リストア、またはトランザクションの検証など、ストアからのイベントをAdaptyが受信したときにのみトリガーされます。 **無効** 最初にアクセスレベルを取得した識別済みユーザープロファイルが、それを永続的に保持します。これは、ビジネスロジック上、購入を単一のCustomer User IDに紐付ける必要がある場合に最適なオプションです。 なお、匿名ユーザー間ではアクセスレベルは引き続き共有されます。 [オーナーのユーザープロファイルを削除する](https://adapty.io/docs/ja/api-adapty/operations/deleteProfile)ことで、購入の紐付けを解除できます。削除後、アクセスレベルは最初にそれを要求したユーザープロファイル(匿名または識別済みを問わず)に付与されます。 共有の無効化は新しいユーザーにのみ影響します。すでにユーザー間で共有されているサブスクリプションは、このオプションを無効にした後も共有され続けます。 :::warning AppleとGoogleは、購入をApple/Google IDに紐付けているため、ユーザー間でアプリ内課金を共有または移譲することを求めています。共有がなければ、その後の再インストール時に購入のリストアが機能しない可能性があります。 共有を無効にすると、ログイン後にユーザーがアクセスを取り戻せなくなる場合があります。 共有の無効化は、ユーザーが購入前に**ログインを必須とする**場合にのみ推奨します。そうでない場合、識別済みユーザーがサブスクリプションを購入した後に別のアカウントにログインすると、アクセスを永続的に失う可能性があります。 ::: ### どの設定を選べばよいですか? \{#which-setting-should-i-choose\} | アプリの条件 | 選択するオプション | | ------------------------------------------------------------ | ------------------------------------------------------------ | | ログインシステムがなく、AdaptyのみMatch anonymous profile IDを使用している。 | デフォルトオプションを使用してください。3つのオプションすべてで、匿名プロファイルID間ではアクセスレベルが常に共有されます。 | | オプションのログインシステムがあり、アカウント作成前に購入できる。 | **新しいユーザーへアクセスを移譲**を選択してください。アカウントなしで購入したユーザーが後でトランザクションをリストアできるようになります。 | | 購入前にアカウント作成を必須とするが、購入を複数のCustomer User IDに紐付けることを許可している。 | **新しいユーザーへアクセスを移譲**を選択してください。一度にアクセスできるCustomer User IDは1つに限られますが、別のCustomer User IDでログインしても有料アクセスを失わずに済みます。 | | 購入前にアカウント作成を必須とし、購入を単一のCustomer User IDに厳密に紐付けるルールがある。 | **無効**を選択してください。アカウント間でトランザクションが移譲されないことが保証されます。 | ## 7. SDK および API キー \{#7-sdk-and-api-keys\} アプリに Adapty SDK を組み込むには Public SDK キーを使用し、Adapty の Server API にアクセスするには Secret キーを使用します。必要に応じて新しいキーを生成したり、既存のキーを無効化することができます。Developer CLI 用のトークンを作成するには、**Settings → Developer API** に移動してください。詳細は [Authentication](developer-cli-authentication) をご覧ください。 ## 8. テストデバイス \{#8-test-devices\} テストに使用するデバイスを指定することで、キャッシュによる遅延をバイパスし、ペイウォールやプレースメントの変更が即座に反映されるようにします。詳細は [Testing devices](test-devices) をご覧ください。 ## 9. クロスプレースメントバリエーションのスティッキネス \{#9-cross-placement-variation-stickiness\} テスト終了後、どのくらいの期間ユーザーがテスト内のバリアントを引き続き表示されるかを定義します。これはアナリティクスの精度とユーザー体験に影響します。ユーザーが以前に見たものとは異なるオファーを表示すると、購入の意思決定に影響を与える可能性があります。 スティッキネス期間の最大値かつデフォルト値は 90 日間です。 :::warning 以下の点を考慮してください: - この設定を変更すると、以前にバリアントを受け取ったすべてのユーザーに影響します。対象ユーザーはプレースメントを表示した際に即座に新しいペイウォールの対象となるため、実行中の A/B テストの結果に影響する可能性があります。 - スティッキネス期間が終了したユーザーには、新しいペイウォールや A/B テストが表示される場合があります。ただし、その場合でも、他のクロスプレースメントテストに参加することは永久にできなくなります。 ::: ## 10. アプリの削除 \{#10-delete-the-app\} アプリが不要になった場合、Adapty から削除することができます。 :::warning この操作は元に戻せません。アプリやそのデータを復元することはできません。 ::: --- # File: ios-settings --- --- title: "Apple App Store の認証情報" description: "AdaptyでiOSの設定を構成し、サブスクリプション管理をシームレスに実現します。" --- App Storeの認証情報を設定し、Adapty iOS SDKの最適な動作を確保するには、Adapty ダッシュボードの App Settings ページ内の [iOS SDK](https://app.adapty.io/settings/ios-sdk) タブに移動します。次に、以下のパラメーターを設定してください: <img src="/assets/shared/img/3d4087e-CleanShot_2023-06-26_at_13.27.042x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> | フィールド | 説明 | |----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Bundle ID** | アプリの [Bundle ID](app-store-connection-configuration#step-1-provide-bundle-id-and-apple-app-id)。 | | **In-app purchase API (StoreKit 2)** | アプリ内課金のトランザクション履歴リクエストの安全な認証と検証を有効にするための [キー](app-store-connection-configuration#step-2-provide-issuer-id-and-key-id)。 | | **App Store Server Notifications** | App Store からの [サーバー間通知](enable-app-store-server-notifications) を有効にし、ユーザーのサブスクリプション状態の変化を監視・対応するために使用するURL。 | | **App Store Promotional Offers** | 特定のプロダクトに対してAdaptyで [プロモーションオファー](generate-in-app-purchase-key) を作成するためのサブスクリプションキー。 | | **Apple app ID** | App StoreにおけるアプリのID。確認するには、App Store Connectでアプリのページを開き、左メニューから **App Information** ページを開いて **Apple ID** をコピーしてください。 | | **App Store Connect shared secret (LEGACY)** | <p>**Adapty SDK v2.9.0 以前向けのレガシーキー**</p><p></p><p>アプリのレシート検証と不正防止のための [キー](app-store-connection-configuration#step-5-enter-app-store-shared-secret)。</p> | --- # File: google-play-store-connection-configuration --- --- title: "Google Play Storeとの連携を設定する" description: "AdaptyでGoogle Play Storeの接続を設定し、アプリ内課金をスムーズに処理しましょう。" --- このセクションでは、Google Play経由で販売されているモバイルアプリをAdaptyと連携する手順を説明します。Play StoreのアプリケーションデータをAdapty ダッシュボードに入力する必要があります。この作業は、AdaptyがPlay Storeから購入を検証し、サブスクリプションの更新情報を受け取るために欠かせないステップです。 この設定は初回オンボーディング時に行うか、後からAdapty ダッシュボードの **App Settings** で変更できます。 :::danger 設定の変更は、Adaptyのペイウォールをアプリにリリースするまでのみ許容されます。リリース後に変更すると連携が壊れ、モバイルアプリでペイウォールが表示されなくなります。 ::: ## ステップ1. パッケージ名を入力する \{#step-1-provide-package-name\} パッケージ名は、Google Play StoreにおけるアプリのユニークなIDです。サブスクリプション処理などAdaptyの基本機能に必要です。 1. [Google Play Developer Console](https://play.google.com/console/u/0/developers)を開きます。 2. IDを確認したいアプリを選択します。**Dashboard** 画面が開きます。 <img src="/assets/shared/img/7889edb-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. アプリケーション名の下にあるプロダクトIDを確認し、コピーします。 4. AdaptyトップメニューからA[**App settings**](https://app.adapty.io/settings/android-sdk)を開きます。 <img src="/assets/shared/img/b00066c-package_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **App settings** 画面の **Android SDK** タブで、コピーした **Package name** を貼り付けます。 ## ステップ2. アカウントキーファイルをアップロードする \{#step-2-upload-the-account-key-file\} 1. [サービスアカウントキーファイルの作成](create-service-account)ステップで作成したサービスアカウントの秘密鍵ファイル(JSON形式)を、**Service account key file** エリアにアップロードします。 <img src="/assets/shared/img/20fdba1-service_key_file.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 変更を確定するために、**Save** ボタンをクリックするのを忘れずに。 **次のステップ** - [Google Play ConsoleでRTDN(リアルタイム デベロッパー通知)を有効にする](enable-real-time-developer-notifications-rtdn) --- # File: enable-real-time-developer-notifications-rtdn --- --- title: "Google Play ConsoleでリアルタイムデベロッパーNotification(RTDN)を有効にする" description: "Google Play ConsoleでリアルタイムデベロッパーNotification(RTDN)を有効にしてAdaptyのデータ精度を維持しましょう。払い戻しやその他の重要なイベントに関する即時更新を受け取るためのRTDNセットアップ方法を学びます" --- リアルタイムデベロッパーNotification(RTDN)を設定することは、データ精度を確保するうえで非常に重要です。これにより、払い戻しやその他のイベントに関する情報を含む、Play Storeからの更新をリアルタイムで受け取れるようになります。 ## 通知を有効にする \{#enable-notifications\} 1. **Google Cloud Pub/Sub** が有効になっていることを確認してください。[こちらのリンク](https://console.cloud.google.com/flows/enableapi?apiid=pubsub)を開き、アプリのプロジェクトを選択します。**Google Cloud Pub/Sub** をまだ有効にしていない場合は、ここで有効にする必要があります。 <img src="/assets/shared/img/pubsub.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Adaptyのトップメニューから [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) に移動し、**Google Play RTDN topic name** タイトルの横にある **Enable Pub/Sub API** フィールドの内容をコピーします。 <img src="/assets/shared/img/a72ff2d-copy_topic.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note **Enable Pub/Sub API** フィールドの内容が正しくない形式の場合(正しい形式は `projects/...` で始まります)、[Enable Pub/Sub APIフィールドの形式を修正する](enable-real-time-developer-notifications-rtdn#fixing-incorrect-format-in-enable-pubsub-api-field) セクションを参照してください。 ::: 3. [Google Play Console](https://play.google.com/console/) を開き、アプリを選択して、**Monetize with Play** -> **Monetization setup** に進みます。**Google Play Billing** セクションで、**Enable real-time notifications** チェックボックスをオンにします。 4. Adaptyの **App Settings** でコピーした **Enable Pub/Sub API** フィールドの内容を、**Topic name** フィールドに貼り付けます。 5. Google Play Consoleで **Save changes** をクリックします。 <img src="/assets/shared/img/e55ba0e-paste_topic_name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 通知をテストする \{#test-notifications\} リアルタイムデベロッパーNotificationへの登録が成功したかどうかを確認するには: 1. Google Play Consoleの設定で変更を保存します。 2. Google Play Consoleの **Topic name** の下にある **Send test notification** をクリックします。 <img src="/assets/shared/img/rtdn-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. AdaptyのメニューにあるトップメニューからAdaptyの [**App settings > Android SDK**](https://app.adapty.io/settings/android-sdk) に移動します。テスト通知が送信されると、トピック名の上にそのステータスが表示されます。 <img src="/assets/shared/img/rtdn-adapty-test.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## Enable Pub/Sub APIフィールドの形式を修正する \{#fixing-incorrect-format-in-enable-pubsub-api-field\} **Enable Pub/Sub API** フィールドの内容が誤った形式の場合(正しい形式は `projects/...` で始まります)、以下の手順に従って問題を解決してください。 ### 1. APIの有効化と権限を確認する \{#1-verify-api-enablement-and-permissions\} 必要なAPIがすべて有効になっており、サービスアカウントに正しく権限が付与されていることを慎重に確認してください。これらの手順をすでに完了している場合でも、サブステップが抜けていないことを確かめるために再度確認することが重要です。以下のセクションの手順を繰り返してください: 1. [Google Play ConsoleでデベロッパーAPIを有効にする](enabling-of-devepoler-api) 2. [Google Cloud Consoleでサービスアカウントを作成する](create-service-account) 3. [Google Play Consoleでサービスアカウントに権限を付与する](grant-permissions-to-service-account) 4. [Google Play Consoleでサービスアカウントのキーファイルを生成する](create-service-account-key-file) 5. [Google Play Storeインテグレーションを設定する](google-play-store-connection-configuration) ### 2. ドメインポリシーを調整する \{#2-adjust-domain-policies\} **Domain restricted contacts** および **Domain restricted sharing** ポリシーを変更します: 1. [Google Cloud Console](https://console.cloud.google.com/) を開き、アプリを管理するためのサービスアカウントを作成したプロジェクトを選択します。 2. **Quick Access** セクションで、**IAM & Admin** を選択します。 <img src="/assets/shared/img/google-cloud-IAM-and-Admin.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 左ペインで **Organization Policies** を選択します。 4. **Domain restricted contacts** ポリシーを見つけます。 <img src="/assets/shared/img/google-cloud-policy-action.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Actions** 列の省略記号ボタンをクリックし、**Edit policy** を選択します。 6. ポリシー編集ウィンドウで: 1. **Policy source** の下で、**Override parent's policy** ラジオボタンを選択します。 2. **Policy enforcement** の下で、**Replace** ラジオボタンを選択します。 3. **Rules** の下で、**ADD A RULE** ボタンをクリックします。 <img src="/assets/shared/img/google-cloud-edit-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **New rule** -> **Policy values** の下で、**Allow All** を選択します。 <img src="/assets/shared/img/google-cloud-allow-all-policy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **SET POLICY** をクリックします。 7. **Domain restricted sharing** ポリシーについても、手順4〜6を繰り返します。 最後に、**Google Play RTDN topic name** タイトルの横にある **Enable Pub/Sub API** フィールドの内容を再作成します。フィールドは正しい形式になります。 リアルタイムデベロッパーNotification(RTDN)の有効化に成功したら、更新したポリシーの **Policy source** を **Inherit parent's policy** に戻すことを忘れずに行ってください。 ## 生イベントの転送 \{#raw-events-forwarding\} 場合によっては、Googleからの生のS2Sイベントを引き続き受け取りたいこともあるでしょう。Adaptyを使用しながらそれらを受け取り続けるには、**URL for forwarding raw Google events** フィールドにエンドポイントを追加するだけで、Googleからの生イベントをそのまま送信します。 <img src="/assets/shared/img/e388892-001774-September-22-GhkjOFbT.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- **次のステップ** 以下のプラットフォーム向けにAdapty SDKを設定します: - [Android](sdk-installation-android) - [React Native](sdk-installation-reactnative) - [Flutter](sdk-installation-flutter) - [Kotlin Multiplatform](sdk-installation-kotlin-multiplatform) - [Unity](sdk-installation-unity) --- # File: apple-search-ads --- --- title: "Apple Ads" description: "Adapty と Apple Ads を統合してサブスクリプションのコンバージョンを最適化しましょう。" --- :::important **App settings** の Apple Ads 統合は、基本的なアナリティクスおよび SplitMetrics Acquire と Asapty の統合にのみ使用されます。 [Adapty Ads Manager](adapty-ads-manager)は別の接続を使用します。Apple Ads アカウントを[Adapty Ads Manager](adapty-ads-manager-get-started)で接続してください。 ::: Adapty は Apple Ads からアトリビューションデータを取得し、キャンペーンおよびキーワードのセグメンテーションで指標を分析するのに役立ちます。Adapty は SDK と AdServices Framework を通じて、Apple Ads のアトリビューションデータを自動的に収集します。 Apple Ads インテグレーションを設定すると、Adapty は Apple Ads からアトリビューションデータの受信を開始します。このデータはプロファイルページで簡単に確認できます。 <img src="/assets/shared/img/ba4a3e9-CleanShot_2023-08-21_at_15.14.592x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 連携の設定 \{#set-up-integration\} ### AdServicesフレームワークをAdaptyに接続する \{#connect-adapty-to-the-adservices-framework\} [AdServices](https://developer.apple.com/documentation/adservices)を使ったApple Adsは、Adapty ダッシュボードでの設定が必要です。また、アプリ側での有効化も必要です。AdServicesフレームワークを使ってAdapty経由でApple Adsを設定するには、以下の手順に従ってください。 #### ステップ1:公開鍵を取得する \{#step-1-obtain-public-key\} Adapty ダッシュボードで[Settings -> Apple Ads](https://app.adapty.io/settings/apple-search-ads)に移動します。 あらかじめ生成された公開鍵(Adaptyがキーペアを提供します)を見つけてコピーします。 <img src="/assets/shared/img/baa5998-CleanShot_2023-08-21_at_14.55.542x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::note Apple Ads のアトリビューションに別のサービスや独自のソリューションを使用している場合は、独自のプライベートキーをアップロードできます。 ::: #### ステップ 2: Apple Ads でユーザー管理を設定する \{#step-2-configure-user-management-on-apple-ads\} [Apple Ads アカウント](https://ads.apple.com/app-store)で **Settings > User Management** ページに移動します。Adapty がアトリビューションデータを取得するには、別の Apple ID アカウントを招待し、API Account Manager のアクセス権を付与する必要があります。既存のアカウントを使用することも、この目的専用に新しいアカウントを作成することもできます。重要なのは、その Apple ID で Apple Ads にログインできる必要があるという点です。 <img src="/assets/shared/img/ec183b2-kdjsfldsfjkdsfdfd.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### ステップ 3: API 認証情報を生成する \{#step-3-generate-api-credentials\} 次に、Apple Ads に新しく追加したアカウントでログインします。Apple Ads の画面で Settings -> API に移動し、先ほどコピーした公開鍵を所定のフィールドに貼り付けて、新しい API 認証情報を生成してください。 #### ステップ 4: Apple Ads の認証情報を Adapty に設定する \{#step-4-configure-adapty-with-apple-ads-credentials\} Apple Ads の設定画面から Client ID、Team ID、Key ID の各フィールドをコピーし、Adapty ダッシュボードの対応するフィールドに貼り付けます。 <img src="/assets/shared/img/7356113-CleanShot_2023-08-21_at_15.08.512x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### アプリを AdServices ネットワークに接続する \{#connect-your-app-to-the-adservices-network\} [AdServices フレームワークの設定](#connect-the-adservices-framework)が完了すると、Adapty は Apple Search Ad のアトリビューションデータの収集を自動的に開始します。SDK コードを追加する必要はありません。 iOS アプリケーションでは、このアトリビューションデータは**常に**他のソースからのデータより優先されます。この動作が不要な場合は、以下の手順で ASA アトリビューションを*無効化*してください。 ## インテグレーションを無効にする \{#disable-integration\} Apple Search Ads のアトリビューションをオフにするには、[**App Settings** -> **Apple Search Ads** タブ](https://app.adapty.io/settings/apple-search-ads)を開き、**Receive Apple Search Ads attribution** スイッチをオフにしてください。 <img src="/assets/shared/img/asa-disable.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::warning この設定を無効にすると、ASA アナリティクスの受信が完全に停止します。その結果、ASA はアナリティクスで使用されなくなり、インテグレーションにも送信されなくなります。また、SplitMetrics Acquire と Asapty は ASA アトリビューションに依存して動作しているため、機能しなくなります。 この変更以前に受信済みのアトリビューションには影響しません。 ::: ## 独自のキーをアップロードする \{#uploading-your-own-keys\} :::note オプション これらの手順は Apple Ads アトリビューションには必要ありません。Asapty などの他のサービスや独自ソリューションと連携する場合にのみ必要です。 ::: ASA アトリビューションに他のサービスや独自ソリューションを使用している場合は、独自の公開鍵・秘密鍵ペアを使用できます。 ### ステップ 1 \{#step-1\} ターミナルで秘密鍵を生成する ```text showLineNumbers title="Text" openssl ecparam -genkey -name prime256v1 -noout -out private-key.pem ``` Adapty の Settings -> Apple Ads でアップロードする(**Upload private key** ボタン) ### ステップ 2 \{#step-2\} ターミナルで公開鍵を生成する ```text showLineNumbers title="Text" openssl ec -in private-key.pem -pubout -out public-key.pem ``` この公開鍵は、API Account Manager ロールを持つアカウントの Apple Ads 設定で使用できます。これにより、生成された Client ID、Team ID、Key ID の値を Adapty や他のサービスで利用できます。 --- # File: account --- --- title: "アカウント詳細と請求" description: "Adapty アカウントを管理し、サブスクリプションのトラッキングに最適な設定を行いましょう。" --- **Account** ページでは、プロファイル、チームメンバー、請求情報を管理できます。 このページには 3 つのタブがあります。 - [一般設定](#general-settings) - [サブスクリプションと請求](#billing-info) - [メンバー](#members) アカウント設定にアクセスするには、右上の **Account** をクリックするか、[app.adapty.io/account](https://app.adapty.io/account) にアクセスしてください。 <img src="/assets/shared/img/account-info.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 一般設定 \{#general-settings\} 「General」タブには、プロファイル、アカウント設定、表示設定、レポート設定が含まれています。 - **Profile**: 名前、姓、会社名を入力します。会社名は最大 256 文字まで入力できます。 - **Account settings**: 登録済みのメールアドレスを確認し、パスワードを変更できます。 - **Date & Time formats**: Adapty 全体での日付と時刻の表示形式を選択します。 - **American format**: January 31, 2022 および 12 時間表示 (AM/PM) - **European format**: 31 January, 2022 および 24 時間表示 (16:00) - **Email reports**: 1 つまたはすべてのアプリに対して、日次・週次・月次のレポートを設定します。すべてのアプリのレポートをまとめて受け取るか、選択した各アプリの詳細レポートを受け取るかを選べます。 <img src="/assets/shared/img/account-info.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## サブスクリプションと請求 \{#billing-info\} **Subscription & Billing** タブでは、支払い情報と機能へのアクセスを管理できます。 - 支払い情報の追加または更新 - 請求情報の確認 - 追加の有料機能の購入 機能と料金の詳細については、[こちら](https://adapty.io/pricing)をご覧ください。 ## メンバー \{#members\} アカウント設定からチームメンバーを管理できます。チームメンバーを追加するには、メールアドレスで招待してロールを割り当ててください。 チームメンバーとアクセス権限の管理については、[こちら](members-settings)をご覧ください。 --- # File: members-settings --- --- title: "メンバー" description: "Adaptyダッシュボードでメンバーの設定と権限を管理します。" --- :::note このページはAdaptyダッシュボードのメンバーに関するものです アプリのユーザーに異なるアクセスレベルを付与したい場合は、[アクセスレベル](access-level)を参照してください。 ::: Adaptyダッシュボードのメンバーシステムでは、Adaptyへのアクセスレベルを各メンバーごとに設定し、利用可能なアプリを指定することができます。 ## ロール \{#roles\} Adapty ダッシュボードのメンバーには、以下のロールが利用できます。 | ロール | 請求情報へのアクセス | メンバーの追加 | 変更の実行 | 全セクションへのアクセス | |-------------|-------------------|-----------------|-----------------|------------------------| | Owner | ✅ | ✅ | ✅ | ✅ | | Admin | ❌ | ✅ | ✅ | ✅ | | Developer | ❌ | ❌ | ✅ | ❌ | | Viewer | ❌ | ❌ | ❌ | ✅ | | Support | ❌ | ❌ | ❌ | ❌ | | ASA manager | ❌ | ❌ | ❌ | ❌ | - **Owner:** オーナーはAdaptyアカウントの最初の作成者であり、最高レベルのアクセス権と管理権を持ちます。Adaptyの請求に対して完全なアクセス権を持ち、支払い情報やサブスクリプションプランを管理できます。また、新しいメンバーのアプリケーションアクセスを指定できるのはオーナーと管理者のみです。各Adaptyアカウントにオーナーは1人だけです。 - **Admin:** 管理者ロールのメンバーは、選択したアプリケーションへの完全なアクセス権を持ちます。ペイウォールの作成・変更、A/B テストの実施、アナリティクスの分析、アプリケーション内のメンバー管理など、さまざまな管理タスクを実行できます。 - **Developer:** デベロッパーロールのメンバーは、アナリティクスとアカウントメンバーを除くすべてのエンティティへの完全なアクセス権を持ちます。請求設定へのアクセスはできません。このロールは、ペイウォール・A/B テスト・その他のエンティティのセットアップやAdaptyのアプリへの統合を担当するが、財務データを閲覧すべきでない人向けです。 - **Viewer:** ビューワーロールのメンバーは、選択したアプリケーションへの読み取り専用アクセス権を持ちます。情報の閲覧はできますが、ペイウォールやA/B テストなどの機能の作成・変更、新規ユーザーの招待、新規アプリの作成、アプリ設定の変更はできません。 - **Support:** サポートロールのメンバーは、選択したアプリケーションのユーザープロファイルにのみアクセスできます。ただし、新しいメンバーの追加やAdaptyの他のセクションへのアクセスなどの操作は行えません。このロールは、サブスクリプションに関する問い合わせやトラブルシューティングでお客様をサポートする必要があるサポートチームや個人に特に適しています。 - **ASA manager:** ASAマネージャーロールのメンバーは、[Adapty Ads Manager](adapty-ads-manager)のダッシュボードにのみアクセスできます。 ## メンバーを追加する \{#add-a-member\} Adaptyでは、最大256人のチームメンバーを招待できます。新しいメンバーの追加は無料です。 :::note 招待できるのは、Adaptyにまだ登録されていないメールアドレスのみです。同僚がすでに個人アカウントを持っている場合は、別のメールアドレスで招待するか、Adaptyサポートに既存アカウントの削除を依頼してください。 ::: チームメンバーを追加するには: 1. 右上の **Account** をクリックして、**Members** タブを開きます。 2. **Invite member** をクリックします。 <img src="/assets/shared/img/invite-member.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. メンバーのメールアドレスを入力します。 4. リストから[ロール](#roles)を選択します。 5. アクセスを許可するアプリを選択します。 6. (任意)**Always allow access to new apps** を有効にすると、今後追加されるアプリへのアクセスも自動的に付与されます。 7. **Save** をクリックします。 <img src="/assets/shared/img/add-member.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## アカウントのオーナーシップを移譲する \{#transfer-account-ownership\} **アカウントのオーナーシップ**全体を移譲する必要がある場合は、[support@adapty.io](mailto:support@adapty.io)のサポートチームにお問い合わせください。 **アプリのオーナーシップ**を移譲する必要がある場合は、[専用ガイド](transfer-apps)を参照してください。 --- # File: set-up-app-store-connect --- --- title: "App Store Connect のセットアップ" description: "Apple Developer Program への登録とアプリ内課金のための App Store Connect セットアップを初めて行う開発者向けガイド。" --- **初めて iOS アプリを開発する場合**、Adapty を統合する前に Apple Developer アカウントと App Store Connect のセットアップを行う必要があります。 :::note すでに Apple Developer アカウントをお持ちで、App Store Connect にアプリを登録済みの場合は、このガイドをスキップして [App Store との初期連携](initial_ios) に直接進んでください。 ::: ## ステップ 1. Apple Developer Program に登録する \{#step-1-enroll-in-apple-developer-program\} App Store でアプリを配布してアプリ内課金を販売するには、[Apple Developer Program](https://developer.apple.com/programs/) に参加する必要があります。 ### 登録タイプを選択する \{#choose-enrollment-type\} Apple では 2 種類の登録タイプを用意しています。 | | 個人 | 組織 | |-----------------------------|--------------------|------------------------------| | **対象者** | 個人開発者 | 企業・チーム・非営利団体 | | **D-U-N-S ナンバーの要否** | 不要 | 必要 | | **アプリの公開名** | 個人名 | 組織名 | | **チーム管理** | 利用不可 | 利用可能 | :::tip 組織として登録する場合は、**D-U-N-S ナンバー**(Dun & Bradstreet が発行する 9 桁の企業識別番号)が必要です。[組織にすでに番号が割り当てられているか確認する](https://developer.apple.com/enroll/duns-lookup/) か、ページ下部のリンクから新規取得を申請できます。D-U-N-S ナンバーの発行には最大 5 営業日かかる場合があります。 ::: ### 登録する \{#enroll\} 1. [Apple Developer Program の登録ページ](https://developer.apple.com/programs/enroll/) にアクセスします。 2. Apple ID でサインインします。Apple ID をお持ちでない場合は、先に作成してください。 3. 登録タイプ(個人または組織)に応じた手順に従います。 4. 年会費を支払います。 Apple が登録を処理すると、[App Store Connect](https://appstoreconnect.apple.com) へのアクセスが付与されます。登録には通常最大 48 時間かかります。組織の場合、D-U-N-S の確認が必要なときはさらに時間がかかることがあります。 ## ステップ 2. App Store Connect でアプリをセットアップする \{#step-2-set-up-your-app-in-app-store-connect\} アプリ内課金を販売する前に、App Store Connect で初期設定を完了する必要があります。この設定には、契約への署名、支払い情報の追加、アプリの登録が含まれます。 ### 有料アプリケーション契約に署名する \{#sign-the-paid-applications-agreement\} App Store で販売するには、Apple の Paid Applications Agreement(有料アプリケーション契約)への署名が必要です。これは有料アプリだけでなく、無料アプリ内のアプリ内課金にも適用されます。 1. [App Store Connect](https://appstoreconnect.apple.com/business) の **Business** ページに移動します。 2. **Paid Apps** の契約を見つけ、**Review and Agree** をクリックします。 3. 必要な情報を入力します。 - **Banking information**: Apple から収益が振り込まれる銀行口座を追加します。 - **Tax information**: 販売したい国の税務フォームに記入します。 - **Contact information**: 連絡先情報を入力します。 :::important 契約を有効にするには、3 つのセクション(銀行情報、税務情報、連絡先情報)をすべて入力する必要があります。契約が有効になるまで、アプリ内課金を販売することはできません。 ::: ### Bundle ID を作成する \{#create-a-bundle-id\} Bundle ID は、Apple のエコシステム全体でアプリを一意に識別します。App Store Connect へのアプリ登録と Adapty 連携の設定に必要です。 1. [Apple Developer ポータル](https://developer.apple.com/account) を開きます。 2. **Certificates, Identifiers & Profiles** → **Identifiers** に移動します。 3. **+** をクリックして新しい識別子を登録します。 4. **App IDs** を選択して **Continue** をクリックします。 5. タイプとして **App** を選択し、**Continue** をクリックします。 6. 以下の項目を入力します。 - **Description**: この Bundle ID を識別するための名前(例:「My Subscription App」)。 - **Bundle ID**: **Explicit** を選択し、逆ドメイン形式の一意の識別子を入力します(例:`com.yourcompany.yourapp`)。 7. **Capabilities** セクションで下にスクロールし、**In-App Purchase** にチェックを入れます。 8. **Continue** をクリックし、次に **Register** をクリックします。 ### App Store Connect にアプリを登録する \{#register-your-app-in-app-store-connect\} 1. [App Store Connect](https://appstoreconnect.apple.com/apps) の **Apps** ページに移動します。 2. **+** → **New App** をクリックします。 3. 必要な項目を入力します。 - **Platforms**: **iOS** を選択します。 - **Name**: App Store に表示されるアプリ名。 - **Primary language**: アプリのメタデータのデフォルト言語。 - **Bundle ID**: 前の手順で作成した Bundle ID を選択します。 - **SKU**: アプリの一意の識別子(ユーザーには表示されません)。例:`my_subscription_app_2025`。 4. **Create** をクリックします。 これでアプリが App Store Connect に登録され、Adapty 連携の準備が整いました。 ## 次のステップ \{#whats-next\} - [App Store との初期連携](initial_ios): App Store アプリを Adapty に接続する - [SDK の統合](quickstart-sdk): Adapty SDK をアプリのコードに統合する - [サンドボックステスト](test-purchases-in-sandbox): リリース前にアプリ内課金をテストする - [iOS アプリを App Store に提出する](submit-app-to-app-store): ビルドをアップロードして Apple の審査に提出する - [App Store Small Business Program](app-store-small-business-program): App Store の手数料を 30% から 15% に引き下げる --- # File: app-store-products --- --- title: "App Store のプロダクト" description: "Adapty のサブスクリプションツールを使って App Store のプロダクトを効率的に管理しましょう。" --- このページでは、App Store Connect でプロダクトを作成する方法を説明します。Adapty の機能とは直接関係ない内容も含まれますが、App Store Connect アカウントでプロダクトを作成する際に困ったときに役立つ情報です。 Adapty に連携するプロダクトを作成するには、以下の手順に従ってください。 1. **App Store Connect** を開き、左側メニューの [**Monetization** → **Subscriptions**](https://appstoreconnect.apple.com/apps/6477523342/distribution/subscriptions) セクションに進みます。 <img src="/assets/shared/img/148c3b5-subscriptions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループをまだ作成していない場合は、**Subscription Groups** タイトルの下にある **Create** ボタンをクリックして作成を開始します。App Store Connect の [Subscription Groups](https://developer.apple.com/help/app-store-connect/manage-subscriptions/offer-auto-renewable-subscriptions) は、プロダクトを分類・管理し、ユーザーがさまざまなプランをシームレスに切り替えられるようにするための機能です。なお、グループ外にサブスクリプションを作成することはできません。 3. 表示された **Create Subscription Group** ウィンドウで、**Reference Name** フィールドに新しいサブスクリプショングループ名を入力します。参照名は、アプリ内の異なるサブスクリプショングループを区別・管理するために自分で定義するラベルまたは識別子です。 参照名はユーザーには表示されず、主に内部での整理・管理に使用します。App Store Connect の管理画面で特定のサブスクリプショングループを識別・参照する際に役立ちます。複数のサブスクリプションプランがある場合や、アプリの構成に合った形でカテゴリ分けしたい場合に特に便利です。 <img src="/assets/shared/img/3f93c44-create_subscription_group.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Create** ボタンをクリックして、サブスクリプショングループの作成を確定します。 5. サブスクリプショングループが作成され、開かれます。次に、グループ内にサブスクリプションを作成します。**Subscriptions** タイトルの下にある **Create** ボタンをクリックします。既存のグループに新しいサブスクリプションを追加する場合は、**Subscriptions** タイトルの隣にある **Plus** ボタンをクリックします。 <img src="/assets/shared/img/22fc643-add_subscription.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. 表示された **Create Subscription** ウィンドウで、**Reference Name** フィールドに名前を、**Product ID** フィールドにサブスクリプションの固有コードを入力します。 Reference Name は、App Store Connect 内でアプリ内サブスクリプションを識別するための専用識別子です。App Store のユーザーには表示されません。作成するサブスクリプションの内容が明確にわかる、人が読みやすい説明文を使用することをお勧めします。なお、この名前は 64 文字以内にする必要があります。 Product ID は、開発フェーズでプロダクトにアクセスし、アプリ内サブスクリプションを管理するサービスである Adapty と同期するために必要な、一意の英数字識別子です。Product ID には英数字、ピリオド、アンダースコアのみ使用できます。 <img src="/assets/shared/img/04aca55-create_subscription.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. **Create** ボタンをクリックして、サブスクリプションの作成を確定します。 8. サブスクリプションが作成され、開かれます。次に、**Subscription Duration** リストからサブスクリプションの期間を選択します。サブスクリプション名に期間が既に含まれている場合でも、**Subscription Duration** フィールドへの入力を忘れずに行ってください。 <img src="/assets/shared/img/f56cf0f-subscription_duration.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 9. 次は、サブスクリプションの価格を設定します。**Subscription Prices** タイトルの下にある **Add Subscription Price** ボタンをクリックしてください。見つからない場合は、下にスクロールしてみてください。 10. 表示された **Subscription Price** ウィンドウで、**Country or Region** リストから基準となる国を、**Price** リストから基準となる通貨を選択します。Appleがこの基本価格と最新の為替レートをもとに、175 か国・地域すべての価格を自動計算します。 <img src="/assets/shared/img/de1cec8-subscription_price.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 11. **Next** ボタンをクリックします。表示された **Price by Country or Region** ウィンドウには、すべての国の価格が自動計算された状態で表示されます。必要に応じて変更することもできます。 <img src="/assets/shared/img/2a047a6-price_by_country.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 12. 地域別の価格を更新したら、ウィンドウ下部の **Next** ボタンをクリックして進みます。 13. 表示された **Confirm Subscription Price?** ウィンドウで、最終的な価格を慎重に確認します。価格を修正する場合は、**Back** ボタンをクリックして **Price by Country or Region** ウィンドウに戻り、更新できます。価格に問題がなければ、**Confirm** ボタンをクリックします。 <img src="/assets/shared/img/d2b2031-confirm_prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 14. **Confirm Subscription Price?** ウィンドウを閉じた後、サブスクリプションウィンドウで **Save** ボタンをクリックするのを忘れないでください。クリックしないと、サブスクリプションが作成されず、入力したデータがすべて失われます。 なお、ここまでの手順は自動更新サブスクリプション(Auto-Renewable Subscription)の設定を対象としています。その他の種類のアプリ内課金を設定する場合は、サイドバーの「Subscriptions」ではなく **In-App Purchases** タブをクリックしてください。そこから、さまざまな種類のアプリ内課金を管理・作成できるセクションにアクセスできます。 <img src="/assets/shared/img/5663d85-in-app_purchases.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### Adapty にプロダクトを追加する \{#add-products-to-adapty\} App Store Connect でのアプリ内課金、サブスクリプション、オファーの追加が完了したら、次は [これらのプロダクトを Adapty に追加](create-product) します。 --- # File: apple-app-privacy --- --- title: "Apple App Privacy" description: "Appleアプリのプライバシーポリシーとサブスクリプションアプリへの影響を理解する。" --- Appleは、App Store Connectの **App Privacy** セクションおよびアプリのマニフェストファイルとして、すべての新しいアプリおよびアップデートに対してプライバシーの開示を義務付けています。AdaptyはアプリのサードパーティSDKであるため、ユーザーデータに関してAdaptyをどのように使用しているかを開示する必要があります。 ## Apple アプリプライバシーマニフェスト \{#apple-app-privacy-manifest\} `PrivacyInfo.xcprivacy` という名前の[プライバシーマニフェストファイル](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests)は、アプリが使用するプライベートデータとその理由を記述します。アプリオーナーはすべて、自分のアプリ用のマニフェストファイルを作成する必要があります。さらに、追加のSDKを統合している場合は、[プライバシーマニフェストと署名が必要なSDK](https://developer.apple.com/support/third-party-SDK-requirements/)リストに含まれるSDKのマニフェストファイルが含まれていることを確認してください。アプリをビルドする際、Xcodeはこれらすべてのマニフェストファイルを1つにまとめます。 Adaptyは[プライバシーマニフェストと署名が必要なSDK](https://developer.apple.com/support/third-party-SDK-requirements/)のリストには含まれていませんが、Adapty SDK バージョン2.10.2以降では便宜のためにマニフェストが含まれています。マニフェストを取得するためにSDKを更新してください。 Adaptyはアプリプライバシーレポートとも呼ばれるマニフェストファイルにデータを含める必要はありませんが、トラッキングのためにAdaptyの `customerUserId` を使用している場合は、次のようにマニフェストファイルに指定する必要があります: 1. プライバシー情報ファイルの `NSPrivacyCollectedDataTypes` 配列にディクショナリを追加します。 2. ディクショナリに `NSPrivacyCollectedDataType`、`NSPrivacyCollectedDataTypeLinked`、`NSPrivacyCollectedDataTypeTracking` キーを追加します。 3. `NSPrivacyCollectedDataTypes` ディクショナリの `NSPrivacyCollectedDataType` キーに、文字列 `NSPrivacyCollectedDataTypeUserID`([マニフェストファイルで報告するデータカテゴリとタイプの一覧](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Describe-the-data-your-app-or-third-party-SDK-collects)における `UserID` データタイプの識別子)を追加します。 4. `NSPrivacyCollectedDataTypes` ディクショナリの `NSPrivacyCollectedDataTypeTracking` および `NSPrivacyCollectedDataTypeLinked` キーに `true` を追加します。 5. `NSPrivacyCollectedDataTypes` ディクショナリの `NSPrivacyCollectedDataTypePurposes` キーの値として、文字列 `NSPrivacyCollectedDataTypePurposeProductPersonalization` を使用します。 カスタム属性を使用してオーディエンスにペイウォールをターゲティングしている場合は、使用しているカスタム属性が[マニフェストファイルで報告するデータカテゴリとタイプ](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests)に該当するかどうかを慎重に確認してください。該当する場合は、データタイプごとに上記の手順を繰り返してください。 収集するすべてのデータタイプとカテゴリを報告したら、[Appleのドキュメント](https://developer.apple.com/documentation/bundleresources/describing-data-use-in-privacy-manifests#Create-your-apps-privacy-report)に従ってアプリのプライバシーレポートを作成してください。 ## App Store Connectでのプライバシー開示 \{#apple-app-privacy-disclosure-in-app-store-connect\} 1. [App Store Connect](https://appstoreconnect.apple.com/)でアプリを開き、**App Privacy** に移動します。**Get Started** をクリックします。 <img src="/assets/shared/img/app-privacy-get-started.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Yes, we collect data from this app** を選択し、**Next** をクリックします。 <img src="/assets/shared/img/app-privacy-data-collection.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### データタイプ \{#data-types\} 以下の表は、Appleが開示を求めるデータタイプと、Adaptyが必要とするものを示しています。**これはAdaptyのみを対象としています。** アプリが他のSDKや独自のコードを通じて追加データを収集する場合は、それらのデータタイプも選択してください。 ✅ = Adaptyが必要とする 👀 = 必要な場合あり(詳細は下記参照) ❌ = Adaptyでは不要 — アプリが他の手段でこのデータを収集する場合に選択 | データタイプ | 必要 | 備考 | |--------------------------------------------------------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------| | 識別子 | ✅ | <p>customerUserIdでユーザーを識別している場合は、「User ID」を選択します。</p><p></p><p>AdaptyはIDFAを収集するため、「Device ID」を選択する必要があります。</p> | | 購入 | ✅ | Adaptyはユーザーの購入履歴を収集します。 | | 名前、電話番号、メールアドレスなどの連絡先情報 | 👀 | **`updateProfile`** メソッドを使用して名前、電話番号、メールアドレスなどの個人データを渡す場合に必要です。 | | 使用状況データ | 👀 | Amplitude、Mixpanel、AppMetrica、Firebaseなどのアナリティクスを使用している場合に必要な場合があります。 | | 位置情報 | ❌ | Adaptyは正確な位置情報を収集しません。アプリが収集する場合は選択してください。 | | ヘルス&フィットネス | ❌ | Adaptyはヘルスやフィットネスデータを収集しません。アプリが収集する場合は選択してください。 | | 機密情報 | ❌ | Adaptyは機密情報を収集しません。アプリが収集する場合は選択してください。 | | ユーザーコンテンツ | ❌ | Adaptyはユーザーコンテンツを収集しません。アプリが収集する場合は選択してください。 | | 診断情報 | ❌ | Adaptyは診断データを収集しません。アプリが収集する場合は選択してください。 | | 閲覧履歴 | ❌ | Adaptyは閲覧履歴を収集しません。アプリが収集する場合は選択してください。 | | 検索履歴 | ❌ | Adaptyは検索履歴を収集しません。アプリが収集する場合は選択してください。 | | 連絡先 | ❌ | Adaptyは連絡先リストを収集しません。アプリが収集する場合は選択してください。 | | 財務情報 | ❌ | Adaptyは財務情報を収集しません。アプリが収集する場合は選択してください。 | ### 必須データタイプ \{#required-data-types\} #### 購入 \{#purchases\} Adaptyを使用する場合、アプリが**購入履歴**を収集することを開示する必要があります。 <img src="/assets/shared/img/feb3b9f-CleanShot_2023-08-25_at_12.32.552x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> #### 識別子 \{#identifiers\} Adaptyを使用する場合、次の識別子を開示する必要があります: - **Device ID** — AdaptyはIDFAを収集します。 - **User ID** — **`customerUserId`** でユーザーを識別する場合に必要です。 <img src="/assets/shared/img/93f3daa-CleanShot_2023-08-25_at_12.35.272x.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### データの使用目的 \{#data-usage\} **データタイプ**を保存した後、データの使用目的を示す必要があります: 1. **Purchases** ブロック内の **Set up purchase history** をクリックします。 <img src="/assets/shared/img/purchase-privacy.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. Appleが購入履歴データの使用目的を尋ねてきたら、Adaptyに関して以下を選択します: - **Analytics** — Adaptyは収益アナリティクス、コホート、および指標のために購入履歴を使用します。 - **Product Personalization** — Adaptyはオーディエンスのセグメンテーションとペイウォールのターゲティングのために購入データを使用します。 - **App Functionality** — Adaptyは購入を検証し、アクセスレベルを管理し、サブスクリプションの状態を追跡します。 アプリが他の方法で購入データを使用する場合(例:Adaptyインテグレーション経由で広告プラットフォームに購入イベントを送信する場合)は、追加の目的を選択してください。 <img src="/assets/shared/img/purchase-history.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Next** をクリックします。 4. **Device ID** および **User ID**(使用している場合)のいずれについても: 1. **User/Device ID** ブロック内の **Set up user/device ID** をクリックします。 2. Appleが識別子データの使用目的を尋ねてきたら、Adaptyに関して以下を選択します: - **App Functionality** — Adaptyはユーザープロファイルの管理、購入の紐付け、アクセスレベルの追跡のために識別子を使用します。 Adaptyインテグレーション(AppsFlyerやAdjustなど)経由でサードパーティプラットフォームにアトリビューションデータを送信する場合は、**Third-Party Advertising** も選択してください。アプリが他の方法で識別子を使用する場合は、追加の目的を選択してください。 <img src="/assets/shared/img/user-id-privacy.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Next** をクリックします。 --- # File: apple-family-sharing --- --- title: "Appleファミリー共有" description: "AdaptyでAppleファミリー共有を有効にして、共有サブスクリプションをサポートします。" --- Appleのファミリー共有を使うと、アプリ内課金を家族メンバー間で共有できます。ビデオストリーミングサービスや子ども向けアプリなど、グループ向けアプリのユーザーが、Apple IDを共有せずにサブスクリプションを分け合える便利な仕組みです。最大5人の家族メンバーがサブスクリプションを利用できるようになるため、[ファミリー共有](https://developer.apple.com/documentation/storekit/supporting-family-sharing-in-your-app)はアプリのユーザーエンゲージメントや継続率の向上に役立ちます。 このガイドでは、ファミリー共有にサブスクリプションをオプトインする方法と、Adaptyがファミリー内で共有された購入をどのように管理するかについて説明します。 特定のプロダクトのファミリー共有を有効にするには、まず[App Store Connect](https://appstoreconnect.apple.com/)にアクセスしてください。ファミリー共有は、新規・既存のアプリ内課金いずれもデフォルトでオフになっているため、各アプリ内課金ごとに個別に有効化する必要があります。**アプリのページ**にアクセスし、対象のアプリ内課金ページに移動して、ファミリー共有セクションの**Turn On**オプションを選択するだけで簡単に設定できます。 一度プロダクトのファミリー共有を有効にすると、**再び無効にすることはできません**。すでに家族とサブスクリプションを共有しているユーザーのエクスペリエンスが損なわれるためです。 また、共有できるのは非消耗型アイテムとサブスクリプションのみである点にもご注意ください。 <img src="/assets/shared/img/6db165a-CleanShot_2023-03-28_at_17.15.342x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 表示されたモーダルで**Confirm**ボタンをクリックすると、設定が完了します。完了すると、ファミリー共有セクションに「このサブスクリプションはファミリーグループの全員で共有できます」というメッセージが表示されます。これにより、サブスクリプションがファミリー共有に対応し、最大5人の家族メンバーと共有できるようになったことが確認できます。 Adaptyでは、追加の作業なしでファミリー共有をサポートできます。[App Storeのプロダクトを設定](app-store-products)するだけで、App Store Connectで**ファミリー共有**を**有効化**すると、**Adapty**に自動的に反映され、Webhookでイベントとして受信されます。 :::note ファミリー共有はサンドボックス環境ではサポートされていません。 ::: ユーザーがサブスクリプションを購入して家族メンバーと共有した場合、家族メンバーが利用できるようになるまで**最大1時間の遅延**が発生することがあります。これはAppleが意図的に設けたもので、ユーザーが気が変わった際に共有を取り消せるようにするためです。ただし、サブスクリプションが更新された場合、家族メンバーへの反映に遅延はありません。 ユーザーがファミリー共有対応のアプリ内プロダクトを購入すると、通常通りレシートにトランザクションが記録されますが、`in_app_ownership_type`というフィールドが追加され、値は`PURCHASED`となります。さらに、すべての家族メンバーに対して新しいトランザクションが作成され、元の購入とは異なる`web_order_line_item_id`および`original_transaction_id`が付与されます。この場合、`in_app_ownership_type`フィールドの値は`FAMILY_SHARED`となります。 正確な収益計算を行うため、Adaptyアナリティクスでは`in_app_ownership_type`が`PURCHASED`のトランザクションのみを集計します。`FAMILY_SHARED`トランザクションは収益およびコンバージョン指標から除外されます。 **ファミリー共有トランザクションに送信されるイベント** `FAMILY_SHARED`トランザクションは**アクセスレベル更新**イベントのみを発火します。プロダクト単位のサブスクリプションイベントは家族メンバーには発火しません。 | イベント | `FAMILY_SHARED` | `PURCHASED` | | --- | --- | --- | | **アクセスレベル更新** | あり | あり | | **サブスクリプション開始** | なし | あり | | **トライアル開始** | なし | あり | | **サブスクリプション更新** | なし | あり | | **サブスクリプション終了** | なし | あり | | **サブスクリプション返金** | なし | あり | | **請求エラー検出** | なし | あり | ダウンストリームのアナリティクスが**サブスクリプション開始**を基準にしている場合、家族メンバーはそこに表示されません。アクティブな家族メンバーを検出するには、**アクセスレベル更新**を使用してください。 Adaptyで他の家族メンバーを特定するには、イベントの詳細を確認します。まず、元のファミリー購入トランザクションを見つけます。次に、そのトランザクションのイベント詳細で、同じプロダクト、購入日、有効期限のものを探してください。イベント詳細を分析することで、元の購入に関連する他のファミリーメンバーシップトランザクションを特定できます。 --- # File: app-store-small-business-program --- --- title: "App Store Small Business Program" description: "Apple の Small Business Program の内容と、収益および Adapty のアナリティクスへの影響について説明します" --- :::link 対応する Play Store プログラムについては、[Google 手数料減額サービス](google-reduced-service-fee)をご覧ください。 ::: 年間の App Store 収益が 100 万ドル以下の組織は、Apple の [Small Business Program](https://developer.apple.com/app-store/small-business-program/) に参加できます。登録すると、標準の 30% ストア手数料が **15%** に引き下げられます。 プログラムに参加する場合は、収益計算とインテグレーションイベントの処理を正確に行うために、**Adapty の設定を変更する**必要があります。 この記事では以下について説明します: * [アプリが Small Business Program に登録されている場合の Adapty 設定方法](#configure-adapty) * [ストア手数料を削減するためのプログラム登録方法](#apply-for-the-program) ## Adapty の設定 \{#configure-adapty\} Adapty では、[アナリティクス](analytics)および[インテグレーションイベント](analytics-integration)に対して引き下げられた手数料率を適用できます。有効にするには、アプリごとに Small Business Program のステータスを指定してください。 :::warning 承認を受けたら**すぐに** Adapty で SBP ステータスを設定してください。遅れて変更しても、配信済みの Webhook イベントは書き換えられません([詳細](#retroactive-setting-changes))。 ::: 1. [**App Settings** → **General**](https://app.adapty.io/account) を開きます。 2. **Small Business Program** セクションを見つけます。 3. **Add period** をクリックします。 4. メンバーシップの開始日を選択します。 5. 終了日を選択するか、**At the current moment** チェックマークを有効にしてステータスを無期限に延長します。将来[資格を失った](#losing-eligibility)場合は、終了日を変更できます。 6. **Apply** をクリックします。 組織がプログラムの資格を維持している場合、メンバーシップは翌暦年に引き継がれます。ただし、メンバーシップステータスは**指定した期間のみ**に適用されます。 * **Add period** をクリックして新しいメンバーシップ期間を追加します。 * ステータスを無期限に延長するには、**At the current moment** チェックマークを有効にします。 設定を確認するには、[収益チャート](revenue)を開き、**Proceeds after store commission** を選択します。表示される収益が引き下げ後の手数料率を反映していることを確認してください。 ## プログラムへの申請 \{#apply-for-the-program\} ### 資格要件 \{#eligibility-requirements\} Apple は**年間収益**(前暦年の売上からストア手数料と税金を差し引いた金額)に基づいて SBP の資格を判定します。 資格を得るには、あなたの組織とその<InlineTooltip tooltip="関連デベロッパーアカウント">あなたまたはあなたの組織が過半数の所有権(50%超)または意思決定権を持つアカウント。</InlineTooltip>の年間収益の合計が 100 万ドル以下である必要があります。 新規作成の組織は、自動的にプログラムへの申請資格があります。 ### 申請前の確認事項 \{#before-you-apply\} 以下を確認してください: - Apple Developer Program のアカウントホルダーであること - App Store Connect で最新の有料アプリケーション契約に同意していること - すべての関連デベロッパーアカウントをリストアップできること ### 登録手順 \{#enrollment\} 1. [App Store Small Business Program 登録ページ](https://developer.apple.com/app-store/small-business-program/)にアクセスします。 2. **Enroll** をクリックし、Apple Developer アカウントでサインインします。 3. 事前入力された情報(名前、メール、Team ID)を確認して送信します。 ### 審査 \{#review\} 審査プロセスには 1 か月以上かかる場合があります。資格がある場合は、Apple から承認メールが届きます。 承認後、待機期間があります。引き下げられた手数料は、Apple の[次の会計期間](https://adapty.io/apple-fiscal-calendar/)の 15 日目から適用されます。それ以前の取引には適用されません。 ### 資格の喪失 \{#losing-eligibility\} 現在の暦年の累計収益が 100 万ドルを超えると、プログラムのメンバーシップを失い、Apple が標準の 30% 手数料を適用し始めます。 :::important ビジネスが Small Business Program を離れる場合は、設定の終了日を**すぐに変更してください**。変更しないと、Adapty は引き続き引き下げ後の手数料率で計算を続けます。 ::: 年間収益が再び 100 万ドルを下回った**翌年**に、プログラムに再申請できます。詳細については、[公式プログラム規約](https://developer.apple.com/app-store/small-business-program/)をご覧ください。 ## 設定の遡及的変更 \{#retroactive-setting-changes\} Adapty で手数料減額ステータスをさかのぼって変更した場合、新しい手数料率は Adapty のデータに異なるスケジュールで反映されます: | 反映される場所 | 手数料率を変更した後の動作 | | --- | --- | | アナリティクスダッシュボード(Revenue、Proceeds、MRR、ARR) | 日次再計算が実行される24時間以内に、新しい手数料率が適用されます。 | | S3、GCS、BigQuery エクスポート | 次回のスケジュールされたエクスポート時に、新しい手数料率が適用されます。 | | 配信済みの Webhook イベント | Adapty は配信後の Webhook イベントを変更できません。古い手数料率のままになります。 | データウェアハウスに Webhook イベントからの収益データが保存されている場合、それらのレコードには古い手数料率が残ります。データを調整するには、アナリティクスダッシュボードから該当期間のデータを取得するか、S3、GCS、または BigQuery への新しいエクスポートを生成してください。 --- # File: android-products --- --- title: "Play Storeのプロダクト" description: "AdaptyでAndroidプロダクトを管理し、アプリ内課金を効率化して、収益化戦略を最適化しましょう。" --- このページでは、Play Storeでのプロダクト作成に関するガイダンスを提供します。この情報はAdaptyの機能に直接関係するものではありませんが、Google PlayコンソールでのプロダクトZo作成に困った際の参考資料として役立ちます。 プロダクトとは、Play Storeのアプリ内でユーザーに提供するデジタルアイテムやサービスのことで、通常は購入可能なものを指します。買い切り購入、サブスクリプション、その他のデジタルグッズなど、さまざまなアプリ内課金アイテムが含まれます。 [Googleの課金システム](https://developer.android.com/google/play/billing/compatibility)では、サブスクリプションに複数のベースプランを設定でき、各ベースプランにさまざまな割引やオファーを追加できます。この仕組みは、主に以下の3つの要素で構成されています: - **サブスクリプション:** 特定の期間、ユーザーが享受できるサービスセットを表します(販売するアイテム本体)。例えば、プレミアム機能を提供する「ゴールドティア」などがこれにあたります。 - **ベースプラン:** 請求期間、更新タイプ、価格の具体的な設定を表します(アイテムの販売方法)。「自動更新付き年間プラン」や「前払い月額プラン」などが例として挙げられます。 - **オファー:** 対象ユーザーに提供される割引で、ベースプランの価格を変更します。例えば「新規ユーザー向け14日間無料トライアル」などがこれにあたります。 ## Play Storeでプロダクトを作成するには? \{#how-to-create-a-product-in-play-store\} プロダクトとは、アプリ内でユーザーに提供するデジタルアイテムやサービスのことで、通常は購入可能なものを指します。買い切り購入、サブスクリプション、その他のデジタルグッズなど、さまざまなアプリ内課金アイテムが含まれます。 Androidデバイス向けにプロダクトを設定するには: 1. Google PlayコンソールのLeft menuから [**Monetize** -> **Subscriptions**](https://console.cloud.google.com/iam-admin/serviceaccounts) または [**Monetize** -> **In-app products**](https://console.cloud.google.com/iam-admin/serviceaccounts) セクションを開きます。 <img src="/assets/shared/img/6eff1d1-subscription_GP.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Create subscription** ボタンをクリックします。 <img src="/assets/shared/img/af7fe02-create_subscription_GP.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 表示された **Create subscription** ウィンドウで、**Product ID** フィールドにサブスクリプションIDを、**Name** フィールドにサブスクリプション名を入力します。 Product IDはユニークである必要があり、数字または小文字で始まり、アンダースコア(\_)やピリオド(.)を含めることができます。開発中にプロダクトにアクセスしたり、Adaptyと同期したりするために使用されます。一度Google PlayコンソールでProduct IDがプロダクトに割り当てられると、そのプロダクトが削除されても、他のアプリで再利用することはできません。 Product IDの命名には、標準化されたフォーマットに従うことをお勧めします。より簡潔なアプローチとして、`<サブスクリプション名>.<アクセスレベル>` という形式でプロダクトに名前を付けることを推奨します。そうすることで、weekly、monthlyなどのベースプランを使って期間や請求頻度を管理できます。 Nameはあくまで内部参照用ですが、Google Playストアの掲載ページにも表示されるため、分かりやすい名前を自由に付けてください。最大55文字まで使用できます。 4. **Create** ボタンをクリックしてサブスクリプションの作成を確定します。 :::note AdaptyにおけるGoogle Playサブスクリプションプロダクト Adaptyのプロダクトは、Google Playサブスクリプションのベースプランに対応します。これは、ベースプランがユーザーが実際に購入できるプロダクトだからです。Adaptyは既存のGoogle Playサブスクリプションとそれに対応するベースプランの移行をシームレスに処理するため、追加の作業は不要です。ただし、Adaptyで新しいプロダクトを追加する際は、ベースプランIDとProduct IDの両方を指定する必要があります。 ::: ### ベースプランを作成する \{#create-a-base-plan\} サブスクリプションプロダクトには、ベースプランを追加する必要があります。ベースプランは、ユーザーがサブスクリプションを購入する際の請求期間、価格、更新タイプを決定します。なお、ユーザーはサブスクリプションプロダクトを直接購入するのではなく、常にサブスクリプション内のベースプランを購入する形になります。 ベースプランを作成するには: 1. Google PlayコンソールのLeft menuから [**Monetize** -> **Subscriptions**](https://console.cloud.google.com/iam-admin/serviceaccounts) セクションを開きます。そこで、ベースプランを追加したいサブスクリプションを見つけます。 2. サブスクリプションの横にある **View subscription** ボタンをクリックします。 <img src="/assets/shared/img/4072a2a-subscriptions_GP.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. サブスクリプションの詳細が表示されたら、**Base plans and offers** タイトルの下にある **Add base plan** ボタンをクリックします。スクロールダウンしないと表示されない場合があります。 <img src="/assets/shared/img/b493b60-add_base_plan.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 表示された **Add base plan** ウィンドウで、**Plan ID** フィールドにベースプランのユニークな識別子を入力し、必須項目を入力します。IDは数字または小文字で始まり、数字(0-9)、小文字(a-z)、ハイフン(-)を含めることができます。 <img src="/assets/shared/img/8146763-CleanShot_2023-07-20_at_16.51.412x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 地域ごとの価格を設定します。 <img src="/assets/shared/img/8b26e1d-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. **Save** ボタンをクリックして設定を確定します。 7. **Activate** ボタンをクリックしてベースプランを有効化します。 Adaptyでは、サブスクリプションプロダクトには期間と更新タイプが一致する単一のベースプランのみ設定できる点にご注意ください。 ### フォールバックプロダクト \{#fallback-products\} :::warning 後方互換性のないベースプランのサポートについて 古いバージョンのAdapty SDKは、Google Billing Library v5+の機能(サブスクリプションプロダクトごとの複数ベースプランおよびオファー)をサポートしていません。これらのSDKバージョンでは、Google PlayコンソールでGame **[後方互換](https://support.google.com/googleplay/android-developer/answer/12124625?hl=en#backwards_compatible)** とマークされたベースプランのみにアクセスできます。なお、後方互換としてマークできるベースプランはサブスクリプションごとに1つだけです。 ::: <img src="/assets/shared/img/b5e70cb-CleanShot_2023-07-20_at_17.03.252x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adaptyで強化されたGoogleサブスクリプションの設定と機能を最大限に活用するために、後方互換のフォールバックプロダクトを設定する機能を提供しています。このフォールバックプロダクトは、古いバージョンのAdapty SDKを使用するアプリ専用に使用されます。Google Playプロダクトを作成する際に、そのプロダクトをPlayコンソールで後方互換としてマークするかどうかを指定できます。Adaptyはこの情報を使って、そのプロダクトが古いバージョンのSDK(バージョン2.5以下)で購入可能かどうかを判断します。 例えば、`subscription.premium` というサブスクリプションに「週次(後方互換)」と「月次」の2つのベースプランがあるとします。`subscription.premium:weekly` プロダクトをAdaptyに追加する場合、後方互換プロダクトを指定する必要はありません。しかし、`subscription.premium:monthly` プロダクトの場合は、後方互換プロダクトを指定する必要があります。指定しないと、Google Billing Library v4で意図せず `subscription.premium:weekly` プロダクトが購入されてしまう可能性があります。このシナリオに対応するために、月次でかつ後方互換としてマークされたベースプランを持つ別のプロダクトを作成する必要があります。これにより、`subscription.premium:monthly` を選択したユーザーが正しい頻度で請求されることが保証されます。 ## Adaptyにプロダクトを追加する \{#add-products-to-adapty\} App Store Connectでアプリ内課金、サブスクリプション、オファーの追加が完了したら、次のステップとして[これらのプロダクトをAdaptyに追加](create-product)します。 --- # File: google-play-data-safety --- --- title: "Google Play データセーフティ" description: "AdaptyでGoogle Playデータセーフティポリシーへの準拠を確認します。" --- Google Playのデータセーフティセクションは、アプリ開発者がユーザーに対して、アプリが収集または共有するデータについて簡単に説明し、アプリの重要なプライバシーおよびセキュリティ対策を強調するための方法を提供しています。この情報により、ユーザーはダウンロードして使用するアプリを選ぶ際に、より十分な情報に基づいた判断ができるようになります。 以下は、Adaptyが収集するデータについての簡単なガイドです。Google Playに必要な情報を提供する際にご活用ください。 ## データ収集とセキュリティ \{#data-collection-and-security\} <img src="/assets/shared/img/3508c24-image4.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **アプリは必要なユーザーデータタイプを収集または共有していますか?** Adaptyはユーザーの購入履歴を収集するため、「はい」を選択してください。 **アプリが収集するすべてのユーザーデータは転送中に暗号化されますか?** Adaptyは転送中のデータを暗号化するため、「はい」を選択してください。 **ユーザーがデータの削除をリクエストできる方法を提供していますか?** 「はい」を選択する場合は、ユーザーがサポートチームにデータ削除をリクエストできる手段を確保してください。Adapty ダッシュボードまたはREST APIから直接ユーザーを削除できます。 ## データタイプ \{#data-types\} 以下は、Googleが申告を求めるデータタイプの一覧です。Adaptyが各タイプのデータを収集するかどうかを示しています。 | データタイプ | 詳細 | | :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 位置情報 | Adaptyは収集しません | | 健康とフィットネス | Adaptyは収集しません | | 写真と動画 | Adaptyは収集しません | | ファイルとドキュメント | Adaptyは収集しません | | カレンダー | Adaptyは収集しません | | 連絡先 | Adaptyは収集しません | | ユーザーコンテンツ | Adaptyは収集しません | | 閲覧履歴 | Adaptyは収集しません | | 検索履歴 | Adaptyは収集しません | | アプリ情報とパフォーマンス | Adaptyは収集しません | | Webブラウジング | Adaptyは収集しません | | 連絡先情報 | Adaptyは収集しません | | 財務情報 | Adaptyはユーザーの購入履歴を収集します | | 個人情報と識別子 | Adaptyは、ユーザーIDと、氏名・メールアドレス・電話番号などの識別可能な連絡先情報を、Adapty SDKに明示的に渡した場合に収集します。 | | デバイスおよびその他の識別子 | AdaptyはデバイスIDのデータを収集します。 | ## データの利用と取り扱い \{#data-usage-and-handling\} ### ユーザーID \{#user-ids\} **1. このデータは収集されますか、共有されますか、それとも両方ですか?** このデータはAdaptyによって収集されます。Adaptyとサービスプロバイダーとみなされないサードパーティとの連携を使用している場合は、「共有」も開示する必要がある場合があります。 **2. このデータは一時的に処理されますか?** 「いいえ」を選択してください。 **3. このデータの収集はアプリに必須ですか、それともユーザーが選択できますか?** このデータ収集は必須であり、オフにすることはできません。 <img src="/assets/shared/img/2c60161-image5.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> **4. このユーザーデータはなぜ収集されますか? / なぜ共有されますか?** 「アプリの機能」と「分析」のチェックボックスを選択してください。 <img src="/assets/shared/img/07a3c9e-image2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 財務情報 \{#financial-info\} Adaptyを使用している場合は、Google Play Consoleのデータタイプセクションで、アプリが「購入履歴」情報を収集することを開示する必要があります。 <img src="/assets/shared/img/1057870-image7.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### デバイスまたはその他のID \{#device-or-other-ids\} <img src="/assets/shared/img/d10f132-CleanShot_2023-03-01_at_17.55.312x.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <img src="/assets/shared/img/ccb1a2a-image5.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 次のステップ \{#next-steps\} データセーフティの選択が完了すると、Googleはアプリのプライバシーセクションのプレビューを表示します。前述のとおり「財務情報」と「デバイスまたはその他のID」を選択した場合、プライバシー情報は次の例のように表示されます。 <img src="/assets/shared/img/e8d9b73-image3.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> アプリのレビュー申請の準備ができている場合は、[リリースチェックリスト](release-checklist)ドキュメントを参照し、申請の準備について詳しくご確認ください。 --- # File: google-reduced-service-fee --- --- title: "Googleの手数料減額プログラム" description: "Googleの手数料減額プログラムの内容と、収益やAdaptyのアナリティクスへの影響について理解しましょう" --- :::link App Storeの対応プログラムについては、[App Store中小企業プログラム](app-store-small-business-program)をご覧ください。 ::: Google Playの[手数料減額プログラム](https://support.google.com/googleplay/android-developer/answer/112622?hl=en)は、年間収益の最初の100万ドルに対する手数料を30%から**15%**に引き下げます。同一カレンダーイヤーの100万ドルを超える収益には、通常の30%の手数料が適用されます。 :::note 2022年1月1日以降、Googleはこのプログラムに関係なく、すべての自動更新サブスクリプションに対して15%の手数料を課しています。手数料減額プログラムは主に、非サブスクリプションのアプリ内課金と有料アプリに恩恵をもたらします。 ::: プログラムのメンバーは、正確な収益計算とインテグレーションイベントの処理を確保するために、**Adaptyの設定を変更する必要があります**。 この記事では以下について説明します: * [アプリが手数料減額プログラムに登録されている場合のAdaptyの設定方法](#configure-adapty) * [ストア手数料を削減したい場合のプログラム登録方法](#enroll-in-the-program) ## Adaptyの設定 \{#configure-adapty\} Adaptyは、[アナリティクス](analytics)と[インテグレーションイベント](analytics-integration)に減額された手数料率を適用できます。これを有効にするには、アプリごとに手数料減額プログラムのステータスを指定してください。 :::warning **登録したらすぐに**AdaptyでReducedService Feeのステータスを設定してください。設定を後から変更しても、配信済みのWebhookイベントを書き換えることはできません([詳細](#retroactive-setting-changes))。 ::: 1. [**App Settings** → **General**](https://app.adapty.io/account)を開きます。 2. **Reduced Service Fee**セクションを見つけます。 3. **Add period**をクリックします。 4. メンバーシップの開始日を選択します。 5. 終了日を選択するか、**At the current moment**チェックマークを有効にして、このステータスを無期限に延長します。[年間収益が100万ドルを超えた場合](#exceeding-the-threshold)、終了日を変更できます。 6. **Apply**をクリックします。 メンバーシップのステータスは、**指定した日付範囲にのみ**適用されます。プログラムはカレンダーイヤーごとにリセットされます。 * **Add period**をクリックして、新しいメンバーシップ期間を追加します。 * このステータスを無期限に延長するには、**At the current moment**チェックマークを有効にします。 設定を確認するには、[Revenueチャート](revenue)を開いて**Proceeds after store commission**を選択します。表示された収益が減額された手数料率を反映しているか確認してください。 ## プログラムへの登録 \{#enroll-in-the-program\} ### 資格要件 \{#eligibility-requirements\} Googleは、<InlineTooltip tooltip="アカウントグループ">収益が合算されるデベロッパーアカウントのグループです。デベロッパーアカウントをプライマリデベロッパーアカウントとして指定し、関連するアカウントをグループにリンクする必要があります。</InlineTooltip>内のすべてのアカウントの**年間収益**に基づいて資格を判断します。 15%の手数料率は、合算した年間収益の最初の100万ドルに適用されます。その閾値を超えた収益には30%が課されます。 ### 登録前の確認事項 \{#before-you-enroll\} 以下を確認してください: - [支払いプロフィール](https://support.google.com/googleplay/android-developer/answer/10632485)が設定されていること - すべての関連デベロッパーアカウントをリストアップできること ### 登録手順 \{#enrollment\} 1. [Google Play Console](https://play.google.com/console/)にアクセスします。 2. アカウントグループを作成し、デベロッパーアカウントをプライマリデベロッパーアカウントとして設定します。 3. 関連するデベロッパーアカウントをグループにリンクします。 4. 手数料減額プログラムの利用規約に同意します。 これらの手順を完了すると、Googleが自動的に登録します。手動レビューや承認メールはありません。詳細な手順については、Googleの[登録ガイド](https://support.google.com/googleplay/android-developer/answer/10632485)をご覧ください。 ### 閾値を超えた場合 \{#exceeding-the-threshold\} 合算した年間収益が100万ドルを超えると、Googleはそのカレンダーイヤーの残りの期間、閾値を超えた部分に30%の手数料を課します。 :::important 年間収益が100万ドルを超えた場合は、**すぐにAdaptyの設定で終了日を変更してください**。変更しないと、Adaptyは引き続き減額された手数料率で計算を続けます。 ::: プログラムはカレンダーイヤーごとにリセットされます。ある年に収益が100万ドルを超えた場合でも、翌年は最初の100万ドルに対して15%の手数料率が自動的に再適用されます。再登録は不要です。詳細については、[公式プログラム規約](https://support.google.com/googleplay/android-developer/answer/112622?hl=en)をお読みください。 ## 設定の遡及的な変更 \{#retroactive-setting-changes\} Adapty で手数料減額ステータスをさかのぼって変更した場合、新しい手数料率は Adapty のデータに異なるスケジュールで反映されます: | 反映される場所 | 手数料率を変更した後の動作 | | --- | --- | | アナリティクスダッシュボード(Revenue、Proceeds、MRR、ARR) | 日次再計算が実行される24時間以内に、新しい手数料率が適用されます。 | | S3、GCS、BigQuery エクスポート | 次回のスケジュールされたエクスポート時に、新しい手数料率が適用されます。 | | 配信済みの Webhook イベント | Adapty は配信後の Webhook イベントを変更できません。古い手数料率のままになります。 | データウェアハウスに Webhook イベントからの収益データが保存されている場合、それらのレコードには古い手数料率が残ります。データを調整するには、アナリティクスダッシュボードから該当期間のデータを取得するか、S3、GCS、または BigQuery への新しいエクスポートを生成してください。 --- # File: google-play-quota-increase --- --- title: "Google Play Developer API クォータ増加のリクエスト" description: "履歴データのインポートや大規模なサブスクライバーベースでデフォルトの上限を超えた場合に、Google Play Developer API のクォータ増加をリクエストします。" --- Adapty は [Google Play Developer API](https://developers.google.com/android-publisher) を使用して、購入の検証とサブスクリプションデータの同期を行います。この API のデフォルトクォータは 1 分あたり 3,000 クエリです。アプリがこの上限を超えると、Google からメール通知が届きます。これは主に[履歴データのインポート](importing-historical-data-to-adapty)時や、アクティブなサブスクライバーが多いアプリで発生します。 大規模なインポートを実行する前、またはクォータ超過の通知を受け取った場合は、サービスの中断を防ぐために Google にクォータ増加をリクエストしてください。 ## 始める前に \{#before-you-start\} まだ設定していない場合は、[リアルタイムデベロッパー通知 (RTDN)](enable-real-time-developer-notifications-rtdn) を有効にしてください。RTDN はポーリングではなくプッシュ通知でサブスクリプションの更新を配信するため、API の消費量を削減できます。RTDN が有効になっていない場合、Google はクォータ増加リクエストを却下することがあります。 ## 必要な情報を収集する \{#gather-required-information\} リクエストフォームを開く前に、以下の情報を準備してください。 - **デベロッパーアカウント ID**: [Google Play Console](https://play.google.com/console/) で **Settings > Developer account > Account details** に移動すると確認できます。ID はページの上部に表示されています。 - **アプリのパッケージ名**: Android アプリのパッケージ名(例: `com.example.app`)。Google Play Console のアプリの **Dashboard** ページで確認できます。 - **Google Cloud プロジェクト番号**: [Google Cloud Console](https://console.cloud.google.com/) でプロジェクトを選択すると確認できます。プロジェクト番号は **Dashboard** ページに表示されています。 ## クォータ増加をリクエストする \{#request-the-quota-increase\} 1. [Google Play Developer API クォータ増加リクエストフォーム](https://support.google.com/googleplay/android-developer/contact/apiqr)を開きます。 2. デベロッパーアカウント ID、アプリのパッケージ名、Google Cloud プロジェクト番号を入力します。 3. 増加が必要な API とクォータバケットを選択します。クォータ超過について Google からメールが届いている場合は、そのメールにどのバケットかが記載されています。 4. 正当化フィールドに、購入の検証とサブスクリプションデータの同期に API アクセスが必要なサードパーティのサブスクリプション管理サービスを使用していることを説明します。 5. リクエストするクォータ量に、必要な数値を入力します。必要な量が不明な場合は、[Google Cloud Console](https://console.cloud.google.com/) の **IAM & Admin > Quotas**(「Google Play Android Developer API」でフィルタリング)で現在の使用状況を確認し、使用状況データとインポートを予定している履歴エントリ数を [support@adapty.io](mailto:support@adapty.io) に送信してください。適切な量の判断をサポートします。 6. フォームを送信します。 Google は通常、数営業日以内にクォータ増加リクエストを処理します。 --- # File: prepare-your-app-for-store-review --- --- title: "ストアレビューに向けてアプリを準備する" description: "App StoreおよびGoogle Play Storeでアプリを承認してもらうためのアドバイス" --- この記事では、ストアがアプリ申請をレビューする際のプロセスを説明し、より迅速に承認を得るためのヒントを紹介します。情報は以下の公式申請ガイドラインを参考にしています: * [App Store 審査ガイドライン](https://developer.apple.com/app-store/review/guidelines/) * [Google Play Store 審査ガイドライン](https://play.google/developer-content-policy/) :::important 両ストアは同様の審査プロセスに従っています。いずれかのストアにのみ適用されるポリシーについては、記事内でそのストア名を明記しています。 ::: Adapty ユーザーは、[ペイウォールとアプリ内課金に関する要件](#iap-related-requirements)のコンプライアンスに特に注意してください。これらはリジェクトの最も一般的な原因の一つです。 ## はじめる前に \{#before-you-begin\} アプリが提出の準備ができているか確認してください。 Adaptyには、アプリのリリース準備を整えるための[リリースチェックリスト](release-checklist)があります。 Google Play Storeでは、初めてアプリを公開するデベロッパーが、提出前に[アプリをテスト](https://support.google.com/googleplay/android-developer/answer/14151465?hl=en)することを求めています。テストには少なくとも12人が参加し、最低14日間継続して実施する必要があります。この要件は、Google の審査スタッフに届くバグの多いアプリを減らすために2025年に導入されました。 ## レビュープロセスの概要 \{#review-process-overview\} #### ステップ1:自動スクリーニング \{#step-1-the-automated-screening\} App Store と Google Play Store はどちらも、同様の2ステップのレビュープロセスに従っています。申請直後、アプリは自動スキャンを受けます。このスキャンには数時間かかる場合があります。 両ストアともアプリのマルウェアスキャンを行いますが、Googleは特にこのプロセスを重視しています。不審なサーバーへの接続やユーザーデータへの不正アクセスなど、悪意のある活動を示す行動指標を検出します。アプリが潜在的に有害と判断された場合は、フラグが立てられ、人間のセキュリティアナリストに渡されます。このステップで実行されるチェックの概要リストは、[Google Play Protect のドキュメント](https://developers.google.com/android/play-protect/cloud-based-protections#machine-learning)に掲載されています。 ストアはまた、必要なメタデータの存在、有害または著しく古い依存関係がないこと、そしてビルドの整合性も確認します。 #### ステップ 2: 人間によるレビュー \{#step-2-the-human-review\} アプリが自動審査を通過すると、次は人間のレビュアーによる審査が行われます。このステップは、アプリの複雑さや現在のレビューキューの状況によっては、数日かかる場合があります。機密データを処理するアプリは、レビューにより長い時間がかかります。 ## 一般的な要件 \{#general-requirements\} ### 安定性 \{#stability\} 審査中にクラッシュするアプリは却下されます。審査担当者は意図的に不安定なネットワーク状況をシミュレートすることがあるため、アプリはそのような状況にも適切に対応できる必要があります。 ### 完全性 \{#completeness\} Apple と Google はどちらも、ストアコンテンツに対して*完全性*(「最低限の機能」)の要件を課しています。 * プレースホルダー、「近日公開」画面、機能の不備はiOSアプリの審査却下につながります。 * Googleは[より柔軟](https://support.google.com/googleplay/android-developer/answer/9898783?hl=en)で、特にアプリが[Early Access](https://knowledge.workspace.google.com/admin/users/access/turn-early-access-apps-on-or-off-for-users)の場合はその傾向があります。 * 両ストアとも、機能がほとんどない、またはまったくないアプリを**却下します**。これには、画像1枚、PDFファイル、またはWebページのみを表示するアプリも含まれます。 コンテンツが不足している場合も同じカテゴリに該当します。 * アプリが宣伝した内容を実現していない場合、リジェクトされます。 * ダッシュボードでアプリ内課金を設定しているにもかかわらず、ビルドに含めていない場合、アプリはリジェクトされます。 ### メタデータの正確性 \{#metadata-accuracy\} 説明、スクリーンショット、その他のメタデータに誤解を招く、不正確な、または一貫性のない情報があると、却下につながる可能性があります。 ストアのリスティングを使って将来のアプリ機能を宣伝しないでください。 アプリが一般向けに設計されていない場合、審査担当者はそのワークフローを説明する追加のドキュメントを求めます。アプリのメタデータに明確な説明を含めてください。 ### コンテンツレーティング \{#content-rating\} アプリ内のコンテンツは、宣言されたレーティングと一致している必要があります。 ### 法的側面 \{#legal-aspects\} * アプリのプライバシーポリシーは、アプリ内からアクセスできるようにする必要があります。ペイウォールビルダーの[リンクボタン](paywall-buttons#links)を使用できます。 * 法的合意事項は、発効**前**にユーザーが読んで同意するよう求めてください。 * アプリ内の広告の存在を開示してください。開示しない場合、却下につながる可能性があります。 * iOS アプリにアプリ内課金が含まれる場合、App Store Connect のダッシュボードで**有料アプリ契約**に同意する必要があります。 ### 認証 \{#authentication\} アプリのコンテンツの一部が認証後にのみ利用可能な場合、審査担当者に有効なアクセス認証情報を提供してください。コンテンツに完全にアクセスできない場合は却下されます。 アプリでユーザーがアカウントを作成できる場合、アカウントを削除することもできるようにする必要があります。メールベースのサポートやウェブサイトに誘導するだけでは、この要件を満たしません。 ### アクセスとプライバシー \{#access-and-privacy\} アプリのメタデータには、要求する各権限の理由を明確に記載する必要があります。最も機密性の高い権限(例:テキストメッセージや通話履歴へのアクセス)には、動画によるデモが必要になる場合があります。 同じ原則が機密性の高いユーザーデータにも適用されます。要求する場合は、その理由を説明してください。 ## アプリ内課金に関する要件 \{#iap-related-requirements\} ビジネスポリシーの違反は、アプリ却下の最も一般的な理由の一つです。アプリの主な収益化方法がサブスクリプションとアプリ内課金の場合、より厳しい審査を受けます。 ### ペイウォールの要件 \{#paywall-requirements\} アプリの審査担当者は、わかりやすく明確なペイウォールを求めています。 ユーザー操作が疑われると、アプリは却下されます。複数の審査で不正な慣行の証拠が見つかった場合、アカウントが無効化され、アプリが[停止](https://support.google.com/googleplay/android-developer/community-guide/287283557/app-suspended-for-repeated-rejections?hl=en)される可能性があります。Google Play は[ストライクシステム](https://support.google.com/googleplay/android-developer/answer/9899234?hl=en)を採用しており、最悪の場合、すべてのアプリが削除されることもあります。 ペイウォールのデザインでは、以下のプラクティスを遵守してください。 - **透明性を持ち、率直に伝える。** ユーザーに購入を促す前に、プロダクトの正確な価格、請求頻度、特典、およびキャンセル条件を明示する。 買い切り購入と定期的な支払いが必要なプロダクトを明確に区別する。 プロダクトに無料トライアルが含まれる場合は、その期間と条件を明示する。 ユーザーを誤解させるような意図的にわかりにくい表現は使用しない。 - **一貫性を保つ。** プロダクトの価格は、App Store の掲載情報、アプリ内画面、サブスクリプション管理画面、マーケティングコンテンツの間で一致している必要があります。どんなに些細な価格の不一致でも、審査却下の理由になります。 Adapty のペイウォールビルダーを使えば、ペイウォールと App Store Connect のプロダクト間で価格が自動的に同期されます。ペイウォールを手動でコーディングしている場合は、データ配列から[各プロダクトの価格を取得](fetch-paywalls-and-products)する必要があります。 - **すべてのティアを平等に表示する。** 最も高価なオプションをあらかじめ選択した状態にしたり、安価なオプションを非表示にしたりしないでください。 - **「ダークパターン」を避ける。** 偽の緊迫感や希少性を演出しないでください。 無料機能を意図的に使いにくくしたり、見つけにくくしたりして、ユーザーに購入を強制しないでください。 ### アクセスの保証 \{#access-guarantee\} アプリは、ユーザーが自分の購入にアクセスする権利を保証しなければなりません。 * **即時アクセス** 購入が成功したら、目に見える遅延なく即座にプロダクトへのアクセスが解放される必要があります。 支払い承認の中間状態によってエラーが発生したり、ユーザー体験が損なわれたりしてはなりません。 購入が成功したら、ペイウォールを即座に非表示にする必要があります。購入後もペイウォールを表示し続けると、ユーザーが支払い済みのコンテンツにアクセスできなくなります。 * **アクセスの復元** ユーザーが新しいデバイスからプロダクトへのアクセスを復元できるようにする必要があります。復元ボタンは見やすい場所に配置してください。 [フローBuilder](adapty-flow-builder)でペイウォールを作成した場合、復元ボタンは自動的に復元処理を起動します。[手動でペイウォールを実装した](ios-implement-paywalls-manually)場合は、[restorePurchases](restore-purchase)メソッドを呼び出すコードを追加してください。SDKを[オブザーバーモード](observer-vs-full-mode)で使用している場合を**除き**、Adaptyはユーザーのアクセスレベルを復元します。 アプリは、プロダクトのストアページやApp Store内の他の場所で行われたアプリ内課金を認識できる必要があります。 ### 適切な支払い方法 \{#appropriate-payment-methods\} どちらのストアも、アプリ内課金による物理的な商品の販売を禁止しており、ほとんどのデジタルコンテンツにはストア内課金の使用を義務付けています。 ただし、米国やEUを含む一部の地域では、このストア内課金の義務が適用されません。国によっては、[ストア内課金を完全に回避する](https://support.google.com/googleplay/android-developer/answer/16497028)か、[アプリストア課金と代替課金のどちらかをユーザーに選ばせる](https://support.google.com/googleplay/android-developer/answer/13821247)ことができる場合があります。 一部のアプリカテゴリ(電子書籍リーダーやマッチングアプリなど)は、これらの地域以外でも代替決済方法の対象となる場合があります。詳細はストアの公式ガイドラインをご確認ください。 :::tip [Google](https://support.google.com/googleplay/android-developer/answer/13821247) と異なり、Apple は代替決済方法を許可している国の確定的なリストを公開していません。新たな法律が各地域で施行されるにつれ、対応国は拡大していく見込みです。作業を進める前に、お住まいの国に関するドキュメントをご確認ください。 ::: 両ストアとも決済プロバイダーとの連携に関するガイドラインを設けており、これらのサービスを利用したトランザクションには引き続き手数料が発生します。 ## 却下への対処 \{#handling-rejection\} アプリが却下された場合、審査担当者はどのガイドラインに違反しているかを通知します。該当するガイドラインを全文で確認し、修正してください。 * [App Store 申請ガイドライン](https://developer.apple.com/app-store/review/guidelines/) * [Google Play ストア申請ガイドライン](https://play.google/developer-content-policy/) 却下が不当だと感じた場合は、異議申し立てを行う権利があります。コンプライアンスの証拠を提示し、ストアに問い合わせてください。 * レビュー中はアプリを更新しないでください。 * 審査を申請するたびに、担当者が変わる場合があります。有利に働くこともあれば、不利になることもあります。 * 問題を一つずつ修正して申請するのではなく、すべての修正が完了してから再審査を申請してください。 * Google Play がポリシー違反でアプリを拒否した場合は、一時停止中や非アクティブなトラックも含め、すべてのトラックで該当データを更新してください。 * 2回目以降の審査は、通常、初回より早く完了します。 * 重大なバグや締め切りがある場合は優先審査を利用できる場合があります。ただし、使用は控えめにしてください。 ## レビュー後:継続的なモニタリング \{#after-the-review-continuous-monitoring\} アプリがレビューを通過した後も、両方のアプリストアはアプリの監視を続けます。 承認後にアプリの機能が変わった場合(たとえば、動的に読み込まれるコードによる変更など)、フラグが立てられ、リストから削除されます。ネガティブなユーザーフィードバックの急増も、追加審査の対象となる可能性があります。 2024年から2025年にかけて、Googleは平均品質を高めるために[Play Storeのアプリの47%を削除しました](https://techcrunch.com/2025/04/29/google-play-sees-47-decline-in-apps-since-start-of-last-year/)。 アプリを放棄することにもリスクがあります。[Google](https://www.cnet.com/tech/mobile/google-play-store-will-hide-apps-that-havent-been-updated-in-years/) も [Apple](https://developer.apple.com/support/app-store-improvements/#:~:text=Developers%20of%20apps%20that%20have,launch%20will%20be%20removed%20immediately.) も、更新やダウンロードがないアプリをストアから削除します。 ## 関連項目 \{#see-also\} * [サンドボックステスト](test-purchases-in-sandbox) * [リリースチェックリスト](release-checklist) --- # File: firebase-apps --- --- title: "Firebase アプリ" description: "Firebase と Adapty を連携して、モバイルアプリのユーザー分析とサブスクリプション追跡を強化しましょう。" --- このページは、Firebase 上で動作するアプリへの Adapty 連携についての説明です。 :::note はじめに これは Adapty を動作させるために必要なすべての手順ではなく、Firebase との連携に役立つヒントをまとめたものです。アプリに Adapty を導入したい場合は、まず [クイックスタートガイド](quickstart) をお読みください。 ::: ## ユーザーの識別 \{#user-identification\} Firebase 認証を使用している場合、このスニペットを参考にすることで Firebase と Adapty 間のユーザーを同期できます。これはあくまでサンプルコードであり、アプリの認証仕様に合わせて適宜調整してください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS with Firebase" default> ```swift showLineNumbers @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Configure Adapty before Firebase Adapty.activate("YOUR_API_KEY") Adapty.delegate = self // Configure Firebase FirebaseApp.configure() // Add state change listener for Firebase Authentication Auth.auth().addStateDidChangeListener { (auth, user) in if let uid = user?.uid { // identify Adapty SDK with new Firebase user Adapty.identify(uid) { error in if let e = error { print("Sign in error: \(e.localizedDescription)") } else { print("User \(uid) signed in") } } } } return true } } extension AppDelegate: AdaptyDelegate { // MARK: - Adapty delegate func didReceiveUpdatedPurchaserInfo(_ purchaserInfo: PurchaserInfoModel) { // You can optionally post to the notification center whenever // purchaser info changes. // You can subscribe to this notification throughout your app // to refresh tableViews or change the UI based on the user's // subscription status NotificationCenter.default.post(name: NSNotification.Name(rawValue: "com.Adapty.PurchaserInfoUpdatedNotification"), object: purchaserInfo) } } ``` </TabItem> <TabItem value="kotlin" label="Android with Firebase" default> ```kotlin showLineNumbers class App : Application() { override fun onCreate() { super.onCreate() // Configure Adapty Adapty.activate(this, "YOUR_API_KEY") Adapty.setOnPurchaserInfoUpdatedListener(object : OnPurchaserInfoUpdatedListener { override fun onPurchaserInfoReceived(purchaserInfo: PurchaserInfoModel) { // handle any changes to subscription state } }) // Add state change listener for Firebase Authentication FirebaseAuth.getInstance().addAuthStateListener { auth -> val currentUserId = auth.currentUser?.uid if (currentUserId != null) { // identify Adapty SDK with new Firebase user Adapty.identify(currentUserId) { error -> if (error == null) { //success } } } else { Adapty.logout { } } } } } ``` </TabItem> </Tabs> --- # File: refund-saver --- --- title: "Refund Saver" description: "Adapty Refund Saverを使用して払い戻しを最小化し、収益を最大化しましょう。" --- ユーザーが払い戻しをリクエストすると、Appleは調査を行います。**払い戻しが正当かどうか**を判断するために、Appleはそのユーザーのアクティビティに関する情報を開発者に求めます。この証拠がなければ、頻繁に利用されているサブスクリプションでも払い戻しが承認される可能性が高くなります。 **Refund Saver**はAppleの消費情報リクエストに[自動的に](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information-v1)対応し、収益を守りながら、不正なリクエストが**拒否される可能性を高めます**。自動更新サブスクリプション、買い切りサブスクリプション、消耗型アイテム、非消耗型アイテム(永続アクセス商品を含む)など、Appleのすべてのアプリ内課金タイプに対応しています。 ## Refund Saverの仕組み \{#how-refund-saver-works\} 1. ユーザーが払い戻しリクエストを開始すると、App Storeはトランザクションと利用状況の詳細を求める通知を送信します。 この通知を**無視**したり**遅延**したりすると、Appleは払い戻しを**承認**する可能性が高くなります。 2. Adapty Refund Saverはこれらの通知を自動的に処理し、Appleに必要なデータを提供します。 この自動化により、不要な払い戻しの発生を抑えながら、時間の節約と収益の保護を実現します。 3. Adaptyは各結果(払い戻し済みまたは拒否)を記録します。そのデータがダッシュボードのRefund Saver分析を支えます。 :::info Refund Saverを使用することで、払い戻しリクエストによる収益損失の最大40%を守ることができます。 ::: ## Refund Saverを使用するための要件 \{#requirements-to-use-refund-saver\} この機能を使用するには、以下の前提条件を満たしていることを確認してください。 1. **App Store Connectのプライバシーポリシーを更新する:** アプリのプライバシーポリシーに、消費データの収集と使用についての開示が必要です。これにより、ユーザーがアプリをダウンロードする前にプライバシー慣行を理解できます。詳しくは[Appleのアプリプライバシーの詳細](https://developer.apple.com/app-store/app-privacy-details/)を参照してください。 2. **アプリ内でデータ共有に関するユーザーの同意を取得する:** Appleは、ユーザーの個人データを共有する前に有効な同意を取得することを義務付けています。ユーザーデータをAppleと共有するのは開発者であるため、この同意の取得は開発者の責任です。詳細はAppleの[ガイドライン](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information)を参照してください。 3. **Server Notifications V2を有効にする:** V1通知はサポートされていないため、Apple Developerアカウントでサーバー通知V2が有効になっており、Adaptyで正しく設定されていることを確認してください。まだ有効にしていない場合は、[App Storeサーバー通知の有効化](enable-app-store-server-notifications)ガイドの手順に従ってください。 ## Refund Saverを有効にする \{#turn-on-refund-saver\} 1. Adapty ダッシュボードで[Refund Saver](https://app.adapty.io/refund-saver)セクションを開きます。 2. **Turn on Refund Saver**をクリックして機能を有効にします。 ## デフォルトの払い戻し動作を設定する \{#set-a-default-refund-behavior\} Appleは、各払い戻しリクエストへの対応時に開発者が希望する結果を指定することを許可しています。この設定の目的は、払い戻しの拒否と承認の適切なバランスを見つけて、正当な払い戻しのみが行われるようにすることです。なお、この設定はあくまで結果に影響を与えるためのものであり、最終的な判断はAppleが行います。 Adaptyはこの設定に対応していますが、すべての払い戻しリクエストに同じ値を使用します。 1. 設定を変更するには、**Edit refund preference**をクリックします。 2. **Edit refund preference**ウィンドウで、**Default refund request preference**オプションを選択します。 | オプション | 説明 | | -------------------------------------------- | ------------------------------------------------------------ | | Always decline | (デフォルト)デフォルトのオプションで、通常は払い戻しを最小化する最良の結果をもたらします。 | | Decline first refund request, grant all next | Refund Saverが処理するすべてのトランザクションに対して、最初はAppleに払い戻しを拒否するよう求めます。ただし、同じトランザクションが再度現れた場合は、常に払い戻しを承認するよう推奨します。このアプローチにより、不当な払い戻し拒否によるユーザーの不満を最小化できます。ユーザーは単に再度リクエストするだけで払い戻しを受けられる可能性があります。 | | Always refund | すべての払い戻しリクエストをAppleが承認するよう推奨します。 | | No preference | Appleに対して何も推奨しません。この場合、Appleはあなたの設定からの影響を受けず、内部ポリシーとユーザー履歴のみに基づいて払い戻し結果を決定します。最も中立的なアプローチです。 | ## ダッシュボードで特定ユーザーの払い戻し動作を設定する \{#set-refund-behavior-for-a-specific-user-in-the-dashboard\} アプリ全体のデフォルトのRefund Saver動作を設定していても、特定のユーザーに個別の設定を行いたい場合があります。Adapty ダッシュボードでは、ユーザーのプロファイルからこれを行うことができます。左下にある**Refund Saver Preferences**セクションを使用してください。 :::note ユーザーごとの設定はアプリレベルのデフォルト(「Decline first refund request, grant all next」の動作を含む)より優先されます。 ::: ## SDKで特定ユーザーの払い戻し動作を設定する \{#set-refund-behavior-for-a-specific-user-in-the-sdk\} ユーザーのアクションに応じて、インストールごとに個別に払い戻し設定をアプリコードで行うことができます。以下のスニペットを使用して設定を行ってください。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (3.4.1+)" default> ```swift showLineNumbers code do { try await Adapty.updateRefundPreference(<PREFERENCE_VALUE>) // possible values: .noPreference, .grant, .decline } catch { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter (3.4.0+)" default> ```javascript showLineNumbers code try { // possible values: AdaptyRefundPreference.noPreference, AdaptyRefundPreference.grant, AdaptyRefundPreference.decline await Adapty().updateRefundPreference(<PREFERENCE_VALUE>); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native (3.4.0+)" default> ```typescript showLineNumbers try { await adapty.updateRefundPreference(<PREFERENCE_VALUE>); // possible values: RefundPreference.NoPreference, RefundPreference.Grant, RefundPreference.Decline } catch (error) { // handle the `AdaptyError` } ``` </TabItem> <TabItem value="unity" label="Unity (3.3.0+)" default> ```csharp showLineNumbers Adapty.UpdateAppStoreRefundPreference(<PREFERENCE_VALUE>, (error) => { if (error != null) { // handle the error return; } }); ``` </TabItem> </Tabs> :::note Server-side APIを使用して[個別の払い戻し設定を行う](api-adapty/operations/setRefundSaverSettings)こともできます。 - ユーザーがボタンをクリックして設定を行うなど、設定がクライアントの操作に直接紐づいている場合はSDKを使用してください。 - サーバーサイドの処理が必要な場合や、アプリケーションのアーキテクチャに適している場合はAPIを使用してください。 ::: ## ユーザーの同意を取得する \{#obtain-user-consent\} データ共有に関するユーザーの同意をどのように収集するかはお客様次第ですが、Appleは個人データを共有する前に有効なユーザーの同意を取得することを義務付けています。Appleは**オプトインアプローチ**を推奨しており、データの使用方法を説明し、明示的なユーザーアクションを求めるアプリ内プロンプトを使用します。ユーザーがプロンプトを無視または拒否した場合、同意したとは見なされません。詳細はAppleの[ガイドライン](https://developer.apple.com/documentation/appstoreserverapi/send-consumption-information)を参照してください。 アプリで明示的な同意が実用的でない場合は、**オプトアウトアプローチ**を検討することもできます。これは、利用規約にデータ共有条項を含め、利用規約に同意することでデータ共有に同意したものとみなす方法です。ユーザーが同意を取り消す方法を明確に説明することも忘れずに。 以下は、共有する可能性のあるデータの種類を含むオプトアウトアプローチの条項例です。これはあくまで参考のためのサンプルです。最終版がすべての適用法およびAppleの要件に準拠していることを確認する責任はお客様にあります。 *「アプリ内購入の払い戻しリクエストを受け取った場合、ユーザーのアプリ内購入アクティビティに関する情報をAppleに提供することがあります。これには、アプリのインストールからの経過時間、総アプリ使用時間、匿名のアカウント識別子、アプリ内購入が完全に消費されたかどうか、トライアル期間が含まれていたかどうか、総支出額、総払い戻し額などの詳細が含まれる場合があります。」* 選択したアプローチに応じて、**Edit refund preferences**メニューの**Default consent policy**オプションを設定してください。 <p> </p> | オプション | 説明 | | ------- | ------------------------------------------------------------ | | Opt-out | (デフォルト)Adaptyがユーザーの同意状態を把握していない場合、同意が**与えられた**と見なし、Refund Saverは払い戻し関連データをAppleと**共有します**。 | | Opt-in | Adaptyがユーザーの同意状態を把握していない場合、同意が**与えられていない**と見なし、Refund Saverはデータを**共有しません**。これはAppleが推奨するアプローチです。 | ## SDKでユーザーの同意を更新する \{#update-user-consent-in-the-sdk\} 特定のユーザーが同意を与えたかどうかをAdaptyに伝えるには、`updateCollectingRefundDataConsent`メソッドを使用します。この値はプロファイルごとにサーバーサイドで保持されるため、同意が変更された場合のみ呼び出す必要があります。 <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS (3.4.1+)" default> ```swift showLineNumbers do { try await Adapty.updateCollectingRefundDataConsent(<CONSENT_VALUE>) // true = consent is explicitly provided, false = consent is explicitly revoked } catch { // handle the error } ``` </TabItem> <TabItem value="flutter" label="Flutter (3.4.0+)" default> ```dart showLineNumbers try { // true = user gave consent, false = user revoked consent await Adapty().updateCollectingRefundDataConsent(<CONSENT_VALUE>); } on AdaptyError catch (adaptyError) { // handle the error } catch (e) { // handle the error } ``` </TabItem> <TabItem value="rn" label="React Native (3.4.0+)" default> ```typescript showLineNumbers try { await adapty.updateCollectingRefundDataConsent(<CONSENT_VALUE>); // true = consent is explicitly provided, false = consent is explicitly revoked } catch (error) { // handle the `AdaptyError` } ``` </TabItem> <TabItem value="unity" label="Unity (3.3.0+)" default> ```csharp showLineNumbers Adapty.UpdateAppStoreCollectingRefundDataConsent(<CONSENT_VALUE>, (error) => { if (error != null) { // handle the error return; } }); ``` </TabItem> </Tabs> :::note Server-side APIを使用して[個別のデータ共有設定を行う](api-adapty/operations/setRefundSaverSettings)こともできます。 - ユーザーがボタンをクリックして設定を行うなど、設定がクライアントの操作に直接紐づいている場合はSDKを使用してください。 - サーバーサイドの処理が必要な場合や、アプリケーションのアーキテクチャに適している場合はAPIを使用してください。 ::: ## ユーザーの同意を確認する \{#check-user-consent\} ユーザーの現在の同意状態はいつでも確認できます。Adapty ダッシュボードでユーザーのプロファイルを開き、左下の**Refund Saver Preferences**セクションにある**Allow data sharing**設定を確認してください。 :::note Server-side APIを使用して[個別の払い戻しと共有の設定を取得する](api-adapty/operations/getRefundSaverSettings)こともできます。 ::: ## 制限事項 \{#limitations\} - **AppleのApp Storeのみ対応:** Refund SaverはAppleのApp Storeへの払い戻しリクエストにのみ対応しています。Google Playは払い戻しに対する消費データ分析を提供していません。Google Playでの払い戻し決定はGoogleのポリシーとユーザーが提供する情報のみに基づいています。 - **Server Notifications V2が必要:** Refund SaverはApp Store Server Notifications V1とは互換性がありません。現在AdaptyでV1を使用している場合はV2に切り替える必要があります。詳細は[App Storeサーバー通知をAdaptyに送信する](enable-app-store-server-notifications)ガイドを参照してください。V2に切り替えることで、より正確で包括的なデータが提供され、Adaptyの分析も向上します。 --- # File: meta-create-campaign --- --- title: "Meta Ads でアプリを宣伝する" --- このステップバイステップガイドでは、Meta でアプリの広告を作成・設定し、パフォーマンスを簡単に最適化・追跡する方法を説明します。 ## Meta における広告の構造 \{#how-ads-in-meta-are-structured\} Meta Ads で広告を出すには、3 つの階層レベルを設定する必要があります。 - **キャンペーン**: キャンペーンでは広告の目的を定義します。 - **広告セット**: 広告セットではターゲットオーディエンスとプレースメントを指定し、広告を誰にどこで表示するかを決定します。1 つのキャンペーンに複数の広告セットを含めることができます。 - **広告**: 広告はユーザーが実際に目にして操作するクリエイティブです。1 つの広告セットに複数の広告を含めることができますが、最適なパフォーマンスのために広告セットあたり 5 件以内に抑えることが推奨されます。 ## ステップ 1. Meta Ads Manager アカウントの作成 \{#step-1-create-meta-ads-manager-account\} Meta Ads を始めるには、Facebook ビジネスページが必要です。個人ページから広告を出稿することはできません。 そのため、ビジネスページを Meta Ads のビジネスポートフォリオにリンクする必要があります。 1. [business.facebook.com](https://business.facebook.com/) にアクセスします。ビジネスポートフォリオにビジネスページがまだない場合は、追加する必要があります。**Go to settings** をクリックします。 2. 左サイドバーから **Account > Pages** に移動します。**Add** をクリックし、**Add an existing Facebook page** または **Create a new Facebook page** を選択してください。まだビジネスページをお持ちでない場合は、[ビジネスページ作成ガイド](https://www.facebook.com/business/help/473994396650734)をご参照ください。 3. 必要に応じて、設定の **Account > Instagram accounts** ページからInstagramアカウントを連携できます。 ビジネスページの接続が完了したら、次のステップに進みましょう。 ## ステップ 2. Meta ピクセルを追加する \{#step-2-add-meta-pixel\} キャンペーンデータを収益と紐付けてより良い結果を得るには、Meta ピクセルが必要です。 データを接続してピクセルを作成する前に、以下が必要です。 - ビジネスページ – [**Settings > Accounts > Pages**](https://business.facebook.com/latest/settings/pages) でビジネスポートフォリオに追加してください - ビジネスマネージャーアカウント – ビジネスポートフォリオの完全な管理権限が必要です - ビジネスメール – [**Settings > Business info**](https://business.facebook.com/latest/settings/business_info) で設定してください - 広告アカウント – [**Settings > Accounts > Ad accounts**](https://business.facebook.com/latest/settings/ad_accounts) でビジネスポートフォリオに追加してください ピクセルを作成する準備ができたら、次の手順で進めてください: 1. [**Events Manager**](https://www.facebook.com/events_manager2) にアクセスし、**Connect data** をクリックします。 2. データソースの種類として **Web** を選択します。 3. データセットに名前を付け、**Create** をクリックします。 4. [Adapty アトリビューション](adapty-user-acquisition)では、ピクセルの完全なインストールを行う必要はありません。インテグレーションについて尋ねられたら、セットアップウィンドウの **x** をクリックするだけで、ページを更新するとピクセルがリストに表示されます。 5. データセットがリストに表示されたら、キャンペーンの作成に進むことができます。 ## ステップ 3. キャンペーンを作成する \{#step-3-create-campaign\} Meta Ads Managerでキャンペーンを作成するには: 1. [Meta Ads Manager](https://adsmanager.facebook.com/adsmanager/manage)を開きます。**Campaign**タブで**Create**をクリックします。 2. キャンペーンの目標として**Sales**を選択し、**Continue**をクリックします。 3. **Campaign name** セクションでキャンペーン名を入力します。 4. **Budget** セクションの **Budget strategy** で、予算の管理方法を選択します。 - **Campaign budget**: どのオポチュニティが最も効果的か判断できない場合に最も手軽な選択肢です。これを選択すると、Meta Ads がトップパフォーマーを自動的に検出し、パフォーマンスの高い広告セットにより多くの予算を配分します。 次に、**Daily**(日別)または**Lifetime**(通算)のどちらの予算が必要かを選択し、ご自身の通貨で上限を入力します。**Daily** 予算は、まだ学習中の段階でより柔軟に対応できるため、少額からスタートして随時調整することが可能です。または、**Schedule budget increase** を選択してルールを設定し、金額またはパーセンテージで予算を自動的に増やすこともできます。 - **Ad set budget**: どのオーディエンスにキャンペーン予算を多く、または少なく割り当てるかを手動で設定したい場合はこのオプションを選択します。はっきりわからない場合は、**Share some of your budget with other ad sets** を選択すると、Meta が広告パフォーマンスの向上に役立つ場合に広告セットの予算を最大20%まで自動調整できます。 5. **Campaign bid strategy** で、目標に合った最適なオプションを選択します。 - **Highest volume (default)**: 最も手軽に始められるオプションです。これを選択すると、Meta が予算内で最良の結果を得られるようクリック単価を最適化します。 - **Cost per result goal**: 自社のベンチマークがわかっている場合に、目標とする結果あたりのコストを設定します。 - **Bid cap**: 入札する最高単価を設定します。 6. Adapty では包括的な [A/B テスト](ab-tests)を実施できます。ただし、必要に応じて Meta Ads で A/B テストを有効にすることも可能です。Meta Ads Manager の A/B テストについて詳しくは[こちら](https://www.facebook.com/business/help/1159714227408868)をご覧ください。 7. いよいよキャンペーンに最初の広告セットを追加します。**Next** をクリックして進みます。 ## ステップ 4. 広告セットを作成する \{#step-4-create-ad-set\} 広告セットを作成するには: 1. **Ad set name** フィールドに広告セットの名前を入力します。 2. **Conversion location** ドロップダウンで **Website** を選択します。 3. **Performance goal** フィールドで、ランディングページがある場合は **Maximize number of landing page views** を、ユーザーをストアに直接誘導するスマートリンクを使用する場合は **Maximize number of link clicks** を選択します。 4. **Dataset** フィールドで、[ステップ 2](#step-2-add-meta-pixel) で作成したデータセットを選択します。 5. **Conversion event** を選択します。今回の場合、おそらく **Purchase** または **Start trial** になるでしょう。データセットにまだイベントがないという警告が表示されても心配しないでください。データセットが新しいだけです。 6. キャンペーン設定時に **Ad set budget** を選択した場合は、**Daily**(日別)または **Lifetime**(通算)のどちらの予算が必要かを選択し、通貨で上限金額を入力します。**Daily** 予算は学習中により柔軟に対応できるため、少額からスタートして都度調整していくことができます。 広告セットの開始日と、必要に応じて終了日を設定します。たとえば、アプリ内のプロモーションオファーを宣伝する場合は、広告セットの期間をオファーの期間に合わせることが重要です。 7. **Audience controls** セクションで、オーディエンスの設定を行います: - **Location**: 必要に応じて広く設定することも狭く設定することもできます。広告の地域特性に合わせて、広告セットの **Locations** を絞り込むことができます。 - **Minimum age**: 広告を表示するユーザーの最低年齢を選択します。広告の種類によっては、法律上の要件となる場合があります。グローバルでは18歳未満、タイでは20歳未満を最低年齢として設定することはできません。 - **Language**: **Language** は、選択した国で最も一般的な言語でない場合にのみ設定してください。たとえば、アメリカ合衆国を対象とする場合は **English** を選択する必要はありませんが、そこに住むスペイン語話者をターゲットにする場合は **Spanish** を選択するとよいでしょう。 8. デフォルトでは、Meta が広告に関連性の高い小グループを自動的に見つけます。ただし、オーディエンスの候補を追加すると、反応しそうなユーザー層へ Meta を誘導できます。**Advantage+ audience** セクションでは以下を調整できます: - **Age**:特定の年齢層に合わせてターゲットの年齢範囲を設定します。 - **Gender**:すべてのユーザーに広告を表示するか、性別でターゲティングするかを選択します。 - **Detailed targeting**:広告やアプリのオーディエンスを最も細かく制御できる設定です。**Demographics**(人口統計)、**Interests**(興味・関心)、**Behaviors**(行動)に基づいてグループを作成できます。アプリの内容に合わせて、たとえば特定の職業、特定のミュージシャンのファン、新生児の親、またはオンラインショッピングをよく利用するユーザーなどに絞り込むことが可能です。 :::note **Detailed targeting** の設定は **Or** 演算子で適用されます。**And** 演算子で条件を適用したい場合は、**Define further** をクリックして新しい条件を追加してください。 ::: 9. **Placements** セクションでは、広告の掲載場所を選択できます。デフォルトでは **Advantage+** が選択されており、Meta がパフォーマンスの見込みに基づいて複数のプレースメントに広告セットの予算を自動配分します。掲載場所が決まっていない場合はこのオプションの使用をお勧めします。特定のプレースメントを手動で指定したい場合は、**Manual placements** を選択してカスタマイズしてください。詳細は[こちら](https://www.facebook.com/business/help/965529646866485)をご覧ください。 10. **推奨**: デバイスによるターゲティングを設定すると、支出を最適化できます。**Placements** セクションで **Show more settings** をクリックします。**Devices and operating system** サブセクションで、オーディエンスに含めるデバイス、OS、OSバージョンを選択します。これにより、広告は関連するユーザーにのみ表示されます。たとえば、デスクトップユーザーには広告が表示されず、アプリがサポートしていない古いOSバージョンのユーザーは除外されます。 11. 準備ができたら、**Next** をクリックして次に進みます。 ## ステップ5. 広告を作成する \{#step-5-create-ads\} Meta Ads Managerで広告を作成するには: 1. **Ad name** フィールドに広告名を入力します。 2. **Identity** セクションで、広告の投稿に使用するFacebookページを選択します。アプリ専用のInstagramアカウントをお持ちで、[ステップ1](#step-1-create-meta-ads-manager-account)でMeta Business Suiteに接続済みの場合は、**Instagram account** ドロップダウンからそのアカウントを選択してください。そうでない場合は **Use Facebook page** を選択すると、FacebookページでInstagramの広告が投稿されます。 3. **Ad setup** で、広告の投稿方法を選択します。アプリの宣伝には **Create ad** を選択することをおすすめします。これにより、ユーザーをFacebookページではなくアプリへ誘導できます。**Format** フィールドでは、用意しているクリエイティブの数と表示方法に応じてオプションを選択してください。 4. **Destination** セクションで、**Main destination** として **Website** が選択されていることを確認します。**Website URL** フィールドに `https://api-ua.adapty.io/api/v1/attribution/click` を貼り付けます。[Adapty Attribution](adapty-user-acquisition) で[ウェブキャンペーンを作成](ua-facebook)し、**Click link** の内容を `https://api-ua.adapty.io/api/v1/attribution/click` の後ろに付け加えた上で、**Tracking** セクションの **URL parameters** フィールドに貼り付けます。 5. **Ad creative** セクションで **Set up creative** をクリックし、**Image ad** または **Video ad** を選択します。新しいウィンドウが開き、メディアファイルのアップロード、トリミング、テキストの追加を行えます。 6. 広告テキストを自動翻訳したい場合は、**Languages** セクションで **Add languages** をクリックします。次に主言語を追加すると、クリエイティブからテキストが自動的に取り込まれます。続けて自動翻訳したい言語を追加してください。 7. 準備ができたら **Publish** をクリックして広告を配信します。 ## 次のステップ \{#whats-next\} 広告を有効にするには、まだ支払い方法を追加していない場合は追加する必要があります。 その後、[Adapty User Acquisition ダッシュボードでキャンペーンがアプリ収益に与える影響を確認](adapty-user-acquisition)できます。 Adapty User Acquisition をまだご利用でないですか?[こちらからお問い合わせ](https://calendly.com/tnurutdinov-adapty/30min)いただくと、広告キャンペーンの追跡と最適化にどのように役立つかをご説明します。 --- # File: tiktok-create-campaign --- --- title: "TikTok for Businessでアプリを宣伝する" --- このステップバイステップガイドでは、TikTok for Businessでアプリの広告を作成・設定する方法を説明します。広告のパフォーマンスを簡単に最適化・追跡できるようになります。 ## ステップ1. ビジネス情報を追加する \{#step-1-add-business-info\} TikTok for Businessを初めて利用する場合は、まずビジネス情報を追加する必要があります: 1. [https://ads.tiktok.com](https://ads.tiktok.com/business/) にアクセスし、**Get started** をクリックします。 2. メールアドレスまたはTikTokアカウントでサインアップします。 3. ビジネス情報を入力し、画面の指示に従います。 ビジネスアカウントが承認されると、最初のキャンペーン作成画面にリダイレクトされます。 ## ステップ 2. ピクセルを作成する \{#step-2-create-a-pixel\} キャンペーンデータを収益と紐付けてより良い結果を得るには、TikTok ピクセルが必要です: 1. [**Events Manager**](https://ads.tiktok.com/i18n/events_manager/home) にアクセスし、**Connect data source** をクリックします。 2. データソースのタイプとして **Web** を選択します。 3. **Add your website** ウィンドウで **Skip** をクリックします。 4. **Manual setup** を選択し、**Next** をクリックします。 5. **TikTok pixel + Events API** を選択し、**Next** をクリックします。 6. ピクセルに名前を付け、**Create** をクリックします。 7. [Adapty アトリビューション](adapty-user-acquisition) では、ピクセルの完全なインストールを完了する必要はありません。そのためセットアップウィンドウを閉じるだけで、ピクセルがリストに表示されます。 8. このピクセルをキャンペーンで使用できるようにするには、[Adapty アトリビューション](adapty-user-acquisition) からテストイベントを送信する必要があります: 1. [新しい TikTok キャンペーンを作成](ua-tiktok)します。 2. プラットフォーム別のセクション(例:iOS)を展開します。 3. ドロップダウンからピクセルを選択します。 4. **Send test event** をクリックします。 5. ドロップダウンで、広告の最適化に使用するイベントを選択します。 6. TikTok for Business でピクセルを開き、**Test events** タブに切り替えます。`test_event_code` をコピーします。 7. Adapty の **Test event code** フィールドに貼り付け、**Send** をクリックします。 9. テストイベントは数分後に TikTok に表示されます。ピクセルの詳細に表示されたら、TikTok Ads Manager でキャンペーンの設定を続行できます。 ## ステップ3. キャンペーンの目標を選択する \{#step-3-select-the-campaign-objective\} :::important このチュートリアルでは、TikTok Ads ManagerのQuick setupビューを使用しています。いくつかの推奨設定はFull viewにのみ表示されます。該当するステップでその旨を記載しています。 ::: Ads Managerの[広告作成ページ](https://ads.tiktok.com/i18n/nb_creation/create/objectives)にアクセスします。 最初の画面で広告の目標を選択し、**Continue** をクリックします。 **Sales > Website conversion** を選択します。 ## ステップ 4. キャンペーン情報を入力する \{#step-4-fill-in-the-campaign-info\} 次に、キャンペーン情報を入力します。 1. **Campaign name** フィールドにキャンペーン名を入力します。 2. **Optimization goal** フィールドで **Conversion** を選択します。 3. ドロップダウンからアクティブなピクセルを選択し、**Optimization event** を選択します。選択できるのはアクティブなイベントのみです。必要なイベントが表示されない場合は、[ステップ 2](#step-2-create-a-pixel) の手順に従ってテストイベントを送信してください。 4. 広告は TikTok のフィードと検索に表示されます。追加設定を行うには **Advanced settings** をクリックします。**Placements** でプレースメントの設定を行います: - **User comment**: コメント欄にも広告を表示する場合は選択します。ユーザーコメントをオンにすると広告のインプレッション数が増えやすくなるため、TikTok ではオンのままにすることを推奨しています。 - **Allow video download**: 視聴者が広告動画をダウンロードできるようにします。 - **Allow video sharing**: 視聴者が広告動画をシェアできるようにします。 5. **Continue** をクリックします。 ## ステップ 5. 広告コンテンツを追加する \{#step-5-add-ad-content\} 次は、クリエイティブとリンク先 URL を設定します。 1. **TikTok account** フィールドで、投稿に使用するアカウントを選択します。 2. [Adapty アトリビューション](adapty-user-acquisition) で [ウェブキャンペーンを作成](ua-tiktok) し、**Click link** を **Destination URL** フィールドに貼り付けます。 3. **Creatives** セクションで **+ Videos and images** をクリックします。 4. TikTok の投稿をクリエイティブとして使用したい場合は、**TikTok post** タブで選択します。それ以外の場合は **Creative library** タブに切り替えて **Upload** をクリックします。アップロードしたファイルはこのタブから後で利用でき、他のキャンペーンでも再利用できます。 5. クリエイティブを TikTok フォーマットに合わせてトリミングし、シングル広告として使用するか、1 つのカルーセルとして使用するかを選択します。 6. アップロードしたクリエイティブを展開し、**No music selected** の横にある **+** をクリックします。ここに mp3 ファイルをアップロードできます。音楽の追加は必須です。 7. **Add text** フィールドに、説明として使用するテキストを入力します。 8. この広告を TikTok アカウントに投稿として公開したい場合は、**Place the ads on this TikTok account as a post** を選択します。 9. **Call to action** フィールドで、広告に関連する行動喚起を選択または削除します。選択した内容は TikTok によって広告に自動的に追加されます。 10. **Continue** をクリックします。 ## ステップ 6. ターゲティングと予算を設定する \{#step-6-configure-targeting-and-budget\} 最後に、広告を表示する対象ユーザーと予算を設定します。 1. **Targeting** セクションで、**Automatic** または **Custom** を選択します。オーディエンスをまだ把握していない場合は、**Automatic** が最も簡単です。ただし、**Custom** を選択すると、広告に反応しやすいユーザーグループを絞り込んで費用を最適化できます。 2. **Custom** を選択した場合は、以下を設定します: - **Location**:デフォルトの場所は広告アカウントの所在地です。ターゲットとする国や地域を複数選択した場合、広告審査の結果はロケーションごとに個別に返されます。実際の広告配信は、プレースメントがサポートする地域によっても異なる場合があります。 - **Languages**:デフォルトではすべての言語が選択されています。選択した地域で最もよく使われる言語に基づいて、ターゲット言語を選択してください。 - **Gender**:デフォルトではすべての性別が選択されています。 :::tip フルモードに切り替えると、**Targeting** の下に **Device** セクションが追加で表示されます。ここでデバイスの種類・OS・OSバージョンでオーディエンスを絞り込めます。アプリに最小バージョンの要件がある場合に便利です。 ::: 3. **Budget** セクションで、表示されているいずれかのオプションを選択するか、**Custom** を選択します。 4. **Custom** を選択した場合は、**Daily**(日次)または **Lifetime**(通算)予算を選び、通貨で上限金額を入力します。学習中は **Daily** 予算の方が柔軟性が高く、少額から始めて随時調整しやすいのでおすすめです。 5. **Schedule** セクションで、**Continue for at least 7 days** または **Custom** を選択します。広告に掲載期限がある場合は、**Custom** スケジュールを設定することをおすすめします。終了タイミングを逃さずに済みます。 6. **Custom** を選択した場合は、広告の開始日時または開始・終了日時を設定します。アカウントのタイムゾーンが使用されることにご注意ください。 7. **Publish** をクリックします。 完了すると、1つの広告グループを含む新しいキャンペーンが作成されます。カルーセルを設定した場合は1つの広告が、クリエイティブを個別の広告として追加した場合は複数の広告が広告グループに含まれます。 ## ステップ7. 支払い情報を入力する \{#step-7-enter-payment-details\} 広告を掲載し始めるには、ターゲティングと広告予算を設定した後に支払い情報を入力します。これで準備完了です! ## 次のステップ \{#whats-next\} [Adapty User Acquisitionダッシュボードでキャンペーンがアプリの収益に与える影響を確認](adapty-user-acquisition)できます。 Adapty User Acquisitionをまだ使っていませんか?[こちらからお問い合わせ](https://calendly.com/tnurutdinov-adapty/30min)いただければ、広告キャンペーンの追跡と最適化にどのように役立つかご説明します。 --- # File: getting-started-with-server-side-api --- --- title: "サーバーサイド API" description: "サブスクリプション管理のための Adapty サーバーサイド API を使ってみましょう。" --- :::tip AI コーディングエージェントを使っていますか?[バックエンドからサブスクリプションアクセスを確認・付与する](server-side-api-with-ai)に、一つのページにまとめたエンドツーエンドのレシピがあります。 ::: この API を使うと、以下のことができます: 1. ユーザーのサブスクリプション状態を確認する。 2. アクセスレベルでユーザーのサブスクリプションを有効化する。 3. ユーザー属性を取得する。 4. ユーザー属性を設定する。 5. ペイウォール設定を取得・更新する。 <img src="/assets/shared/img/server.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> <p> </p> :::note サブスクリプションイベントを追跡するには、Adapty の [Webhook](webhook) 連携を利用するか、既存のサービスと直接連携してください。 ::: ## ウェブとモバイル間でサブスクライバーを同期する場合 \{#case-1-sync-subscribers-between-web-and-mobile\} StripeやChargeBeeなどのWeb決済プロバイダーを使用している場合、サブスクリプションユーザーを簡単に同期できます。手順は以下のとおりです: 1. <InlineTooltip tooltip="各ユーザーに一意のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip> 2. APIを使用して[サブスクリプションのステータスを確認する](api-adapty/operations/getProfile)。 3. ユーザーがフリーミアムプランの場合、Webサイトにペイウォールを表示する。 4. 決済が完了したら、APIを通じてAdaptyの[サブスクリプションステータスを更新する](api-adapty/operations/setTransaction)。 5. サブスクリプションユーザーはモバイルアプリと自動的に同期されます。 ## Case 2: サブスクリプションを付与する \{#case-2-grant-a-subscription\} :::note セキュリティ上の理由から、SDK を使ってサブスクリプションを付与することはできません。 ::: Google Play や App Store 以外のプラットフォーム(独自のオンラインストア、Amazon Appstore、Microsoft Store など)で販売している場合は、アクセス権の付与とアナリティクスでのトランザクション追跡を行うために、それらのトランザクションを Adapty と同期する必要があります。 1. <InlineTooltip tooltip="各ユーザーに固有のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip> 2. [Adapty ダッシュボードでプロダクトのカスタムストアを設定する](custom-store)。 3. [Set transaction](api-adapty/operations/setTransaction) API リクエストを使用して、トランザクションを Adapty に同期する。 ## ケース3: アクセスレベルを付与する \{#case-3-grant-an-access-level\} 7日間の無料トライアルプロモーションを実施していて、プラットフォーム間で一貫したエクスペリエンスを提供したいとします。モバイルアプリと同期するには: 1. <InlineTooltip tooltip="各ユーザーに一意のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip>。 2. APIを使用して、7日間の[プレミアムアクセスを付与](api-adapty/operations/grantAccessLevel)します。 7日間が経過しても購読しないユーザーは、無料プランにダウングレードされます。 ## ケース4: ユーザーのプロパティとカスタム属性を同期する \{#case-4-sync-users-properties-and-custom-attributes\} 言語学習アプリで学習した単語数など、ユーザー独自のカスタム属性がある場合も同期できます。 1. <InlineTooltip tooltip="各ユーザーに一意のIDを割り当てる">[iOS](identifying-users)、[Android](android-identifying-users)、[React Native](react-native-identifying-users)、[Flutter](flutter-identifying-users)、[Unity](unity-identifying-users)</InlineTooltip>。 2. APIまたはSDKで[属性を更新](api-adapty/operations/updateProfile)する。 これらのカスタム属性を使用して、セグメントを作成したり A/B テストを実行したりできます。 ## ケース5: ペイウォール設定を管理する \{#case-5-manage-paywall-configurations\} アプリを再デプロイすることなく、ペイウォールの外観や動作を動的に変更するために、[ペイウォールのリモートコンフィグを更新](api-adapty/operations/updatePaywall)できます。 --- **次のステップ:** - [サーバーサイド API の認証](ss-authorization)に進む - リクエスト: - [プロファイルを取得する](api-adapty/operations/getProfile) - [プロファイルを作成する](api-adapty/operations/createProfile) - [プロファイルを更新する](api-adapty/operations/updateProfile) - [プロファイルを削除する](api-adapty/operations/deleteProfile) - [アクセスレベルを付与する](api-adapty/operations/grantAccessLevel) - [アクセスレベルを取り消す](api-adapty/operations/revokeAccessLevel) - [トランザクションを設定する](api-adapty/operations/setTransaction) - [購入を検証し、顧客にアクセスレベルを付与し、トランザクション履歴をインポートする](api-adapty/operations/validateStripePurchase) - [インテグレーション識別子を追加する](api-adapty/operations/setIntegrationIdentifiers) - [ペイウォールを取得する](api-adapty/operations/getPaywall) - [ペイウォール一覧を取得する](api-adapty/operations/listPaywalls) - [ペイウォールを更新する](api-adapty/operations/updatePaywall) --- # File: onboardings --- --- title: "オンボーディング" --- :::warning ノーコードのオンボーディングビルダーは完全に機能していますが、Adapty はこれ以上の機能追加やアップデートの提供を行わない予定です。新規プロジェクトには、[Adapty Flow Builder](adapty-flow-builder) の使用をご検討ください。これは、シングルスクリーンのペイウォールやマルチスクリーンのオンボーディングフローをデバイス上でネイティブレンダリングするビジュアルなノーコードエディタです。 - **あらゆるフロータイプに対応**: シングルスクリーンのペイウォール、ペイウォールを含むマルチステップのオンボーディング、さらにその中間にあたるものまで構築できます。 - **ネイティブレンダリング**: フローは Adapty SDK を通じてレンダリングされ、ウェブビューを使用しません。 - **再デプロイ不要で更新可能**: コピー、デザイン、ロジックをいつでも変更でき、アプリのリリースなしにユーザーへ更新が届きます。 ::: Adapty のオンボーディング機能を使えば、技術的な知識がないチームでもコードなしでオンボーディングフローを構築できます。ノーコードビルダーでは、ユーザーにアプリを紹介する一連のスクリーンを作成できます。インタラクティブな質問や変数を使ってスクリーンをパーソナライズし、A/B テストを実施してパフォーマンスの高いフローを見つけることも可能です。 オンボーディングは、Adapty SDK v3.8.0 以上(iOS、Android、React Native、Flutter)、v3.14.0 以上(Unity)、または v3.15.0 以上(Kotlin Multiplatform、Capacitor)を使用するアプリで利用できます。 ## 使い方 \{#how-it-works\} 1. [ノーコードエディタでオンボーディングをデザインする。](design-onboarding) 2. [オンボーディング用のプレースメントを作成する。](create-onboarding#step-2-create-a-placement-for-your-onboarding) 3. Adapty SDK を使ってオンボーディングをプロジェクトに組み込む: - [iOS](ios-onboardings) - [Android](android-onboardings) - [React Native](react-native-onboardings) - [Flutter](flutter-onboardings) - [Unity](unity-onboardings) - [Kotlin Multiplatform](kmp-onboardings) - [Capacitor](capacitor-onboardings) 4. オンボーディングをテストし、ユーザーへ公開する。 --- # File: create-onboarding --- --- title: "オンボーディングを作成する" --- [オンボーディング](onboardings)は、モバイルアプリの価値・機能・使い方を新規ユーザーに紹介するものです。 ## ステップ 1. オンボーディングを作成する \{#step-1-create-an-onboarding\} Adapty ダッシュボードで新しいオンボーディングを作成するには: 1. Adapty のメインメニューから **Onboardings** に移動します。このページでは、設定済みのすべてのオンボーディングとその指標の概要を確認できます。**Create onboarding** をクリックします。 <img src="/assets/shared/img/create-onboarding1.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. オンボーディングのわかりやすい名前を入力し、**Proceed to build onboarding** をクリックします。 <img src="/assets/shared/img/create-onboarding2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. オンボーディングビルダーにリダイレクトされます。 デフォルトのデモテンプレートが用意されており、オンボーディングがどのようにデータを収集するか、変数やクイズを使ってどのようにパーソナライズできるかを確認できます。不要な画面は自由に削除し、[独自のオンボーディング体験をデザイン](design-onboarding)してください。 <img src="/assets/shared/img/create-onboarding3.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 準備ができたら、右上の **Preview** ボタンをクリックします。すべてが期待どおりに動作することを確認するために、実際にオンボーディングフローを最後まで体験してください。 <img src="/assets/shared/img/create-onboarding4.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 問題がなければ、右上の **Publish** をクリックします。Adapty に戻る前に、公開が完了するまで待ってください。そうしないと、作業内容が失われます。 :::danger **Publish** をクリックしないと、SDK は作成したオンボーディングを取得できません。 ::: <img src="/assets/shared/img/create-onboarding5.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> オンボーディングが公開されたら、**Back to Adapty** をクリックします。オンボーディングが作成されました。プレースメントに追加して使い始めることができます。 ## ステップ 2. オンボーディング用のプレースメントを作成する \{#step-2-create-a-placement-for-your-onboarding\} 1. メインメニューから **Placements** に移動し、**Onboardings** タブに切り替えます。**Create placement** をクリックします。 <img src="/assets/shared/img/create-onboarding6.png" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. プレースメントの名前と ID を入力します。次に、**Run onboarding** をクリックし、すべてのユーザーに表示するオンボーディングを選択します。 3. 特定のユーザーグループ向けに別のオンボーディングを用意している場合は、[オーディエンスを追加](audience)して、そのグループに別のオンボーディングを選択してください。 ## ステップ 3. オンボーディングをアプリに組み込む \{#step-3-integrate-the-onboarding-into-your-app\} :::important オンボーディングは、Adapty SDK v3.8.0 以降(iOS、Android、React Native、Flutter)、v3.14.0 以降(Unity)、または v3.15.0 以降(Kotlin Multiplatform、Capacitor)を使用するアプリで利用できます。 ::: アプリでオンボーディングの表示を開始するには、Adapty SDK を使用して組み込んでください: - [iOS](ios-onboardings) - [Android](android-onboardings) - [React Native](react-native-onboardings) - [Flutter](flutter-onboardings) - [Unity](unity-onboardings) - [Kotlin Multiplatform](kmp-onboardings) - [Capacitor](capacitor-onboardings) どのオンボーディングがより効果的かを把握するために、[A/B テスト](ab-tests)を実施することもできます。 --- # File: design-onboarding --- --- title: "オンボーディングをデザインする" description: "効果的なオンボーディングを作成しましょう。" --- ノーコードのモバイルアプリ向けオンボーディングビルダーは、ユーザーに最高のオンボーディング体験を提供するための強力でカスタマイズ性の高いツールです。開発者やデザイナーでなくても、優れた結果を得ることができます。 ## オンボーディングの画面 \{#onboarding-screens\} オンボーディングのフローは、追加してデザインする複数の画面で構成されます。 ユーザーはボタンをタップして画面間を移動します。 :::tip 一部のユーザーに少し異なるフローが必要な場合(たとえば、フィットネスアプリでユーザーの性別に応じて異なる「目標」画像を表示したい場合)、別のオンボーディングを作成する必要はありません。 代わりに、一部の画面をデフォルトで非表示にし、特定の条件のときだけ表示されるよう設定できます。 ::: ## オンボーディングの要素 \{#onboarding-elements\} オンボーディングの要素は、左側に表示順で表示されます。右上の **Add** をクリックして新しい要素を追加します。 追加できる要素のグループは以下のとおりです: - **Containers**:コンテナを使うと、柔軟なレイアウトを設定できます。たとえば、2カラムのテキストを追加したい場合は、**Columns** を追加してから、左ペインの **Columns** に2つのテキストブロックをドラッグします。カルーセルを追加する場合は、内部の **Media** 要素に画像を追加する必要があります。 - **Typography**:事前にフォーマットされたテキストブロックを追加し、見た目を自由に設定できます。 - **Media & Display**:画像や動画のほか、アプリの価値をアピールしてユーザーの意欲を高めるアニメーションチャートも追加できます。 **対応している動画フォーマット**はMP4とWebMです。**メディアファイルの最大サイズ**は15MBです。 Lottieのような非対応のアニメーション要素を追加したい場合は、動画に変換して(例:[このツール](https://www.lottielab.com/lottie/lottie-to-video)を使用)、動画として埋め込むことができます。 - **Quiz**:テキストや画像の選択肢を使った短いアンケートを作成し、オンボーディング体験をカスタマイズしながらユーザーのことをより深く知ることができます。 - **Inputs**:ユーザーのデータを収集します。 - **Buttons**:ボタンを使うと、画面間の移動、オンボーディングの終了、ペイウォールへの移動をユーザーが行えます。光沢のあるボタンや動くボタンを追加して、ユーザーの注意を引き、インストールを購入につなげることもできます。 - **Loaders**:アニメーションローダーで、処理中もユーザーを飽きさせません。 - **User engagement**:テスティモニアル、ユーザーメールリスト、カウントダウンを追加できます。 :::note **Media & Display** グループの一部として、提供されているカスタマイズオプションでは不十分な場合にカスタムHTMLコードも追加できます。 ただし、カスタムHTML要素はプリロードもキャッシュもされないため、**Raw HTML** は小さく軽量な要素にのみ使用することを推奨します。 ::: <img src="/assets/shared/img/design-onboarding4.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### 要素IDとアクションID \{#element-id-and-action-id\} ボタンをカスタムアクションに使用したい場合は、**アクションID** を割り当て、ソースコード内で使用します。アクションIDを使うと、同じアクションIDを持つ複数のボタンを同じ方法で処理できます。 <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 特定のフィールドでユーザーの入力を処理したい場合(例:年齢やメールアドレスを保存する)は、**要素ID** を割り当て、ソースコード内で質問と回答を紐付けるために使用します。要素IDはオンボーディング内で1回だけ使用できます。 <img src="/assets/shared/img/design-onboarding5.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## カスタマイズオプション \{#customization-options\} ビルダーでは以下のカスタマイズオプションを利用できます: - **Styles** タブ:要素の見た目を調整します。 <img src="/assets/shared/img/design-onboarding1.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **Element** タブ:表示/非表示、ボタン押下時のアクションなど、要素の見た目以外の属性を設定します。 <img src="/assets/shared/img/design-onboarding2.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> - **Screen** タブ:ヘッダーや画面カウンターの表示など、画面全体の設定を行います。 <img src="/assets/shared/img/design-onboarding3.png" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## 画面と要素のコピー \{#copy-screens-and-elements\} オンボーディングを作成済みで、その一部を再利用したい場合や、少し変更を加えてA/Bテストを行いたい場合は、1つまたは複数の画面を別のオンボーディングにコピーできます。 画面をコピーするには、オンボーディングビルダーを開き、次のいずれかを行います: - 単一の画面を右クリックして **Copy** を選択する - 目的の画面を選択して `Ctrl+C`(Windows)または `⌘+C`(Mac)を押す 個々の要素やテキストブロックも、同じオンボーディング内でも別のオンボーディング間でもコピーできます。 ## ウェブ to アプリファネルからの画面のコピー \{#copy-screens-from-web-to-app-funnels\} [FunnelFox](https://funnelfox.com/) で作成したウェブ to アプリファネルを使用していて、ファネルの画面をオンボーディングで使いたい場合は、ファネルビルダーで画面をコピーしてオンボーディングビルダーに貼り付けることで素早く実現できます: 1. FunnelFoxのファネルビルダーで画面を右クリックして **Copy** を選択するか、画面を選択して `Ctrl+C`/`⌘+C` を押します。 2. オンボーディングビルダーを開きます。 3. コピーした画面を挿入したい画面を右クリックして **Paste** を選択するか、その画面を選択して `Ctrl+V`/`⌘+V` を押します。コピーされた画面は選択した画面の下に挿入されます。 <img src="/assets/shared/img/funnel-to-onboarding.gif" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> --- # File: adapty-paywall-builder --- --- title: "Adapty Paywall Builder (Legacy)" description: "ビジュアルなノーコードビルダーでペイウォールとオンボーディングフローを作成します。" --- :::warning ペイウォールビルダーは引き続き完全に動作しますが、Adapty は今後このビルダーへの機能追加やアップデートの提供を終了しています。新規プロジェクトには、[Adapty フロービルダー](adapty-flow-builder) の利用をご検討ください。これは、デバイス上でネイティブにレンダリングされる単一画面のペイウォールおよびマルチ画面オンボーディングフロー向けのビジュアルノーコードエディターです。 - **あらゆるフロータイプに対応**: 単一画面のペイウォール、ペイウォールを含むマルチステップのオンボーディング、そしてその中間にあたるあらゆる構成を構築できます。 - **ネイティブレンダリング**: フローは Adapty SDK を通じてレンダリングされ、Web ビューは使用しません。 - **再デプロイ不要で更新可能**: コピー、デザイン、ロジックをいつでも変更でき、アプリのリリースなしにユーザーへ更新が反映されます。 ::: Adapty の**ペイウォールビルダー**は、カスタムペイウォールをデザインするためのビジュアルノーコードツールです。テンプレートから始めてレイアウトをカスタマイズし、カルーセル、カード、プロダクトリスト、フッターなどの要素を追加できます。カスタムフォント、プロダクトタグ、ローカライズにも対応しています。 ペイウォールビルダーを使用するには Adapty SDK v3.0 以降が必要です。ペイウォールを作成したら、[プレースメントに追加](add-audience-paywall-ab-test)してアプリ内で表示しましょう。 - [iOS](ios-quickstart-paywalls) - [Android](android-quickstart-paywalls) - [React Native](react-native-quickstart-paywalls) - [Flutter](flutter-quickstart-paywalls) - [Unity](unity-quickstart-paywalls) - [Capacitor](capacitor-quickstart-paywalls) - [Kotlin Multiplatform](kmp-quickstart-paywalls) --- # File: flutterflow --- --- title: "Adapty Plugin for FlutterFlow" description: "サブスクリプション管理を強化するために FlutterFlow と Adapty を連携する方法を紹介します。" --- Adapty はモバイルアプリの成長を支援するために設計された多機能プラットフォームです。立ち上げたばかりのアプリでも、すでに数千人のユーザーを抱えているアプリでも、Adapty を使えばアプリ内課金の組み込みにかかる時間を大幅に短縮し、ペイウォール管理でサブスクリプション収益を倍増させることができます。 FlutterFlow 向け Adapty プラグインを使えば、コードを一切書かずに Adapty のすべての機能を活用できます。FlutterFlow でペイウォールページをデザインし、購入機能を有効化した上で、表示するプロダクトをリモートで管理できます。特定のユーザーグループへのターゲティングや A/B テストも利用可能です。アプリをリリースした後は、ダッシュボード上でユーザーの購入に関する詳細な分析データに即座にアクセスできます。 ペイウォールに表示するプロダクトを変更したいときも簡単です! Adapty ダッシュボード内で数クリックするだけで変更が反映され、ユーザーはすぐに新しいプロダクトを確認できます。新バージョンのアプリをリリースする必要はありません! Adapty が提供するその他の機能: - **サブスクリプションとアプリ内課金**: Adapty がサーバーサイドのレシート検証を代わりに行い、ウェブを含むすべてのプラットフォーム間でユーザー情報を同期します。 - **ペイウォールの A/B テスト**: 価格、期間、トライアル期間、ビジュアル要素をテストして、サブスクリプションや買い切り購入を最適化します。 - **強力な分析機能**: 詳細な指標にアクセスして、アプリのマネタイズをより深く理解し改善できます。 - **インテグレーション**: Adapty は Amplitude、AppsFlyer、Adjust、Branch、Mixpanel、Facebook Ads、AppMetrica、カスタム Webhook など、サードパーティの分析ツールとシームレスに連携します。 --- # File: ff-getting-started --- --- title: "はじめに" description: "Adapty フィーチャーフラグを使って、サブスクリプションフローをパーソナライズしましょう。" --- Adapty を使うと、モバイルアプリのユーザーの旅のさまざまな時点(オンボーディング、設定画面など)でペイウォールや A/B テストを作成・実行できます。これらの時点を[プレースメント](placements)と呼びます。アプリ内のプレースメントは、複数のペイウォールや [A/B テスト](ab-tests)を同時に管理でき、それぞれ特定のユーザーグループ([オーディエンス](audience)と呼びます)向けに作成されます。さらに、新しいアプリバージョンをリリースせずに、ペイウォールを別のものと入れ替えながら実験することも可能です。モバイルアプリにハードコードするのはプレースメント ID だけです。 <img src="/assets/shared/img/audience.jpg" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty ライブラリは、Adapty ダッシュボードから最新のプロダクトを取得し、ペイウォールを常に最新の状態に保ちます。[プロダクトデータを取得](ff-action-flow)して[ペイウォールに表示](ff-add-variables-to-paywalls)し、[購入を処理](ff-make-purchase)し、[ユーザーのアクセスレベルを確認](ff-check-subscription-status)して有料コンテンツを表示すべきかどうかを判断します。 始めるには、以下の手順に従って FlutterFlow プロジェクトに [Adapty ライブラリを追加](ff-getting-started#add-the-adapty-library-as-a-dependency)し、[初期化](ff-getting-started#initiate-adapty-plugin)してください。 :::warning 始める前に、以下の制限事項を確認してください: - FlutterFlow 用 Adapty ライブラリは Web アプリをサポートしていません。Web アプリへのコンパイルは避けてください。 - FlutterFlow 用 Adapty ライブラリは、Adapty のペイウォールビルダーで作成されたペイウォールをサポートしていません。Adapty で購入を有効にする前に、FlutterFlow で独自のペイウォールをデザインする必要があります。 ::: ## Adapty ライブラリを依存関係として追加する \{#add-the-adapty-library-as-a-dependency\} 1. [FlutterFlow ダッシュボード](https://app.flutterflow.io/dashboard)でプロジェクトを開き、左メニューから **Settings and Integrations** をクリックします。左側の **Project setup** セクションで **Project dependencies** を選択します。 <img src="/assets/shared/img/main_settings.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **FlutterFlow Libraries** セクションで **Add Library** をクリックし、`adapty-xtuel0` と入力します。**Add** をクリックします。 3. 次に、SDK キーをライブラリに関連付けます。ライブラリの横にある **View details** をクリックします。 <img src="/assets/shared/img/ff_view_details.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. Adapty ダッシュボードの [**App Settings** -> **General** タブ](https://app.adapty.io/settings/general)から **Public SDK key** をコピーします。 <img src="/assets/shared/FF_img/adaptyapikey.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. FlutterFlow の **AdaptyApiKey** にキーを貼り付けます。 <img src="/assets/shared/img/ff_apikey.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty FF ライブラリがプロジェクトの依存関係として追加されます。**Adapty** FF ライブラリウィンドウには、プロジェクトにインポートされたすべての Adapty リソースが表示されます。 ## アプリ起動時に新しいアクティベーションアクションを呼び出す \{#call-the-new-activation-action-at-application-launch\} 1. 左メニューから **Custom Code** セクションに移動し、`main.dart` を開きます。 <img src="/assets/shared/img/ff_dartmain.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **+** をクリックして `activate (Adapty)` を選択します。 <img src="/assets/shared/img/ff_activate.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Save** をクリックします。 ## Adapty プラグインを初期化する \{#initiate-adapty-plugin\} Adapty ダッシュボードにアプリを認識させるには、FlutterFlow で特別なキーを設定する必要があります。 1. FlutterFlow プロジェクトで、左メニューから **Settings and Integrations > Permissions** に移動します。 2. 開いた **Permissions** ウィンドウで、**Add Permission** ボタンをクリックします。 3. **iOS Permission Key** と **Android Permission Key** の両方のフィールドに `AdaptyPublicSdkKey` を貼り付けます。 4. **Permission Message** には、Adapty ダッシュボードの [**App Settings** -> **General** タブ](https://app.adapty.io/settings/general)から **Public SDK key** をコピーして貼り付けます。各アプリには固有の SDK キーがあるため、複数のアプリがある場合は正しいキーを使用してください。 <img src="/assets/shared/img/ff_permissions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これらの手順が完了すると、FlutterFlow アプリでペイウォールを呼び出し、そこから購入を有効にできるようになります。 ## 次のステップ \{#whats-next\} 1. FlutterFlow で Adapty ペイウォールのプロダクトとそのデータを処理するための[アクションフローを作成](ff-action-flow)します。 2. 受け取ったデータを FlutterFlow でデザインした[ペイウォールにマッピング](ff-add-variables-to-paywalls)します。 3. ペイウォールの[購入ボタンを設定](ff-make-purchase)して、クリック時に Adapty 経由でトランザクションを処理できるようにします。 4. 最後に、[サブスクリプションステータスの確認を追加](ff-check-subscription-status)して、ユーザーに有料コンテンツを表示するかどうかを判断します。 --- # File: ff-action-flow --- --- title: "ステップ1. ペイウォールデータを表示するフローを作成する" description: "Adaptyでフィーチャーフラグのアクションフローを設定し、ユーザーのサブスクリプション体験をパーソナライズする方法を解説します。" --- :::important FlutterFlowプラグインを使用する場合、Adaptyのペイウォールビルダーで作成したペイウォールは使用できません。FlutterFlowで独自のペイウォールページを実装し、Adaptyと連携させる必要があります。 ::: AdaptyライブラリをFlutterFlowプロジェクトの依存関係として追加したら、次は**AdaptyのペイウォールとプロダクトデータをFlutterFlowで設計したペイウォールに取得して表示する**フローを構築します。 まずAdaptyからペイウォールデータを受け取る必要があります。最初にAdaptyのペイウォールをリクエストし、次にそれに関連するプロダクトをリクエストし、最後にデータが正常に受信されたかどうかを確認します。成功した場合はペイウォールページにプロダクトのタイトルと価格を表示し、失敗した場合はエラーメッセージを表示します。 先に進む前に、以下の作業が完了していることを確認してください。 1. Adapty ダッシュボードで[ペイウォールを少なくとも1つ作成し、プロダクトを少なくとも1つ追加している](create-paywall)こと。 2. Adapty ダッシュボードで[プレースメントを少なくとも1つ作成](create-placement)し、[そのペイウォールを追加している](add-audience-paywall-ab-test)こと。 それでは始めましょう! ## ステップ1.1. Adaptyペイウォールをリクエストする \{#step-11-request-adapty-paywall\} 前述の通り、FlutterFlowのペイウォールにデータを表示するには、まずAdaptyからデータを取得する必要があります。最初のステップはAdaptyのペイウォール自体を取得することです。手順は以下の通りです。 1. ペイウォール画面を開き、右ペインの **Actions** セクションに切り替えます。そこから **Action Flow Editor** を開きます。 <img src="/assets/shared/img/ff_action_flow.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Select Action Trigger** ウィンドウで **On Page Load** を選択します。 <img src="/assets/shared/img/ff_action_trigger.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Add Action** をクリックします。次に、`getPaywall` カスタムアクションを検索して選択します。 <img src="/assets/shared/img/ff_getpaywall.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Set Actions Arguments** セクションで、ペイウォールを含むAdapity ダッシュボードで[作成したプレースメント](create-placement)の実際のIDを入力します。この例では `monthly` です。必ず実際のプレースメントIDを使用してください! <img src="/assets/shared/img/ff_placementid.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. Adapty ダッシュボードでペイウォールを[ローカライズ](localizations-and-locale-codes)している場合は、**locale** 引数も設定できます。 6. **Action Output Variable Name** で新しい変数を作成し、`getPaywallResult` という名前を付けます。次のステップでAdaptyのペイウォールを参照してプロダクトをリクエストする際に使用します。 <img src="/assets/shared/img/ff_getpaywallresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ1.2. Adaptyペイウォールプロダクトをリクエストする \{#step-12-request-adapty-paywall-products\} Adaptyのペイウォールを取得しました。次は、このペイウォールに関連するプロダクトを取得しましょう。 1. 作成したアクションの下にある **+** をクリックし、**Add Action** を選択します。このアクションでAdaptyペイウォールのプロダクトを受け取ります。`getPaywallProducts` を検索して選択します。 2. **Set Actions Arguments** セクションで、先ほど作成した `getPaywallResult` 変数を選択します。 <img src="/assets/shared/img/ff_getpaywallproduct.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 残りのフィールドを以下のように入力します。 - **Available Options**: Data Structured Field - **Select Field**: value - **Available Options**: No further changes <img src="/assets/shared/img/ff_getpaywallresult2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Confirm** をクリックします。 5. **Action Output Variable Name** で新しい変数を作成し、`getPaywallProductsResult` という名前を付けます。FlutterFlowで設計したペイウォールとAdaptyのペイウォールデータをマッピングする際に使用します。 <img src="/assets/shared/img/ff_getpaywallproductsresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ1.3. ペイウォールが正常にアップロードされたか確認する \{#step-13-add-check-if-the-paywall-uploaded-successfully\} 次に進む前に、Adaptyのペイウォールが正常に受信されたかどうかを確認しましょう。成功した場合はプロダクトデータでペイウォールを更新し、失敗した場合はエラーを処理します。確認を追加する手順は以下の通りです。 1. **+** をクリックし、**Add Conditional** をクリックします。 <img src="/assets/shared/img/ff-add-conditional.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. **Action Output** セクションで、先ほど作成したアクション出力変数(この例では `getPaywallResult`)を選択します。 <img src="/assets/shared/img/ff-getpaywallresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. Adaptyのペイウォールが受信されたことを確認するため、値を持つフィールドの存在を確認します。フィールドを以下のように入力します。 - **Available Options**: Has Field - **Field (AdaptyGetPaywallResult)**: value 4. **Confirm** をクリックして条件を確定します。 ## ステップ1.4. ペイウォールの表示をログに記録する \{#step-14-log-the-paywall-review\} Adaptyのアナリティクスがペイウォールの表示を追跡できるよう、このイベントをログに記録する必要があります。この手順を省略すると、表示がアナリティクスでカウントされません。手順は以下の通りです。 1. **TRUE** ラベルの下にある **+** をクリックし、**Add Action** をクリックします。 2. **Select Action** フィールドで **logShowPaywall** を検索して選択します。 <img src="/assets/shared/img/ff-logshowpaywall.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Set Action Arguments** エリアで **Value** をクリックし、作成した `getPaywallResult` 変数を選択します。この変数にはペイウォールデータが含まれています。 4. フィールドを以下のように入力します。 - **Available Options**: Data Structured Field - **Select Field**: value 5. **Confirm** をクリックします。 <img src="/assets/shared/img/ff-lohsgowpaywallresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ1.5. ペイウォールが受信されなかった場合にエラーを表示する \{#step-15-show-error-if-paywall-not-received\} Adaptyのペイウォールが受信されなかった場合は、[エラーを処理する](error-handling-on-flutter-react-native-unity#system-storekit-codes)必要があります。この例では、アラートメッセージを表示するだけにします。 1. **FALSE** ラベルに **Informational Dialog** アクションを追加します。 2. **Title** フィールドに、ダイアログのタイトルとして表示したいテキストを入力します。この例では **Error** です。 3. **Message** ボックスで **Value** をクリックします。 4. フィールドを以下のように入力します。 - **Set Variable**: 作成した `getPaywallProductResult` 変数 - **Available Options**: Data Structure Field - **Select Field**: error - **Available Options**: Data Structure Field - **Select Field**: errorMessage <img src="/assets/shared/img/ff-error.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Confirm** をクリックします。 6. **FALSE** フローに **Terminate action** を追加します。 <img src="/assets/shared/img/ff-terminate.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. 右上隅の **Close** をクリックします。 おめでとうございます!プロダクトデータの取得に成功しました。次は[FlutterFlowで設計したペイウォールにデータをマッピング](ff-add-variables-to-paywalls)しましょう。 --- # File: ff-add-variables-to-paywalls --- --- title: "ステップ 2. ペイウォールページにデータを追加する" description: "Adapty のペイウォールに Feature Flag 変数を追加する。" --- [必要なプロダクトデータをすべて取得](ff-action-flow)したら、FlutterFlow でデザインした美しいペイウォールにそのデータをマッピングしましょう。この例では、プロダクトのタイトルと価格をマッピングします。 ## ステップ 2.1. ペイウォールページにプロダクトタイトルを追加する \{#step-21-add-product-title-to-paywall-page\} 1. ペイウォールページのプロダクトテキストをダブルクリックします。**Set from Variable** ウィンドウで `getPaywallProductResult` 変数を検索して選択します。 <img src="/assets/shared/img/ff-paywall-text.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 各フィールドを以下のように入力します: - **Available Options**: Data Structured Field - **Select Field**: value - **Available Options**: Item at Index - **List Index Options**: First - **Available Options**: Data Structured Field - **Select Field**: localizedTitle - **Default Variable Value**: null - **UI Builder Display Value**: 任意の値。この例では `product.title` <img src="/assets/shared/img/ff-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Confirm** をクリックして変更を保存します。 ## ステップ 2.2. ペイウォールページに価格テキストを追加する \{#step-22-add-price-text-to-paywall-page\} ステップ 2.1 と同じ手順を、以下のように価格テキストに対しても繰り返します: 1. ペイウォールページの価格テキストをダブルクリックします。**Set from Variable** ウィンドウで `getPaywallProductResult` 変数を検索して選択します。 <img src="/assets/shared/img/ff-price.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 各フィールドを以下のように入力します: - **Available Options**: Data Structured Field - **Select Field**: value - **Available Options**: Item at Index - **List Index Options**: First - **Available Options**: Data Structured Field - **Select Field**: price - **Default Variable Value**: null - **UI Builder Display Value**: 任意の値。この例では `product.price` 3. **Confirm** ボタンをクリックして変更を保存します。 ### ペイウォールページに現地通貨の価格を追加する \{#add-price-in-local-currency-to-paywall-page\} 1. ペイウォールページの価格をダブルクリックします。**Set from Variable** ウィンドウで `getPaywallProductResult` 変数を検索して選択します。 2. 各フィールドを以下のように入力します: - **Available Options**: Data Structured Field - **Select Field**: value - **Available Options**: Item at Index - **List Index Options**: First - **Available Options**: Data Structured Field - **Select Field**: price - **Available Options**: Data Structured Field - **Select Field**: amount - **Available Options**: Decimal - **Decimal Type**: Automatic - **Default Variable Value**: null - **UI Builder Display Value**: 任意の値。この例では `price.amount` 3. **Confirm** をクリックして変更を保存します。 これで完了です!アプリを起動すると、Adapty ペイウォールのプロダクトデータがペイウォールページに表示されるようになります! 次は[ユーザーがプロダクトを購入できるようにする](ff-make-purchase)ステップに進みましょう。 --- # File: ff-make-purchase --- --- title: "ステップ 3. 購入を有効にする" description: "AdaptyのFeature Flagsシステムを使って購入を行う方法を学びましょう。" --- おめでとうございます![Adaptyからのプロダクトデータをペイウォールに表示する設定](ff-add-variables-to-paywalls)(プロダクト名や価格を含む)が完了しました。 次は最終ステップとして、ユーザーがペイウォールを通じて購入できるようにしましょう。 ## ステップ 3.1. ユーザーが購入できるようにする \{#step-31-enable-users-to-make-purchases\} 1. ペイウォールページの購入ボタンをダブルクリックします。右パネルで **Actions** セクションがまだ開いていなければ開きます。 2. **Action Flow Editor** を開きます。 <img src="/assets/shared/img/ff-action-flow-editor.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Select Action Trigger** ウィンドウで **On Tap** を選択します。 4. **No Actions Created** ウィンドウで **Add Action** をクリックします。`makePurchase` アクションを検索して選択します。 <img src="/assets/shared/img/ff-makepurchase.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Set Actions Arguments** セクションで、以前作成した `getPaywallProductsResult` 変数を選択します。 6. 各フィールドを次のように入力します: - **Available Options**: Data Structure Field - **Select Field**: value - **Available Options**: Item at Index - **List Index Options**: First <img src="/assets/shared/img/ff-makepurchase-value.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 7. `subscriptionUpdateParameters` をクリックし、`AdaptySubscriptionUpdateParameters` を検索して選択します。**Confirm** をクリックします。 :::info デフォルトでは、オブジェクトのフィールドはすべて空のままにしておけます。Android アプリで一つのサブスクリプションを別のものに置き換える場合にのみ入力が必要です。詳細は[こちら](https://android.adapty.io/adapty/com.adapty.models/-adapty-subscription-update-parameters/)をご覧ください。 ::: <img src="/assets/shared/img/ff-subupdate.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 8. **Confirm** をクリックします。 9. **Action Output Variable Name** で新しい変数を作成し、`makePurchaseResult` という名前を付けます。これは後で購入が成功したことを確認するために使用します。 <img src="/assets/shared/img/ff-makepurchaseresult.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 3.2. 購入が成功したか確認する \{#step-32-check-if-the-purchase-was-successful\} 購入が正常に完了したか確認する処理を設定しましょう。 1. **+** をクリックして **Add Conditional** をクリックします。 2. **Set Condition for Action** で `makePurchaseResult` 変数を選択します。 3. **Set Variable** ウィンドウで各フィールドを次のように入力します: - **Available Options**: Has Field - **Select Field**: profile <img src="/assets/shared/img/ff-makepurchaseresult-conditional.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Confirm** をクリックします。 ## ステップ 3.3. 有料コンテンツを開く \{#step-33-open-paid-content\} 購入が成功したら、有料コンテンツのロックを解除できます。設定方法は次のとおりです: 1. **TRUE** ラベルの下の **+** をクリックして **Add Action** をクリックします。 2. **Define Action** フィールドで、**Navigate To** リストから開きたいページを検索して選択します。この例では **Questions** ページです。 <img src="/assets/shared/img/ff-questions.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ 3.4. 購入失敗時にエラーメッセージを表示する \{#step-34-show-error-message-if-purchase-failed\} 購入が失敗した場合は、ユーザーにアラートを表示しましょう。 1. **FALSE** ラベルに **Informational Dialog** アクションを追加します。 2. **Title** フィールドに、ダイアログのタイトルとして表示するテキストを入力します(例:**Purchase Failed**)。 <img src="/assets/shared/img/ff-purchase-fail.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Message** ボックスの **Value** をクリックします。**Set from Variable** ウィンドウで `makePurchaseResult` を検索して選択します。各フィールドを次のように入力します: - **Available Options**: Data Structure Field - **Select Field**: error - **Available Options**: Data Structure Field - **Select Field**: errorMessage <img src="/assets/shared/img/ff-fail-message.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Confirm** をクリックします。 5. **FALSE** フローに **Terminate** アクションを追加します。 <img src="/assets/shared/img/ff-terminate-purchase.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. 最後に、右上隅の **Close** をクリックします。 おめでとうございます!これでユーザーがプロダクトを購入できるようになりました。追加のステップとして、[有料コンテンツへのユーザーアクセスを確認する設定](ff-check-subscription-status)を行い、有料コンテンツまたはペイウォールのどちらを表示するかを判断できるようにしましょう。 --- # File: ff-check-subscription-status --- --- title: "ステップ 4. 有料コンテンツへのアクセスを確認する" description: "Adaptyのフィーチャーフラグを使用してサブスクリプションステータスを確認し、ユーザーセグメンテーションを改善する方法を学びましょう。" --- ユーザーが特定の有料コンテンツにアクセスできるかどうかを確認するには、そのユーザーのアクセスレベルを検証する必要があります。具体的には、ユーザーが少なくとも1つのアクセスレベルを持っているか、またそのレベルが必要なものであるかをチェックします。 これは、利用可能なすべてのアクセスレベルを含むユーザーのプロファイルを確認することで行えます。 それでは、ユーザーがプロダクトを購入できるようにしましょう: 1. 有料コンテンツを表示するボタンをダブルクリックし、右ペインの **Actions** セクションがまだ開いていない場合は開きます。 2. **Action Flow Editor** を開きます。 <img src="/assets/shared/img/ff-open-paid-content.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. **Select Action Trigger** ウィンドウで、**On Tap** を選択します。 4. **No Actions Created** ウィンドウで、**Add Conditional Action** ボタンをクリックします。 5. **UNSET** をクリックしてアクション引数を設定し、`currentProfile` 変数を選択します。これは現在のユーザーのプロファイルに関するデータを保持するAdaptyの変数です。 <img src="/assets/shared/img/ff-currentprofile.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '300px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 6. 以下のようにフィールドを入力します: - **Available Options**: Data Structure Field - **Select Field**: accessLevels - **Available Options**: Filter List Items - **Filter Conditions**: 1. **Conditions -> Single Condition** を選択し、**UNSET** をクリックします。 2. **First value** フィールドで、**Source** として **Item in list** を選択し、以下のようにフィールドを入力します: - **Available Options**: Data Structure Field - **Select Field**: accessLevelIdentifier 3. フィルター演算子を **Equal to** に設定します。 4. **Second value** の隣にある **UNSET** をクリックし、**Value** フィールドにアクセスレベルのIDを入力します。この例では `premium` を使用します。 <img src="/assets/shared/img/ff-filter.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '500px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. **Confirm** をクリックし、以下の他のフィールドへの入力を続けます。 - **Available Options**: Item at Index - **List Index Options**: First - **Available Options**: Data Structure Field - **Select Field**: accessLevel - **Available Options**: Data Structure Field - **Select Field**: isActive 7. **Confirm** をクリックします。 次に、ユーザーが適切なサブスクリプションを持っているかどうかに応じて、次に何が起こるかのアクションを追加します。プレミアムサブスクライバーが利用できるページに移動させるか、アクセスを購入できるようにペイウォールページを開きます。 --- # File: ff-resources --- --- title: "Adapty FlutterFlow プラグインのアクションとデータ型" description: "Adaptyの機能フラグリソースにアクセスして、サブスクリプションベースの機能を効率化しましょう。" --- ## カスタムアクション \{#custom-actions\} 以下は、Adapty プラグインを通じて FlutterFlow に提供される Adapty メソッドです。FlutterFlow のカスタムアクションとして使用できます。 | カスタムアクション | 説明 | アクション引数 | Adapty データ型 - アクション出力変数 | |---|----|--------|----| | activate | Adapty SDK を初期化します | なし || | <p id="getPaywall">getPaywall</p> | ペイウォールを取得します。ペイウォールのプロダクトは返しません。実際のプロダクトを取得するには `getPaywallProducts` アクションを使用してください | <ul><li>[Placement_ID](placements)</li><li>[Locale](localizations-and-locale-codes)</li></ul> | [AdaptyGetPaywallResult](ff-resources#adaptygetpaywallresult)| | <p id="getPaywallProducts">getPaywallProducts</p> | 実際のペイウォールプロダクトのリストを返します | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyGetProductsResult](ff-resources#adaptygetproductsresult) | | <p id="getproductsintroductoryoffereligibility">getProductsIntroductoryOfferEligibility</p> | ユーザーが iOS サブスクリプションの初回オファーを利用できるか確認します | [AdaptyPaywallProduct](product) | [AdaptyGetIntroEligibilitiesResult](ff-resources#adaptygetintroeligibilitiesresult) | | <p id="makePurchase">makePurchase</p> | 購入を完了してコンテンツを解放します。ペイウォールにプロモーションオファーがある場合、Adapty は自動的にチェックアウト時に適用します | <ul><li> **product**: ペイウォールから取得した AdaptyPaywallProduct オブジェクト。</li><li> **subscriptionUpdateParams**: サブスクリプションのアップグレードまたはダウングレードに使用する [`AdaptySubscriptionUpdateParameters`](ff-resources#adaptysubscriptionupdateparameters) オブジェクト(Android で使用)。</li><li>**isOfferPersonalized**: オファーが購入者にパーソナライズされているかどうかを指定します(Android で使用)。</li></ul> | [AdaptyMakePurchaseResult](ff-resources#adaptymakepurchaseresult) | | <p id="getprofile">getProfile</p> | <p>現在のアプリユーザーのプロファイルを取得します。これによりアクセスレベルやその他のパラメーターを設定できます。</p><p>失敗した場合(例: インターネット接続なし)、キャッシュされたデータが返されます。Adapty はプロファイルのキャッシュを定期的に更新し、情報をできる限り最新の状態に保ちます。</p> | なし | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | updateProfile | メールアドレスや電話番号などの現在のユーザープロファイルのオプション属性を変更します。属性を使ってユーザーの[セグメント](segments)を作成したり、CRM で閲覧したりすることができます | [AdaptyProfile](ff-resources#adaptyprofile) の ID および更新が必要なパラメーター | [AdaptyError](ff-resources#adaptyerror)(オプション) | | restorePurchases | ユーザーが行った購入を復元します | なし | [AdaptyGetProfileResult](ff-resources#adaptygetprofileresult) | | logShowPaywall | 特定のペイウォールがユーザーに表示されたときにログを記録します | [AdaptyPaywall](ff-resources#adaptypaywall) | [AdaptyError](ff-resources#adaptyerror)(オプション) | | identify | システムの `customerUserId` を使用してユーザーを識別します | customerUserId | [AdaptyError](ff-resources#adaptyerror)(オプション) | | logout | 現在のユーザーをアプリからログアウトします | なし | [AdaptyError](ff-resources#adaptyerror)(オプション)| | presentCodeRedemptionSheet | ユーザーがコードを引き換えるためのシートを表示します(iOS のみ) | なし | なし | ## データ型 \{#data-types\} Adapty プラグインを通じて FlutterFlow に届く Adapty のデータ型(データ値のコレクション)です。 ### AdaptyAccessLevel ユーザーの[アクセスレベル](access-level)に関する情報。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | activatedAt | DateTime | このアクセスレベルが有効化された日時 | | activeIntroductoryOfferType | String | 有効な初回オファーのタイプ。設定されている場合、このサブスクリプション期間中にオファーが適用されたことを意味します | | activePromotionalOfferId | String | 有効なプロモーションオファーのID(iOSから購入) | | activePromotionalOfferType | String | 有効なプロモーションオファーのタイプ(iOSから購入)。設定されている場合、このサブスクリプション期間中にオファーが適用されたことを意味します | | billingIssueDetectedAt | DateTime | 請求の問題が検出された日時。サブスクリプションは引き続き有効な場合があります。支払いが正常に処理された場合はnullに設定されます | | cancellationReason | String | サブスクリプションがキャンセルされた理由 | | expiresAt | DateTime | アクセスレベルの有効期限(過去の日時になる場合や、永続アクセスの場合は未設定になる場合があります) | | id | String | アクセスレベルの識別子 | | isActive | Boolean | このアクセスレベルが有効な場合はtrue。一般的に、ユーザーがプレミアム機能にアクセスできるかどうかの判定にこのプロパティを使用できます | | isInGracePeriod | Boolean | この自動更新サブスクリプションが[グレース期間](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions)中の場合はtrue | | isLifetime | Boolean | このアクセスレベルが永続的に有効(有効期限なし)な場合はtrue | | isRefund | Boolean | この購入が返金された場合はtrue | | offerId | String | 有効なプロモーションオファーのID(Androidから購入) | | renewedAt | DateTime | アクセスレベルが最後に更新された日時 | | startsAt | DateTime | このアクセスレベルの開始日時(将来の日時になる場合があります) | | store | String | 購入が行われたストア | | unsubscribedAt | DateTime | サブスクリプションの自動更新がオフになった日時。サブスクリプションは引き続き有効な場合があります。未設定の場合、ユーザーはサブスクリプションを再有効化しています | | vendorProductId | String | このアクセスレベルを解放したストアのプロダクトID | | willRenew | Boolean | この自動更新サブスクリプションが更新設定になっている場合はtrue | ### AdaptyAccessLevelIdentifiers この構造体は、`Map<String, AdaptyAccessLevel` [AdaptyAccessLevel](ff-resources#adaptyaccesslevel) のキーと値のペアを置き換えるためのものです。 | フィールド名 | 型 | 説明 | |------------|------|-------------| | accessLevelIdentifier | String | アクセスレベルの ID | | accessLevel | Data ([AdaptyAccessLevel](ff-resources#adaptyaccesslevel)) | 関連する [AdaptyAccessLevel](ff-resources#adaptyaccesslevel) | ### AdaptyCustomDoubleAttribute [ユーザー](ff-resources#adaptyprofile)に定義されたカスタムDouble属性に関する情報です。 | フィールド名 | 型 | 説明 | |------------|------|-------------| | key | String | カスタムDouble属性のID | | value | Double | カスタムDouble属性の値 | ### AdaptyCustomStringAttribute [ユーザー](ff-resources#adaptyprofile)に定義されたカスタム文字列属性の情報です。 | フィールド名 | 型 | 説明 | |------------|------|-------------| | key | String | カスタム文字列属性のID | | value | String | カスタム文字列属性の値 | ### AdaptyError エラーの詳細情報を含みます。エラーコードの完全なリストについては、[React Native、Flutter、Unity - エラー処理](error-handling-on-flutter-react-native-unity)を参照してください。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | errorMessage | String | エラーの人間が読める説明 | | errorCode | Integer | エラーを識別する数値コード | ### AdaptyGetIntroEligibilitiesResult `getProductsIntroductoryOfferEligibility` カスタムアクションの結果を含みます。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | value | List < Data ([AdaptyProductIntroEligibility](ff-resources#adaptyproductintroeligibility)) > | ユーザーのプロモーションオファー利用資格のリスト | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | [`AdaptyError`](ff-resources#adaptyerror) を通じたエラーの詳細 | ### AdaptyGetPaywallResult `getPaywall` カスタムアクションの結果を格納します。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | value | Data ([AdaptyPaywall](ff-resources#adaptypaywall)) | [AdaptyPaywall](ff-resources#adaptypaywall) オブジェクトのリストを格納します | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | [AdaptyError](ff-resources#adaptyerror) を通じたエラー情報を格納します | ### AdaptyGetProductsResult `getPaywallProducts` カスタムアクションの結果を格納します。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | value | List < Data ([AdaptyPaywallProduct](product)) > | [AdaptyPaywallProduct](product) のリストを格納します | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | [AdaptyError](ff-resources#adaptyerror) を通じてエラー情報を格納します | ### AdaptyGetProfileResult `getProfile` カスタムアクションの結果を含みます。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | value | Data ([AdaptyProfile](ff-resources#adaptyprofile)) | [AdaptyProfile](ff-resources#adaptyprofile) としてユーザープロファイルを含みます | | error | Data (AdaptyError) | [AdaptyError](ff-resources#adaptyerror) を通じてエラー情報を含みます | ### AdaptyMakePurchaseResult `makePurchase` カスタムアクションの結果を含みます。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | value | Data ([AdaptyProfile](ff-resources#adaptyprofile)) | [AdaptyProfile](ff-resources#adaptyprofile) としてユーザーのプロファイルを含みます | | error | Data ([AdaptyError](ff-resources#adaptyerror)) | [AdaptyError](ff-resources#adaptyerror) を通じたエラー情報を含みます | ### AdaptyNonSubscription サブスクリプション以外の購入に関する情報です。これには、消耗型アイテム(一度限りの購入)やアンロック(ゲームの新しいマップのアンロックなど)が含まれます。 | フィールド名 | 型 | 説明 | |--------------------------|----------|-------------| | isConsumable | Boolean | プロダクトが消耗型アイテムかどうかを示す | | isOneTime | Boolean | プロダクトが買い切り購入かどうかを示す(true の場合、購入は一度だけ処理される) | | isRefund | Boolean | プロダクトが返金済みかどうかを示す | | isSandbox | Boolean | プロダクトがサンドボックス環境で購入されたかどうかを示す | | purchasedAt | DateTime | プロダクトが購入された日時 | | purchaseId | String | Adapty における購入の ID。買い切り購入のトラッキングに使用できる | | store | String | プロダクトが購入されたストア(App Store、Google Play など) | | vendorProductId | String | ベンダーのシステムにおけるプロダクト ID | | vendorTransactionId | String | ベンダーのシステムにおけるトランザクション ID | ### AdaptyPaywall [ペイウォール](paywalls)に関する情報です。 | フィールド名 | 型 | 説明 | |----------------------|----------|-------------| | abTestName | String | 親 A/B テストの名前 | | hasViewConfiguration | Boolean | ペイウォールにビュー設定があるかどうかを示す | | locale | String | ペイウォールのロケール ID | | name | String | ペイウォール名 | | placement.id | String | 親プレースメントの ID | | remoteConfigString | String | このペイウォールに関連付けられた Adapty ダッシュボードのカスタムディクショナリ | | placement.revision | Integer | ペイウォールの現在のリビジョン/バージョン。変更のたびに新しいリビジョンが生成される | | variationId | String | このペイウォールへの購入を紐付けるために使用するバリエーション ID | | vendorProductIds | String | ペイウォールに関連するプロダクト ID の配列 | ### AdaptyPaywallProduct [プロダクト](product)に関する情報です。 | フィールド名 | 型 | 説明 | | -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | vendorProductId | String | アプリストアのプロダクトID | | localizedDescription | String | ユーザーの言語によるプロダクトの説明 | | localizedTitle | String | ユーザーの言語によるプロダクト名 | | regionCode | String | プロダクトの価格をフォーマットする際に使用するロケールのリージョンコード(iOS用) | | isFamilyShareable | Boolean | App Store Connectでプロダクトのファミリー共有が有効かどうかを示すBoolean値。iOS 14.0未満およびmacOS 11.0未満では常にFALSEになります(iOS用) | | paywallVariationId | String | バリアントのID。購入をこのペイウォールにアトリビュートするために使用します | | paywallABTestName | String | 親A/B テスト名 | | paywallName | String | 親ペイウォール名 | | price | Data ([AdaptyPriceData](#adaptyprice)) | プロダクトの価格 | | subscriptionDetails | Data ([AdaptySubscriptionDetails](#adaptysubscriptiondetails)) | サブスクリプションに関する情報 | ### AdaptyPrice プロダクトの価格に関する情報です。 | フィールド名 | 型 | 説明 | | --------------- | ------ | ------------------------------ | | amount | Double | 価格の数値 | | currencyCode | String | 価格の通貨コード | | currencySymbol | String | 通貨に使用される記号 | | localizedString | String | ユーザーの言語で表示された価格 | ### AdaptyProductIntroEligibility iOSサブスクリプションの初回オファー対象資格をユーザーが持っているかどうかを定義します。 | フィールド名 | 型 | 説明 | | --------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | | vendorProductId | String | アプリストアのプロダクトID | | eligibility | [AdaptyEligibilityEnum](ff-resources#adaptyeligibilityenum) | iOSサブスクリプションの初回オファーにユーザーが適格かどうかの定義 | ### AdaptyProductNonsubscriptions このプロダクトに紐づくアクティブな買い切り購入の詳細。 | フィールド名 | 型 | 説明 | | ---------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | | productId | String | アプリストアにおけるプロダクトのID | | nonsubscriptions | [AdaptyNonSubscription](ff-resources#adaptynonsubscription) | サブスクリプション以外の購入に関する情報。消耗型アイテム(コンシューマブル)や、ゲームの新マップ解放などの買い切り購入が含まれます。 | ### AdaptyProductSubscriptions このプロダクトに紐づくアクティブなサブスクリプションの詳細。 | フィールド名 | 型 | 説明 | | ------------ | ----------------------------------------------------- | ---------------------------------------- | | productId | String | ストアのプロダクトID | | subscription | [AdaptySubscription](ff-resources#adaptysubscription) | サブスクリプション購入に関する情報 | ### AdaptyProfile ユーザーのプロファイルに関する情報 | フィールド名 | 型 | 説明 | | ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | accessLevels | List < Data ([AdaptyAccessLevelIdentifiers](ff-resources#adaptyaccesslevelidentifiers)) > | ユーザーに紐づくすべてのアクセスレベルのリスト | | profileId | String | ユーザープロファイルのID | | customerUserId | String | ベンダーシステム上のユーザーID | | subscriptions | List < Data ([MapKeySubscriptions](#mapkeysubscriptions)) > | ユーザーが購入したすべてのサブスクリプションのリスト | | nonSubscriptions | List < Data ([MapKeyNonSubscriptions](#mapkeynonsubscriptions)) > | ユーザーが購入したすべての非サブスクリプションプロダクトのリスト | ### AdaptyProfileParameters ユーザーに関する情報。 | フィールド名 | 型 | 説明 | | ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | firstName | String | ユーザーの名前 | | lastName | String | ユーザーの苗字 | | gender | [AdaptyGenderEnum](#adaptygenderenum) | ユーザーの性別 | | birthday | String | ユーザーの生年月日 | | email | String | ユーザーのメールアドレス | | phoneNumber | String | ユーザーの電話番号 | | facebookAnonymousId | String | [Facebook Ads 連携](facebook-ads)におけるユーザーの ID | | amplitudeUserId | String | [Amplitude 連携](amplitude)におけるユーザーの ID | | amplitudeDeviceId | String | [Amplitude 連携](amplitude)におけるユーザーのデバイス ID | | mixpanelUserId | String | [Mixpanel 連携](mixpanel)におけるユーザーの ID | | appmetricaProfileId | String | [AppMetrica 連携](appmetrica)におけるユーザーの ID | | appmetricaDeviceId | String | [AppMetrica 連携](appmetrica)におけるユーザーのデバイス ID | | oneSignalPlayerId | String | [OneSignal 連携](onesignal)におけるユーザーの ID | | pushwooshHWID | String | [Pushwoosh 連携](pushwoosh)におけるユーザーのデバイス ID | | firebaseAppInstanceId | String | [Firebase 連携](firebase-and-google-analytics)におけるユーザーの ID | | airbridgeDeviceId | String | [Airbridge 連携](airbridge)におけるユーザーのデバイス ID | | appTrackingTransparencyStatus | AdaptyATTStatus | IDFA へのアクセスステータス(iOS 用) | | analyticsDisabled | Boolean | [特定のユーザーに対して外部アナリティクスをオプトアウト](analytics-integration#disabling-external-analytics-for-a-specific-customer)するかどうかの設定 | | customStringAttributes | List < Data ([AdaptyCustomStringAttribute](ff-resources#adaptycustomstringattribute)) > | ユーザーのカスタム文字列属性のリスト | | customDoubleAttributes | List < Data ([AdaptyCustomDoubleAttribute](ff-resources#adaptycustomdoubleattribute)) > | ユーザーのカスタム数値(double)属性のリスト | ### AdaptySubscription 既存のユーザーサブスクリプションに関する情報。 | フィールド名 | 型 | 説明 | | --------------------------- | -------- | ------------------------------------------------------------ | | activatedAt | DateTime | このサブスクリプションがアクティベートされた日時 | | activeIntroductoryOfferType | String | 有効な初回オファーのタイプ。設定されている場合、このサブスクリプション期間中にオファーが適用されたことを意味します | | activePromotionalOfferId | String | 有効なプロモーションオファーのID(iOS用) | | activePromotionalOfferType | String | 有効なプロモーションオファーのタイプ(iOS用)。設定されている場合、このサブスクリプション期間中にオファーが適用されたことを意味します | | cancellationReason | String | サブスクリプションがキャンセルされた理由 | | expiresAt | DateTime | サブスクリプションの有効期限 | | renewedAt | DateTime | サブスクリプションが最後に更新された日時 | | unsubscribedAt | DateTime | サブスクリプションの自動更新がオフになった日時。サブスクリプション自体はまだ有効な場合があります。設定されていない場合、ユーザーがサブスクリプションを再有効化したことを意味します | | billingIssueDetectedAt | DateTime | 請求の問題が検出された日時。サブスクリプション自体はまだ有効な場合があります。支払いが正常に処理された場合はnullに設定されます | | isActive | Boolean | このサブスクリプションが有効な場合はTrue。一般的に、ユーザーがプレミアム機能にアクセスできるかどうかを判断するにはこのプロパティを確認します | | isInGracePeriod | Boolean | この自動更新サブスクリプションが[グレース期間](https://developer.apple.com/help/app-store-connect/manage-subscriptions/enable-billing-grace-period-for-auto-renewable-subscriptions)内にある場合はTrue | | isLifetime | Boolean | このサブスクリプションが永続アクセス(有効期限なし)の場合はTrue | | isRefund | Boolean | この購入が返金された場合はTrue | | isSandbox | Boolean | プロダクトがサンドボックス環境で購入されたかどうかを示します | | offerId | String | 有効なプロモーションオファーのID(Android用) | | startsAt | DateTime | このアクセスレベルの開始日時(将来の日時になる場合もあります) | | store | String | プロダクトが購入されたストア(例:App Store、Google Play) | | vendorOriginalTransactionId | String | ベンダーシステムにおける最初のサブスクリプションのID | | vendorProductId | String | ベンダーシステムにおけるプロダクトのID | | vendorTransactionId | String | ベンダーシステムにおけるトランザクションID | | willRenew | Boolean | この自動更新サブスクリプションが更新される設定になっている場合はTrue | ### AdaptySubscriptionDetails [AdaptyPaywallProduct](product) の一部である Subscription オブジェクトのスキーマ。 | フィールド名 | 型 | 説明 | | ----------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | androidBasePlanId | String | Google Play ストアの[ベースプランID](https://support.google.com/googleplay/android-developer/answer/12154973)、またはStripeの[価格ID](https://docs.stripe.com/products-prices/how-products-and-prices-work#use-products-and-prices)。 | | androidIntroductoryOfferEligibility | [AdaptyEligibilityEnum](ff-resources#adaptyeligibilityenum) | iOSサブスクリプションの初回オファーにユーザーが適格かどうかの定義 | | androidOfferId | String | アクティブなプロモーションオファーのID(Android用) | | androidOfferTags | List < String > | ベースプランおよびサブスクリプションオファーに指定された[カスタムタグ](https://developers.google.com/android-publisher/api-ref/rest/v3/OfferTag)のリスト。 | | introductoryOffer | List < Data ([AdaptySubscriptionPhase](ff-resources#adaptysubscriptionphase)) > | 初回オファーのID(iOS用) | | localizedSubscriptionPeriod | String | ユーザーの言語によるサブスクリプション期間 | | promotionalOffer | Data ([AdaptySubscriptionPhase](ff-resources#adaptysubscriptionphase)) | プロモーションオファーの詳細(iOS用) | | promotionalOfferEligibility | Boolean | iOSサブスクリプションのプロモーションオファーにユーザーが適格かどうかの定義 | | promotionalOfferId | String | プロモーションオファーのID(iOS用) | | renewalType | [AdaptyRenewalTypeEnum](#adaptyrenewaltypeenum) | [AdaptyRenewalTypeEnum](ff-resources#adaptyrenewaltypeenum) によって、サブスクリプションが自動更新かどうかを定義する | | subscriptionGroupIdentifier | String | プロダクトが属するプロダクトグループのID(iOS用) | | subscriptionPeriod | Data ([AdaptySubscriptionPeriod](#adaptysubscriptionperiod)) | サブスクリプションの期間 | ### AdaptySubscriptionPeriod サブスクリプションの期間。 | フィールド名 | 型 | 説明 | | ------------- | --------------------------------------------- | ----------------------------------------------------------- | | numberOfUnits | Integer | サブスクリプションの期間(日数・週数・月数・年数)。 | | unit | [AdaptyPeriodUnitEnum](#adaptyperiodunitenum) | 期間の単位(日・週・月・年)。 | ### AdaptySubscriptionPhase サブスクリプションのフェーズ(無料トライアルや初回オファー期間など)を表します。 | フィールド名 | 型 | 説明 | | --------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | | identifier | String | フェーズのID | | localizedNumberOfPeriods | String | フェーズの長さ。たとえば、6ヶ月のオファーはユーザーの言語で `6 months` のように表示されます。 | | localizedSubscriptionPeriod | String | ユーザーの言語でのサブスクリプション期間(例:`3 months`)。 | | numberOfPeriods | Integer | このフェーズのサブスクリプション期間の数。たとえば、6ヶ月のオファーは3ヶ月の期間が2つになります。 | | paymentMode | [AdaptyPaymentModeEnum](#adaptypaymentmodeenum) | このフェーズに使用される支払いモデル。 | | price | Data ([AdaptyPrice](#adaptyprice)) | このフェーズの価格。 | | subscriptionPeriod | Data ([AdaptySubscriptionPeriod](#adaptysubscriptionperiod)) | このフェーズが基づくサブスクリプション期間。 | ### AdaptySubscriptionUpdateParameters (*Android のみ*) サブスクリプションを別のサブスクリプションに切り替えるためのパラメーター。 | フィールド名 | 型 | 説明 | | ---------- | ------------------------------------------------------------ | ---------- | | oldSubVendorProductId | String | 置き換えたい現在のサブスクリプションの Play Store 上の ID。 | | replacementMode | [AdaptySubscriptionUpdateReplacementMode](ff-resources#adaptysubscriptionupdatereplacementmode) | [`BillingFlowParams.ProrationMode`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode) の値に対応する Enum。 | ### MapKeyNonSubscriptions [AdaptyNonSubscription](ff-resources#adaptynonsubscription) の辞書の代替です。 | フィールド名 | 型 | | ------------ | ------------------------------------------------------------ | | key | String | | value | List < Data ([AdaptyNonSubscription](ff-resources#adaptynonsubscription)) > | ### MapKeySubscriptions [AdaptySubscription](ff-resources#adaptysubscription) の辞書の代替。 | フィールド名 | 型 | | ------------ | ------------------------------------------------------------ | | key | String | | value | List < Data ([AdaptySubscription](ff-resources#adaptysubscription)) > | ## 列挙型 \{#enums\} Adapty プラグインを通じて FlutterFlow に提供される Adapty の列挙型(あらかじめ定義された定数の集合)です。 ### AdaptyEligibilityEnum iOSサブスクリプションの初回オファーにユーザーが適格かどうかを定義します。 | フィールド名 | 説明 | |--------------------------|-------------| | eligible | ユーザーは初回オファーの対象です。この情報をUIに表示しても問題ありません | | ineligible | ユーザーはいかなるオファーの対象でもありません。UIに表示しないでください | | notApplicable | このプロダクトにはオファーが設定されていません | ### AdaptyGenderEnum ユーザーの性別を定義します。 | フィールド名 | 説明 | | ------------ | ---------------------------------- | | none | 性別が設定されていない | | female | ユーザーの性別が女性 | | male | ユーザーの性別が男性 | | Other | ユーザーが性別を「その他」と設定した | ### AdaptyPaymentModeEnum 支払いモデルを定義します。 | フィールド名 | 説明 | | ---------- | ------------------------------------------------------------ | | payAsYouGo | 固定料金を前払いするのではなく、プロダクト/サービスの実際の使用量や消費量に基づいて請求される料金モデル | | payUpFront | プロダクト/サービスを受け取る前に請求される料金モデル | | freeTrial | 無料トライアル期間中のユーザー | | unknown | 料金モデルが定義されていない | ### AdaptyPeriodUnitEnum 期間を計測する単位を定義します。 | フィールド名 | 説明 | | ---------- | ----------- | | day | 日単位 | | week | 週単位 | | month | 月単位 | | year | 年単位 | | unknown | 未定義 | ### AdaptyRenewalTypeEnum サブスクリプションが自動更新かどうかを定義します。 | フィールド名 | 説明 | | ------------- | -------------------------------------------- | | prepaid | サブスクリプションはプリペイドで、自動更新ではありません。 | | autorenewable | サブスクリプションは自動更新です。 | ### AdaptySubscriptionUpdateReplacementMode Androidのサブスクリプション更新モードを定義します。 | フィールド名 | 説明 | | ------------- | --------------------------------------------------- | | withTimeProration | (デフォルト)新しいプランはすぐに有効になり、残り期間は日割り計算されてユーザーにクレジットされます。 | | chargeProratedPrice | 新しいプランはすぐに有効になり、請求サイクルはそのまま維持されます。残り期間分の料金が請求されます。このオプションはサブスクリプションのアップグレード時のみ使用できます。 | | withoutProration | 新しいプランはすぐに有効になり、次回の更新タイミングで新しい料金が請求されます。請求サイクルはそのまま維持されます。 | | deferred | 新しい購入はすぐに有効になり、古いアイテムの有効期限が切れた時点で新しいプランが適用されます。 | | chargeFullPrice | 新しいプランはすぐに有効になり、請求サイクルはそのまま維持されます。残り期間分の料金が請求されます。このオプションはサブスクリプションのアップグレード時のみ使用できます。 | ### アプリの状態 \{#app-states\} アプリ状態変数は、アプリケーションの現在の状態を保持する特別な変数です。すべてのページやコンポーネントにわたってアプリ全体からアクセス・変更できます。この種の変数は、ユーザー設定や認証トークンなど、アプリのさまざまな部分で共有する必要があるデータを保存する際に役立ちます。 | フィールド名 | データ型 | 永続化 | 説明 | | -------------- | -------------------------------------------------- | --------- | ------------------------------------------------------------ | | currentProfile | Data ([AdaptyProfile](ff-resources#adaptyprofile)) | False | 現在のユーザープロファイルの情報を格納する変数です。常に最新の状態を保つようにしてください。 | --- # End of Documentation _Generated on: 2026-07-24T13:00:57.841Z_ _Successfully processed: 277/277 files_ # UNITY - 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.848Z Total files: 41 --- # File: sdk-installation-unity --- --- title: "Unity SDKのインストールと設定" description: "サブスクリプションアプリ向けにUnityにAdapty SDKをインストールするためのステップバイステップガイド。" --- Adapty SDK には、Unity アプリへのシームレスな統合のための 2 つの主要モジュールが含まれています: - **Core Adapty**: Adapty をアプリで正しく機能させるために必要な必須 SDK です。 - **AdaptyUI**: クロスプラットフォームのペイウォールを簡単に作成できるノーコードツール、[Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合に必要なモジュールです。 :::tip Adapty SDKがモバイルアプリにどのように統合されるか、実際の例を見てみたい方は、[サンプルアプリ](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Assets)をご確認ください。ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを紹介しています。 ::: ## 必要条件 \{#requirements\} Adapty SDK は iOS 13.0 以上をサポートしていますが、ペイウォールビルダーで作成したペイウォールを使用するには iOS 15.0 以上が必要です。 :::info Adapty は Google Play Billing Library 8.x までに対応しています。デフォルトでは Adapty は Google Play Billing Library v7.0.0 を使用します。新しいバージョンを使用するには、Android ビルドで [Billing の依存関係をオーバーライド](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-Unity.svg?style=flat&logo=unity)](https://github.com/adaptyteam/AdaptySDK-Unity/releases) インストール方法を選択してください: <Tabs groupId="unity-install-method"> <TabItem value="git-url" label="Git URL"> Git URL を使って Unity Package Manager 経由で Adapty SDK をインストールします: 1. Unity で **Window → Package Manager** を開きます。 2. 左上の **+** をクリックし、**Add package from git URL...** を選択します。 3. 以下の URL を入力して **Add** をクリックします: ``` https://github.com/adaptyteam/AdaptySDK-Unity.git?path=Packages/com.adapty.unity-sdk#upm ``` 詳細については、Unityの[Git URLからUPMパッケージをインストールする](https://docs.unity3d.com/Manual/upm-ui-giturl.html)ガイドを参照してください。 </TabItem> <TabItem value="unity-package" label="Unity package" default> GitHubから[`adapty-unity-plugin-*.unitypackage`](https://github.com/adaptyteam/AdaptySDK-Unity/tree/main/Releases)をダウンロードして、プロジェクトにインポートしてください。 <img src="/assets/shared/img/456bd98-adapty-unity-plugin.webp" style={{ border: 'none', /* border width and color */ width: '400px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </TabItem> </Tabs> SDKをインストールしたら、以下の手順を完了してください: 1. [External Dependency Manager (EDM) プラグイン](https://github.com/googlesamples/unity-jar-resolver#getting-started)をインストールします。Adapty SDKはこれを使用して、iOS CocoapodsおよびAndroid gradleの依存関係を管理します。 2. EDMをインストールした後、依存関係マネージャーを手動で実行する必要がある場合があります: `Assets -> External Dependency Manager -> Android Resolver -> Force Resolve` および `Assets -> External Dependency Manager -> iOS Resolver -> Install Cocoapods` 3. Unity プロジェクトを iOS 向けにビルドすると、`Unity-iPhone.xcworkspace` ファイルが生成されます。Cocoapods の依存関係を正しく使用するには、`Unity-iPhone.xcodeproj` ではなく、こちらのファイルを開いてください。 ## 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** はアプリごとに固有です。複数のアプリがある場合は、正しいキーを選択してください。 ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { void Start() { DontDestroyOnLoad(this.gameObject); Adapty.SetEventListener(this); var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); } public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` :::important 他の Adapty SDK メソッドを呼び出す前に、`Activate` の完了コールバックを待つ必要があります。完全な呼び出し順序については、[Unity SDK の呼び出し順序](unity-sdk-call-order) を参照してください。 ::: ## イベントリスナーの設定 \{#set-up-event-listening\} Adapty のイベントを受け取るスクリプトを作成します。シーン内で `AdaptyListener` という名前を付けてください。アプリケーションのライフサイクル全体を通じてオブジェクトが維持されるよう、`DontDestroyOnLoad` メソッドの使用をお勧めします。 <img src="/assets/shared/img/2ccd564-create_adapty_listener.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> Adapty は `AdaptySDK` 名前空間を使用します。Adapty SDK を使用するスクリプトファイルの先頭に以下を追加できます: ```csharp showLineNumbers title="C#" using AdaptySDK; ``` Adapty のイベントを購読します: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle updated profile data } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` AdaptyListenerをDefault Timeより前に配置するよう、Script Execution Orderを調整することをおすすめします。これにより、Adaptyをできるだけ早く初期化できます。 <img src="/assets/shared/img/activate_unity.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 次に、アプリにペイウォールを設定します: - [Adapty ペイウォールビルダー](adapty-paywall-builder)を使用する場合は、まず以下の[AdaptyUI モジュールを有効化](#activate-adaptyui-module-of-adapty-sdk)してから、[ペイウォールビルダーのクイックスタート](unity-quickstart-paywalls)をご覧ください。 - 独自のペイウォール UI を作成する場合は、[カスタムペイウォールのクイックスタート](unity-quickstart-manual)をご覧ください。 ## Adapty SDKのAdaptyUIモジュールを有効化する \{#activate-adaptyui-module-of-adapty-sdk\} [ペイウォールビルダー](adapty-paywall-builder)を使用する予定があり、AdaptyUIモジュールをインストール済みの場合は、AdaptyUIを有効化する必要があります。設定時に有効化できます: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetActivateUI(true); ``` ## オプション設定 \{#optional-setup\} ### ログ設定 \{#logging\} #### ログシステムの設定 \{#set-up-the-logging-system\} Adapty はエラーやその他の重要な情報をログに記録し、状況を把握しやすくします。以下のログレベルが利用できます。 | レベル | 説明 | | ---------- | ------------------------------------------------------------ | | `error` | エラーのみがログに記録されます | | `warn` | エラーと、致命的なエラーではないものの注意が必要なSDKからのメッセージがログに記録されます | | `info` | エラー、警告、および各種情報メッセージがログに記録されます | | `verbose` | 関数呼び出しやAPIクエリなど、デバッグ時に役立つ追加情報がすべてログに記録されます | Adapty の設定時にログレベルを指定できます: ```csharp showLineNumbers title="C#" // 'verbose' is recommended for development and the first production release var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY"); builder.LogLevel = AdaptyLogLevel.Verbose; ``` 実行時にログレベルを変更することも可能です: ```csharp showLineNumbers title="C#" Adapty.SetLogLevel(AdaptyLogLevel.Verbose, (error) => { // handle result }); ``` ### データポリシー \{#data-policies\} Adapty はユーザーの個人データを保存しませんが(明示的に送信した場合を除く)、ストアや国のガイドラインに準拠するために追加のデータセキュリティポリシーを設定できます。 #### IPアドレスの収集と共有を無効化する \{#disable-ip-address-collection-and-sharing\} Adapty モジュールを有効化する際に、`SetIPAddressCollectionDisabled` を `true` に設定すると、ユーザーの IP アドレスの収集と共有を無効化できます。デフォルト値は `false` です。 このパラメータを使用して、ユーザープライバシーを強化し、地域のデータ保護規制(GDPRやCCPAなど)に準拠し、IPベースの機能がアプリに不要な場合の不必要なデータ収集を削減できます。 ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetIPAddressCollectionDisabled(true); ``` #### 広告IDの収集と共有を無効にする \{#disable-advertising-id-collection-and-sharing\} Adapty モジュールを有効化する際に、広告識別子の収集を無効にするには `SetAppleIDFACollectionDisabled` および/または `SetGoogleAdvertisingIdCollectionDisabled` を `true` に設定します。デフォルト値は `false` です。 App Store / Google Play のポリシーへの準拠、App Tracking Transparency プロンプトの表示回避、または広告 ID に基づくアトリビューションや分析が不要な場合に、このパラメーターを使用してください。 ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAppleIDFACollectionDisabled(true) .SetGoogleAdvertisingIdCollectionDisabled(true); ``` #### AdaptyUI のメディアキャッシュ設定 \{#set-up-media-cache-configuration-for-adaptyui\} デフォルトでは、AdaptyUI はパフォーマンス向上とネットワーク使用量の削減のために、画像や動画などのメディアをキャッシュします。カスタム設定を指定することで、キャッシュの設定を変更できます。 デフォルトのキャッシュ設定を上書きするには、`SetAdaptyUIMediaCache` を使用します: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAdaptyUIMediaCache( 100 * 1024 * 1024, // MemoryStorageTotalCostLimit 100MB null, // MemoryStorageCountLimit 100 * 1024 * 1024 // DiskStorageSizeLimit 100MB ); ``` パラメーター: | Parameter | Required | Description | |-----------------------------|----------|----------------------------------------------------------------------------------| | memoryStorageTotalCostLimit | optional | メモリ内のキャッシュ合計サイズ(バイト単位)。デフォルト値はプラットフォームによって異なります。 | | memoryStorageCountLimit | optional | メモリストレージのアイテム数の上限。デフォルト値はプラットフォームによって異なります。 | | diskStorageSizeLimit | optional | ディスク上のファイルサイズの上限(バイト単位)。デフォルト値はプラットフォームによって異なります。 | ### Android でローカルアクセスレベルを有効にする \{#enable-local-access-levels-android\} デフォルトでは、[ローカルアクセスレベル](local-access-levels)は iOS で有効、Android で無効になっています。Android でも有効にするには、`SetGoogleLocalAccessLevelAllowed` を `true` に設定してください。 ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetGoogleLocalAccessLevelAllowed(true); ``` ### バックアップリストア時のデータクリア \{#clear-data-on-backup-restore\} `SetAppleClearDataOnBackup` を `true` に設定すると、SDKはアプリがiCloudバックアップから復元されたことを検出し、キャッシュされたプロファイル情報、プロダクト詳細、ペイウォールなど、ローカルに保存されているすべてのSDKデータを削除します。その後、SDKはクリーンな状態で初期化されます。デフォルト値は `false` です。 :::note 削除されるのはローカルのSDKキャッシュのみです。Appleとのトランザクション履歴およびAdaptyサーバー上のユーザーデータは変更されません。 ::: ```csharp showLineNumbers title="C#" var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetAppleClearDataOnBackup(true); ``` ## トラブルシューティング \{#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` ファイルのルートの `<manifest>` タグに tools が含まれていることを確認してください: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.app"> ... </manifest> ``` #### 2. `<application>` でバックアップ属性を上書きする \{#2-override-backup-attributes-in-application\} 同じ `AndroidManifest.xml` ファイルで、`<application>` タグを更新して、アプリが最終的な値を提供し、マニフェストマージャーにライブラリの値を置き換えるよう指示します: ```xml <application android:name=".App" android:allowBackup="true" android:fullBackupContent="@xml/sample_backup_rules" android:dataExtractionRules="@xml/sample_data_extraction_rules" tools:replace="android:fullBackupContent,android:dataExtractionRules"> ... </application> ``` いずれかの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" <?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </cloud-backup> <device-transfer> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="appsflyer-purchase-data"/> <exclude domain="database" path="afpurchases.db"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> </device-transfer> </data-extraction-rules> ``` **Android 11以前**(従来のフルバックアップコンテンツ形式を使用): ```xml title="sample_backup_rules.xml" <?xml version="1.0" encoding="utf-8"?> <full-backup-content> <exclude domain="sharedpref" path="appsflyer-data"/> <exclude domain="sharedpref" path="AdaptySDKPrefs.xml"/> :::important Unityでは、これらの変更を `Assets/Plugins/Android/AndroidManifest.xml` に適用し、バックアップルールファイルを `Assets/Plugins/Android/res/xml/` 以下に作成してください。 ::: #### Androidで別のアプリから戻った後に購入が失敗する \{#purchases-fail-after-returning-from-another-app-in-android\} 購入フローを開始するActivityに非デフォルトの `launchMode` が設定されている場合、ユーザーがGoogle Play、銀行アプリ、またはブラウザから戻ってきたときに、Androidがそのアcアクティビティを誤って再作成または再利用することがあります。これにより、購入結果が失われたり、キャンセルとして扱われたりする可能性があります。 購入フローを正しく動作させるには、購入フローを開始する Activity のランチモードを `standard` または `singleTop` のみ使用し、それ以外のモードは避けてください。 `AndroidManifest.xml` で、購入フローを開始する Activity のランチモードが `standard` または `singleTop` に設定されていることを確認してください。 ```xml <activity android:name=".MainActivity" android:launchMode="standard" /> ``` #### Android でペイウォール表示時にアプリがクラッシュする \{#app-crashes-when-a-paywall-is-displayed-on-android\} Android でペイウォールを表示したときにアプリがクラッシュする場合、Kotlin プラグインが Gradle の設定に含まれていない可能性があります。追加するには次の手順を実施してください。 1. **Player Settings** で、**Custom Launcher Gradle Template** と **Custom Base Gradle Template** のオプションが選択されていることを確認します。 <img src="/assets/shared/img/kotlin-plugin1.webp" style={{ border: 'none', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. `/Assets/Plugins/Android/launcherTemplate.gradle` に以下の行を追加します。 ```groovy showLineNumbers apply plugin: 'com.android.application' // highlight-next-line apply plugin: 'kotlin-android' apply from: 'setupSymbols.gradle' apply from: '../shared/keepUnitySymbols.gradle' ``` 3. `/Assets/Plugins/Android/baseProjectTemplate.gradle` に以下の行を追加します: ```groovy showLineNumbers plugins { // If you are changing the Android Gradle Plugin version, make sure it is compatible with the Gradle version preinstalled with Unity // See which Gradle version is preinstalled with Unity here https://docs.unity3d.com/Manual/android-gradle-overview.html // See official Gradle and Android Gradle Plugin compatibility table here https://developer.android.com/studio/releases/gradle-plugin#updating-gradle // To specify a custom Gradle version in Unity, go do "Preferences > External Tools", uncheck "Gradle Installed with Unity (recommended)" and specify a path to a custom Gradle version id 'com.android.application' version '8.3.0' apply false id 'com.android.library' version '8.3.0' apply false // highlight-next-line id 'org.jetbrains.kotlin.android' version '1.8.0' apply false **BUILD_SCRIPT_DEPS** } ``` --- # File: unity-quickstart-paywalls --- --- title: "Unity SDK のペイウォールを使って購入を有効にする" description: "Adapty SDK を使って Unity アプリでペイウォールを表示する方法を学ぶ" --- アプリ内課金を有効にするには、3 つの重要な概念を理解する必要があります。 - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセスなど) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定です。Adapty では、プロダクトの取得はペイウォールを通じてのみ行えます。この設計により、アプリのコードを変更せずにオファー内容、価格、プロダクトの組み合わせを変更できます。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings` など)。ダッシュボードでプレースメントに対してペイウォールを設定し、コード内でプレースメント ID を使ってリクエストします。これにより、A/B テストの実施や、ユーザーごとに異なるペイウォールの表示が容易になります。 Adapty では、アプリ内で購入を有効にする 3 つの方法を提供しています。アプリの要件に応じて選択してください。 | 実装方法 | 複雑さ | 使用場面 | |---------------------------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Adapty ペイウォールビルダー | ✅ 簡単 | [ノーコードビルダーで完全な購入対応ペイウォールを作成します](quickstart-paywalls)。Adapty が自動的にレンダリングし、複雑な購入フロー、レシート検証、サブスクリプション管理をすべて裏側で処理します。 | | 手動作成のペイウォール | 🟡 中程度 | ペイウォールの UI をアプリのコードで実装しますが、プロダクトオファーの柔軟性を保つため、Adapty からペイウォールオブジェクトを取得します。[ガイド](unity-quickstart-manual)を参照してください。 | | オブザーバーモード | 🔴 難しい | 独自の購入処理インフラを既に持っており、それを引き続き使用したい場合に選びます。オブザーバーモードには Adapty における制限があることに注意してください。[記事](observer-vs-full-mode)を参照してください。 | :::important **以下の手順は、Adapty ペイウォールビルダーで作成したペイウォールの実装方法を示しています。** ペイウォールビルダーを使用しない場合は、[手動作成ペイウォールでの購入処理ガイド](unity-making-purchases)を参照してください。 ::: Adapty ペイウォールビルダーで作成したペイウォールを表示するには、アプリのコードで以下の手順を実行するだけです。 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-unity)。 :::tip これらの手順を最短で完了するには、[クイックスタートガイド](quickstart)に従うか、[Developer CLI](developer-cli-quickstart) を使ってペイウォールとプレースメントを作成してください。 ::: ## 1. ペイウォールを取得する \{#1-get-the-paywall\} ペイウォールはダッシュボードで設定したプレースメントに紐付けられています。プレースメントを使うと、異なるオーディエンスに対して別々のペイウォールを表示したり、[A/B テスト](ab-tests)を実施したりできます。 Adapty ペイウォールビルダーで作成したペイウォールを取得するには、以下の手順を実行します。 1. `GetPaywall` メソッドを使って[プレースメント](placements) ID から `paywall` オブジェクトを取得し、`HasViewConfiguration` プロパティでビルダーで作成されたペイウォールかどうかを確認します。 2. `CreatePaywallView` メソッドを使ってペイウォールビューを作成します。このビューには、ペイウォールを表示するために必要な UI 要素とスタイルが含まれています。 :::important ビュー設定を取得するには、ペイウォールビルダーで **Show on device** トグルをオンにする必要があります。オフのままにすると、空のビュー設定が返され、ペイウォールが表示されません。 ::: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if(error != null) { // handle the error return; } // Create paywall view parameters var parameters = new AdaptyUICreatePaywallViewParameters(); // Create the paywall view AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { if(error != null) { // handle the error return; } // view - the paywall view ready to be presented }); }); ``` :::info このクイックスタートはペイウォールを表示するための最小限の設定を提供しています。高度な設定の詳細については、[ペイウォールの取得に関するガイド](unity-get-pb-paywalls)を参照してください。 ::: ## 2. ペイウォールを表示する \{#2-display-the-paywall\} ペイウォール設定を取得したら、数行追加するだけでペイウォールを表示できます。 ペイウォールを表示するには、`CreatePaywallView` メソッドで作成した `view` に対して `view.Present()` メソッドを呼び出します。各 `view` は一度しか使用できません。ペイウォールを再度表示する必要がある場合は、`CreatePaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::info ペイウォールの表示方法の詳細については、[ガイド](unity-present-paywalls)を参照してください。 ::: ## 3. ボタンアクションを処理する \{#3-handle-button-actions\} ユーザーがペイウォール内のボタンをクリックすると、Unity SDK が購入と復元を自動的に処理します。ただし、カスタムまたは事前定義された ID を持つその他のボタンについては、コードでアクションを処理する必要があります。 たとえば、ペイウォールには通常、閉じるボタンや開くべき URL(利用規約やプライバシーポリシーなど)があります。これらのアクションを処理するには、クラスが `AdaptyPaywallsEventsListener` インターフェースを実装し、リスナーとして登録する必要があります。 :::tip ボタンの[アクション](unity-handle-paywall-actions)と[イベント](unity-handling-events)の処理方法については、各ガイドを参照してください。 ::: ```csharp showLineNumbers title="Unity" public class YourClass : MonoBehaviour, AdaptyPaywallsEventsListener { void Start() { // Register this class as the paywall events listener Adapty.SetPaywallsEventsListener(this); } // AdaptyPaywallsEventsListener method - handles button actions public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; case AdaptyUIUserActionType.OpenUrl: Application.OpenURL(action.Value); break; default: break; } } } ``` ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備が整いました。[App Store サンドボックス](test-purchases-in-sandbox)または [Google Play ストア](testing-on-android)でテスト購入を行い、ペイウォールからテスト購入を完了できることを確認してください。 次に、[ユーザーのアクセスレベルを確認し](unity-check-subscription-status)、適切なユーザーにペイウォールを表示したり、有料機能へのアクセスを付与したりできるようにする必要があります。 ## 完全な実装例 \{#full-example\} 以下は、すべての手順をアプリに統合した場合の例です。 ```csharp showLineNumbers using System; using UnityEngine; using AdaptySDK; public class PaywallManager : MonoBehaviour, AdaptyPaywallsEventsListener { [SerializeField] private string placementId = "YOUR_PLACEMENT_ID"; private AdaptyUIPaywallView currentPaywallView; void Start() { // Register for paywall events Adapty.SetPaywallsEventsListener(this); GetAndDisplayPaywall(); } private void GetAndDisplayPaywall() { Adapty.GetPaywall(placementId, (paywall, error) => { if (error != null) { Debug.LogError("Error getting paywall: " + error.Message); return; } if (paywall.HasViewConfiguration) { CreateAndPresentPaywallView(paywall); } else { Debug.LogWarning("Paywall was not created using the builder"); } }); } private void CreateAndPresentPaywallView(AdaptyPaywall paywall) { var parameters = new AdaptyUICreatePaywallViewParameters(); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { if (error != null) { Debug.LogError("Error creating paywall view: " + error.Message); return; } currentPaywallView = view; view.Present((presentError) => { if (presentError != null) { Debug.LogError("Error presenting paywall: " + presentError.Message); return; } Debug.Log("Paywall presented successfully"); }); }); } // AdaptyPaywallsEventsListener implementation public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: Debug.Log("Close button pressed"); view.Dismiss(null); break; case AdaptyUIUserActionType.OpenUrl: Application.OpenURL(action.Value); break; default: break; } } // Required interface methods (implement as needed) public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } public void PaywallViewDidSelectProduct(AdaptyUIPaywallView view, string productId) { } public void PaywallViewDidStartPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product) { } public void PaywallViewDidFinishPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult) { } public void PaywallViewDidFailPurchase(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { } public void PaywallViewDidFinishRestore(AdaptyUIPaywallView view, AdaptyProfile profile) { } public void PaywallViewDidFailRestore(AdaptyUIPaywallView view, AdaptyError error) { } public void PaywallViewDidFailRendering(AdaptyUIPaywallView view, AdaptyError error) { } public void PaywallViewDidFailLoadingProducts(AdaptyUIPaywallView view, AdaptyError error) { } public void PaywallViewDidFinishWebPaymentNavigation(AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error) { } public void ShowPaywall() { GetAndDisplayPaywall(); } void OnDestroy() { if (currentPaywallView != null) { currentPaywallView.Dismiss(null); } } } ``` --- # File: unity-check-subscription-status --- --- title: "Unity SDKでサブスクリプションステータスを確認する" description: "AdaptyでUnityアプリのサブスクリプションステータスを確認する方法を学びます。" --- ユーザーが有料コンテンツにアクセスできるか、またはペイウォールを表示するかどうかを判断するには、プロファイル内の[アクセスレベル](access-level)を確認する必要があります。 この記事では、プロファイルの状態にアクセスして、ユーザーにペイウォールを表示するか有料機能へのアクセスを許可するかを判断する方法を説明します。 ## サブスクリプションステータスを取得する \{#get-subscription-status\} ユーザーにペイウォールを表示するか有料コンテンツを表示するかを判断する際は、プロファイル内の[アクセスレベル](access-level)を確認します。2つの方法があります: - アプリ起動時などに最新のプロファイルデータがすぐに必要な場合や、強制的に更新したい場合は `GetProfile` を呼び出します。 - サブスクリプションステータスが変わるたびに自動的に更新されるローカルコピーを保持するために、**プロファイルの自動更新**を設定します。 ### プロファイルを取得する \{#get-profile\} サブスクリプションステータスを取得するもっとも簡単な方法は、`GetProfile` メソッドを使ってプロファイルにアクセスすることです: ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` ### サブスクリプションの更新を受け取る \{#listen-to-subscription-updates\} アプリでプロファイルの更新を自動的に受け取るには: 1. `AdaptyEventListener` を継承して `OnLoadLatestProfile` メソッドを実装します。ユーザーのサブスクリプションステータスが変わると、Adaptyが自動的にこのメソッドを呼び出します。 2. このメソッドが呼び出されたときに更新されたプロファイルデータを保存しておくと、追加のネットワークリクエストなしにアプリ全体で利用できます。 ```csharp public class SubscriptionManager : MonoBehaviour, AdaptyEventListener { private AdaptyProfile currentProfile; void Start() { // Register this object as an Adapty event listener Adapty.SetEventListener(this); } // Store the profile when it updates public void OnLoadLatestProfile(AdaptyProfile profile) { currentProfile = profile; // Update UI, unlock content, etc. } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } // Use stored profile instead of calling getProfile() public bool HasAccess() { if (currentProfile?.AccessLevels != null && currentProfile.AccessLevels.ContainsKey("premium")) { return currentProfile.AccessLevels["premium"].IsActive; } return false; } } ``` :::note Adaptyはアプリ起動時に自動的に `OnLoadLatestProfile` を呼び出し、デバイスがオフラインでもキャッシュされたサブスクリプションデータを提供します。 ::: ## プロファイルとペイウォールロジックを連携させる \{#connect-profile-with-paywall-logic\} ペイウォールの表示や有料機能へのアクセス許可をすぐに判断したい場合は、ユーザーのプロファイルを直接確認できます。この方法は、アプリ起動時、プレミアムセクションに入るとき、特定のコンテンツを表示する前など、さまざまなシナリオで役立ちます。 ```csharp private void CheckAccessLevel() { Adapty.GetProfile((profile, error) => { if (error != null) { Debug.LogError("Error checking access level: " + error.Message); // Show paywall if access check fails return; } var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; if (accessLevel == null || !accessLevel.IsActive) { // Show paywall if no access } }); } private void InitializePaywall() { LoadPaywall(); CheckAccessLevel(); } ``` ## 次のステップ \{#next-steps\} サブスクリプションステータスの追跡方法を確認したら、次は[ユーザープロファイルの操作](unity-quickstart-identify)を学んで、ユーザーが購入したものにアクセスできるようにしましょう。 --- # File: unity-quickstart-identify --- --- title: "Unity SDKでユーザーを識別する" description: "UnityでのアプリNの課金管理のための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**でインストールをカウントする必要があります。この場合、再インストールを含む、デバイスへのアプリインストールのたびにインストールとしてカウントされます。 ## 識別済みユーザー \{#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)をご覧ください。 ::: <img src="/assets/shared/img/identify-diagram.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ### ログイン/サインアップ時 \{#during-loginsignup\} アプリ起動後にユーザーを識別する場合(例:アプリへのログイン後やサインアップ後)、`identify`メソッドを使用してカスタマーユーザーIDを設定します。 - **このカスタマーユーザーIDを以前に使用したことがない**場合、Adaptyは自動的に現在のプロファイルに紐付けます。 - **このカスタマーユーザーIDでユーザーを以前に識別したことがある**場合、AdaptyはそのカスタマーユーザーIDに関連付けられたプロファイルに切り替えて処理を行います。 :::important カスタマーユーザーIDは各ユーザーで一意である必要があります。パラメータ値をハードコードすると、すべてのユーザーが同一人物として扱われます。 ::: 他のSDKメソッドを呼び出す前に、`Identify`の完了コールバックを待ってください。同時に呼び出すと`#3006 profileWasChanged`が発生するか、匿名プロファイルに対して処理が行われます。詳細は[Unity SDKの呼び出し順序](unity-sdk-call-order)をご覧ください。 ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { // Unique for each user if(error == null) { // successful identify } }); ``` ### SDKアクティベーション時 \{#during-the-sdk-activation\} SDKをアクティベートする際にすでにカスタマーユーザーIDがわかっている場合は、`identify`を別途呼び出す代わりに、`activate`メソッドに渡すことができます。 カスタマーユーザーIDがわかっているのにアクティベーション後にのみ設定する場合、アクティベーション時にAdaptyが新しい匿名プロファイルを作成し、`identify`を呼び出した後にのみ既存のプロファイルに切り替わります。 既存のカスタマーユーザーID(以前に使用したもの)または新しいものを渡すことができます。新しいものを渡すと、アクティベーション時に作成された新しいプロファイルが自動的にそのカスタマーユーザーIDに紐付けられます。 :::note デフォルトでは、匿名プロファイルの作成はアナリティクスダッシュボードに影響しません。インストールはデバイスIDに基づいてカウントされるためです。 デバイスIDはデバイスへのアプリのストアからの単一インストールを表し、アプリの再インストール後にのみ再生成されます。 初回インストールか再インストールか、または既存のカスタマーユーザーIDが使用されているかどうかには依存しません。 プロファイルの作成(SDKのアクティベーション時またはログアウト時)、ログイン、またはアプリの再インストールなしのアップグレードは、追加のインストールイベントを生成しません。 デバイスではなく一意のユーザーに基づいてインストールをカウントしたい場合は、**App settings**に移動して[**Installs definition for analytics**](general#4-installs-definition-for-analytics)を設定してください。 ::: ```csharp showLineNumbers using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID"); // Customer user IDs must be unique for each user. If you hardcode the parameter value, all users will be considered as one. Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` ### ユーザーをログアウトする \{#log-users-out\} ユーザーをログアウトさせるボタンがある場合は、`logout`メソッドを使用します。 :::important ユーザーをログアウトすると、そのユーザーの新しい匿名プロファイルが作成されます。 ::: ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // successful logout } }); ``` :::info ユーザーをアプリに再度ログインさせるには、`identify`メソッドを使用します。 ::: ### ログインなしでの購入を許可する \{#allow-purchases-without-login\} ユーザーがアプリへのログイン前後の両方で購入できる場合、ログイン後もアクセスが維持されるよう対応が必要です。 1. ログアウト状態のユーザーが購入すると、AdaptyはそれをそのユーザーのアノニマスプロファイルIDに紐付けます。 2. ユーザーがアカウントにログインすると、Adaptyはその識別済みプロファイルへの処理に切り替えます。 - 新しいカスタマーユーザーIDの場合(例:登録前に購入が行われた場合)、Adaptyはカスタマーユーザーをを現在のプロファイルに割り当てるため、すべての購入履歴が維持されます。 - 既存のカスタマーユーザーIDの場合(カスタマーユーザーIDがすでにプロファイルに紐付けられている場合)、プロファイルの切り替え後に実際のアクセスレベルを取得する必要があります。識別後すぐに[`getProfile`](unity-check-subscription-status)を呼び出すか、[プロファイルの更新をリッスン](unity-check-subscription-status)してデータを自動的に同期させることができます。 ## 次のステップ \{#next-steps\} おめでとうございます!アプリにアプリ内課金のロジックを実装できました!アプリの収益化がうまくいくことを願っています! Adaptyをさらに活用するために、以下のトピックも探ってみてください。 - [**テスト**](troubleshooting-test-purchases): すべてが期待どおりに動作することを確認する - [**オンボーディング**](onboardings): オンボーディングでユーザーを引き込み、継続率を高める - [**インテグレーション**](configuration): マーケティングアトリビューションや分析サービスをたった1行のコードで統合する - [**カスタムプロファイル属性を設定する**](unity-setting-user-attributes): ユーザープロファイルにカスタム属性を追加してセグメントを作成し、A/B テストを実施したり、異なるユーザーに異なるペイウォールを表示したりする --- # File: adapty-sdk-integration-skill-unity --- --- title: "SDKインテグレーションスキルを使ってAdaptyをUnityアプリに統合する" description: "adapty-sdk-integrationスキルを使用して、AIコーディングツールでAdapty SDKをUnityアプリにエンドツーエンドで統合します。" --- :::important このスキルはベータ版です。スキルが途中で止まったり予期しない動作をする場合は、代わりに[ステップバイステップの統合ガイド](adapty-cursor-unity)を参照してください。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-unity --- --- title: "AIアシスタンスを使ってUnityアプリにAdaptyを統合する" description: "Cursor、Context7、ChatGPT、Claude、その他のAIツールを使用して、UnityアプリにAdaptyを統合するためのステップバイステップガイド。" --- このガイドでは、AIコーディングツールを使ってUnityアプリにAdaptyを段階的に統合する手順を説明します。適切な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** に移動し、Unityアプリが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("YOUR_PLACEMENT_ID")` に渡す文字列になります。 [ペイウォールを作成する](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サーバーです。質問の内容に基づいて適切なドキュメントを自動的に取得するため、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 Unity SDK ``` :::warning Context7を使うとドキュメントのリンクを手動で貼り付ける必要がなくなりますが、実装の順序は重要です。すべてが正しく動作するよう、以下の[実装ウォークスルー](#implementation-walkthrough)をステップ順に進めてください。 ::: ### プレーンテキストのドキュメントを使う \{#use-plain-text-docs\} AdaptyのドキュメントはプレーンテキストのMarkdownとしてアクセスできます。URLの末尾に `.md` を追加するか、記事タイトルの下にある **Copy for LLM** をクリックしてください。例:[adapty-cursor-unity.md](https://adapty.io/docs/ja/adapty-cursor-unity.md)。 以下の[実装ウォークスルー](#implementation-walkthrough)の各ステージには、貼り付け用の `.md` リンクを含む「LLMに送信するもの」ブロックが含まれています。 より多くのドキュメントが必要な場合は、以下の[インデックスファイルとプラットフォーム別サブセット](#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が自動的にレンダリングします。 - [**手動で作成したペイウォール**](unity-making-purchases): コードで独自のペイウォールUIを構築しますが、プロダクトの取得と購入処理にはAdaptyを使用します。 - [**オブザーバーモード**](observer-vs-full-mode): 既存の購入インフラを維持し、アナリティクスと統合のみにAdaptyを使用します。 どれを選べばいいか迷っていますか?[クイックスタートの比較表](unity-quickstart-paywalls)を読んでください。 ### SDKをインストールして設定する \{#install-and-configure-the-sdk\} Unity Package ManagerでAdapty SDKパッケージを追加し、Public SDKキーで有効化します。これが基盤となり、他のすべての機能はこれなしでは動作しません。 **ガイド:** [Adapty SDKをインストールして設定する](sdk-installation-unity) LLMに送信するもの: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/sdk-installation-unity.md ``` :::tip[チェックポイント] - **期待される結果:** プロジェクトがビルドされ実行されます。UnityコンソールにAdaptyのアクティベーションログが表示されます。 - **注意点:** 「Public API key is missing」→ プレースホルダーをApp settingsの実際のキーに置き換えたか確認してください。 ::: ### ペイウォールを表示して購入を処理する \{#show-paywalls-and-handle-purchases\} プレースメントIDでペイウォールを取得し、表示して、購入イベントを処理します。必要なガイドは購入の処理方法によって異なります。 進めながらサンドボックスで各購入をテストしてください。最後まで待たないようにしましょう。設定手順については[サンドボックスで購入をテストする](test-purchases-in-sandbox)を参照してください。 <Tabs groupId="paywall-approach"> <TabItem value="builder" label="Paywall Builder" default> **ガイド:** - [ペイウォールを使って購入を有効にする(クイックスタート)](unity-quickstart-paywalls) - [ペイウォールビルダーのペイウォールと設定を取得する](unity-get-pb-paywalls) - [ペイウォールを表示する](unity-present-paywalls) - [ペイウォールイベントを処理する](unity-handling-events) - [ボタンアクションに応答する](unity-handle-paywall-actions) LLMに送信するもの: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/unity-quickstart-paywalls.md - https://adapty.io/docs/ja/unity-get-pb-paywalls.md - https://adapty.io/docs/ja/unity-present-paywalls.md - https://adapty.io/docs/ja/unity-handling-events.md - https://adapty.io/docs/ja/unity-handle-paywall-actions.md ``` :::tip[チェックポイント] - **期待される結果:** 設定したプロダクトとともにペイウォールが表示されます。プロダクトをタップするとサンドボックスの購入ダイアログが表示されます。 - **注意点:** ペイウォールが空または `GetPaywall` エラー → プレースメントIDがダッシュボードと完全に一致しているか、またプレースメントにオーディエンスが割り当てられているか確認してください。 ::: </TabItem> <TabItem value="manual" label="Manual paywalls"> **ガイド:** - [カスタムペイウォールで購入を有効にする(クイックスタート)](unity-quickstart-manual) - [ペイウォールとプロダクトを取得する](fetch-paywalls-and-products-unity) - [リモートコンフィグで設計されたペイウォールをレンダリングする](present-remote-config-paywalls-unity) - [購入を行う](unity-making-purchases) - [購入を復元する](unity-restore-purchase) LLMに送信するもの: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/unity-quickstart-manual.md - https://adapty.io/docs/ja/fetch-paywalls-and-products-unity.md - https://adapty.io/docs/ja/present-remote-config-paywalls-unity.md - https://adapty.io/docs/ja/unity-making-purchases.md - https://adapty.io/docs/ja/unity-restore-purchase.md ``` :::tip[チェックポイント] - **期待される結果:** カスタムペイウォールにAdaptyから取得したプロダクトが表示されます。プロダクトをタップするとサンドボックスの購入ダイアログが表示されます。 - **注意点:** プロダクト配列が空 → ダッシュボードでペイウォールにプロダクトが割り当てられているか、またプレースメントにオーディエンスが設定されているか確認してください。 ::: </TabItem> <TabItem value="observer" label="Observer mode"> **ガイド:** - [オブザーバーモードの概要](observer-vs-full-mode) - [オブザーバーモードを実装する](implement-observer-mode-unity) - [オブザーバーモードでトランザクションを報告する](report-transactions-observer-mode-unity) 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-unity.md - https://adapty.io/docs/ja/report-transactions-observer-mode-unity.md ``` :::tip[チェックポイント] - **期待される結果:** 既存の購入フローでサンドボックス購入を行った後、Adapty ダッシュボードの **Event Feed** にトランザクションが表示されます。 - **注意点:** イベントが表示されない → トランザクションをAdaptyに報告しているか確認し、両ストアのサーバー通知が設定されているか確認してください。 ::: </TabItem> </Tabs> ### サブスクリプションのステータスを確認する \{#check-subscription-status\} 購入後、ユーザープロファイルのアクティブなアクセスレベルを確認してプレミアムコンテンツへのアクセスを制御します。 **ガイド:** [サブスクリプションのステータスを確認する](unity-check-subscription-status) LLMに送信するもの: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/unity-check-subscription-status.md ``` :::tip[チェックポイント] - **期待される結果:** サンドボックスで購入した後、`profile.AccessLevels["premium"]?.IsActive` が `true` を返します。 - **注意点:** 購入後に `AccessLevels` が空 → ダッシュボードでプロダクトにアクセスレベルが割り当てられているか確認してください。 ::: ### ユーザーを識別する \{#identify-users\} アプリのユーザーアカウントをAdaptyプロファイルに紐付けて、デバイスをまたいで購入情報が保持されるようにします。 :::important アプリに認証機能がない場合はこのステップをスキップしてください。 ::: **ガイド:** [ユーザーを識別する](unity-quickstart-identify) LLMに送信するもの: ``` Read these Adapty docs before writing code: - https://adapty.io/docs/ja/unity-quickstart-identify.md ``` :::tip[チェックポイント] - **期待される結果:** `Adapty.Identify("your-user-id")` を呼び出した後、ダッシュボードの **Profiles** セクションにカスタムユーザーIDが表示されます。 - **注意点:** 匿名プロファイルのアトリビューションを防ぐため、`Identify` はアクティベーション後、ペイウォール取得前に呼び出してください。 ::: ### リリースの準備をする \{#prepare-for-release\} サンドボックスで統合が正常に動作したら、リリースチェックリストを確認してすべてが本番環境に対応しているか確認します。 **ガイド:** [リリースチェックリスト](release-checklist) LLMに送信するもの: ``` Read these Adapty docs before releasing: - https://adapty.io/docs/ja/release-checklist.md ``` :::tip[チェックポイント] - **期待される結果:** すべてのチェックリスト項目が確認済み:ストア接続、サーバー通知、購入フロー、アクセスレベルの確認、プライバシー要件。 - **注意点:** サーバー通知が未設定 → **App 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つのファイルにまとめたものです。非常に大きなファイルのため、全体像が必要な場合のみ使用してください。 - Unity専用の [`unity-llms.txt`](https://adapty.io/docs/ja/unity-llms.txt) と [`unity-llms-full.txt`](https://adapty.io/docs/ja/unity-llms-full.txt): サイト全体と比べてトークンを節約できるプラットフォーム別サブセットです。 --- # File: unity-get-pb-paywalls --- --- title: "Unity SDKでペイウォールビルダーのペイウォールと設定を取得する" description: "Adaptyでペイウォールビルダーのペイウォールを取得し、Unityアプリのサブスクリプション管理を改善する方法を学びます。" --- Adapty ダッシュボードの新しいペイウォールビルダーで[ペイウォールのビジュアルを設計](adapty-paywall-builder)したら、モバイルアプリに表示できます。まずは、プレースメントに関連付けられたペイウォールとそのビュー設定を取得する必要があります。 :::warning 新しいペイウォールビルダーは Unity SDK バージョン 3.3.0 以降で動作します。 ::: このトピックはペイウォールビルダーでカスタマイズされたペイウォールに関するものです。ペイウォールを手動で実装する場合は、[モバイルアプリでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する](fetch-paywalls-and-products-unity)をご参照ください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールを表示する前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成](create-product)します。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトを追加](create-paywall)します。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールを追加](create-placement)します。 4. モバイルアプリに [Adapty SDK](sdk-installation-unity) をインストールします。 </details> ## ペイウォールビルダーで設計したペイウォールを取得する \{#fetch-paywall-designed-with-paywall-builder\} [ペイウォールビルダーでペイウォールを設計](adapty-paywall-builder)した場合、ユーザーに表示するためにモバイルアプリのコードでレンダリング処理を書く必要はありません。このようなペイウォールには、表示内容と表示方法の両方が含まれています。ただし、プレースメントからペイウォールのIDを取得し、ビュー設定を取得してからモバイルアプリに表示する必要があります。 最適なパフォーマンスを確保するために、ペイウォールと[ビュー設定](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder)はできるだけ早く取得し、ユーザーに表示する前に画像のダウンロードに十分な時間を確保することが重要です。 ペイウォールを取得するには、`GetPaywall` メソッドを使用します: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライズ](add-paywall-locale-in-adapty-paywall-builder)の識別子。マイナス(**-**)文字で区切られた1つまたは2つのサブタグからなる言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p>ロケールコードと推奨される使用方法については、[ローカライズとロケールコード](localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDKはサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーの接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合はそれを返すことを検討してください。この場合、最新のデータが得られないことがありますが、接続状況にかかわらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動クリーンアップ時にのみクリアされます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存します:上述の定期更新キャッシュと[フォールバックペイウォール](fallback-paywalls)です。また、CDNを使用してペイウォールをより高速に取得し、CDNが利用できない場合のためにスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウトを制限する値です。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p>内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間より少し遅くタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | | :-------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォール識別子、リモートコンフィグ、その他のプロパティを含む [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) オブジェクト。 | ## ペイウォールビルダーで設計したペイウォールのビュー設定を取得する \{#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder\} :::important ペイウォールビルダーで **Show on device** トグルが有効になっていることを確認してください。このオプションがオンになっていない場合、ビュー設定を取得できません。 ::: ペイウォールを取得したら、`ViewConfiguration` が含まれているかどうかを確認します。これはペイウォールビルダーで作成されたことを示します。`ViewConfiguration` が存在する場合はペイウォールビルダーのペイウォールとして扱い、存在しない場合は[リモートコンフィグペイウォールとして処理](present-remote-config-paywalls-unity)します。 Unity SDK では、ビュー設定を手動で取得せずに、直接 `CreatePaywallView` メソッドを呼び出します。 :::warning `CreatePaywallView` メソッドの結果は1回のみ使用できます。再度使用する必要がある場合は、`CreatePaywallView` メソッドを再度呼び出してください。再作成せずに2回呼び出すと、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```csharp showLineNumbers var parameters = new AdaptyUICreatePaywallViewParameters() .SetPreloadProducts(preloadProducts) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | :------------------ | :------------- | :----------------------------------------------------------- | | **paywall** | 必須 | 対象のペイウォールのコントローラーを取得するための `AdaptyPaywall` オブジェクト。 | | **loadTimeout** | デフォルト: 5秒 | このメソッドのタイムアウトを制限する値です。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。内部で複数のリクエストが発生する場合があるため、まれに `loadTimeout` で指定した時間より少し遅くタイムアウトすることがあります。 | | **PreloadProducts** | 任意 | `AdaptyPaywallProducts` の配列を提供して、画面上のプロダクト表示タイミングを最適化します。`nil` が渡された場合、AdaptyUI は必要なプロダクトを自動的に取得します。 | | **CustomTags** | 任意 | カスタムタグとその解決済みの値の辞書を定義します。カスタムタグはペイウォールコンテンツのプレースホルダーとして機能し、ペイウォール内のパーソナライズされたコンテンツのために特定の文字列に動的に置き換えられます。詳細はペイウォールビルダーのカスタムタグのトピックを参照してください。 | | **CustomTimers** | 任意 | カスタムタイマーとその終了日時の辞書を定義します。カスタムタイマーを使用すると、ペイウォールにカウントダウンタイマーを表示できます。 | :::note 複数の言語を使用する場合、[ペイウォールビルダーのローカライズ](add-paywall-locale-in-adapty-paywall-builder)を追加する方法と、ロケールコードを正しく使用する方法を[こちら](localizations-and-locale-codes)で確認してください。 ::: ビューを取得したら、[ペイウォールを表示](unity-present-paywalls)します。 ## アセットをカスタマイズする \{#customize-assets\} ペイウォール内の画像や動画をカスタマイズするには、カスタムアセットを実装します。 ヒーロー画像と動画には事前定義されたID(`hero_image` と `hero_video`)があります。カスタムアセットバンドルでは、これらのIDでターゲット要素を指定してカスタマイズします。 その他の画像や動画については、Adapty ダッシュボードで[カスタムIDを設定](custom-media)する必要があります。 例えば、以下のことができます: - 一部のユーザーに異なる画像や動画を表示する。 - リモートのメイン画像の読み込み中にローカルのプレビュー画像を表示する。 - 動画再生前にプレビュー画像を表示する。 :::important この機能を使用するには、Adapty Unity SDK をバージョン 3.8.0 以降に更新してください。 ::: シンプルな辞書でカスタムアセットを提供する例: ```csharp showLineNumbers var customAssets = new Dictionary<string, AdaptyCustomAsset> { { "custom_image", AdaptyCustomAsset.LocalImageFile("custom_assets/images/custom_image.png") }, { "hero_video", AdaptyCustomAsset.LocalVideoFile("custom_assets/videos/custom_video.mp4") } }; var parameters = new AdaptyUICreatePaywallViewParameters() .SetCustomAssets(customAssets) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` :::note アセットが見つからない場合、ペイウォールはデフォルトの表示にフォールバックします。 ::: ## 開発者定義のタイマーを設定する \{#set-up-developer-defined-timers\} Unity アプリでカスタムタイマーを使用するには、タイマーIDと終了日時の辞書を `SetCustomTimers` メソッドに直接渡します。以下に例を示します: ```csharp showLineNumbers var customTimers = new Dictionary<string, DateTime> { { "CUSTOM_TIMER_6H", DateTime.Now.AddHours(6) }, { "CUSTOM_TIMER_NY", new DateTime(2025, 1, 1) } }; var parameters = new AdaptyUICreatePaywallViewParameters() .SetCustomTimers(customTimers) .SetLoadTimeout(new TimeSpan(0, 0, 3)); AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { // handle the result }); ``` この例では、`CUSTOM_TIMER_NY` と `CUSTOM_TIMER_6H` は Adapty ダッシュボードで設定した開発者定義タイマーの **Timer ID** です。タイマーリゾルバーにより、アプリは各タイマーを正しい値で動的に更新します。例えば: - `CUSTOM_TIMER_NY`:元旦などのタイマー終了までの残り時間。 - `CUSTOM_TIMER_6H`:ユーザーがペイウォールを開いてから始まる6時間の残り時間。 ## デフォルトオーディエンスのペイウォールでペイウォール取得を高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ即座に取得されるため、このプロセスを高速化することを心配する必要はありません。ただし、オーディエンスやペイウォールが多数あり、ユーザーのインターネット接続が弱い場合、ペイウォールの取得に想定より時間がかかることがあります。そのような場合、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したいことがあります。 これに対応するために、`GetPaywallForDefaultAudience` メソッドを使用できます。このメソッドは **All Users** オーディエンスの指定されたプレースメントのペイウォールを取得します。ただし、推奨されるアプローチは上記の[ペイウォールを取得する](#fetch-paywall)セクションで詳述されている `getPaywall` メソッドを使用することであることを理解しておくことが重要です。 :::warning `GetPaywallForDefaultAudience` の代わりに `GetPaywall` の使用を検討してください。前者には重要な制限があります: - **互換性の問題**:複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のあるデザインを作成するか、古いバージョンで正しく表示されないことを許容する必要があります。 - **パーソナライズなし**:「All Users」オーディエンスのコンテンツのみが表示され、国、アトリビューション、カスタム属性に基づくターゲティングが利用できません。 ユースケースにおいて高速な取得がこれらのデメリットを上回る場合は、以下のように `GetPaywallForDefaultAudience` を使用してください。それ以外の場合は、[上記](#fetch-paywall)で説明した `GetPaywall` を使用してください。 ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>ペイウォールのローカライズの識別子。マイナス(**-**)文字で区切られた1つまたは2つのサブタグからなる言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDKはサーバーからデータの読み込みを試み、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーの接続が不安定な場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合はそれを返すことを検討してください。この場合、最新のデータが得られないことがありますが、接続状況にかかわらず読み込み時間が短縮されます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動クリーンアップ時にのみクリアされます。</p><p></p><p>Adapty SDK はペイウォールをローカルに2層で保存します:上述の定期更新キャッシュとフォールバックペイウォールです。また、CDNを使用してペイウォールをより高速に取得し、CDNが利用できない場合のためにスタンドアロンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも常に最新バージョンのペイウォールを取得できるよう設計されています。</p> | --- # File: unity-present-paywalls --- --- title: "ペイウォールを表示する" description: "Adapty SDK を使用して Unity アプリでペイウォールを表示する方法を学びましょう。" --- ペイウォールビルダーを使ってペイウォールをカスタマイズしている場合、モバイルアプリのコード内でユーザーに表示するためのレンダリング処理は不要です。このようなペイウォールには、表示する内容と表示方法の両方が含まれています。 :::warning このガイドは、Adapty SDK 3.3.0 以降が必要な**新しいペイウォールビルダー**を対象としています。 リモートコンフィグのペイウォールを表示する場合は、[リモートコンフィグで設計したペイウォールのレンダリング](present-remote-config-paywalls)を参照してください。 ::: ペイウォールを表示するには、[`CreatePaywallView`](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) メソッドで作成した `view` に対して `view.Present()` メソッドを使用します。各 `view` は一度しか使用できません。ペイウォールを再度表示する必要がある場合は、`CreatePaywallView` をもう一度呼び出して新しい `view` インスタンスを作成してください。 :::warning `view` を再作成せずに再利用すると、`AdaptyUIError.viewAlreadyPresented` エラーが発生する場合があります。 ::: ```csharp showLineNumbers title="Unity" view.Present((error) => { // handle the error }); ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## ダイアログを表示する \{#show-dialog\} Android でペイウォールビューが表示されている場合は、ネイティブのアラートダイアログの代わりにこのメソッドを使用してください。Android では、通常のアラートはペイウォールビューの背面に表示されるため、ユーザーには見えません。このメソッドを使用すると、すべてのプラットフォームでペイウォールの上に正しくダイアログが表示されます。 ```csharp showLineNumbers title="Unity" var dialog = new AdaptyUIDialogConfiguration() .SetTitle("Close paywall?") .SetContent("You will lose access to exclusive offers.") .SetDefaultActionTitle("Stay") .SetSecondaryActionTitle("Close"); AdaptyUI.ShowDialog(view, dialog, (action, error) => { if (error == null) { if (action == AdaptyUIDialogActionType.Secondary) { // User confirmed - close the paywall view.Dismiss(); } // If primary - do nothing, user stays } }); ``` ## iOS の表示スタイルを設定する \{#configure-ios-presentation-style\} `Present()` メソッドに `iosPresentationStyle` パラメーターを渡すことで、iOS でのペイウォールの表示方法を設定できます。パラメーターには `AdaptyUIIOSPresentationStyle.FullScreen`(デフォルト)または `AdaptyUIIOSPresentationStyle.PageSheet` を指定できます。 ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` --- # File: unity-handle-paywall-actions --- --- title: "Unity SDKでボタンアクションに応答する" description: "AdaptyのUnityでペイウォールのボタンアクションを処理して、アプリのマネタイズを改善します。" --- Adaptyのペイウォールビルダーを使ってペイウォールを作成する場合、ボタンを適切に設定することが重要です。 1. [ペイウォールビルダーでボタンを追加](paywall-buttons)し、既存のアクションを割り当てるか、カスタムアクションIDを作成します。 2. 割り当てた各アクションを処理するコードをアプリに実装します。 このガイドでは、カスタムアクションと既存のアクションをコードで処理する方法を説明します。 :::warning **購入と復元のみ自動的に処理されます。** ペイウォールを閉じる、リンクを開くなど、その他のボタンアクションはすべて、アプリのコードに適切な処理を実装する必要があります。 ::: ## ペイウォールを閉じる \{#close-paywalls\} ペイウォールを閉じるボタンを追加するには、次の手順に従います。 1. ペイウォールビルダーでボタンを追加し、**Close** アクションを割り当てます。 2. アプリのコードに、ペイウォールを閉じる `close` アクションのハンドラーを実装します。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Close: view.Dismiss(null); break; default: // handle other events break; } } ``` ## ペイウォールからURLを開く \{#open-urls-from-paywalls\} :::tip リンクのグループ(利用規約や購入の復元など)を追加したい場合は、ペイウォールビルダーで **Link** 要素を追加し、**Open URL** アクションが設定されたボタンと同じ方法で処理します。 ::: ペイウォールからリンクを開くボタン(**Terms of use** や **Privacy policy** など)を追加するには、次の手順に従います。 1. ペイウォールビルダーでボタンを追加し、**Open URL** アクションを割り当て、開きたいURLを入力します。 2. アプリのコードに、受け取ったURLをブラウザで開く `openUrl` アクションのハンドラーを実装します。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if(!string.IsNullOrWhiteSpace(urlString)) { Application.OpenURL(urlString); } break; default: // handle other events break; } } ``` ## アプリへのログイン \{#log-into-the-app\} ユーザーをアプリにログインさせるボタンを追加するには、次の手順に従います。 1. ペイウォールビルダーでボタンを追加し、ID `login` の **Custom** アクションを割り当てます。 2. アプリのコードに、ユーザーを識別する `login` カスタムアクションのハンドラーを実装します。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "login") { // Navigate to login scene SceneManager.LoadScene("LoginScene"); } break; default: // handle other events break; } } ``` ## カスタムアクションを処理する \{#handle-custom-actions\} その他のアクションを処理するボタンを追加するには、次の手順に従います。 1. ペイウォールビルダーでボタンを追加し、**Custom** アクションを割り当て、IDを設定します。 2. アプリのコードに、作成したアクションIDのハンドラーを実装します。 たとえば、別のサブスクリプションオファーや買い切り購入がある場合、別のペイウォールを表示するボタンを追加できます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidPerformAction( AdaptyUIPaywallView view, AdaptyUIUserAction action ) { switch (action.Type) { case AdaptyUIUserActionType.Custom: if (action.Value == "openNewPaywall") { // Display another paywall ShowAlternativePaywall(); } break; default: // handle other events break; } } private void ShowAlternativePaywall() { // Implement your logic to show alternative paywall } ``` --- # File: unity-handling-events --- --- title: "ペイウォールイベントの処理" description: "Adapty SDK を使用して Unity アプリでペイウォールイベントを処理する方法を学びましょう。" --- :::important このガイドでは、購入・復元・プロダクト選択・ペイウォールのレンダリングに関するイベント処理を説明します。ボタン操作(ペイウォールを閉じる、リンクを開くなど)の実装も必要です。詳細は[ボタンアクションの処理ガイド](unity-handle-paywall-actions)をご覧ください。 ::: [ペイウォールビルダー](adapty-paywall-builder)で設定されたペイウォールは、購入や復元のために追加コードは不要です。ただし、アプリが応答できるいくつかのイベントが生成されます。これらのイベントには、ボタン操作(閉じるボタン、URL、プロダクト選択など)や、ペイウォール上で行われた購入関連のアクションへの通知が含まれます。以下でこれらのイベントへの対応方法を説明します。 :::warning このガイドは、Adapty SDK v3.3.0 以降が必要な**新しいペイウォールビルダーのペイウォール**専用です。 ::: :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## イベントの処理 \{#handling-events\} モバイルアプリ内のペイウォール画面で発生するプロセスを制御・監視するには、`AdaptyPaywallsEventsListener` インターフェースを実装します。 ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; public class PaywallEventsHandler : MonoBehaviour, AdaptyPaywallsEventsListener { void Start() { Adapty.SetPaywallsEventsListener(this); } // Implement all required interface methods below } ``` ### ユーザーが生成するイベント \{#user-generated-events\} #### ペイウォールの表示 \{#paywall-appeared\} ペイウォールビューが画面に表示されたときに呼び出されます。 :::note iOS では、ユーザーがペイウォール内の[ウェブペイウォールボタン](web-paywall#step-2a-add-a-web-purchase-button)をタップして、インアプリブラウザでウェブペイウォールが開いたときにも呼び出されます。 ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidAppear(AdaptyUIPaywallView view) { } ``` #### ペイウォールの非表示 \{#paywall-disappeared\} ペイウォールビューが画面から閉じられたときに呼び出されます。 :::note iOS では、ペイウォールからインアプリブラウザで開いた[ウェブペイウォール](web-paywall#step-2a-add-a-web-purchase-button)が画面から消えたときにも呼び出されます。 ::: ```csharp showLineNumbers title="Unity" public void PaywallViewDidDisappear(AdaptyUIPaywallView view) { } ``` #### プロダクト選択 \{#product-selection\} プロダクトが購入対象として選択されたとき(ユーザーまたはシステムによる)に呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidSelectProduct( AdaptyUIPaywallView view, string productId ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "productId": "premium_monthly" } ``` </Details> #### 購入開始 \{#started-purchase\} ユーザーが購入プロセスを開始したときに呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" } } ``` </Details> #### 購入成功・キャンセル・保留 \{#successful-canceled-or-pending-purchase\} 購入が成功した場合、ユーザーが購入をキャンセルした場合、または購入が保留中になった場合に、このメソッドが呼び出されます。ユーザーによるキャンセルや保留中の支払い(保護者の承認が必要な場合など)は、`PaywallViewDidFailPurchase` ではなくこのメソッドをトリガーします。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyPurchaseResult purchasedResult ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript // Successful purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Success", "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } } } } } // Cancelled purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "UserCancelled" } } // Pending purchase { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "purchaseResult": { "type": "Pending" } } ``` </Details> その場合は画面を閉じることをお勧めします。 #### 購入失敗 \{#failed-purchase\} エラーにより購入が失敗した場合に、このメソッドが呼び出されます。StoreKit/Google Play Billing のエラー(支払い制限、無効なプロダクト、ネットワーク障害)、トランザクション検証の失敗、システムエラーが含まれます。なお、ユーザーによるキャンセルはキャンセル結果として `PaywallViewDidFinishPurchase` をトリガーし、保留中の支払いはこのメソッドをトリガーしません。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailPurchase( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "purchase_failed", "message": "Purchase failed due to insufficient funds", "details": { "underlyingError": "Insufficient funds in account" } } } ``` </Details> #### 復元開始 \{#started-restore\} ユーザーが復元プロセスを開始したときに呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidStartRestore(AdaptyUIPaywallView view) { } ``` #### 復元成功 \{#successful-restore\} 購入の復元が成功したときに呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishRestore( AdaptyUIPaywallView view, AdaptyProfile profile ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "profile": { "accessLevels": { "premium": { "id": "premium", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } }, "subscriptions": [ { "vendorProductId": "premium_monthly", "isActive": true, "expiresAt": "2024-02-15T10:30:00Z" } ] } } ``` </Details> ユーザーが必要な `accessLevel` を持っている場合は、画面を閉じることをお勧めします。確認方法については、[サブスクリプションのステータス](unity-listen-subscription-changes)を参照してください。 #### 復元失敗 \{#failed-restore\} 購入の復元が失敗したときに呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRestore( AdaptyUIPaywallView view, AdaptyError error ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "restore_failed", "message": "Purchase restoration failed", "details": { "underlyingError": "No previous purchases found" } } } ``` </Details> #### ウェブ支払いナビゲーション完了 \{#finished-web-payment-navigation\} 購入のために[ウェブペイウォール](web-paywall)を開こうとした後(成功・失敗に関わらず)、このメソッドが呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFinishWebPaymentNavigation( AdaptyUIPaywallView view, AdaptyPaywallProduct product, AdaptyError error ) { } ``` **パラメータ:** - `product`: ウェブペイウォールが開かれた(または開こうとした)プロダクト - `error`: ウェブペイウォールが正常に開いた場合は `null`、失敗した場合は `AdaptyError` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript // Successful navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": null } // Failed navigation { "product": { "vendorProductId": "premium_monthly", "localizedTitle": "Premium Monthly", "localizedDescription": "Premium subscription for 1 month", "localizedPrice": "$9.99", "price": 9.99, "currencyCode": "USD" }, "error": { "code": "wrong_param", "message": "Current method is not available for this product", "details": { "underlyingError": "Product not configured for web purchases" } } } ``` </Details> ### データ取得とレンダリング \{#data-fetching-and-rendering\} #### プロダクト読み込みエラー \{#product-loading-errors\} プロダクトの読み込みに失敗し、`AdaptyError` が提供されたときに呼び出されます。初期化時にプロダクト配列を渡さなかった場合、AdaptyUI はサーバーから必要なオブジェクトを自動的に取得します。この処理が失敗した場合、AdaptyUI はこのメソッドを呼び出してエラーを報告します。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailLoadingProducts( AdaptyUIPaywallView view, AdaptyError error ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "products_loading_failed", "message": "Failed to load products from the server", "details": { "underlyingError": "Network timeout" } } } ``` </Details> #### レンダリングエラー \{#rendering-errors\} インターフェースのレンダリング中にエラーが発生し、`AdaptyError` が提供されたときに呼び出されます。 ```csharp showLineNumbers title="Unity" public void PaywallViewDidFailRendering( AdaptyUIPaywallView view, AdaptyError error ) { } ``` <Details> <summary>イベント例(クリックして展開)</summary> ```javascript { "error": { "code": "rendering_failed", "message": "Failed to render paywall interface", "details": { "underlyingError": "Invalid paywall configuration" } } } ``` </Details> 通常の状況ではこのようなエラーは発生しないはずです。もし遭遇した場合はお知らせください。 --- # File: unity-web-paywalls --- --- title: "Unity SDKでWebペイウォールを実装する" description: "App Storeの手数料や審査なしで支払いを受け取るWebペイウォールを設定します。" --- :::important 始める前に、[ダッシュボードでWebペイウォールを設定](web-paywall)し、Adapty SDK バージョン3.14以降をインストールしていることを確認してください。 ::: ## Webペイウォールを開く \{#open-web-paywalls\} 自分で開発したペイウォールを使用している場合は、SDKメソッドでWebペイウォールを処理する必要があります。`Adapty.OpenWebPaywall`メソッドは以下を行います: 1. 特定のユーザーに表示された特定のペイウォールを、リダイレクト先のWebページに紐付けるための一意のURLを生成します。 2. ユーザーがアプリに戻ったタイミングを検知し、短い間隔で`Adapty.GetProfile`をリクエストして、プロファイルのアクセス権が更新されたかどうかを確認します。 これにより、支払いが成功してアクセス権が更新された場合、サブスクリプションはほぼ即座にアプリ内で有効になります。 ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` :::note `OpenWebPaywall`メソッドには2つのバージョンがあります: 1. `OpenWebPaywall(product)` — ペイウォールでURLを生成し、プロダクトデータもURLに追加します。 2. `OpenWebPaywall(paywall)` — プロダクトデータを追加せず、ペイウォールでURLを生成します。AdaptyペイウォールのプロダクトとWebペイウォールのプロダクトが異なる場合に使用してください。 ::: #### エラーの処理 \{#handle-errors\} | エラーコード | 説明 | 推奨アクション | |-----------|--------------------------------------------------------|---------------------------------------------------------------------------| | `AdaptyErrorCode.WrongParam` | ペイウォールまたはプロダクトにWeb購入URLが設定されていない、またはブラウザでURLを開くことができなかった | エラーメッセージで詳細を確認してください。Adapty ダッシュボードでペイウォール/プロダクトの設定を確認するか、デバイスの設定を確認してください。 | | `AdaptyErrorCode.DecodingFailed` | URLのパラメーターを正しくエンコードできなかった | URLパラメーターが有効で適切な形式になっているか確認してください | :::note `WrongParam`は複数の問題(購入URLの欠如、ブラウザを開けないなど)を示す可能性があるため、何が問題だったかの詳細を取得するにはエラーの`Message`プロパティを確認してください。 ::: ## アプリ内ブラウザでWebペイウォールを開く \{#open-web-paywalls-in-an-in-app-browser\} :::important アプリ内ブラウザでWebペイウォールを開く機能は、Adapty SDK v3.15以降でサポートされています。 ::: デフォルトでは、WebペイウォールはアプリのExternalBrowserで開き、ユーザーはアプリの外に移動します。 シームレスなユーザー体験を提供するために、代わりにアプリ内ブラウザでWebペイウォールを開くことができます。これにより、Web購入ページがアプリ内に表示され、ユーザーはアプリを切り替えることなく取引を完了できます。 これを有効にするには、`OpenWebPaywall`メソッドに`AdaptyWebPresentation.InAppBrowser`を渡します: ```csharp showLineNumbers title="Unity" Adapty.OpenWebPaywall( product, AdaptyWebPresentation.InAppBrowser, // default — ExternalBrowser (error) => { if (error != null) { Debug.LogError($"Failed to open web paywall: {error.Message}"); } else { Debug.Log("Web paywall opened successfully"); } } ); ``` --- # File: unity-use-fallback-paywalls --- --- title: "Unity - フォールバックペイウォールの使用" description: "ユーザーがオフラインのとき、またはAdaptyサーバーが利用できないときの処理" --- :::warning フォールバックペイウォールは Unity SDK v2.11 以降でサポートされています。 ::: スムーズなユーザー体験を維持するために、フロー、[ペイウォール](paywalls)、[オンボーディング](onboardings)に[フォールバック](/fallback-paywalls)を設定することが重要です。この対策により、インターネット接続が部分的または完全に失われた場合でも、アプリケーションの機能を維持できます。 * **アプリケーションが Adapty サーバーにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示し、ローカルのオンボーディング設定にアクセスできます。 * **アプリケーションがインターネットにアクセスできない場合:** フォールバックのフローまたはペイウォールを表示できます。オンボーディングはリモートコンテンツを含むため、動作にはインターネット接続が必要です。 :::important このガイドの手順を進める前に、Adapty からフォールバック設定ファイルを[ダウンロード](/local-fallback-paywalls)してください。 ::: ## 設定 \{#configuration\} 1. フォールバック設定ファイルをプロジェクトの共通ディレクトリ `Assets/StreamingAssets` に追加してください。 2. 対象のペイウォールまたはオンボーディングを取得する**前に** `.setFallback` メソッドを呼び出してください。 ```csharp using UnityEngine; using AdaptySDK; #if UNITY_IOS string fileName = "ios_fallback.json"; #elif UNITY_ANDROID string fileName = "android_fallback.json"; #else // Optional: handle Editor or other platforms string fileName = "fallback.json"; #endif Adapty.SetFallback(fileName, (error) => { if (error != null) { Debug.LogError($"Failed to set fallback: {error}"); return; } // Fallback set successfully }); ``` パラメーター: | パラメーター | 説明 | |:-------------|:-----------------------------------------------------| | **fileName** | フォールバック設定ファイルの名前を表す文字列。 | --- # File: unity-localizations-and-locale-codes --- --- title: "Unity SDKでローカライゼーションとロケールコードを使用する" description: "Adapty SDKを使用してUnityアプリのペイウォールをローカライズする方法を説明します。" --- ## なぜこれが重要なのか \{#why-this-is-important\} ロケールコードが関係するシナリオはいくつかあります。たとえば、アプリの現在のローカライゼーションに合った正しいペイウォールを取得しようとする場合などです。 ロケールコードは複雑で、プラットフォームによって異なるため、Adaptyではサポートするすべてのプラットフォームに対して独自の標準を採用しています。ただし、これらのコードが複雑であるがゆえに、サーバーに何を送信して正しいローカライゼーションを取得するのか、そしてその後何が起こるのかを正確に理解することが非常に重要です。そうすれば、常に期待通りの結果を受け取ることができます。 ## AdaptyのロケールコードI標準 \{#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を呼び出す際にそのキーの値を取り出します: ```csharp showLineNumbers // 1. Modify your localization files (e.g., using Unity's Localization package) /* en.json */ { "adapty_paywalls_locale": "en" } /* es.json */ { "adapty_paywalls_locale": "es" } /* pt-BR.json */ { "adapty_paywalls_locale": "pt-br" } // 2. Extract and use the locale code using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.Settings; using AdaptySDK; public class PaywallManager : MonoBehaviour { public async void FetchPaywall() { // Get the current locale from Unity's Localization system var locale = LocalizationSettings.SelectedLocale; var localeCode = GetAdaptyLocaleCode(locale); // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => { if (error != null) { // handle the error return; } // Use the paywall }); } private string GetAdaptyLocaleCode(Locale locale) { // Convert Unity locale to Adapty format var localeIdentifier = locale.Identifier.Code; return localeIdentifier.ToLower().Replace('_', '-'); } } ``` これにより、アプリのすべてのユーザーに対してどのローカライゼーションが取得されるかを完全にコントロールできます。 ## ローカライゼーションの実装:別の方法 \{#implementing-localizations-the-other-way\} すべてのローカライゼーションに対してロケールコードを明示的に定義せずに、同様の(ただし同一ではない)結果を得ることもできます。その場合、プラットフォームが提供する他のオブジェクトからロケールコードを抽出します: ```csharp showLineNumbers using UnityEngine; using System.Globalization; using AdaptySDK; public class PaywallManager : MonoBehaviour { public void FetchPaywall() { var localeCode = GetSystemLocaleCode(); // Pass locale code to Adapty.GetPaywall or Adapty.GetPaywallForDefaultAudience method Adapty.GetPaywall("placement_id", localeCode, (paywall, error) => { if (error != null) { // handle the error return; } // Use the paywall }); } private string GetSystemLocaleCode() { // Get the system's current culture var culture = CultureInfo.CurrentCulture; var languageCode = culture.TwoLetterISOLanguageName; var regionCode = culture.Name.Contains('-') ? culture.Name.Split('-')[1] : null; if (!string.IsNullOrEmpty(regionCode)) { return $"{languageCode}-{regionCode.ToLower()}"; } return languageCode; } } ``` この方法はいくつかの理由からお勧めしません: 1. iOSでは優先言語と現在のロケールは同一ではありません。ローカライゼーションを正しく選択したい場合は、Appleのロジックに頼るか(ローカライズされた文字列ファイルを使った推奨アプローチを使用すれば自動的に機能します)、またはそのロジックを再実装する必要があります。 2. Adaptyのサーバーが受け取る内容を正確に予測することが難しくなります。たとえばiOSでは、デバイスから`ar_OM@numbers='latn'`のようなロケールを取得してサーバーに送信することがあります。この呼び出しに対して、期待していた`ar-om`ローカライゼーションではなく、`ar`が返されることになり、予期しない結果となる可能性があります。 それでもこのアプローチを使用する場合は、関連するユースケースをすべて網羅していることを確認してください。 --- # File: unity-troubleshoot-paywall-builder --- --- title: "Troubleshoot Paywall Builder in Unity SDK" description: "Troubleshoot Paywall Builder in Unity SDK" --- このガイドでは、Unity SDK でAdapty ペイウォールビルダーを使用してデザインしたペイウォールに関する一般的な問題の解決方法を説明します。 ## ペイウォール設定の取得に失敗する \{#getting-a-paywall-configuration-fails\} **問題**: `CreateView` メソッドがペイウォール設定の取得に失敗する。 **原因**: ペイウォールビルダーでデバイス表示が有効になっていない。 **解決策**: ペイウォールビルダーの **Show on device** トグルを有効にしてください。 <img src="/assets/shared/img/show-on-device.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ペイウォールのビュー数が多すぎる \{#the-paywall-view-number-is-too-big\} **問題**: ペイウォールのビュー数が期待値の2倍になっている。 **原因**: コード内で `LogShowPaywall` を呼び出している可能性があります。ペイウォールビルダーを使用している場合、この呼び出しによってビュー数が重複します。ペイウォールビルダーでデザインされたペイウォールでは、アナリティクスが自動的に追跡されるため、このメソッドを使用する必要はありません。 **解決策**: ペイウォールビルダーを使用している場合は、コード内で `LogShowPaywall` を呼び出していないことを確認してください。 ## その他の問題 \{#other-issues\} **問題**: 上記以外のペイウォールビルダー関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](unity-sdk-migration-guides)を参照し、SDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: unity-quickstart-manual --- --- title: "Unity SDKでカスタムペイウォールの購入を有効にする" description: "Adapty SDKをUnityのカスタムペイウォールに統合してアプリ内課金を有効にします。" --- このガイドでは、カスタムペイウォールへのAdapty統合方法を説明します。ペイウォールの実装を完全にコントロールしながら、Adapty SDKがプロダクトの取得、新規購入の処理、過去の購入の復元を担当します。 :::important **このガイドはカスタムペイウォールを実装する開発者向けです。** 購入を最も簡単に有効にする方法をお探しの場合は、[Adapty ペイウォールビルダー](unity-quickstart-paywalls)をご利用ください。ペイウォールビルダーを使えば、ノーコードのビジュアルエディターでペイウォールを作成でき、購入ロジックはAdaptyが自動処理します。また、アプリを再公開することなく異なるデザインをテストできます。 ::: ## 始める前に \{#before-you-start\} ### プロダクトのセットアップ \{#set-up-products\} アプリ内課金を有効にするには、次の3つの重要な概念を理解する必要があります: - [**プロダクト**](product) – ユーザーが購入できるもの(サブスクリプション、消耗型アイテム、永続アクセス) - [**ペイウォール**](paywalls) – どのプロダクトを提供するかを定義する設定。Adaptyではペイウォールがプロダクトを取得する唯一の方法ですが、この設計によりアプリコードを変更せずにプロダクト、価格、オファーを変更できます。 - [**プレースメント**](placements) – アプリ内でペイウォールを表示する場所とタイミング(`main`、`onboarding`、`settings`など)。ダッシュボードでプレースメントにペイウォールを設定し、コード内でプレースメントIDを使ってリクエストします。これにより、A/Bテストの実施や異なるユーザーへの異なるペイウォール表示が簡単になります。 カスタムペイウォールを使う場合でも、これらの概念を理解しておくことが重要です。基本的に、アプリで販売するプロダクトを管理するための手段です。 カスタムペイウォールを実装するには、**ペイウォール**を作成して**プレースメント**に追加する必要があります。この設定によりプロダクトを取得できます。ダッシュボードで何をすべきかを理解するには、[こちら](quickstart)のクイックスタートガイドをご覧ください。 ### ユーザーの管理 \{#manage-users\} バックエンド認証の有無にかかわらず利用できます。 ただし、Adapty SDKは匿名ユーザーと識別済みユーザーを異なる方法で扱います。詳細を確認し、ユーザーを適切に扱うために[識別クイックスタートガイド](unity-quickstart-identify)をお読みください。 ## ステップ1. プロダクトを取得する \{#step-1-get-products\} カスタムペイウォール用のプロダクトを取得するには、次の手順が必要です: 1. `getPaywall`メソッドに[プレースメント](placements)IDを渡して`paywall`オブジェクトを取得します。 2. `getPaywallProducts`メソッドを使ってこのペイウォールのプロダクト配列を取得します。 ```csharp showLineNumbers using AdaptySDK; void LoadPaywall() { Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // Handle the error return; } Adapty.GetPaywallProducts(paywall, (products, productsError) => { if (productsError != null) { // Handle the error return; } // Use products to build your custom paywall UI }); }); } ``` ## ステップ2. 購入を受け付ける \{#step-2-accept-purchases\} ユーザーがカスタムペイウォールでプロダクトをタップしたら、選択されたプロダクトを引数に`makePurchase`メソッドを呼び出します。購入フローが処理され、更新されたプロファイルが返されます。 ```csharp showLineNumbers using AdaptySDK; void PurchaseProduct(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { if (error != null) { // Handle the error return; } switch (result.Type) { case AdaptyPurchaseResultType.Success: var profile = result.Profile; // Purchase successful, profile updated break; case AdaptyPurchaseResultType.UserCancelled: // User canceled the purchase break; case AdaptyPurchaseResultType.Pending: // Purchase is pending (e.g., user will pay offline with cash) break; } }); } ``` ## ステップ3. 購入を復元する \{#step-3-restore-purchases\} アプリストアは、サブスクリプションのあるすべてのアプリに対して、ユーザーが購入を復元できる手段を提供することを要求しています。 ユーザーが復元ボタンをタップしたら`restorePurchases`メソッドを呼び出します。購入履歴がAdaptyと同期され、更新されたプロファイルが返されます。 ```csharp showLineNumbers using AdaptySDK; void RestorePurchases() { Adapty.RestorePurchases((profile, error) => { if (error != null) { // Handle the error return; } // Restore successful, profile updated }); } ``` ## 次のステップ \{#next-steps\} :::tip ご質問やお困りのことがあれば、[サポートフォーラム](https://adapty.featurebase.app/)をご覧ください。よくある質問への回答を見つけたり、ご自身の質問を投稿することができます。チームとコミュニティがサポートいたします! ::: ペイウォールをアプリに表示する準備が整いました。[App Storeサンドボックス](test-purchases-in-sandbox)または[Google Play Store](testing-on-android)でテスト購入を実施して、ペイウォールからテスト購入を完了できることを確認してください。 次に、[ユーザーが購入を完了したかどうか確認](unity-check-subscription-status)して、ペイウォールを表示するか有料機能へのアクセスを許可するかを判断します。 --- # File: fetch-paywalls-and-products-unity --- --- title: "Unity SDKでリモートコンフィグペイウォールのペイウォールとプロダクトを取得する" description: "Adapty Unity SDKでペイウォールとプロダクトを取得し、ユーザーのマネタイズを強化する。" --- リモートコンフィグやカスタムペイウォールを表示する前に、それらの情報を取得する必要があります。このトピックはリモートコンフィグおよびカスタムペイウォールに関するものです。ペイウォールビルダーでカスタマイズしたペイウォールの取得方法については、[ペイウォールビルダーのペイウォールと設定の取得](unity-get-pb-paywalls)を参照してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: <details> <summary>モバイルアプリでペイウォールとプロダクトの取得を始める前に(クリックして展開)</summary> 1. Adapty ダッシュボードで[プロダクトを作成する](create-product)。 2. Adapty ダッシュボードで[ペイウォールを作成し、プロダクトをペイウォールに組み込む](create-paywall)。 3. Adapty ダッシュボードで[プレースメントを作成し、ペイウォールをプレースメントに組み込む](create-placement)。 4. モバイルアプリに[Adapty SDKをインストールする](sdk-installation-unity)。 </details> ## ペイウォール情報の取得 \{#fetch-paywall-information\} Adaptyでは、[プロダクト](product)はApp StoreとGoogle Play両方のプロダクトを組み合わせたものです。これらのクロスプラットフォームプロダクトはペイウォールに統合され、特定のモバイルアプリのプレースメント内で表示できます。 プロダクトを表示するには、`getPaywall` メソッドを使って[プレースメント](placements)のいずれかから[ペイウォール](paywalls)を取得する必要があります。 :::important **プロダクトIDをハードコードしないでください。** ハードコードすべき唯一のIDはプレースメントIDです。ペイウォールはリモートで設定されるため、プロダクトの数や利用可能なオファーはいつでも変わる可能性があります。アプリはこれらの変更を動的に処理する必要があります。今日ペイウォールが2つのプロダクトを返し、明日3つ返しても、コード変更なしにすべて表示できるようにしてください。 ::: ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` | パラメータ | 必須/任意 | 説明 | |---------|--------|-----------| | **placementId** | 必須 | [プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>[ペイウォールのローカライゼーション](add-remote-config-locale)の識別子。このパラメータはマイナス(**-**)文字で区切られた1つ以上のサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p><p></p><p>ロケールコードの詳細と推奨される使い方については、[ローカライゼーションとロケールコード](unity-localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDKはサーバーからデータを読み込もうとし、失敗した場合はキャッシュデータを返します。ユーザーが常に最新のデータを取得できるため、この設定を推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定だと思われる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合に返すことを検討してください。この場合、ユーザーは最新データを取得できないことがありますが、通信状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中のネットワークリクエスト削減に安全に使用できます。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動でのクリア時のみ削除されます。</p><p></p><p>Adapty SDKはペイウォールを2層で保存します。上記の定期更新キャッシュと[フォールバックペイウォール](unity-use-fallback-paywalls)です。また、CDNを使用してペイウォールを高速に取得し、CDNが利用できない場合のスタンドアロンフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な環境でも常に最新バージョンのペイウォールを確実に取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウトを制限します。タイムアウトに達した場合、キャッシュデータまたはローカルフォールバックが返されます。</p><p></p><p>このメソッドは内部で複数のリクエストを実行する場合があるため、まれに `loadTimeout` で指定した時間よりわずかに遅れてタイムアウトすることがあります。</p> | プロダクトIDはハードコードしないでください!ペイウォールはリモートで設定されるため、利用可能なプロダクト、プロダクトの数、特典(無料トライアルなど)は時間とともに変わる場合があります。これらのシナリオをコードで処理するようにしてください。 例えば、最初に2つのプロダクトを取得した場合、アプリはその2つを表示します。後で3つのプロダクトを取得した場合も、コード変更なしにすべての3つを表示できるようにしてください。ハードコードが必要なのはプレースメントIDだけです。 レスポンスパラメータ: | パラメータ | 説明 | | :-------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | | Paywall | プロダクトIDのリスト、ペイウォール識別子、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) オブジェクト。 | ## プロダクトの取得 \{#fetch-products\} ペイウォールを取得したら、対応するプロダクト配列を取得できます: ```csharp showLineNumbers Adapty.GetPaywallProducts(paywall, (products, error) => { if(error != null) { // handle the error return; } // products - the requested products array }); ``` レスポンスパラメータ: | パラメータ | 説明 | | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Products | プロダクト識別子、プロダクト名、価格、通貨、サブスクリプション期間、その他いくつかのプロパティを含む [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) オブジェクトのリスト。 | 独自のペイウォールデザインを実装する場合、[`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) オブジェクトのプロパティへのアクセスが必要になるでしょう。以下によく使用されるプロパティを示しますが、すべての利用可能なプロパティの詳細はリンク先のドキュメントを参照してください。 | プロパティ | 説明 | |-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Title** | プロダクトのタイトルを表示するには `product.LocalizedTitle` を使用してください。ローカライゼーションはデバイス自体のロケールではなく、ユーザーが選択しているストアの国に基づきます。 | | **Price** | ローカライズされた価格を表示するには `product.Price.LocalizedString` を使用してください。このローカライゼーションはデバイスのロケール情報に基づきます。`product.Price.Amount` を使用して価格を数値として取得することもできます。値はローカル通貨で提供されます。関連する通貨記号を取得するには `product.Price.CurrencySymbol` を使用してください。 | | **Subscription Period** | 期間(週、月、年など)を表示するには `product.Subscription?.LocalizedPeriod` を使用してください。このローカライゼーションはデバイスのロケールに基づきます。プログラムでサブスクリプション期間を取得するには `product.Subscription?.Period` を使用してください。そこから `Unit` 列挙型にアクセスして長さを取得できます(`AdaptySubscriptionPeriodUnit.Day`、`AdaptySubscriptionPeriodUnit.Week`、`AdaptySubscriptionPeriodUnit.Month`、`AdaptySubscriptionPeriodUnit.Year`、または `AdaptySubscriptionPeriodUnit.Unknown`)。`NumberOfUnits` の値で期間単位の数を取得できます。例えば、四半期サブスクリプションの場合、Unit プロパティに `AdaptySubscriptionPeriodUnit.Month`、NumberOfUnits プロパティに `3` が表示されます。 | | **Introductory Offer** | サブスクリプションに初回オファーが含まれているかをバッジなどで示すには、`product.Subscription?.Offer?.Phases` プロパティを確認してください。これは最大2つの割引フェーズ(無料トライアルフェーズと初回価格フェーズ)を含むことができるリストです。各フェーズオブジェクトには以下の便利なプロパティが含まれます:<br/>• `PaymentMode`: `AdaptyPaymentMode.FreeTrial`、`AdaptyPaymentMode.PayAsYouGo`、`AdaptyPaymentMode.PayUpFront`、`AdaptyPaymentMode.Unknown` の値を持つ列挙型。無料トライアルは `AdaptyPaymentMode.FreeTrial` 型になります。<br/>• `Price`: 割引価格(数値)。無料トライアルの場合は `0` になります。<br/>• `LocalizedNumberOfPeriods`: オファーの長さをデバイスのロケールでローカライズした文字列。例えば、3日間のトライアルオファーの場合、このフィールドに `"3 days"` が表示されます。<br/>• `SubscriptionPeriod`: オファー期間の個別の詳細をこのプロパティで取得することもできます。オファーに対しても前のセクションと同様に機能します。<br/>• `LocalizedSubscriptionPeriod`: ユーザーのロケールに対応した割引のサブスクリプション期間のフォーマット済み文字列。 | ## デフォルトオーディエンスペイウォールでペイウォール取得を高速化する \{#speed-up-paywall-fetching-with-default-audience-paywall\} 通常、ペイウォールはほぼ即座に取得されるため、このプロセスを高速化することを心配する必要はありません。ただし、多数のオーディエンスやペイウォールがあり、ユーザーのインターネット接続が弱い場合、ペイウォールの取得に予想以上の時間がかかることがあります。そのような状況では、ペイウォールをまったく表示しないよりも、デフォルトのペイウォールを表示してスムーズなユーザー体験を確保したい場合があります。 この問題に対処するには、`GetPaywallForDefaultAudience` メソッドを使用します。このメソッドは **All Users** オーディエンス向けの指定プレースメントのペイウォールを取得します。ただし、上記の[ペイウォールの取得](#fetch-paywall)セクションで詳述した `getPaywall` メソッドでペイウォールを取得することが推奨アプローチであることを理解しておくことが重要です。 :::warning `GetPaywallForDefaultAudience` の代わりに `GetPaywall` の使用を検討してください。前者には以下の重要な制限があります: - **互換性の問題**: 複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のあるデザインが必要か、古いバージョンで表示が崩れることを許容する必要があります。 - **パーソナライゼーションなし**: 「All Users」オーディエンス向けのコンテンツのみ表示され、国、アトリビューション、カスタム属性に基づくターゲティングが無効になります。 ユースケースでこれらのデメリットよりも高速な取得が重要な場合は、以下のように `GetPaywallForDefaultAudience` を使用してください。それ以外の場合は、[上記](#fetch-paywall)で説明した `GetPaywall` を使用してください。 ::: ```csharp showLineNumbers Adapty.GetPaywallForDefaultAudience("YOUR_PLACEMENT_ID", "en", (paywall, error) => { if(error != null) { // handle the error return; } // paywall - the resulting object }); ``` パラメータ: | パラメータ | 必須/任意 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 対象の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>ペイウォールのローカライゼーションの識別子。このパラメータはマイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語、2番目は地域を表します。</p><p></p><p>例: `en` は英語、`pt-br` はブラジルポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDKはサーバーからデータを読み込もうとし、失敗した場合はキャッシュデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーのインターネット接続が不安定だと思われる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータが存在する場合に返すことを検討してください。この場合、ユーザーは最新データを取得できないことがありますが、通信状況に関わらず読み込みが速くなります。キャッシュは定期的に更新されるため、セッション中のネットワークリクエスト削減に安全に使用できます。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリの再インストールまたは手動でのクリア時のみ削除されます。</p><p></p><p>Adapty SDKはペイウォールをローカルに2層で保存します。上記の定期更新キャッシュとフォールバックペイウォールです。また、CDNを使用してペイウォールを高速に取得し、CDNが利用できない場合のスタンドアロンフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な環境でも常に最新バージョンのペイウォールを確実に取得できるよう設計されています。</p> | --- # File: present-remote-config-paywalls-unity --- --- title: "Unity SDKでリモートコンフィグによるペイウォールをレンダリングする" description: "Adapty Unity SDKでリモートコンフィグのペイウォールを表示し、ユーザー体験をパーソナライズする方法を解説します。" --- リモートコンフィグを使ってペイウォールをカスタマイズした場合、ユーザーに表示するためにモバイルアプリのコードでレンダリングを実装する必要があります。リモートコンフィグはニーズに合わせた柔軟性を提供するため、何を含めるか、ペイウォールのビューがどのように表示されるかはすべて開発者が管理します。リモートコンフィグを取得するメソッドを提供しているので、リモートコンフィグで設定したカスタムペイウォールを自由に表示できます。 ## ペイウォールのリモートコンフィグを取得して表示する \{#get-paywall-remote-config-and-present-it\} ペイウォールのリモートコンフィグを取得するには、`remoteConfig` プロパティにアクセスして必要な値を取り出します。 ```csharp showLineNumbers Adapty.GetPaywall("YOUR_PLACEMENT_ID", (paywall, error) => { if (error != null) { // handle the error return; } // Access remote config dictionary var dictionary = paywall.RemoteConfig?.Dictionary; var headerText = dictionary?["header_text"] as string; // Or access raw JSON data var jsonData = paywall.RemoteConfig?.Data; }); ``` 必要な値をすべて取得したら、それらをレンダリングして視覚的に魅力的なページに組み立てます。さまざまなモバイル端末の画面サイズや向きに対応したデザインにして、異なるデバイスでもシームレスで使いやすい体験を提供してください。 :::warning Adapty アナリティクスがファネルや A/B テストのデータを取得できるよう、以下で説明する[ペイウォール表示イベントの記録](present-remote-config-paywalls-unity#track-paywall-view-events)を必ず行ってください。 ::: ペイウォールの表示が完了したら、購入フローの設定に進みます。ユーザーが購入する際は、ペイウォールのプロダクトを引数として `.MakePurchase()` を呼び出すだけです。`.MakePurchase()` メソッドの詳細については、[購入の実装](unity-making-purchases)をご覧ください。 インターネット接続やキャッシュが利用できない場合にユーザーに表示される[フォールバックペイウォールの作成](unity-use-fallback-paywalls)をお勧めします。これにより、そのような状況でもスムーズな体験が確保されます。 ## ペイウォール表示イベントをトラッキングする \{#track-paywall-view-events\} Adapty はペイウォールのパフォーマンス測定をサポートしています。購入データは自動的に収集されますが、ペイウォールの表示ログはユーザーがペイウォールを見たタイミングを把握しているのは開発者だけのため、手動での記録が必要です。 ペイウォール表示イベントをログに記録するには `.LogShowPaywall(paywall)` を呼び出すだけで、ファネルや A/B テストのペイウォール指標に反映されます。 :::important [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールを表示する場合は、`.LogShowPaywall(paywall)` を呼び出す必要はありません。 ::: ```csharp showLineNumbers Adapty.LogShowPaywall(paywall, (error) => { // handle the error }); ``` リクエストパラメーター: | パラメーター | 必須 | 説明 | | :---------- | :------- |:------------------------------------------------------------------| | **paywall** | 必須 | [`AdaptyPaywall`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) オブジェクト。 | --- # File: unity-making-purchases --- --- title: "Unity 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)を使用していますか?** 購入は自動的に処理されるため、このステップは省略できます。 **ステップバイステップのガイドをお探しですか?** エンドツーエンドの実装手順については、[クイックスタートガイド](unity-implement-paywalls-manually)をご確認ください。 ::: ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { switch (result.Type) { case AdaptyPurchaseResultType.Pending: // handle pending purchase break; case AdaptyPurchaseResultType.UserCancelled: // handle purchase cancellation break; case AdaptyPurchaseResultType.Success: var profile = result.Profile; // handle successfull purchase break; default: break; } }); } ``` リクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :---------- | :------- |:------------------------------------------------------------------------------------------------------| | **Product** | 必須 | ペイウォールから取得した [`AdaptyPaywallProduct`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall_product.html) オブジェクト。 | レスポンスパラメーター: | パラメーター | 説明 | |---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>リクエストが成功した場合、このオブジェクトがレスポンスに含まれます。[AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html) オブジェクトは、ユーザーのアクセスレベル、サブスクリプション、アプリ内の買い切り購入に関する包括的な情報を提供します。</p><p>アクセスレベルのステータスを確認して、ユーザーが必要なアクセス権を持っているかどうかを判断してください。</p> | :::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()` メソッドを呼び出します。 ```csharp showLineNumbers // Create subscription update parameters var subscriptionUpdateParams = new AdaptySubscriptionUpdateParameters( "old_product_id", // Product ID of the current subscription AdaptySubscriptionUpdateReplacementMode.WithTimeProration ); Adapty.MakePurchase(product, subscriptionUpdateParams, (profile, error) => { if(error != null) { // Handle the error return; } // successful cross-grade }); ``` 追加のリクエストパラメーター: | パラメーター | 必須/任意 | 説明 | | :--------------------------- | :------- |:-------------------------------------------------------------------------------------------------------| | **subscriptionUpdateParams** | 必須 | [`AdaptySubscriptionUpdateParameters`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_subscription_update_parameters.html) オブジェクト。 | サブスクリプションと置き換えモードの詳細については、Google Developerのドキュメントをご参照ください。 - [置き換えモードについて](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\} <Details> <summary>オファーコードについて</summary> オファーコードを使うと、特定のユーザーに割引や無料トライアルを提供できます。自動的に適用される通常のオファーとは異なり、オファーコードはメールキャンペーン、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アナリティクスとレポートの間に収益の差異が生じていました。 本来は無料であるべきトランザクションが通常価格で記録されている履歴がある場合、それはレガシープロモコードによるものと考えられます。これらのコードは現在廃止されているため、正確な収益追跡のためにオファーコードに移行してください。 </Details> アプリでコード引き換えシートを表示するには: ```csharp showLineNumbers Adapty.PresentCodeRedemptionSheet((error) => { // 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)を有効にできます。 ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetGoogleEnablePendingPrepaidPlans(true); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: unity-restore-purchase --- --- title: "Unity SDKで購入を復元する" description: "Adaptyで購入を復元してシームレスなユーザー体験を確保する方法を学びましょう。" --- iOSとAndroidにおける購入の復元は、ユーザーが再度課金されることなく、サブスクリプションやアプリ内課金などのコンテンツへのアクセスを取り戻せる機能です。アプリをアンインストール・再インストールしたり、新しいデバイスに移行したりしたユーザーが、過去に購入したコンテンツに再アクセスしたい場合に特に役立ちます。 :::note [ペイウォールビルダー](adapty-paywall-builder)で作成したペイウォールでは、追加のコードなしで購入が自動的に復元されます。その場合は、この手順をスキップできます。 ::: [ペイウォールビルダー](adapty-paywall-builder)を使用せずにペイウォールをカスタマイズしている場合に購入を復元するには、`.restorePurchases()` メソッドを呼び出してください。 ```csharp showLineNumbers Adapty.RestorePurchases((profile, error) => { if (error != null) { // handle the error return; } var accessLevel = profile.AccessLevels["YOUR_ACCESS_LEVEL"]; if (accessLevel != null && accessLevel.IsActive) { // restore access } }); ``` レスポンスパラメーター: | パラメーター | 説明 | |---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **Profile** | <p>[`AdaptyProfile`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html) オブジェクト。このモデルには、アクセスレベル、サブスクリプション、非サブスクリプション購入に関する情報が含まれています。</p><p>**アクセスレベルのステータス**を確認して、ユーザーがアプリにアクセスできるかどうかを判断してください。</p> | :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: --- # File: implement-observer-mode-unity --- --- title: "Unity SDKにオブザーバーモードを実装する" description: "Unity SDKのAdaptyでオブザーバーモードを実装し、ユーザーのサブスクリプションイベントを追跡します。" --- すでに独自の購入インフラを持っており、すぐにAdaptyへ完全移行する準備が整っていない場合は、[オブザーバーモード](observer-vs-full-mode)を検討してみてください。基本的な使い方では、オブザーバーモードは高度なアナリティクスやアトリビューション・アナリティクスシステムとのシームレスな連携を提供します。 この方法で問題なければ、必要な作業は以下の2点だけです: 1. `observerMode` パラメータを `true` に設定して、Adapty SDKの設定時にオブザーバーモードを有効にします。設定手順については[Unity](sdk-installation-unity#activate-adapty-module-of-adapty-sdk)を参照してください。 2. 既存の購入インフラからAdaptyへ[トランザクションを報告する](report-transactions-observer-mode-unity)。 ### オブザーバーモードのセットアップ \{#observer-mode-setup\} 購入とサブスクリプションのステータスを自分で管理し、サブスクリプションイベントやアナリティクスの送信にAdaptyを使用する場合は、オブザーバーモードを有効にしてください。 :::important オブザーバーモードで動作している場合、Adapty SDKはトランザクションをクローズしません。そのため、必ずご自身でトランザクションを処理するようにしてください。 ::: ```csharp showLineNumbers title="C#" using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, AdaptyEventListener { void Start() { DontDestroyOnLoad(this.gameObject); Adapty.SetEventListener(this); var builder = new AdaptyConfiguration.Builder("YOUR_PUBLIC_SDK_KEY") .SetObserverMode(true); // Enable observer mode Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); } public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } } ``` パラメータ: | パラメータ | 説明 | |--------------|------------------------------------------------------------------------------------------------------------| | observerMode | [オブザーバーモード](observer-vs-full-mode)を制御するブール値です。デフォルト値は `false` です。 | ## オブザーバーモードでAdaptyのペイウォールを使用する \{#using-adapty-paywalls-in-observer-mode\} Adaptyのペイウォールやアナリティクス機能も使いたい場合は可能ですが、オブザーバーモードでは追加のセットアップが必要です。上記の手順に加えて、以下の対応が必要になります: 1. [リモートコンフィグのペイウォール](present-remote-config-paywalls-unity)と同様にペイウォールを表示する。 3. 購入トランザクションに[ペイウォールを関連付ける](report-transactions-observer-mode-unity)。 --- # File: report-transactions-observer-mode-unity --- --- title: "Unity SDKのObserverモードでトランザクションを報告する" description: "Unity SDKのAdapty Observerモードで購入トランザクションを報告し、ユーザーインサイトと収益トラッキングを実現します。" --- <Tabs groupId="sdk-version" queryString> <TabItem value="current" label="Adapty SDK v3.4+(現行版)" default> Observerモードでは、Adapty SDKは既存の購入システムを通じて行われた購入を自動的に追跡できません。アプリストアからトランザクションを報告する必要があります。アナリティクスのエラーを防ぐため、アプリのリリース**前**にこの設定を行うことが重要です。 `reportTransaction`を使用して、各トランザクションをAdaptyに明示的に報告してください。 :::warning **トランザクションの報告を省略しないでください!** `ReportTransaction`を呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に`variationId`を含めてください。これにより、購入がトリガーしたペイウォールと関連付けられ、正確なペイウォールアナリティクスが確保されます。 ```csharp showLineNumbers Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | -------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | 必須 | <ul><li> iOS の場合:トランザクションの識別子。</li><li> Android の場合:購入の文字列識別子 `purchase.getOrderId`。ここで purchase は billing library の [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。</li></ul> | | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) オブジェクトの `variationId` プロパティを使用して取得できます。 | </TabItem> <TabItem value="old" label="Adapty SDK 3.3.x(レガシー)" default> Observerモードでは、Adapty SDKは既存の購入システムを通じて行われた購入を自動的に追跡できません。アプリストアからトランザクションを報告するか、リストアする必要があります。アナリティクスのエラーを防ぐため、アプリのリリース**前**にこの設定を行うことが重要です。 両プラットフォームで`reportTransaction`を使用して各トランザクションを明示的に報告し、Androidでは追加のステップとして`restorePurchases`を使用してAdaptyに認識させてください。 :::warning **トランザクションの報告と購入のリストアを省略しないでください!** これらのメソッドを呼び出さないと、Adaptyはトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: Adaptyのペイウォールを使用している場合は、トランザクションを報告する際に`PAYWALL_VARIATION_ID`を含めてください。これにより、購入がトリガーしたペイウォールと関連付けられ、正確なペイウォールアナリティクスが確保されます。 ```csharp showLineNumbers // every time when calling transasction.finish() #if UNITY_ANDROID && !UNITY_EDITOR Adapty.RestorePurchases((profile, error) => { // handle the error }); #endif Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` パラメーター: | パラメーター | 必須/任意 | 説明 | | ------------- | -------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | 必須 | <ul><li> iOS、StoreKit 1 の場合:[SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction) オブジェクト。</li><li> iOS、StoreKit 2 の場合:[Transaction](https://developer.apple.com/documentation/storekit/transaction) オブジェクト。</li><li> Android の場合:購入の文字列識別子(`purchase.getOrderId`)。ここで purchase は billing library の [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。</li></ul> | | variationId | 任意 | バリアントの文字列識別子。[AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) オブジェクトの `variationId` プロパティを使用して取得できます。 | </TabItem> <TabItem value="old2" label="Adapty SDK 3.2.x 以前(レガシー)" default> <Tabs groupId="current-os" queryString> <TabItem value="swift" label="iOS" default> **トランザクションの報告** - バージョン 3.1.x 以前は App Store のトランザクションを自動的に監視するため、手動での報告は不要です。 - バージョン 3.2 は Observer モードをサポートしていません。 </TabItem> <TabItem value="kotlin" label="Android および Android ベースのクロスプラットフォーム" default> **トランザクションの報告** Observerモードで Adapty にトランザクションを報告するには、[モバイルコードでの購入リストア](unity-restore-purchase)ページで説明されているように `restorePurchases` を使用してください。 :::warning **トランザクションの報告を省略しないでください!** `restorePurchases` を呼び出さないと、Adapty はトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: </TabItem> </Tabs> **トランザクションへのペイウォールの関連付け** Adapty SDK は購入の発生元を判断できません。購入の処理はお客様が行っているためです。そのため、Observerモードでペイウォールや A/B テストを使用する場合は、アプリストアから来たトランザクションをモバイルアプリのコード内で対応するペイウォールと関連付ける必要があります。アプリのリリース前に正しく設定することが重要です。設定を誤るとアナリティクスにエラーが発生します。 ```csharp Adapty.SetVariationForTransaction("<variationId>", "<transactionId>", (error) => { if(error != null) { // handle the error return; } // successful binding }); ``` | パラメーター | 必須/任意 | 説明 | | ------------------------------------------------------ | -------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | transactionId | 必須 | <p>iOS、StoreKit 1 の場合:[SKPaymentTransaction](https://developer.apple.com/documentation/storekit/skpaymenttransaction) オブジェクト。</p><p>iOS、StoreKit 2 の場合:[Transaction](https://developer.apple.com/documentation/storekit/transaction) オブジェクト。</p><p>Android の場合:購入の文字列識別子(purchase.getOrderId)。ここで purchase は billing library の [Purchase](https://developer.android.com/reference/com/android/billingclient/api/Purchase) クラスのインスタンスです。</p> | | variationId | 必須 | バリアントの文字列識別子。[AdaptyPaywall](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_paywall.html) オブジェクトの `variationId` プロパティを使用して取得できます。 | </TabItem> </Tabs> --- # File: unity-troubleshoot-purchases --- --- title: "Unity SDKでの購入に関するトラブルシューティング" description: "Unity SDKでの購入に関するトラブルシューティング" --- このガイドでは、Unity SDKで購入を手動実装する際によく発生する問題の解決方法を説明します。 ## makePurchaseが正常に呼び出されるが、プロファイルが更新されない \{#makepurchase-is-called-successfully-but-the-profile-is-not-being-updated\} **問題**: `makePurchase` メソッドが正常に完了するのに、ユーザーのプロファイルとサブスクリプションのステータスがAdaptyで更新されない。 **原因**: 通常、Google Play Storeのセットアップが不完全か、設定に問題があることを示しています。 **解決策**: [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-unity)を参照してください。 ## 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 Storeから課金が利用できないというエラーが返ってくる。 **原因**: このエラーはAdaptyとは無関係です。端末で課金が利用できないことを示すGoogle Play Billing Libraryのエラーです。 **解決策**: このエラーはAdaptyとは無関係です。Play Storeのドキュメントで詳細を確認できます: [BillingResultレスポンスコードの処理](https://developer.android.com/google/play/billing/errors#billing_unavailable_error_code_3) | Play Billing | Android Developers。 ## makePurchasesCompletionHandlersが見つからない \{#not-found-makepurchasescompletionhandlers\} **問題**: `makePurchasesCompletionHandlers` が見つからないという問題が発生している。 **原因**: 通常、サンドボックステストに関連する問題です。 **解決策**: 新しいサンドボックスユーザーを作成して再試行してください。サンドボックス環境での購入完了ハンドラーの問題はこれで解決することが多いです。 ## その他の問題 \{#other-issues\} **問題**: 上記に該当しない購入関連の問題が発生している。 **解決策**: 必要に応じて[マイグレーションガイド](unity-sdk-migration-guides)を使用してSDKを最新バージョンに移行してください。多くの問題は新しいSDKバージョンで解決されています。 --- # File: unity-identifying-users --- --- title: "Unity SDKでユーザーを識別する" description: "Adapty SDKを使用してUnityアプリでユーザーを識別する方法をご紹介します。" --- 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`パラメーターとして渡すだけです。 ```csharp showLineNumbers using UnityEngine; using AdaptySDK; var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 設定後にCustomer User IDを設定する \{#setting-customer-user-id-after-configuration\} SDK設定時にユーザーIDがない場合は、`.identify()`メソッドを使っていつでも後から設定できます。このメソッドが最もよく使われるのは、登録後や認証後、つまりユーザーが匿名ユーザーから認証済みユーザーに切り替わるタイミングです。 ```csharp showLineNumbers Adapty.Identify("YOUR_USER_ID", (error) => { if(error == null) { // successful identify } }); ``` リクエストパラメーター: - **Customer User ID**(必須):文字列のユーザー識別子。 :::warning 重要なユーザーデータの再送信について ユーザーが再度ログインした場合など、Adaptyのサーバーにすでにそのユーザーの情報が存在していることがあります。このような場合、Adapty SDKは自動的に新しいユーザーとして切り替わります。カスタム属性やサードパーティネットワークからのアトリビューションなど、匿名ユーザーに対して送信したデータがある場合は、識別されたユーザーに対してそのデータを再送信する必要があります。 また、新しいユーザーのデータが異なる場合があるため、ユーザーを識別した後はすべてのペイウォールとプロダクトを再取得する必要があることにも注意してください。 ::: ### ログアウトとログイン \{#logging-out-and-logging-in\} `.logout()`メソッドを呼び出すことで、いつでもユーザーをログアウトできます。 ```csharp showLineNumbers Adapty.Logout((error) => { if(error == null) { // successful logout } }); ``` その後、`.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`と一緒に渡してください。 トークンだけを渡しても、トランザクションには含まれません。 ::: ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; using System; // During configuration: var appAccountToken = new Guid("YOUR_APP_ACCOUNT_TOKEN"); var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID", appAccountToken); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); // Or when identifying users Adapty.Identify("YOUR_USER_ID", appAccountToken, (error) => { if (error == null) { // successful identify } }); ``` ## 難読化アカウントIDを設定する(Android) \{#set-obfuscated-account-ids-android\} Google Playでは、ユーザーのプライバシーとセキュリティを強化するために、特定のユースケースで難読化アカウントIDが必要です。これらのIDにより、Google Playはユーザー情報を匿名に保ちながら購入を識別できます。これは特に不正防止やアナリティクスにおいて重要です。 アプリが機密性の高いユーザーデータを扱う場合や、特定のプライバシー規制への準拠が求められる場合に、これらのIDを設定する必要が生じることがあります。難読化IDを使用することで、Google Playは実際のユーザー識別子を公開せずに購入を追跡できます。 ```csharp showLineNumbers title="Unity" using UnityEngine; using AdaptySDK; // During configuration: var builder = new AdaptyConfiguration.Builder("YOUR_API_KEY") .SetCustomerUserId("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID"); Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); // Or when identifying users Adapty.Identify("YOUR_USER_ID", null, "YOUR_OBFUSCATED_ACCOUNT_ID", (error) => { if (error == null) { // successful identify } }); ``` ## デバイスをまたいでユーザーを検出する \{#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: unity-setting-user-attributes --- --- title: "Unity SDKでユーザー属性を設定する" description: "Adapty SDKを使用してUnityアプリのユーザー属性とプロファイルデータを更新する方法を学びます。" --- メールアドレスや電話番号などの任意の属性をアプリのユーザーに設定できます。設定した属性は、ユーザー[セグメント](segments)の作成やCRMでの確認に活用できます。 ### ユーザー属性の設定 \{#setting-user-attributes\} ユーザー属性を設定するには、`.updateProfile()`メソッドを呼び出します: ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetFirstName("John") .SetLastName("Appleseed") .SetBirthday(new DateTime(1970, 1, 3)) .SetGender(ProfileGender.Female) .SetEmail("example@adapty.io"); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != nil) { // handle the error } }); ``` `updateProfile`メソッドで以前に設定した属性はリセットされないことに注意してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ### 使用可能なキーの一覧 \{#the-allowed-keys-list\} `AdaptyProfileParameters.Builder`で使用できるキー`<Key>`と値`<Value>`は以下のとおりです: | キー | 値 | |---|-----| | <p>email</p><p>phoneNumber</p><p>firstName</p><p>lastName</p> | String | | gender | 列挙型。使用可能な値:`female`、`male`、`other` | | birthday | Date | ### カスタムユーザー属性 \{#custom-user-attributes\} 独自のカスタム属性を設定することができます。これらは通常、アプリの利用状況に関連します。たとえば、フィットネスアプリなら週あたりの運動回数、語学学習アプリならユーザーの習熟度レベルなどが考えられます。カスタム属性はセグメントに活用してターゲットを絞ったペイウォールやオファーを作成したり、収益に最も影響するプロダクト指標を分析したりするのに役立ちます。 ```csharp showLineNumbers try { builder = builder.SetCustomStringAttribute("string_key", "string_value"); builder = builder.SetCustomDoubleAttribute("double_key", 123.0f); } catch (Exception e) { // handle the exception } ``` 既存のキーを削除するには、`.withRemoved(customAttributeForKey:)`メソッドを使用します: ```csharp showLineNumbers try { builder = builder.RemoveCustomAttribute("key_to_remove"); } catch (Exception e) { // handle the exception } ``` 事前にどのようなカスタム属性が設定されているか確認したい場合は、`AdaptyProfile`オブジェクトの`customAttributes`フィールドを使用してください。 :::warning `customAttributes`の値は最新でない場合があります。ユーザー属性は異なるデバイスからいつでも送信される可能性があるため、最後の同期以降にサーバー上の属性が変更されていることがあります。 ::: ### 制限事項 \{#limits\} - ユーザーあたり最大30個のカスタム属性 - キー名は最大30文字。キー名に使用できる文字は英数字および`_`、`-`、`.`です - 値は文字列または浮動小数点数で、50文字以内 --- # File: unity-listen-subscription-changes --- --- title: "Unity SDKでサブスクリプションステータスを確認する" description: "UnityアプリでAdaptyを使ってユーザーのサブスクリプションステータスを追跡・管理し、顧客維持率を向上させましょう。" --- Adaptyを使えば、サブスクリプションステータスの管理が簡単になります。プロダクトIDをコードに直接記述する必要はありません。アクティブな[アクセスレベル](access-level)を確認するだけで、ユーザーのサブスクリプションステータスを簡単に把握できます。 <details> <summary>サブスクリプションステータスの確認を始める前に(クリックして展開)</summary> - iOSの場合は、[App Store Server Notifications](enable-app-store-server-notifications)を設定してください - Androidの場合は、[リアルタイム デベロッパー通知(RTDN)](enable-real-time-developer-notifications-rtdn)を設定してください </details> ## アクセスレベルとAdaptyProfileオブジェクト \{#access-level-and-the-adaptyprofile-object\} アクセスレベルは[AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html)オブジェクトのプロパティです。アプリ起動時(例えば[ユーザーを識別する](unity-identifying-users#setting-customer-user-id-on-configuration)タイミングなど)にプロファイルを取得し、変更があれば都度更新することをおすすめします。こうすることで、毎回リクエストせずにプロファイルオブジェクトを利用できます。 プロファイルの更新通知を受け取るには、下記の[サブスクリプションステータスの更新をリッスンする](#listening-for-subscription-status-updates)セクションに従って、プロファイルの変更を監視してください。 :::tip Adapty SDK がモバイルアプリにどのように統合されているか、実際の例を見てみませんか?ペイウォールの表示、購入処理、その他の基本機能を含む完全なセットアップを実演している[サンプルアプリ](sample-apps)をご覧ください。 ::: ## サーバーからアクセスレベルを取得する \{#retrieving-the-access-level-from-the-server\} サーバーからアクセスレベルを取得するには、`.GetProfile()`メソッドを使用します。 ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // check the access }); ``` レスポンスのパラメータ: | パラメータ | 説明 | | --------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Profile | <p>[AdaptyProfile](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_profile.html)オブジェクト。通常は、ユーザーがプレミアムアクセスを持っているかどうかを判断するために、プロファイルのアクセスレベルのステータスだけを確認すれば十分です。</p><p></p><p>`.getProfile`メソッドは常にAPIへの問い合わせを試みるため、最新の情報を返します。何らかの理由(例:インターネット接続なし)でAdapty SDKがサーバーから情報を取得できなかった場合は、キャッシュのデータが返されます。また、Adapty SDKは`AdaptyProfile`のキャッシュを定期的に更新し、情報をできる限り最新の状態に保っています。</p> | `.getProfile()`メソッドはユーザープロファイルを返し、そこからアクセスレベルのステータスを取得できます。アプリごとに複数のアクセスレベルを設定することも可能です。たとえば、新聞アプリでさまざまなトピックへのサブスクリプションを独立して販売する場合、「sports」と「science」というアクセスレベルを作成できます。ただし、多くの場合はアクセスレベルは1つで十分であり、その場合はデフォルトの「premium」アクセスレベルを使うだけで問題ありません。 デフォルトの「premium」アクセスレベルを確認する例を示します。 ```csharp showLineNumbers Adapty.GetProfile((profile, error) => { if (error != null) { // handle the error return; } // "premium" is an identifier of default access level var accessLevel = profile.AccessLevels["premium"]; if (accessLevel != null && accessLevel.IsActive) { // grant access to premium features } }); ``` ### サブスクリプションステータスの更新をリッスンする \{#listening-for-subscription-status-updates\} ユーザーのサブスクリプションが変更されるたびに、Adaptyはイベントを発火します。 Adaptyからメッセージを受け取るには、追加の設定が必要です。 ```csharp showLineNumbers // Extend `AdaptyEventListener ` with `OnLoadLatestProfile ` method: public class AdaptyListener : MonoBehaviour, AdaptyEventListener { public void OnLoadLatestProfile(AdaptyProfile profile) { // handle any changes to subscription state } } ``` Adaptyはアプリケーション起動時にもイベントを発火します。この場合、キャッシュされたサブスクリプションステータスが渡されます。 ### サブスクリプションステータスのキャッシュ \{#subscription-status-cache\} Adapty SDKに実装されたキャッシュは、プロファイルのサブスクリプションステータスを保存します。そのため、サーバーにアクセスできない状況でも、キャッシュされたデータを使ってプロファイルのサブスクリプションステータスを確認できます。 ただし、キャッシュからデータを直接取得することはできない点に注意してください。SDKは1分ごとに定期的にサーバーへ問い合わせを行い、プロファイルに関する更新や変更がないかを確認します。新しいトランザクションやその他の更新といった変更があった場合は、サーバーと同期するためにキャッシュデータへ反映されます。 --- # File: unity-deal-with-att --- --- title: "Unity SDKでATTを処理する" description: "UnityでAdaptyを使い始めて、サブスクリプションのセットアップと管理を効率化しましょう。" --- アプリでAppTrackingTransparencyフレームワークを使用しており、ユーザーにアプリトラッキングの認証リクエストを表示する場合は、[認証ステータス](https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/)をAdaptyに送信する必要があります。 ```csharp showLineNumbers var builder = new Adapty.ProfileParameters.Builder() .SetAppTrackingTransparencyStatus(IOSAppTrackingTransparencyStatus.Authorized); Adapty.UpdateProfile(builder.Build(), (error) => { if(error != null) { // handle the error } }); ``` :::warning この値は変更されたタイミングでできるだけ早く送信することを強く推奨します。そうすることで、設定済みのインテグレーションにタイムリーにデータが送信されます。 ::: --- # File: kids-mode-unity --- --- title: "Unity SDKのキッズモード" description: "キッズモードを簡単に有効化してAppleとGoogleのポリシーに準拠。Unity SDKではIDFA、GAID、広告データは収集されません。" --- Unityアプリが子ども向けである場合、[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の取り扱いには注意が必要です。`<FirstName.LastName>`形式のユーザー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\} Unityでのキッズモードサポートはまもなくリリースされます! 現在は、各ネイティブプラットフォームのガイドをご参照ください。 - iOSの設定については[iOS SDKのキッズモード](kids-mode) - Androidの設定については[Android SDKのキッズモード](kids-mode-android) --- # File: unity-get-onboardings --- --- title: "Unity SDKでオンボーディングを取得する" description: "Unity向けAdaptyでオンボーディングを取得する方法を説明します。" --- [Adapty ダッシュボードのビルダーでオンボーディングのビジュアルをデザインした](design-onboarding)後、Unity アプリでそれを表示できます。このプロセスの最初のステップは、以下に説明するように、プレースメントに関連付けられたオンボーディングとそのビュー設定を取得することです。 始める前に、以下を確認してください: 1. [Adapty Unity SDK](sdk-installation-unity) バージョン 3.14.0 以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ## オンボーディングの取得とビューの作成 \{#fetch-onboarding-and-create-view\} ノーコードビルダーで[オンボーディング](onboardings)を作成すると、アプリが取得して表示する必要のある設定を含むコンテナとして保存されます。このコンテナは、表示されるコンテンツ、表示方法、およびユーザーのインタラクション(クイズの回答やフォームの入力など)の処理方法など、全体のエクスペリエンスを管理します。また、コンテナは自動的にアナリティクスイベントを追跡するため、個別にビュートラッキングを実装する必要はありません。 最高のパフォーマンスを得るために、ユーザーに表示する前に画像のダウンロードが完了するよう、早めにオンボーディング設定を取得してください。 オンボーディングを取得するには、`GetOnboarding` メソッドを使用します: ```csharp showLineNumbers Adapty.GetOnboarding("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` パラメーター: | パラメーター | 必須 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 目的の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライゼーション識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語を表し、2番目は地域を表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルのポルトガル語を表します。</p><p>ロケールコードと推奨する使用方法については、[ローカライゼーションとロケールコード](flutter-localizations-and-locale-codes)を参照してください。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境にいると思われる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータ(存在する場合)を返すことを検討してください。この場合、ユーザーは最新のデータを取得できないことがありますが、インターネット接続の状態に関わらず、より速い読み込み時間を体験できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリのアンインストール時または手動でクリアした場合にのみ消去されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層で保存します:上記の定期的に更新されるキャッシュとフォールバックオンボーディングです。また、オンボーディングをより速く取得するためにCDNを使用し、CDNが到達不能な場合のスタンドアローンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | | **loadTimeout** | デフォルト: 5秒 | <p>このメソッドのタイムアウト上限を設定します。タイムアウトに達した場合、キャッシュされたデータまたはローカルフォールバックが返されます。</p><p>このメソッドは内部で複数のリクエストで構成される場合があるため、まれに `loadTimeout` で指定した時間より若干遅れてタイムアウトすることがあります。</p> | レスポンスパラメーター: | パラメーター | 説明 | |:----------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------| | Onboarding | オンボーディングの識別子と設定、リモートコンフィグ、その他いくつかのプロパティを含む [`AdaptyOnboarding`](https://unity.adapty.io/class_adapty_s_d_k_1_1_adapty_onboarding.html) オブジェクト。 | オンボーディングを取得したら、`CreateOnboardingView` メソッドを呼び出します。 :::warning `CreateOnboardingView` メソッドの結果は一度しか使用できません。再度使用する必要がある場合は、`CreateOnboardingView` メソッドを再度呼び出してください。再作成せずに2回呼び出すと、`AdaptyUIError.viewAlreadyPresented` エラーが発生する可能性があります。 ::: ```csharp showLineNumbers AdaptyUI.CreateOnboardingView(onboarding, (view, error) => { // handle the result }); ``` パラメーター: | パラメーター | 必須 | 説明 | |:---------------| :------------- |:-----------------------------------------------------------------------------| | **onboarding** | 必須 | 目的のオンボーディングのビューを取得するための `AdaptyOnboarding` オブジェクト。 | | **externalUrlsPresentation** | <p>任意</p><p>デフォルト: `InAppBrowser`</p> | <p>オンボーディング内のリンクを開く方法を制御します。使用可能なオプション:</p><p>- `AdaptyWebPresentation.InAppBrowser` - リンクをアプリ内ブラウザで開く(デフォルト)</p><p>- `AdaptyWebPresentation.ExternalBrowser` - リンクをデバイスの外部ブラウザで開く</p><p>使用例については、[オンボーディングでのリンクの開き方をカスタマイズする](unity-present-onboardings#customize-how-links-open-in-onboardings)を参照してください。</p> | オンボーディングとそのビュー設定の読み込みに成功したら、[モバイルアプリで表示する](unity-present-onboardings)ことができます。 ## デフォルトオーディエンスのオンボーディングでフェッチを高速化する \{#speed-up-onboarding-fetching-with-default-audience-onboarding\} 通常、オンボーディングはほぼ即座に取得されるため、このプロセスの高速化を心配する必要はありません。ただし、オーディエンスやオンボーディングが多数あり、ユーザーのインターネット接続が弱い場合、オンボーディングの取得に予想以上の時間がかかることがあります。そのような状況では、オンボーディングをまったく表示しないよりも、スムーズなユーザー体験を確保するためにデフォルトのオンボーディングを表示したい場合があります。 これに対処するために、`GetOnboardingForDefaultAudience` メソッドを使用できます。このメソッドは、**All Users** オーディエンス向けの指定されたプレースメントのオンボーディングを取得します。ただし、上記の[オンボーディングの取得とビューの作成](#fetch-onboarding-and-create-view)セクションで説明した `getOnboarding` メソッドでオンボーディングを取得することが推奨されるアプローチであることを理解することが重要です。 :::warning `GetOnboardingForDefaultAudience` の代わりに `GetOnboarding` の使用を検討してください。前者には重要な制限があります: - **互換性の問題**:複数のアプリバージョンをサポートする際に問題が生じる可能性があり、後方互換性のあるデザインを作成するか、古いバージョンで正しく表示されないことを許容する必要があります。 - **パーソナライゼーションなし**:「All Users」オーディエンス向けのコンテンツのみを表示し、国、アトリビューション、またはカスタム属性に基づくターゲティングが行われません。 ユースケースでこれらのデメリットよりも高速な取得が重要な場合は、以下に示すように `GetOnboardingForDefaultAudience` を使用してください。そうでない場合は、[上記](#fetch-onboarding-and-create-view)の説明通り `GetOnboarding` を使用してください。 ::: ```csharp showLineNumbers Adapty.GetOnboardingForDefaultAudience("YOUR_PLACEMENT_ID", (onboarding, error) => { if (error != null) { // handle the error return; } // the requested onboarding }); ``` パラメーター: | パラメーター | 必須 | 説明 | |---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **placementId** | 必須 | 目的の[プレースメント](placements)の識別子。Adapty ダッシュボードでプレースメントを作成する際に指定した値です。 | | **locale** | <p>任意</p><p>デフォルト: `en`</p> | <p>オンボーディングのローカライゼーション識別子。このパラメーターは、マイナス(**-**)文字で区切られた1つまたは2つのサブタグで構成される言語コードを指定します。最初のサブタグは言語を表し、2番目は地域を表します。</p><p></p><p>例:`en` は英語、`pt-br` はブラジルのポルトガル語を表します。</p> | | **fetchPolicy** | デフォルト: `.reloadRevalidatingCacheData` | <p>デフォルトでは、SDK はサーバーからデータを読み込もうとし、失敗した場合はキャッシュされたデータを返します。ユーザーが常に最新のデータを取得できるため、このオプションを推奨します。</p><p></p><p>ただし、ユーザーが不安定なインターネット環境にいると思われる場合は、`.returnCacheDataElseLoad` を使用してキャッシュデータ(存在する場合)を返すことを検討してください。この場合、ユーザーは最新のデータを取得できないことがありますが、インターネット接続の状態に関わらず、より速い読み込み時間を体験できます。キャッシュは定期的に更新されるため、セッション中にネットワークリクエストを避けるために使用しても安全です。</p><p></p><p>キャッシュはアプリの再起動後も保持され、アプリのアンインストール時または手動でクリアした場合にのみ消去されます。</p><p></p><p>Adapty SDK はオンボーディングをローカルに2層で保存します:上記の定期的に更新されるキャッシュとフォールバックオンボーディングです。また、オンボーディングをより速く取得するためにCDNを使用し、CDNが到達不能な場合のスタンドアローンのフォールバックサーバーも用意しています。このシステムは、インターネット接続が不安定な場合でも、常に最新バージョンのオンボーディングを取得できるよう設計されています。</p> | --- # File: unity-present-onboardings --- --- title: "Unity SDKでオンボーディングを表示する" description: "コンバージョンを高めるためにオンボーディングを効果的に表示する方法を学びましょう。" --- ビルダーでオンボーディングをカスタマイズしている場合、ユーザーに表示するためにUnityアプリのコードでレンダリングを実装する必要はありません。そのようなオンボーディングには、表示する内容と表示方法の両方が含まれています。 始める前に、以下を確認してください。 1. [Adapty Unity SDK](sdk-installation-unity) 3.14.0以降をインストールしていること。 2. [オンボーディングを作成](create-onboarding)していること。 3. オンボーディングを[プレースメント](placements)に追加していること。 オンボーディングを表示するには、`CreateOnboardingView`メソッドで作成した`view`に対して`view.Present()`メソッドを使用します。各`view`は一度しか使用できません。再度ペイウォールを表示する必要がある場合は、`CreateOnboardingView`をもう一度呼び出して新しい`view`インスタンスを作成してください。 :::warning `view`を再作成せずに再利用すると、`AdaptyUIError.viewAlreadyPresented`エラーが発生する可能性があります。 ::: ```csharp showLineNumbers title="Unity" view.Present((presentError) => { if (presentError != null) { // handle the error } }; ``` ## iOS表示スタイルの設定 \{#configure-ios-presentation-style\} `Present()`メソッドに`iosPresentationStyle`パラメーターを渡すことで、iOSでのオンボーディングの表示方法を設定できます。パラメーターには`AdaptyUIIOSPresentationStyle.FullScreen`(デフォルト)または`AdaptyUIIOSPresentationStyle.PageSheet`を指定できます。 ```csharp showLineNumbers title="Unity" view.Present(AdaptyUIIOSPresentationStyle.PageSheet, (error) => { // handle the error }); ``` ## オンボーディングでのリンクの開き方をカスタマイズする \{#customize-how-links-open-in-onboardings\} :::important オンボーディングでのリンクの開き方のカスタマイズは、Adapty SDK v3.15以降でサポートされています。 ::: デフォルトでは、オンボーディング内のリンクはアプリ内ブラウザで開かれ、アプリを切り替えることなくウェブページをアプリ内で表示できるシームレスな体験を提供します。 代わりに外部ブラウザでリンクを開くには、`CreateOnboardingView`メソッドに`AdaptyWebPresentation.ExternalBrowser`を渡してください。 ```csharp showLineNumbers title="Unity" AdaptyUI.CreateOnboardingView( onboarding, AdaptyWebPresentation.ExternalBrowser, // default — InAppBrowser (view, error) => { if (error != null) { // handle the error return; } // present the onboarding view view.Present((presentError) => { if (presentError != null) { // handle the error } }); } ); ``` 利用可能なオプション: - `AdaptyWebPresentation.InAppBrowser` - アプリ内ブラウザでリンクを開く(デフォルト) - `AdaptyWebPresentation.ExternalBrowser` - デバイスの外部ブラウザでリンクを開く --- # File: unity-handling-onboarding-events --- --- title: "Unity SDKでオンボーディングイベントを処理する" description: "Adaptyを使ってUnityでオンボーディング関連のイベントを処理します。" --- 始める前に、以下を確認してください: 1. [Adapty Unity SDK](sdk-installation-unity) 3.14.0以降をインストール済みであること。 2. [オンボーディングを作成済み](create-onboarding)であること。 3. オンボーディングを[プレースメント](placements)に追加済みであること。 ビルダーで設定されたオンボーディングは、アプリが反応できるイベントを生成します。これらのイベントへの対応方法を以下で説明します。 Unityアプリ内のオンボーディング画面で発生するプロセスを制御・監視するには、`AdaptyOnboardingsEventsListener`インターフェースを実装してください。 ## カスタムアクション \{#custom-actions\} ビルダーでは、ボタンに**カスタム**アクションを追加してIDを割り当てることができます。 <img src="/assets/shared/img/ios-events-1.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> このIDをコード内で使用し、カスタムアクションとして処理できます。たとえば、ユーザーが**ログイン**や**通知を許可**などのカスタムボタンをタップすると、`OnboardingViewOnCustomAction`メソッドが呼び出され、`actionId`パラメーターにビルダーで設定した**アクションID**が渡されます。"allowNotifications"のような独自のIDを作成できます。 オンボーディングイベントを処理するには、`AdaptyOnboardingsEventsListener`インターフェースを実装してください: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { void Start() { Adapty.SetOnboardingsEventsListener(this); } public void OnboardingViewOnCustomAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { if (actionId == "allowNotifications") { // request notification permissions } } public void OnboardingViewDidFailWithError( AdaptyUIOnboardingView view, AdaptyError error ) { // handle errors } // Implement other required interface methods (see examples below) } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "actionId": "allowNotifications", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 } } ``` </Details> ## オンボーディングを閉じる \{#closing-onboarding\} オンボーディングは、ユーザーが**閉じる**アクションが割り当てられたボタンをタップしたときに閉じられたとみなされます。 <img src="/assets/shared/img/ios-events-2.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> :::important ユーザーがオンボーディングを閉じたときの動作を自分で管理する必要があります。たとえば、オンボーディング自体の表示を停止する処理が必要です。 ::: クラスに`OnboardingViewOnCloseAction`メソッドを実装してください: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnCloseAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { view.Dismiss((error) => { if (error != null) { // handle the error } }); } // ... other interface methods } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "close_button", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "final_screen", "screen_index": 3, "total_screens": 4 } } ``` </Details> ## ペイウォールを開く \{#opening-a-paywall\} :::tip オンボーディング内でペイウォールを開きたい場合は、このイベントを処理してください。オンボーディングが閉じた後にペイウォールを開く場合は、[`OnboardingViewOnCloseAction`](#closing-onboarding)を処理してイベントデータに依存せずにペイウォールを開く方がシンプルです。 ::: オンボーディングでペイウォールを扱う最もシームレスな方法は、アクションIDをペイウォールのプレースメントIDと同じにすることです。こうすることで、`OnboardingViewOnPaywallAction`の後にそのプレースメントIDを使ってすぐにペイウォールを取得して開くことができます。 iOS では、ペイウォールとオンボーディングのどちらか一方しか同時に表示できません。オンボーディングの上にペイウォールを表示した場合、バックグラウンドのオンボーディングをプログラムで制御することはできません。オンボーディングを閉じようとするとペイウォールが閉じられてしまい、オンボーディングがそのまま表示された状態になります。これを避けるため、ペイウォールを表示する前に必ずオンボーディングビューを閉じてください。 ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnPaywallAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string actionId ) { // Dismiss onboarding before presenting paywall view.Dismiss((dismissError) => { if (dismissError != null) { // handle the error return; } Adapty.GetPaywall(actionId, (paywall, error) => { if (error != null) { // handle the error return; } AdaptyUI.CreatePaywallView(paywall, (paywallView, createError) => { if (createError != null) { // handle the error return; } paywallView.Present((presentError) => { if (presentError != null) { // handle the error } }); }); }); }); } // ... other interface methods } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "action_id": "premium_offer_1", "meta": { "onboarding_id": "onboarding_123", "screen_cid": "pricing_screen", "screen_index": 2, "total_screens": 4 } } ``` </Details> ## オンボーディングの読み込み完了 \{#finishing-loading-onboarding\} オンボーディングの読み込みが完了したら、`OnboardingViewDidFinishLoading`メソッドを実装してください: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewDidFinishLoading( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta ) { // handle loading completion } // ... other interface methods } ``` <Details> <summary>イベントの例(クリックして展開)</summary> ```json { "meta": { "onboarding_id": "onboarding_123", "screen_cid": "welcome_screen", "screen_index": 0, "total_screens": 4 } } ``` </Details> ## ナビゲーションのトラッキング \{#tracking-navigation\} `OnboardingViewOnAnalyticsEvent`メソッドは、オンボーディングフロー中にさまざまな分析イベントが発生したときに呼び出されます。 `analyticsEvent`オブジェクトは以下のいずれかの型になります: | 型 | 説明 | |------------|-------------| | `AdaptyOnboardingsAnalyticsEventOnboardingStarted` | オンボーディングが読み込まれたとき | | `AdaptyOnboardingsAnalyticsEventScreenPresented` | 任意の画面が表示されたとき | | `AdaptyOnboardingsAnalyticsEventScreenCompleted` | 画面が完了したとき。オプションの`ElementId`(完了した要素の識別子)とオプションの`Reply`(ユーザーからの応答)を含みます。ユーザーが画面を離れるアクションを実行したときに発火します。 | | `AdaptyOnboardingsAnalyticsEventSecondScreenPresented` | 2番目の画面が表示されたとき | | `AdaptyOnboardingsAnalyticsEventUserEmailCollected` | 入力フィールドでユーザーのメールアドレスが収集されたとき | | `AdaptyOnboardingsAnalyticsEventOnboardingCompleted` | ユーザーが`final`IDを持つ画面に到達したときに発火します。このイベントが必要な場合は、[最後の画面に`final`IDを割り当てて](design-onboarding)ください。 | | `AdaptyOnboardingsAnalyticsEventUnknown` | 認識できないイベントタイプの場合。`Name`(不明なイベントの名前)と`meta`(追加のメタデータ)を含みます。 | 各イベントには以下の`meta`情報が含まれます: | フィールド | 説明 | |------------|-------------| | `OnboardingId` | オンボーディングフローの一意識別子 | | `ScreenClientId` | 現在の画面の識別子 | | `ScreenIndex` | フロー内の現在の画面の位置 | | `ScreensTotal` | フロー内の総画面数 | 分析イベントをトラッキングに使用する例を以下に示します: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnAnalyticsEvent( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, AdaptyOnboardingsAnalyticsEvent analyticsEvent ) { switch (analyticsEvent) { case AdaptyOnboardingsAnalyticsEventOnboardingStarted: // track onboarding start TrackEvent("onboarding_started", meta); break; case AdaptyOnboardingsAnalyticsEventScreenPresented: // track screen presentation TrackEvent("screen_presented", meta); break; case AdaptyOnboardingsAnalyticsEventScreenCompleted screenCompleted: // track screen completion with user response TrackEvent("screen_completed", meta, screenCompleted.ElementId, screenCompleted.Reply); break; case AdaptyOnboardingsAnalyticsEventOnboardingCompleted: // track successful onboarding completion TrackEvent("onboarding_completed", meta); break; case AdaptyOnboardingsAnalyticsEventUnknown unknownEvent: // handle unknown events TrackEvent(unknownEvent.Name, meta); break; // handle other cases as needed } } // ... other interface methods } ``` :::note `TrackEvent`メソッドは、お好みの分析サービスに分析データを送信するために自分で実装する必要があるプレースホルダーです。 ::: <Details> <summary>イベントの例(クリックして展開)</summary> ```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 } } ``` </Details> --- # File: unity-onboarding-input --- --- title: "Unity SDKでオンボーディングのデータを処理する" description: "Adapty SDKを使ってUnityアプリのオンボーディングからデータを保存・活用する方法を解説します。" --- ユーザーがクイズの質問に回答したり、入力フィールドにデータを入力したりすると、`OnboardingViewOnStateUpdatedAction` メソッドが呼び出されます。このフィールドタイプをコード内で保存・処理することができます。 クラスに `OnboardingViewOnStateUpdatedAction` メソッドを実装してください: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { switch (@params) { case AdaptyOnboardingsSelectParams selectParams: // handle single selection break; case AdaptyOnboardingsMultiSelectParams multiSelectParams: // handle multiple selections break; case AdaptyOnboardingsInputParams inputParams: // handle text input break; case AdaptyOnboardingsDatePickerParams datePickerParams: // handle date selection break; } } // ... other interface methods } ``` パラメーターの説明: | パラメーター | 説明 | |----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `elementId` | 入力要素の一意の識別子。回答を保存する際に、質問と回答を関連付けるために使用できます。 | | `@params` | ユーザーの入力データオブジェクト。以下のいずれかの型になります。 | | `AdaptyOnboardingsSelectParams` | オプションからの単一選択。`Id`、`Value`、`Label` を含みます。 | | `AdaptyOnboardingsMultiSelectParams` | オプションからの複数選択。`Params` のリスト(各要素に `Id`、`Value`、`Label`)を含みます。<br/>• `input`:`type`、`value` を持つオブジェクト<br/>• `datePicker`:`day`、`month`、`year` を持つオブジェクト | | `AdaptyOnboardingsInputParams` | テキスト入力フィールド。`AdaptyOnboardingsTextInput`、`AdaptyOnboardingsEmailInput`、`AdaptyOnboardingsNumberInput` のいずれかである `Input` を含みます。 | | `AdaptyOnboardingsDatePickerParams` | 日付の選択。null許容の `Day`、`Month`、`Year` を含みます。 | <Details> <summary>保存済みデータの例(実装によって異なる場合があります)</summary> ```javascript // Example of a saved select action { "elementId": "preference_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "preferences_screen", "screenIndex": 1, "screensTotal": 3 }, "params": { "type": "select", "value": { "id": "option_1", "value": "premium", "label": "Premium Plan" } } } // Example of a saved multi-select action { "elementId": "interests_selector", "meta": { "onboardingId": "onboarding_123", "screenClientId": "interests_screen", "screenIndex": 2, "screensTotal": 3 }, "params": { "type": "multiSelect", "value": [ { "id": "interest_1", "value": "sports", "label": "Sports" }, { "id": "interest_2", "value": "music", "label": "Music" } ] } } // Example of a saved input action { "elementId": "name_input", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "input", "value": { "type": "text", "value": "John Doe" } } } // Example of a saved date picker action { "elementId": "birthday_picker", "meta": { "onboardingId": "onboarding_123", "screenClientId": "profile_screen", "screenIndex": 0, "screensTotal": 3 }, "params": { "type": "datePicker", "value": { "day": 15, "month": 6, "year": 1990 } } } ``` </Details> ## ユースケース \{#use-cases\} ### 入力データでユーザープロファイルを充実させる \{#enrich-user-profiles-with-data\} 入力データをすぐにユーザープロファイルと紐付けて、同じ情報を二度聞かないようにするには、アクションを処理する際に入力データで[ユーザープロファイルを更新](unity-setting-user-attributes)する必要があります。 たとえば、`name` IDを持つテキストフィールドでユーザーに名前を入力してもらい、その値をユーザーのファーストネームとして設定する場合や、`email` フィールドにメールアドレスを入力してもらう場合、アプリのコードは次のようになります: ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { if (@params is AdaptyOnboardingsInputParams inputParams) { var builder = new AdaptyProfileParameters.Builder(); switch (elementId) { case "name": if (inputParams.Input is AdaptyOnboardingsTextInput textInput) { builder.SetFirstName(textInput.Value); } break; case "email": if (inputParams.Input is AdaptyOnboardingsEmailInput emailInput) { builder.SetEmail(emailInput.Value); } break; } Adapty.UpdateProfile(builder.Build(), (error) => { if (error != null) { // handle the error } }); } } // ... other interface methods } ``` ### 回答に基づいてペイウォールをカスタマイズする \{#customize-paywalls-based-on-answers\} オンボーディングのクイズを活用して、ユーザーがオンボーディングを完了した後に表示するペイウォールをカスタマイズすることもできます。 たとえば、スポーツの経験について質問し、ユーザーグループごとに異なるCTAやプロダクトを表示できます。 1. オンボーディングビルダーで[クイズを追加](onboarding-quizzes)し、各オプションにわかりやすいIDを設定します。 2. IDに基づいてクイズの回答を処理し、ユーザーに[カスタム属性を設定](unity-setting-user-attributes)します。 ```csharp showLineNumbers title="Unity" public class OnboardingManager : MonoBehaviour, AdaptyOnboardingsEventsListener { public void OnboardingViewOnStateUpdatedAction( AdaptyUIOnboardingView view, AdaptyUIOnboardingMeta meta, string elementId, AdaptyOnboardingsStateUpdatedParams @params ) { if (@params is AdaptyOnboardingsSelectParams selectParams) { var builder = new AdaptyProfileParameters.Builder(); switch (elementId) { case "experience": // set custom attribute 'experience' with the selected value (beginner, amateur, pro) builder.SetCustomStringAttribute("experience", selectParams.Value); break; } Adapty.UpdateProfile(builder.Build(), (error) => { if (error != null) { // handle the error } }); } } // ... other interface methods } ``` 3. カスタム属性の値ごとに[セグメントを作成](segments)します。 4. [プレースメント](placements)を作成し、作成した各セグメントに対して[オーディエンス](audience)を追加します。 5. アプリのコードでそのプレースメントの[ペイウォールを表示](unity-paywalls)します。オンボーディングにペイウォールを開くボタンがある場合は、[このボタンのアクションへの応答](unity-handling-onboarding-events#opening-a-paywall)としてペイウォールのコードを実装してください。 --- # File: unity-sdk-call-order --- --- title: "Unity SDKの呼び出し順序" description: "Adapty SDKのメソッドを正しい順序で呼び出すことで、プレミアムアクセスの喪失、アトリビューションの欠落、断続的な#2002エラーを回避できます。" --- `Adapty.Activate()` は、他のAdapty SDKメソッドを呼び出す前に完了している必要があります。完了コールバックが発火するまで、SDKには状態がありません。`Activate()` の前または並行して発行された呼び出しは、[`#2002 notActivated`](unity-handle-errors#custom-network-codes) でエラーになります。 アプリがユーザー認証を行い、起動後にカスタマーユーザーIDを取得する場合は、そのタイミングで `Adapty.Identify()` を呼び出してください。`Identify` コールバックが発火するまでユーザーアクションのメソッドを呼び出してはいけません。`Identify` と競合する呼び出しは [`#3006 profileWasChanged`](unity-handle-errors#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コールバック(例: `getAppsFlyerId`)を待ってください。 | | 2a | `Adapty.Activate(builder.Build(), ...)` — builderに `SetCustomerUserId` を設定 | アプリ起動時、ステップ1の後、カスタマーユーザーIDが判明している場合 | 推奨。匿名プロファイルは一切作成されません。 | | 2b | `Adapty.Activate(builder.Build(), ...)` — `SetCustomerUserId` なし | アプリ起動時、ステップ1の後、カスタマーユーザーIDが不明な場合(または取得しない場合) | Adaptはが匿名プロファイルを作成します。 | | 3 | 各MMPに対して `Adapty.SetIntegrationIdentifier(key, value, callback)` | ステップ2の後、ユーザーアクション呼び出しの前 | MMP IDを正しいプロファイルに紐づけるために必要です。 | | 4 | `Adapty.Identify("YOUR_USER_ID", callback)` | ステップ3の後(MMPがない場合はステップ2の後)、ステップ5の前 — 認証ありの2bパスのみ | 完了コールバックを待ってください。`Identify` 中の並行呼び出しは `#3006 profileWasChanged` を引き起こします。 | | 5 | `GetPaywall`、`GetPaywallProducts`、`RestorePurchases`、`MakePurchase`、`UpdateAttribution`、`UpdateProfile` | `Identify` を呼び出す場合はステップ4の後、それ以外はステップ3の後(MMPがない場合はステップ2の後) | これらの呼び出しには安定したプロファイルが必要です。 | :::important これらのステップをスキップすると、リターンユーザーのプレミアムアクセスの喪失、プロファイルへの `appsflyer_id` の欠落、誤ったオーディエンスに対するペイウォールの返却といった問題が発生します。 ::: ## Web2appとウェブファネルからのインストール \{#web2app-and-web-funnel-installs\} ユーザーがWebチェックアウト(Stripe、Paddle)で購入してからネイティブアプリをインストールした場合、デバイスの最初の `Activate()` によって新しい匿名プロファイルが作成されます。このプロファイルはWebプロファイルと紐づきません。認証フローやインストールリファラーからアプリ起動前にカスタマーユーザーIDを解決できる場合は、`Activate()` に直接渡してください。そうでない場合、`Identify("YOUR_USER_ID")` を呼び出してから `RestorePurchases` を実行するまで、Web上での購入はデバイス上で確認できません。 各Webチェックアウトで送信するメタデータについては、以下を参照してください: - [Stripe](stripe) - [Paddle](paddle) --- # File: unity-optimize-paywall-fetching --- --- title: "Unity SDKでのペイウォール取得を最適化する" description: "Adaptyのペイウォールを確実に取得する: Unityにおけるタイミングとキャッシュおよびフォールバックのパターン。" --- Unity でペイウォールを確実に取得するには、次の3つが必要です: 高速な表示、オーディエンスにターゲティングされたペイウォールの返却、そしてネットワークが遅い場合のグレースフルなフォールバック。以下のルールでは、そのためのタイミング、キャッシュ、フォールバックのパターンについて説明します。 :::tip これらのルールは、`Adapty.Activate()` と `Adapty.Identify()` がすでに解決済みであることを前提としています。詳細は [Unity SDK のコール順序](unity-sdk-call-order) を参照してください。 ::: ## ルールと注意点 \{#rules-and-pitfalls\} | このようにする | このようにしない | 理由 | |---|---|---| | 表示しようとしているプレースメントを取得する。 | 起動時にすべてのプレースメントを並行してプリフェッチする。 | 一括プリフェッチはメインスレッドをブロックし、バースト中にブラックスクリーンが発生する。 | | アトリビューションが解決する時間を確保した後で `GetPaywall` を取得する(例: `Activate` から 1〜2 秒後、または `OnLoadLatestProfile` が発火した後)。 | `Awake()` で `GetPaywall` を呼び出す。 | アトリビューションがまだ到達していない。ペイウォールはデフォルトのオーディエンスに対して解決され、セグメントや ASA パーソナライゼーションがサイレントにバイパスされる。 | | `loadTimeout` を設定し、すべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 | `GetPaywall` を無期限に待機する。 | タイムアウトを設定しない場合、接続品質の低いユーザーはネットワークが解決するまで空白画面を見続けるか、アプリを閉じてしまう。 | `fetchPolicy` と `loadTimeout` パラメータのリファレンスは [ペイウォールとプロダクトの取得](fetch-paywalls-and-products-unity) を参照してください。また、適切なプレースメントの選び方は [プレースメント](placements) を参照してください。 ## 接続が不安定な環境向けの調整 \{#tune-for-poor-connectivity\} 接続品質が一貫して低い市場(農村部、交通機関内、ルーティングの影響を受ける地域)向け: - 最初のフェッチ以外のすべてのフェッチで `fetchPolicy` を `AdaptyPlacementFetchPolicy.ReturnCacheDataElseLoad` に設定する。 - Adapty ダッシュボードですべてのプレースメントに[フォールバックペイウォール](fallback-paywalls)を設定する。 - `loadTimeout` を 3〜5 秒に設定し、タイムアウト発生時はフォールバックを受け入れる。 - ペイウォールの表示を `GetProfile` に依存させない。`GetPaywall` を独立して呼び出すことで、プロファイルの取得が遅くても UI がブロックされないようにする。 --- # File: unity-test --- --- title: "Unity SDKでのテストとリリース" description: "Adapty SDKを使用したUnityアプリのテストとリリース方法をご紹介します。" --- Unityアプリに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-unity --- --- title: "Unity 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** をコピーします。 <Zoom> <img src="/docs/img/afd5012-bundle_id_apple.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 3. Adapty のトップメニューから [**App settings** -> **iOS SDK** タブ](https://app.adapty.io/settings/ios-sdk) を開き、コピーした値を **Bundle ID** フィールドに貼り付けます。 <Zoom> <img src="/docs/img/2d64163-bundle_id.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> </Zoom> 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) に移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックすると、**Subscriptions** セクションにプロダクトの一覧が表示されます。 3. テストしているプロダクトが **Ready to Submit** としてマークされていることを確認します。 <img src="/assets/shared/img/ready-to-submit.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. 表内のプロダクトIDと、Adapty ダッシュボードの [**Products**](https://app.adapty.io/products) タブに表示されているIDを比較します。IDが一致しない場合は、表からプロダクトIDをコピーし、Adapty ダッシュボードで[プロダクトを作成](create-product)してください。 <img src="/assets/shared/img/product-id-copy.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ3. プロダクトの提供地域を確認する \{#step-4-check-product-availability\} 1. **App Store Connect** に戻り、同じ **Subscriptions** セクションを開きます。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックしてプロダクトを表示します。 3. テストしているプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Availability** セクションまでスクロールし、必要なすべての国・地域が一覧に含まれていることを確認します。 <img src="/assets/shared/img/product-availability.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ4. プロダクトの価格を確認する \{#step-5-check-product-prices\} 1. **App Store Connect** の **Monetization** → **Subscriptions** セクションに移動します。 <img src="/assets/shared/img/subscription_group_open.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. サブスクリプショングループ名をクリックします。 3. テストしているプロダクトを選択します。 <img src="/assets/shared/img/click-product.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 4. **Subscription Pricing** までスクロールし、**Current Pricing for New Subscribers** セクションを展開します。 <img src="/assets/shared/img/check-prices.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 5. 必要なすべての価格が一覧に表示されていることを確認します。 <img src="/assets/shared/img/product-pricing.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> ## ステップ5. アプリの有料ステータス、銀行口座、税務フォームが有効であることを確認する \{#step-5-check-app-paid-status-bank-account-and-tax-forms-are-active\} 1. [**App Store Connect**](https://appstoreconnect.apple.com/) のホームページで **Business** をクリックします。 <img src="/assets/shared/img/business.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 2. 会社名を選択します。 <img src="/assets/shared/img/business-name.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> 3. 下にスクロールし、**Paid Apps Agreement**、**Bank Account**、**Tax forms** がすべて **Active** になっていることを確認します。 <img src="/assets/shared/img/appstore-connect-status.webp" style={{ border: '1px solid #727272', /* border width and color */ width: '700px', /* image width */ display: 'block', /* for alignment */ margin: '0 auto' /* center alignment */ }} /> これらの手順を実行することで、`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-unity --- --- title: "Unity SDK における Code-1003 cantMakePayment エラーの修正" description: "Adapty でサブスクリプションを管理する際に発生する決済エラーを解決します。" --- 1003エラー(`cantMakePayments`)は、このデバイスでアプリ内課金ができないことを示しています。 `cantMakePayments`エラーが発生している場合、通常は以下のいずれかの原因が考えられます: - デバイスの制限:このエラーはAdaptyとは無関係です。以下の解決方法を参照してください。 - オブザーバーモードの設定:`makePurchase`メソッドとオブザーバーモードは同時に使用できません。以下のセクションを参照してください。 ## 問題:デバイスの制限 \{#issue-device-restrictions\} | 問題 | 解決方法 | |-----------------------------|---------------------------------------------------------| | スクリーンタイムの制限 | [スクリーンタイム](https://support.apple.com/en-us/102470)でアプリ内課金の制限を無効にする | | アカウントの停止 | Appleサポートに連絡してアカウントの問題を解決する | | 地域の制限 | 対応地域のApp Storeアカウントを使用する | ## 問題:オブザーバーモードとmakePurchaseの併用 \{#issue-using-both-observer-mode-and-makepurchase\} 購入処理に`makePurchase`を使用している場合、オブザーバーモードを使用する必要はありません。[オブザーバーモード](observer-vs-full-mode)が必要なのは、購入ロジックを自分で実装する場合のみです。 したがって、`makePurchase`を使用している場合は、SDK有効化コードからオブザーバーモードの有効化を安全に削除できます。 --- # File: migration-to-unity-sdk-314 --- --- title: "Adapty Unity SDK を v3.14 へ移行する" description: "より高いパフォーマンスと新しいマネタイズ機能のために Adapty Unity SDK v3.14 へ移行します。" --- Adapty SDK 3.14.0 はメジャーリリースであり、いくつかの改善が含まれています。ただし、以下の移行手順が必要になる場合があります。 1. ペイウォールイベント用の専用イベントリスナーの分離。 2. `AdaptyUI.CreateView` を `AdaptyUI.CreatePaywallView` およびその関連メソッドにリネーム。 3. `MakePurchase` メソッドで個別パラメーターの代わりに `AdaptyPurchaseParameters` を使用するよう更新。 4. `SetFallbackPaywalls` を `SetFallback` メソッドに置き換え。 5. `AdaptyPlacement` を使用してペイウォールプロパティにアクセスするよう更新。 6. `AdaptyRemoteConfig` オブジェクトを使用してリモートコンフィグにアクセスするよう更新。 7. `AdaptyPaywall` モデルの `VendorProductIds` を `ProductIdentifiers` に置き換え。 8. `GetPaywall` のフェッチポリシーで `AdaptyFetchPolicy` を使用するよう更新。 ## ペイウォールイベント用の専用イベントリスナーの分離 \{#separate-event-listener-for-paywall-events\} [ペイウォールビルダー](adapty-paywall-builder)でデザインしたペイウォールを表示する場合、ペイウォールビューのイベントは専用の `AdaptyPaywallsEventsListener` インターフェースと `SetPaywallsEventsListener` メソッドを使用するようになりました。コアの `AdaptyEventListener` インターフェースは、プロファイル更新とインストール詳細のために引き続き使用されます。 ```diff showLineNumbers using UnityEngine; using AdaptySDK; public class AdaptyListener : MonoBehaviour, - AdaptyEventListener { + AdaptyEventListener, + AdaptyPaywallsEventsListener { void Start() { Adapty.SetEventListener(this); + Adapty.SetPaywallsEventsListener(this); } // AdaptyEventListener methods public void OnLoadLatestProfile(AdaptyProfile profile) { } public void OnInstallationDetailsSuccess(AdaptyInstallationDetails details) { } public void OnInstallationDetailsFail(AdaptyError error) { } + // AdaptyPaywallsEventsListener methods + // Implement paywall event handlers here } ``` [ペイウォールイベントの処理について詳しく見る](unity-handling-events)。 ## ビュー作成・表示メソッドのリネーム \{#rename-view-creation-and-presentation-methods\} ビューの作成と表示に使用するメソッドがリネームされました。 ```diff showLineNumbers using AdaptySDK; - AdaptyUI.CreateView(paywall, parameters, (view, error) => { + AdaptyUI.CreatePaywallView(paywall, parameters, (view, error) => { if (error != null) { // handle the error return; } - AdaptyUI.PresentView(view, (error) => { + AdaptyUI.PresentPaywallView(view, (error) => { // handle the error }); }); } ``` 同様に、閉じるメソッドもリネームされました。 ```diff showLineNumbers - AdaptyUI.DismissView(view, (error) => { + AdaptyUI.DismissPaywallView(view, (error) => { // handle the error }); ``` ## MakePurchase メソッドの更新 \{#update-makepurchase-method\} `MakePurchase` メソッドは、個別の `subscriptionUpdateParams` および `isOfferPersonalized` 引数の代わりに `AdaptyPurchaseParameters` を使用するようになりました。これにより型安全性が向上し、将来的な購入パラメーターの拡張にも対応しやすくなります。 ```diff showLineNumbers using AdaptySDK; void MakePurchase( AdaptyPaywallProduct product, AdaptySubscriptionUpdateParameters subscriptionUpdate, bool? isOfferPersonalized ) { - Adapty.MakePurchase(product, subscriptionUpdate, isOfferPersonalized, (result, error) => { + var parameters = new AdaptyPurchaseParametersBuilder() + .SetSubscriptionUpdateParams(subscriptionUpdate) + .SetIsOfferPersonalized(isOfferPersonalized) + .Build(); + + Adapty.MakePurchase(product, parameters, (result, error) => { switch (result.Type) { case AdaptyPurchaseResultType.Pending: // handle pending purchase break; case AdaptyPurchaseResultType.UserCancelled: // handle purchase cancellation break; case AdaptyPurchaseResultType.Success: var profile = result.Profile; // handle successful purchase break; default: break; } }); } ``` 追加パラメーターが不要な場合は、次のように簡単に記述できます。 ```csharp showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { Adapty.MakePurchase(product, (result, error) => { // handle purchase result }); } ``` ## フォールバックメソッドの更新 \{#update-fallback-method\} :::important Unity SDK 3.14 にアップグレードする際は、Adapty ダッシュボードから新しいフォールバックファイルをダウンロードし、プロジェクト内の既存ファイルと置き換える必要があります。 ::: フォールバックを設定するメソッドが更新されました。`SetFallbackPaywalls` メソッドは `SetFallback` にリネームされました。 ```diff showLineNumbers using AdaptySDK; void SetFallBackPaywalls() { #if UNITY_IOS var assetId = "adapty_fallback_ios.json"; #elif UNITY_ANDROID var assetId = "adapty_fallback_android.json"; #else var assetId = ""; #endif - Adapty.SetFallbackPaywalls(assetId, (error) => { + Adapty.SetFallback(assetId, (error) => { // handle the error }); } ``` 最終的なコード例は [Unity でフォールバックペイウォールを使用する](unity-use-fallback-paywalls) のページをご覧ください。 ## ペイウォールプロパティアクセスの更新 \{#update-paywall-property-access\} 以下のプロパティが `AdaptyPaywall` から `AdaptyPlacement` に移動されました。 ```diff showLineNumbers using AdaptySDK; void ProcessPaywall(AdaptyPaywall paywall) { - var abTestName = paywall.ABTestName; - var audienceName = paywall.AudienceName; - var revision = paywall.Revision; - var placementId = paywall.PlacementId; + var abTestName = paywall.Placement.ABTestName; + var audienceName = paywall.Placement.AudienceName; + var revision = paywall.Placement.Revision; + var placementId = paywall.Placement.Id; } ``` ## リモートコンフィグアクセスの更新 \{#update-remote-config-access\} リモートコンフィグのプロパティが `AdaptyRemoteConfig` オブジェクトに再構成され、より整理された形になりました。 ```diff showLineNumbers using AdaptySDK; void ProcessRemoteConfig(AdaptyPaywall paywall) { - var remoteConfigString = paywall.RemoteConfigString; - var locale = paywall.Locale; - var remoteConfigDict = paywall.RemoteConfig; + var remoteConfigString = paywall.RemoteConfig.Data; + var locale = paywall.RemoteConfig.Locale; + var remoteConfigDict = paywall.RemoteConfig.Dictionary; } ``` ## AdaptyPaywall モデルの使用方法の更新 \{#update-adapty-paywall-model-usage\} `VendorProductIds` プロパティは非推奨となり、`ProductIdentifiers` に置き換えられました。新しいプロパティは単純な文字列ではなく `AdaptyProductIdentifier` オブジェクトを返すため、プロダクト情報がより構造化されています。 ```diff showLineNumbers using AdaptySDK; void ProcessPaywallProducts(AdaptyPaywall paywall) { - var productIds = paywall.VendorProductIds; - foreach (var vendorId in productIds) { - // use vendorId - } + var productIdentifiers = paywall.ProductIdentifiers; + foreach (var productId in productIdentifiers) { + var vendorId = productId.VendorProductId; + // use vendorId + } } ``` `AdaptyProductIdentifier` オブジェクトは `VendorProductId` プロパティを通じてベンダープロダクト ID にアクセスでき、従来と同じ機能を維持しつつ、将来の拡張に向けてより良い構造を提供します。 ## GetPaywall フェッチポリシーの更新 \{#update-getpaywall-fetch-policy\} `GetPaywall` メソッドの `fetchPolicy` パラメーターの型が `AdaptyPaywallFetchPolicy` から `AdaptyPlacementFetchPolicy` に変更されました。この変更により、SDK 全体でフェッチポリシーの使用が統一されます。 ```diff showLineNumbers using AdaptySDK; void GetPaywall(string placementId) { - Adapty.GetPaywall(placementId, AdaptyPaywallFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => { + Adapty.GetPaywall(placementId, AdaptyPlacementFetchPolicy.ReloadRevalidatingCacheData, null, (paywall, error) => { // handle the result }); } ``` --- # File: migration-to-unity-sdk-34 --- --- title: "Adapty Unity SDK を v3.4 へ移行する" description: "Adapty Unity SDK v3.4 に移行して、パフォーマンス向上と新しいマネタイゼーション機能をご活用ください。" --- Adapty SDK 3.4.0 はメジャーリリースであり、お客様側での移行手順が必要な改善が含まれています。 ## フォールバックペイウォールファイルの更新 \{#update-fallback-paywall-files\} 新しい SDK バージョンとの互換性を確保するため、フォールバックペイウォールファイルを更新してください。 1. Adapty ダッシュボードから[更新済みのフォールバックペイウォールファイルをダウンロード](fallback-paywalls)します。 2. モバイルアプリ内の既存のフォールバックペイウォールを[新しいファイルに置き換えます](unity-use-fallback-paywalls)。 ## オブザーバーモードの実装を更新する \{#update-implementation-of-observer-mode\} オブザーバーモードを使用している場合は、その実装を必ず更新してください。 以前は、トランザクションを Adapty に報告するために異なるメソッドが使用されていました。新しいバージョンでは、Android と iOS の両方で `reportTransaction` メソッドを一貫して使用する必要があります。このメソッドは各トランザクションを Adapty に明示的に報告し、認識されることを保証します。ペイウォールを使用した場合は、トランザクションをそのペイウォールに紐付けるためにバリエーション ID を渡してください。 :::warning **トランザクションの報告をスキップしないでください!** `reportTransaction` を呼び出さないと、Adapty はトランザクションを認識できず、アナリティクスに表示されず、インテグレーションにも送信されません。 ::: ```diff showLineNumbers - #if UNITY_ANDROID && !UNITY_EDITOR - Adapty.RestorePurchases((profile, error) => { - // handle the error - }); - #endif Adapty.ReportTransaction( "YOUR_TRANSACTION_ID", "PAYWALL_VARIATION_ID", // optional (error) => { // handle the error }); ``` --- # File: migration-to-unity330 --- --- title: "Adapty Unity SDK を v3.3 へ移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty Unity SDK v3.3.3 へ移行する方法を説明します。" --- Adapty SDK 3.3.0 はメジャーリリースであり、いくつかの改善が含まれていますが、移行作業が必要な場合があります。 1. Adapty SDK v3.3.x へアップグレードする。 2. Adapty SDK の Adapty モジュールおよび AdaptyUI モジュールで、複数のクラス・プロパティ・メソッドの名前が変更されました。 3. `SetLogLevel` メソッドがコールバックを引数として受け取るようになりました。 4. `PresentCodeRedemptionSheet` メソッドがコールバックを引数として受け取るようになりました。 5. ペイウォールビューの作成方法を変更する。 6. `GetProductsIntroductoryOfferEligibility` メソッドを削除する。 7. フォールバックペイウォールをプラットフォームごとに別々のファイル(各プラットフォーム1ファイル)として `Assets/StreamingAssets/` に保存し、そのファイル名を `SetFallbackPaywalls` メソッドに渡す。 8. 購入処理を更新する。 9. ペイウォールビルダーのイベント処理を更新する。 10. ペイウォールビルダーのペイウォールエラー処理を更新する。 11. Adjust、Amplitude、AppMetrica、Appsflyer、Branch、Firebase および Google Analytics、Mixpanel、OneSignal、Pushwoosh のインテグレーション設定を更新する。 13. Observer モードの実装を更新する。 14. 明示的な `Activate` 呼び出しで Unity プラグインの初期化を更新する。 ## Adapty Unity SDK を 3.3.x へアップグレードする \{#upgrade-adapty-unity-sdk-to-33x\} このバージョンまでは、Adapty SDK がアプリ内で Adapty を正常に動作させるためのコアかつ必須の SDK であり、AdaptyUI SDK はペイウォールビルダーを使用する場合にのみ必要なオプションの SDK でした。 バージョン 3.3.0 以降、AdaptyUI SDK は非推奨となり、AdaptyUI は Adapty SDK のモジュールとして統合されました。この変更により、AdaptyUISDK を削除し、AdaptySDK を再インストールする必要があります。 1. プロジェクトから **AdaptySDK** と **AdaptyUISDK** の両方のパッケージ依存関係を削除する。 2. **AdaptySDK** フォルダーと **AdaptyUISDK** フォルダーを削除する。 3. [Adapty SDK installation & configuration for Unity](sdk-installation-unity) ページの説明に従って、AdaptySDK パッケージを再度インポートする。 ## 名前変更 \{#renamings\} 1. Adapty モジュールでの名前変更: | 旧バージョン | 新バージョン | | ------------------------- | ------------------------ | | Adapty.sdkVersion | Adapty.SDKVersion | | Adapty.LogLevel | AdaptyLogLevel | | Adapty.Paywall | AdaptyPaywall | | Adapty.PaywallFetchPolicy | AdaptyPaywallFetchPolicy | | PaywallProduct | AdaptyPaywallProduct | | Adapty.Profile | AdaptyProfile | | Adapty.ProfileParameters | AdaptyProfileParameters | | ProfileGender | AdaptyProfileGender | | Error | AdaptyError | 2. AdaptyUI モジュールでの名前変更: | 旧バージョン | 新バージョン | | ------------------ | ------------------ | | CreatePaywallView | CreateView | | PresentPaywallView | PresentView | | DismissPaywallView | DismissView | | AdaptyUI.View | AdaptyUIView | | AdaptyUI.Action | AdaptyUIUserAction | ## SetLogLevel メソッドの変更 \{#change-the-setloglevel-method\} `SetLogLevel` メソッドがコールバックを引数として受け取るようになりました。 ```diff showLineNumbers - Adapty.SetLogLevel(Adapty.LogLevel.Verbose); + Adapty.SetLogLevel(Adapty.LogLevel.Verbose, null); // or you can pass the callback to handle the possible error ``` ## PresentCodeRedemptionSheet メソッドの変更 \{#change-the-presentcoderedemptionsheet-method\} `PresentCodeRedemptionSheet` メソッドがコールバックを引数として受け取るようになりました。 ```diff showLineNumbers - Adapty.PresentCodeRedemptionSheet(); + Adapty.PresentCodeRedemptionSheet(null); // or you can pass the callback to handle the possible error ``` ## ペイウォールビューの作成方法を変更する \{#change-how-the-paywall-view-is-created\} 完全なコード例については、[ペイウォールビルダーで作成したペイウォールのビュー設定を取得する](unity-get-pb-paywalls#fetch-the-view-configuration-of-paywall-designed-using-paywall-builder) を参照してください。 ```diff showLineNumbers + var parameters = new AdaptyUICreateViewParameters() + .SetPreloadProducts(true); - AdaptyUI.CreatePaywallView( + AdaptyUI.CreateView( paywall, - preloadProducts: true, + parameters, (view, error) => { // use the view }); ``` ## GetProductsIntroductoryOfferEligibility メソッドの削除 \{#remove-the-getproductsintroductoryoffereligibility-method\} Adapty iOS SDK 3.3.0 より前は、ユーザーが対象かどうかに関わらず、プロダクトオブジェクトには常にオファーが含まれていました。そのため、オファーを使用する前に手動で対象確認を行う必要がありました。 現在は、ユーザーが対象である場合にのみプロダクトオブジェクトにオファーが含まれます。つまり、対象確認は不要になりました — オファーが存在する場合、そのユーザーは対象です。 ## フォールバックペイウォールの提供方法を更新する \{#update-method-for-providing-fallback-paywalls\} このバージョンまでは、フォールバックペイウォールはシリアライズされた JSON として渡されていました。v 3.3.0 以降、仕組みが変更されました。 1. フォールバックペイウォールを `/Assets/StreamingAssets/` 内のファイルに保存する(Android 用に 1 ファイル、iOS 用に 1 ファイル)。 2. ファイル名を `SetFallbackPaywalls` メソッドに渡す。 コードの変更は次のようになります。 ```diff showLineNumbers using AdaptySDK; void SetFallBackPaywalls() { + #if UNITY_IOS + var assetId = "adapty_fallback_ios.json"; + #elif UNITY_ANDROID + var assetId = "adapty_fallback_android.json"; + #else + var assetId = ""; + #endif - Adapty.SetFallbackPaywalls("FALLBACK_PAYWALLS_JSON_STRING", (error) => { + Adapty.SetFallbackPaywalls(assetId, (error) => { // handle the error }); } ``` 最終的なコード例は [Unity でフォールバックペイウォールを使用する](unity-use-fallback-paywalls) ページを参照してください。 ## 購入処理の更新 \{#update-making-purchase\} 以前は、キャンセルされた購入と保留中の購入はエラーとして扱われ、それぞれ `PaymentCancelled` と `PendingPurchase` コードが返されていました。 新しい `AdaptyPurchaseResultType` クラスを使用して、キャンセル済み・成功・保留中の購入を処理します。購入コードを次のように更新してください。 ```diff showLineNumbers using AdaptySDK; void MakePurchase(AdaptyPaywallProduct product) { - Adapty.MakePurchase(product, (profile, error) => { - // handle successfull purchase + Adapty.MakePurchase(product, (result, error) => { + switch (result.Type) { + case AdaptyPurchaseResultType.Pending: + // handle pending purchase + break; + case AdaptyPurchaseResultType.UserCancelled: + // handle purchase cancellation + break; + case AdaptyPurchaseResultType.Success: + var profile = result.Profile; + // handle successful purchase + break; + default: + break; } }); } ``` 最終的なコード例は [モバイルアプリで購入する](unity-making-purchases) ページを参照してください。 ## ペイウォールビルダーのイベント処理を更新する \{#update-handling-of-paywall-builder-events\} キャンセルされた購入と保留中の購入はエラーとして扱われなくなり、これらのケースはすべて `PaywallViewDidFinishPurchase` メソッドで処理されます。 1. キャンセルされた購入イベントの処理を削除する。 2. 購入成功イベントの処理を次のように更新する。 ```diff showLineNumbers - public void OnFinishPurchase( - AdaptyUI.View view, - Adapty.PaywallProduct product, - Adapty.Profile profile - ) { } + public void PaywallViewDidFinishPurchase( + AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyPurchaseResult purchasedResult + ) { } ``` 3. アクションの処理を更新する。 ```diff showLineNumbers - public void OnPerformAction( - AdaptyUI.View view, - AdaptyUI.Action action - ) { + public void PaywallViewDidPerformAction( + AdaptyUIView view, + AdaptyUIUserAction action + ) { switch (action.Type) { - case AdaptyUI.ActionType.Close: + case AdaptyUIUserActionType.Close: view.Dismiss(null); break; - case AdaptyUI.ActionType.OpenUrl: + case AdaptyUIUserActionType.OpenUrl: var urlString = action.Value; if (urlString != null { Application.OpenURL(urlString); } default: // handle other events break; } } ``` 4. 購入開始の処理を更新する。 ```diff showLineNumbers - public void OnSelectProduct( - AdaptyUI.View view, - Adapty.PaywallProduct product - ) { } + public void PaywallViewDidSelectProduct( + AdaptyUIView view, + string productId + ) { } ``` 5. 購入失敗の処理を更新する。 ```diff showLineNumbers - public void OnFailPurchase( - AdaptyUI.View view, - Adapty.PaywallProduct product, - Adapty.Error error - ) { } + public void PaywallViewDidFailPurchase( + AdaptyUIView view, + AdaptyPaywallProduct product, + AdaptyError error + ) { } ``` 6. リストア成功イベントの処理を更新する。 ```diff showLineNumbers - public void OnFailRestore( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailRestore( + AdaptyUIView view, + AdaptyError error + ) { } ``` 最終的なコード例は [ペイウォールのイベントを処理する](unity-handling-events) ページを参照してください。 ## ペイウォールビルダーのペイウォールエラー処理を更新する \{#update-handling-of-paywall-builder-paywall-errors\} エラーの処理も変更されました。以下のガイダンスに従ってコードを更新してください。 1. プロダクト読み込みエラーの処理を更新する。 ```diff showLineNumbers - public void OnFailLoadingProducts( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailLoadingProducts( + AdaptyUIView view, + AdaptyError error + ) { } ``` 2. レンダリングエラーの処理を更新する。 ```diff showLineNumbers - public void OnFailRendering( - AdaptyUI.View view, - Adapty.Error error - ) { } + public void PaywallViewDidFailRendering( + AdaptyUIView view, + AdaptyError error + ) { } ``` ## サードパーティインテグレーション SDK 設定の更新 \{#update-third-party-integration-sdk-configuration\} Adapty Unity SDK 3.3.0 以降、`updateAttribution` メソッドのパブリック API を更新しました。以前は `[AnyHashable: Any]` ディクショナリを受け取り、さまざまなサービスからアトリビューションオブジェクトを直接渡すことができました。現在は `[String: any Sendable]` が必要なため、渡す前にアトリビューションオブジェクトを変換する必要があります。 Adapty Unity SDK 3.3.0 以降でインテグレーションが正しく機能するよう、以下のセクションに記載されているインテグレーションの SDK 設定を更新してください。 ### Adjust 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Adjust インテグレーションの SDK 設定](adjust#connect-your-app-to-adjust) を参照してください。 ```diff showLineNumbers - using static AdaptySDK.Adapty; using AdaptySDK; Adjust.GetAdid((adid) => { - Adjust.GetAttribution((attribution) => { - Dictionary<String, object> data = new Dictionary<String, object>(); - - data["network"] = attribution.Network; - data["campaign"] = attribution.Campaign; - data["adgroup"] = attribution.Adgroup; - data["creative"] = attribution.Creative; - - String attributionString = JsonUtility.ToJson(data); - Adapty.UpdateAttribution(attributionString, AttributionSource.Adjust, adid, (error) => { - // handle the error - }); + if (adid != null) { + Adapty.SetIntegrationIdentifier( + "adjust_device_id", + adid, + (error) => { + // handle the error + }); } }); Adjust.GetAttribution((attribution) => { Dictionary<String, object> data = new Dictionary<String, object>(); data["network"] = attribution.Network; data["campaign"] = attribution.Campaign; data["adgroup"] = attribution.Adgroup; data["creative"] = attribution.Creative; String attributionString = JsonUtility.ToJson(data); - Adapty.UpdateAttribution(attributionString, AttributionSource.Adjust, adid, (error) => { + Adapty.UpdateAttribution(attributionString, "adjust", (error) => { // handle the error }); }); ``` ### Amplitude 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Amplitude インテグレーションの SDK 設定](amplitude#sdk-configuration) を参照してください。 ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetAmplitudeUserId("YOUR_AMPLITUDE_USER_ID"); - builder.SetAmplitudeDeviceId(amplitude.getDeviceId()); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + Adapty.SetIntegrationIdentifier( + "amplitude_user_id", + "YOUR_AMPLITUDE_USER_ID", + (error) => { + // handle the error + }); + Adapty.SetIntegrationIdentifier( + "amplitude_device_id", + amplitude.getDeviceId(), + (error) => { + // handle the error + }); ``` ### AppMetrica 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppMetrica インテグレーションの SDK 設定](appmetrica#sdk-configuration) を参照してください。 ```diff showLineNumbers using AdaptySDK; - var deviceId = AppMetrica.GetDeviceId(); - if (deviceId != null { - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetAppmetricaProfileId("YOUR_ADAPTY_CUSTOMER_USER_ID"); - builder.SetAppmetricaDeviceId(deviceId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); - } + var deviceId = AppMetrica.GetDeviceId(); + if (deviceId != null { + Adapty.SetIntegrationIdentifier( + "appmetrica_device_id", + deviceId, + (error) => { + // handle the error + }); + + Adapty.SetIntegrationIdentifier( + "appmetrica_profile_id", + "YOUR_ADAPTY_CUSTOMER_USER_ID", + (error) => { + // handle the error + }); + } ``` ### AppsFlyer 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[AppsFlyer インテグレーションの SDK 設定](appsflyer#connect-your-app-to-appsflyer) を参照してください。 ```diff showLineNumbers using AppsFlyerSDK; using AdaptySDK; // before SDK initialization AppsFlyer.getConversionData(this.name); // in your IAppsFlyerConversionData void onConversionDataSuccess(string conversionData) { // It's important to include the network user ID - string appsFlyerId = AppsFlyer.getAppsFlyerId(); - Adapty.UpdateAttribution(conversionData, AttributionSource.Appsflyer, appsFlyerId, (error) => { + string appsFlyerId = AppsFlyer.getAppsFlyerId(); + + Adapty.SetIntegrationIdentifier( + "appsflyer_id", + appsFlyerId, + (error) => { // handle the error }); + + Adapty.UpdateAttribution( + conversionData, + "appsflyer", + (error) => { + // handle the error + }); } ``` ### Branch 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Branch インテグレーションの SDK 設定](branch#connect-your-app-to-branch) を参照してください。 ```diff showLineNumbers using AdaptySDK; - class YourBranchImplementation { - func initializeBranch() { - Branch.getInstance().initSession(launchOptions: launchOptions) { (data, error) in - if let data { - Adapty.updateAttribution(data, source: .branch) - } - } - } - } + Branch.initSession(delegate(Dictionary<string, object> parameters, string error) { + string attributionString = JsonUtility.ToJson(parameters); + + Adapty.UpdateAttribution( + attributionString, + "branch", + (error) => { + // handle the error + }); + }); ``` ### Firebase と Google Analytics \{#firebase-and-google-analytics\} 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Firebase および Google Analytics インテグレーションの SDK 設定](firebase-and-google-analytics) を参照してください。 ```diff showLineNumbers // We suppose FirebaseAnalytics Unity Plugin is already installed using AdaptySDK; Firebase.Analytics .FirebaseAnalytics .GetAnalyticsInstanceIdAsync() .ContinueWithOnMainThread((task) => { if (!task.IsCompletedSuccessfully) { // handle error return; } var firebaseId = task.Result var builder = new Adapty.ProfileParameters.Builder(); - builder.SetFirebaseAppInstanceId(firebaseId); - - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error + Adapty.SetIntegrationIdentifier( + "firebase_app_instance_id", + firebaseId, + (error) => { + // handle the error }); }); ``` ### Mixpanel 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Mixpanel インテグレーションの SDK 設定](mixpanel#sdk-configuration) を参照してください。 ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetMixpanelUserId(Mixpanel.DistinctId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + var distinctId = Mixpanel.DistinctId; + if (distinctId != null) { + Adapty.SetIntegrationIdentifier( + "mixpanel_user_id", + distinctId, + (error) => { + // handle the error + }); + } ``` ### OneSignal 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[OneSignal インテグレーションの SDK 設定](onesignal#sdk-configuration) を参照してください。 ```diff showLineNumbers using AdaptySDK; - using OneSignalSDK; - var pushUserId = OneSignal.Default.PushSubscriptionState.userId; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetOneSignalPlayerId(pushUserId); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + var distinctId = Mixpanel.DistinctId; + if (distinctId != null) { + Adapty.SetIntegrationIdentifier( + "mixpanel_user_id", + distinctId, + (error) => { + // handle the error + }); + } ``` ### Pushwoosh 以下のようにモバイルアプリのコードを更新してください。完全なコード例については、[Pushwoosh インテグレーションの SDK 設定](pushwoosh#sdk-configuration) を参照してください。 ```diff showLineNumbers using AdaptySDK; - var builder = new Adapty.ProfileParameters.Builder(); - builder.SetPushwooshHWID(Pushwoosh.Instance.HWID); - Adapty.UpdateProfile(builder.Build(), (error) => { - // handle error - }); + Adapty.SetIntegrationIdentifier( + "pushwoosh_hwid", + Pushwoosh.Instance.HWID, + (error) => { + // handle the error + }); ``` ## Observer モードの実装を更新する \{#update-observer-mode-implementation\} ペイウォールとトランザクションの紐付け方法を更新してください。以前は `setVariationId` メソッドを使用して `variationId` を割り当てていました。現在は、新しい `reportTransaction` メソッドを使用してトランザクションを記録する際に `variationId` を直接含めることができます。最終的なコード例は [Observer モードで購入トランザクションにペイウォールを紐付ける](report-transactions-observer-mode-unity) ページを参照してください。 ```diff showLineNumbers // every time when calling transaction.finish() - Adapty.SetVariationForTransaction("<variationId>", "<transactionId>", (error) => { - if(error != null) { - // handle the error - return; - } - - // successful binding - }); + Adapty.ReportTransaction( + "YOUR_TRANSACTION_ID", + "PAYWALL_VARIATION_ID", // optional + (error) => { + // handle the error + }); ``` ## Unity プラグインの初期化を更新する \{#update-the-unity-plugin-initialization\} Adapty Unity SDK 3.3.0 以降、プラグインの初期化時に `Activate` メソッドを明示的に呼び出すことが必須になりました。 ```csharp showLineNumbers Adapty.Activate(builder.Build(), (error) => { if (error != null) { // handle the error return; } }); ``` --- # File: migration-to-unity-sdk-v3 --- --- title: "Adapty Unity SDK を v3.0 に移行する" description: "パフォーマンス向上と新しいマネタイズ機能のために Adapty Unity SDK v3.0 に移行しましょう。" --- Adapty SDK v3.0 では、新しい [Adapty ペイウォールビルダー](adapty-paywall-builder)がサポートされました。これはペイウォールをノーコードで作成できる使いやすいツールの最新バージョンです。高い柔軟性と豊富なデザイン機能により、ペイウォールの効果と収益性をさらに高めることができます。 ## アップグレードの手順 \{#upgrade-process\} Unity のアップグレード手順は他のプラットフォームと同様です。 1. Adapty SDK v3.x にアップグレードする 2. 既存のペイウォールを新しいペイウォールビルダーに移行する Unity 固有の詳細な移行手順については、[Unity SDK インストールガイド](sdk-installation-unity)を参照し、メインの移行ガイドに記載されている一般的な移行手順に従ってください。 --- # File: unity-migration-guide --- --- title: "SDK移行ガイド" description: "Unity Adapty SDKの移行ガイド。" --- ## 移行ガイド \{#migration-guides\} ### [Unity Adapty SDK 3.xへの移行ガイド](unity-sdk-migration-guides) 旧バージョンからUnity Adapty SDK 3.xへの移行方法を説明します。 ## 新機能 \{#whats-new\} ### バージョン 3.x \{#version-3x\} - ペイウォール表示の強化 - エラーハンドリングの改善 - C#サポートの向上 - パフォーマンスの最適化 ### バージョン 2.x \{#version-2x\} - オンボーディング機能の追加 - アナリティクスの強化 - 購入フローの改善 - バグ修正と安定性の向上 ## 破壊的変更 \{#breaking-changes\} ### バージョン 3.x \{#version-3x-1\} - オブザーバーAPIの更新 - ペイウォール表示メソッドの変更 - エラーハンドリング構造の変更 ### バージョン 2.x \{#version-2x-1\} - オンボーディングAPIの更新 - プロファイル構造の変更 - 購入フローの変更 ## 移行チェックリスト \{#migration-checklist\} 新しいバージョンへ移行する際は、以下を確認してください: - [ ] 破壊的変更の確認 - [ ] APIコールの更新 - [ ] 全機能のテスト - [ ] エラーハンドリングの更新 - [ ] アナリティクストラッキングの確認 - [ ] 全プラットフォームでのテスト --- # End of Documentation _Generated on: 2026-07-24T13:00:57.863Z_ _Successfully processed: 41/41 files_