---
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 バージョン 2.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 result = await adapty.makePurchase(
    product: product,
    subscriptionUpdateParams: subscriptionUpdateParams,
  );
  
  // successful cross-grade
} on AdaptyError catch (adaptyError) {
  // Handle the error
} catch (e) {
  // Handle the error
}
```
追加リクエストパラメータ：

| パラメータ                    | 必須/任意 | 説明                                                                                             |
| :--------------------------- | :------- |:--------------------------------------------------------------------------------------------------------|
| **subscriptionUpdateParams** | 必須 | [`AdaptyAndroidSubscriptionUpdateParameters`](https://pub.dev/documentation/adapty_flutter/latest/adapty_flutter/AdaptyAndroidSubscriptionUpdateParameters-class.html) オブジェクト。 |

サブスクリプションと置き換えモードについては、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\}

---
no_index: true
---
import Callout from '../../../components/Callout.astro';

<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\}

<Callout type="warning">
Appleは2026年3月にアプリ内課金向けのプロモコードを廃止しました。オファーコードはより多くの機能（適格性の設定、有効期限、四半期あたり最大100万コード）を備えた後継機能です。アプリ内課金にプロモコードを使用していた場合は、App Store Connectでオファーコードに移行してください。
</Callout>

レガシープロモコード（アプリのバージョンごとに最大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),
);
```