Flutterアプリへの決済機能導入ガイド(2025年版)
背景:スマホ新法と決済手段の多様化促進
2025年12月18日に日本で施行された「スマートフォンソフトウェア競争促進法(通称:スマホ新法)」により、AppleやGoogleによるアプリストア運営(課金導線・手数料・決済手段の制約など)に大きな変更が入りました。
この流れの中で、開発者が取りうる課金導線は大きく次のように整理できます。
-
公式ストアの課金システム(IAP)
従来通り App Store / Google Play の決済を使う方式 -
代替の決済プロバイダをアプリ内に組み込む
サードパーティ決済SDK等をアプリ内で直接利用する方式 -
外部Webサイトへの決済誘導
アプリから外部ブラウザでWeb上の支払いページに遷移させる方式 -
代替アプリストアでの配信と決済
他社ストア経由でアプリ配布・決済を行う方式
重要:ただし、iOS/Androidともに「地域」「カテゴリ」「年齢」などの条件で要件が変わる可能性があるため、実務では“出し分け前提”で設計するのが安全です。
本記事では Flutter を使った決済機能の導入方法について、外部決済(Web決済やカード決済SDKの組み込み) と ストア内課金(IAP) のパターンを整理します。主要な Flutter 向け決済パッケージの比較や、実装のポイント・注意点を中級〜上級者向けに解説します。
IAP vs 外部決済:まず方式を選ぶ
最初のステップは、自分のアプリの課金形態に応じて 「IAP」 と 「外部決済」 のどちらを採用するか(または併用するか)を決めることです。
アプリ内課金(IAP)が基本になるケース
- アプリ内で消費される デジタルコンテンツ(追加機能、ゲーム内アイテム、サブスク等)
- 公式SDKの恩恵(レシート検証・購入復元・返金導線など)を活かしたい
- 実装をシンプルにしたい / 審査観点の不確実性を減らしたい
- 海外展開などで地域差に追随しづらい
外部決済(Web課金/決済SDK)が適するケース
- 物理的サービス / 物理商品の購入(IAPの対象外)
- Webにもサービスがあり Web課金した権利をアプリでも有効化したい
- 手数料削減・決済手段の多様化(コンビニ払い・QR・銀行振込等)がユーザーメリットになる
- 既存の決済基盤(PayPal/Braintree等)を流用したい
デメリット:実装/運用/セキュリティ(不正、チャージバック、二重決済、税務処理)の負担が増えやすい。UX面でも外部ブラウザ遷移は離脱要因になり得ます。
💡ハイブリッド運用も現実解
- iOSはIAP中心、Androidは独自決済も併用
- 日本向けのみ外部決済を出して、他地域はIAPのみ
- Remote Config などで課金ボタン自体を出し分け
Flutter なら Platform.isIOS だけでなく、地域/年齢/審査状況に応じた出し分けも比較的作りやすいです。
Flutter主要決済パッケージの比較
代表的なものをまとめます。
| パッケージ名 | 主な対応サービス・機能 | 対応プラットフォーム | 実装方式 | 主な用途・特徴 |
|---|---|---|---|---|
flutter_stripe |
Stripe(カード、Apple Pay/Google Pay 等) | iOS / Android(※Webは別実装) | ネイティブSDK連携 | 外部決済の本命。汎用性が高い |
pay |
Apple Pay / Google Pay | iOS / Android | ネイティブAPI連携 | “ウォレットボタンだけ”追加したい時に最適 |
payjp_flutter |
PAY.JP(国内カード決済 + Apple Pay) | iOS / Android | ネイティブSDK連携 | 国内向け。日本語情報も多い |
flutter_braintree |
Braintree(カード、PayPal等) | iOS / Android | ネイティブSDKラッパー | Braintree運用中なら候補 |
flutter_paypal_payment |
PayPal単独 | iOS / Android / Web / Desktop | WebView + APIラッパー | 早くPayPalを入れたい時の簡易解 |
paypay_uo(非公式) |
PayPay(Open API) | Dartのみ(UI自前) | REST APIクライアント | 日本向けQR決済。運用/審査/保守は要注意 |
in_app_purchase |
App Store / Play課金 | iOS / Android | 公式ラッパー | 単発購入 / サブスクを直接実装(設計は自前) |
purchases_flutter |
RevenueCat(IAP管理) | iOS / Android | IAP抽象化 + バックエンド | サブスク管理の王道。Entitlements一元化 |
purchases_ui_flutter |
RevenueCat Paywalls | iOS / Android | 課金UIコンポーネント | 課金画面を“丸ごと”導入したい時に便利 |
外部決済の実装パターン
Flutterで外部決済を導入する方法は大きく 「Webベースの決済フロー」 と 「ネイティブ決済SDK組み込み」 の2つです。
パターン1:Web決済フロー(外部ブラウザ / WebView)
アプリ → Webで決済 → アプリに戻って同期 という流れです。
決済UIやセキュリティをWeb側に寄せられる一方、決済完了をアプリ側にどう反映するかが要点になります。
典型フロー:
- アプリから購入URLを開いてWebで決済
- 決済成功データを決済基盤(Stripe等)で確定
- アプリ復帰時に購入状態を再取得して機能を解放
RevenueCat Web Purchase Links の例(url_launcher)
// RevenueCat購入リンクを組み立て
Uri buildWebPurchaseLink({
required String token, // RevenueCat発行のリンクトークン
required String appUserId, // 紐付けるユーザーID
String? packageId, // (任意)特定プラン指定
}) {
final base = Uri.parse(
"https://pay.rev.cat/$token/${Uri.encodeComponent(appUserId)}",
);
final params = <String, String>{
"utm_source": "app",
if (packageId != null) "package_id": packageId,
};
return base.replace(queryParameters: params);
}
// 外部ブラウザでリンクを開く
Future<void> openExternalCheckout(Uri url) async {
await launchUrl(url, mode: LaunchMode.externalApplication);
}
💡実務TIP(反映ラグ対策)
購入直後は entitlement 反映に数秒ラグが出ることがあります。
- resumed でまず1回同期
- 反映が無ければ数秒おきに2〜3回再試行
- それでもダメなら「購入済みの方はこちら(復元)」ボタンを用意
Stripe(自前)を使う場合の要点
- Web側の決済成功は Webhook(例:
checkout.session.completed)で受けてDB更新 - アプリは復帰時に「購入状態」APIを叩いて同期(ポーリング / pushでも可)
- 二重決済対策として
idempotency_key/ サーバ側の購入済みチェックは必須
パターン2:ネイティブ決済SDKを組み込む(アプリ内完結)
例:flutter_stripe で PaymentSheet / CardField を出し、その場で決済確定まで行うパターンです。
UXは良い一方、ストア規約・審査の扱いが難所になりがちです。
代表的な手順
- バックエンドで Intent / Token を作る(カード情報を直接サーバに送らない)
- クライアントで支払いUIを表示して確定
- 成功/失敗を処理し、必要ならサーバにも結果保存
注意:iOSでデジタル商品を代替決済で売る場合、表示文言・導線・要件が変わる可能性があるため、最初から出し分けできる設計が重要です。
RevenueCatを用いた外部決済連携(Web Purchase Links)
RevenueCat はIAP管理サービスですが、近年「Web課金 → Entitlement付与」の形で外部課金を扱う運用が可能になっています。
基本はこうです
- RevenueCat ダッシュボードで Web課金(Stripe等)を設定
- Web Purchase Link を発行
- アプリからリンクを開かせて購入
- アプリ復帰時に
Purchases.getCustomerInfo()で entitlement 同期
Redemption Links(引き換えリンク)
ログイン前ユーザーでも Webで購入 → 後からアプリに購入権利を紐付け できる仕組み。
- Webで購入(App User IDなし)
- 決済完了後に一回限りの Redeem URL が発行される
- ユーザーが踏むとアプリ起動 → SDKが購入を現在のユーザーIDへ紐付け
-
getCustomerInfo()で entitlement が active になっていれば有効化完了
制約例:リンクが1回限り / 失効時間あり、など運用設計が必要。
ストア規約とプラットフォームごとの注意点
外部決済導入時の最大難所はここです。特に デジタル商品 は要注意。
iOS(Apple)
- 年齢やカテゴリにより外部決済リンクが制限される可能性
- UI上の表記(「Appleの決済ではない」等)や、導線要件が変わり得る
- 地域別に外部決済ボタンを出し分けるのが現実解になりやすい
Android(Google)
- iOSより柔軟なケースが多いが、ユーザーに混乱を与えないUIが重要
- Google決済と並列で選ばせるUIなど、設計パターンが増える
共通の注意点
- 外部決済を選ぶなら「なぜ外部なのか」を説明できる設計・文言が必要
- 価格表示・ボタン文言・リンク先の扱いは審査で突っ込まれやすい
- 最新のガイドライン/事例に追随する前提で、設計を固定化しない
UX面での考慮事項
- 事前案内:外部ブラウザへ遷移するなら「ブラウザで決済を続けます」など説明を出す
- 復帰後の同期:ローディング表示・自動同期・再試行・復元ボタンを用意
- エラー処理:通信不良/拒否/キャンセルの分岐を定義し、リカバリ導線を作る
- 重複購入防止:購入済み表示、ボタン無効化、サーバ側の二重購入防止
- 端末移行/再ログイン:IAPは復元、外部はDB照会、RevenueCatは同期設計を整理
- テスト:成功/失敗/キャンセル/遅延/復帰などシナリオ網羅。Deep Link/Universal Linksも検証
日本国内での実装上の課題とヒント
PayPayなど国内スマホ決済
- 公式Flutter SDKが無いケースが多く、REST API連携+UI自前になりやすい
- Webhookで結果を受ける設計が必要(支払い作成 → 支払い完了通知 → 反映)
- 非公式ライブラリ採用は保守・審査・仕様変更リスクを織り込む
国内向けカード決済サービス
- Stripeは強力だが、国内事業者向けにPAY.JP等の選択肢もある
- SDKが無い決済代行は Web決済(WebView/外部ブラウザ)が現実解になりやすい
法規制・年齢制限(未成年対応)
- 独自決済を導入すると、親権者同意やUI設計を自前で持つ必要が出やすい
- トラブル回避のため、利用規約・同意フロー・記録(ログ)も含めて設計
手数料と会計処理
- Apple売上とStripe売上で入金サイクル/手数料/税務が変わる
- 購入経路(IAP / Web / SDK)をイベント・ログで区別しておくと後々楽
まとめ
- 実装はまず IAP vs 外部決済 を整理すると迷いが減る
- 外部決済は Webフロー(外部ブラウザ + 復帰時同期)が導入しやすい
- サブスク運用なら RevenueCat の Web Purchase Links +
getCustomerInfo()同期 が最短ルート - ただし、デジタル商品を外部へ誘導する場合は規約/地域差が絡むため、最初から出し分け設計を入れるのが安全