9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【明日施行】スマホ新法で「外部決済」どうする?Flutter実装パターン総まとめ

Last updated at Posted at 2025-12-17

12月18日(木)施行「スマホ新法」Flutter完全ガイド

明日(12/18)全面施行されるスマホ新法で注目される「決済手段の多様化」を、Flutter実装の観点から整理しました。

「RevenueCatってIAP専用では?外部決済はできないのでは?」と思い調べたところ、
RevenueCatには Web上で決済 → アプリ側でEntitlementを同期する仕組み(Web Billing) が用意されていることが分かりました。

本記事では、カード決済SDKをアプリに直接組み込む“外部決済” ではなく、
アプリ → Web決済 → RevenueCatで購入状態を管理 → アプリで機能解放
という運用パターンを前提に整理しています。

目次

  • はじめに:AppleとGoogleに影響するスマホ新法とは
  • スマホ新法とは?
    • 規制対象企業(指定:2025年3月26日)
  • 何が変わる?主な変更点
      1. 代替アプリストアの解禁
      1. 決済手段の多様化
      1. ブラウザ・検索エンジンの選択画面表示
  • ユーザーへの影響(ざっくり)
    • プラス面
    • マイナス面
  • セキュリティへの配慮(正当化事由)
  • ここから本題に入ります:Flutterで外部決済を導入する
  • Flutter決済連携 完全ガイド(スマホ新法 × 外部決済 × RevenueCat)
  • まず決める:あなたの決済はどっち?(IAP / 外部決済)
      1. アプリ内課金(IAP)が基本になるケース
      1. 外部決済(Web/決済SDK)が取りやすいケース
  • Flutter決済連携用パッケージ一覧(主要どころ)
  • RevenueCatで“外部決済”をやる全体像
  • 実装:RevenueCat Web Purchase Links(identified)最小構成
      1. 前提(重要)
      1. RevenueCat側でやること(最短)
      1. Flutter側でやること(最小)
      • 依存関係
      • RevenueCat初期化(App User IDを統一)
      • Purchase Link を外部ブラウザで開く
      • アプリ復帰時にCustomerInfoを再取得してentitlement反映
  • 実装:Redemption Links(匿名購入→後から紐付け)
    • ざっくり流れ
  • ストア規約の注意点(ここが一番詰まる)
  • まとめ
  • 参考リンク
  • お知らせ(採用情報)

はじめに:AppleとGoogleに影響するスマホ新法とは

スマートフォン

2025年12月18日、日本で「スマートフォンにおいて利用される特定ソフトウェアに係る競争の促進に関する法律」(通称:スマホ新法)が全面施行されます。
本記事では、スマホ新法の要点を簡潔に整理したうえで、Flutterアプリで「決済手段の多様化」に対応するための実装パターンをまとめます。


スマホ新法とは?

スマホ新法は、Apple・Googleによる市場の寡占状態を是正し、
競争を促進することを目的とした法律です。
EUの「デジタル市場法(DMA)」も参考に制度設計が進められ、
公正取引委員会が所管します。

規制対象企業(指定:2025年3月26日)

  • Apple Inc.(モバイルOS/アプリストア/ブラウザ)
  • iTunes株式会社(アプリストア)
  • Google LLC(モバイルOS/アプリストア/ブラウザ/検索エンジン)

何が変わる?主な変更点

1) 代替アプリストアの解禁

0012.png

現状:App Store / Google Play が中心
変更後:第三者ストアの利用を不当に妨げることが禁止される

メリット

  • 開発者・ユーザー双方の選択肢が増える
  • 新しい流通・サービスが登場しやすくなる

注意点

  • マルウェア等のリスクが増える可能性
  • インストール前にストアの信頼性確認が必要

2) 決済手段の多様化

Gemini_Generated_Image_mkot6tmkot6tmkot.png

現状:決済手段がOS標準の課金(IAP)中心になりやすい
変更後:外部決済を不当に排除しないことが求められる

※ ただし、デジタルコンテンツの外部決済誘導が
 常に許可されるわけではなく、
 具体的な導線はストア規約・地域・プログラム条件に依存する

メリット

  • 手数料や価格設計の自由度が上がる可能性
  • ユーザーの決済手段の選択肢が増える

注意点

  • 決済ごとにセキュリティ/返金対応が異なる
  • UX(購入フロー/購入確認)を丁寧に作る必要がある

3) ブラウザ・検索エンジンの選択画面表示

Gemini_Generated_Image_fiidzofiidzofiid.png

現状:iOS=Safari、Android=Chromeが標準
変更後:初期設定時などに選択画面が提示されることが求められる、自由に選べる

メリット

  • 自分に合ったブラウザ・検索を選びやすい
  • 競争促進による機能改善が期待される

注意点

  • セキュリティ機能の比較が必要
  • 青少年端末はフィルタリング対応の確認が重要

ユーザーへの影響(ざっくり)

Gemini_Generated_Image_4y6urf4y6urf4y6u.png

プラス面

✅ 選択肢が増える
✅ 価格やサービス改善が期待できる
✅ 競争促進によるイノベーション
✅ 体験のカスタマイズ性向上

マイナス面

⚠️ セキュリティリスクが増える可能性
⚠️ 悪意あるアプリへの警戒が必要
⚠️ 選択肢が増えて分かりにくくなる
⚠️ ITリテラシーが低い層への配慮が課題


セキュリティへの配慮(正当化事由)

スマホ新法では、一定の条件を満たす場合は例外的に制限が許容されます(正当化事由)。

  • セキュリティ確保
  • 利用者情報の保護
  • 青少年の保護
  • 犯罪行為の防止

そのためApple/Google側も、マルウェア疑いのアプリを拒否する等の対応を取り得ます。


ここから本題に入ります:Flutterで外部決済を導入する

ここまでで「スマホ新法の概要」と「何が変わるか」を整理しました。
ここからは Flutterアプリで“外部決済”を導入する現実的な方法にフォーカスして解説します。


Flutter決済連携 完全ガイド(スマホ新法 × 外部決済 × RevenueCat)

スマホ新法で“外部決済”が話題になっていますが、実装の整理はシンプルです。

  • Flutterで決済を入れる方法は (A)アプリ内課金(IAP)(B)外部決済(Web/決済SDK) に大別できる
  • ただし デジタル商品(サブスク/コンテンツ)をアプリから外部決済に誘導できるか は、iOS/Androidともに制度・地域・プログラム依存
    → 最初から「出し分け」前提で設計するのが安全

この記事ではまず「Flutterの主要決済パッケージ」を整理し、後半で RevenueCatを使った“外部決済(Web Billing / Web Purchase Links)” を、最小実装で紹介します。

まず決める:あなたの決済はどっち?(IAP / 外部決済)

1) アプリ内課金(IAP)が基本になるケース

  • サブスク(Proプラン)
  • デジタルコンテンツ(ポイント/コイン、追加機能、デジタル配信)

RevenueCat(purchases_flutter)は、IAPを StoreKit / Google Play Billing + RevenueCat backend で扱いやすくするSDKです。

2) 外部決済(Web/決済SDK)が取りやすいケース

  • 物販
  • 予約
  • リアルサービス(配送、来店、イベントなど)

ただし「デジタル商品をアプリから外部決済へ誘導」するのは、ストアの制度・地域条件が絡みます。
→ 後述の「出し分け(OS×国×プラン)」設計が重要です。


Flutter決済連携用パッケージ一覧(主要どころ)

パッケージ 対応サービス プラットフォーム 実装方式 使いどころ
flutter_stripe Stripe(カード/Apple Pay/Google Pay等) iOS / Android(Webは別実装) ネイティブSDK連携(PaymentSheet等) 外部決済の本命。汎用性が高い
pay Apple Pay / Google Pay iOS / Android ネイティブAPI連携 “ウォレットボタンだけ”追加したい時
payjp_flutter PAY.JP(カード/Apple Pay※iOS) 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 Payment API)※非公式 Dart APIクライアント UI自前。採用は慎重に
purchases_flutter RevenueCat(IAP) iOS / Android IAP抽象化 + RC backend “サブスク運用”の王道
purchases_ui_flutter RevenueCat Paywalls iOS / Android Paywall UI 課金UIも丸ごと寄せたい時

RevenueCatで“外部決済”をやる全体像

RevenueCatで「外部決済(Web課金)」をやる場合の基本形はこれです。

アプリ → Web(RevenueCat Web Billing / Web Purchase Links)で決済 → RevenueCatでentitlement有効化 → アプリ側でCustomerInfo再取得して解放

RevenueCat側には、アプリ→Webへ誘導する仕組みが複数あります。

  • Web Purchase Links:RevenueCatホストの購入ページURL(ノーコード)
  • Web Purchase Button:Paywalls上のボタンをWebへ向ける
  • Redemption Links:匿名購入→後からアプリに紐付け(deep link)

実装:RevenueCat Web Purchase Links(identified)最小構成

0) 前提(重要)

Web Purchase Linksは App User ID をURL末尾に付けないと404 になります。
つまり「購入を誰に紐付けるか(App User ID設計)」が最初の関門です。


1) RevenueCat側でやること(最短)

  1. Web Billingを有効化し、Stripe等の決済プロバイダーを接続
  2. Web向けプロダクト/Offeringを用意
  3. Web Purchase Linkを発行(Production / Sandbox)
  4. (任意)UTMやメタデータを付けて計測

2) Flutter側でやること(最小)

依存関係

dependencies:
  purchases_flutter: ^8.0.0
  url_launcher: ^6.3.0

RevenueCat初期化(App User IDを統一)

import 'package:purchases_flutter/purchases_flutter.dart';

Future<void> initRevenueCat({required String appUserId}) async {
  final config = PurchasesConfiguration("public_sdk_key")
    ..appUserID = appUserId;

  await Purchases.configure(config);

  // 初回同期(念のため)
  await Purchases.getCustomerInfo();
}

Purchase Link を外部ブラウザで開く

import 'package:url_launcher/url_launcher.dart';

Uri buildWebPurchaseLink({
  required String token,
  required String appUserId,
  String? packageId, // 任意:特定パッケージへ直行させたい時
}) {
  final base = Uri.parse("https://pay.rev.cat/$token/${Uri.encodeComponent(appUserId)}");

  final qp = <String, String>{
    "utm_source": "app",
  };
  if (packageId != null) qp["package_id"] = packageId;

  return base.replace(queryParameters: qp);
}

Future<void> openExternalCheckout(Uri url) async {
  await launchUrl(url, mode: LaunchMode.externalApplication);
}

アプリ復帰時にCustomerInfoを再取得してentitlement反映

import 'package:flutter/widgets.dart';
import 'package:purchases_flutter/purchases_flutter.dart';

class RevenueCatSyncOnResume with WidgetsBindingObserver {
  RevenueCatSyncOnResume() {
    WidgetsBinding.instance.addObserver(this);
  }

  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      _refresh();
    }
  }

  Future<void> _refresh() async {
    final info = await Purchases.getCustomerInfo();
    final hasPro = info.entitlements.active.containsKey("pro");
    // TODO: Riverpod/BLoCなどへ反映して機能解放
  }
}

実務TIP:決済直後は反映が数秒遅れることもあるので、

  • resumeで1回
  • ダメなら数秒おきに2〜3回だけ再試行
  • 「購入済みの方はこちら(更新)」ボタンを用意
    が事故りにくいです。

実装:Redemption Links(匿名購入→後から紐付け)

「ログイン前に買わせたい」「匿名購入も許容したい」場合はRedemption Linksが便利です。

ざっくり流れ

  1. Web側で購入(App User ID不要)
  2. 決済完了後に redeemリンク(深いリンク) を発行
  3. そのリンクを踏むとアプリが起動 → getCustomerInfo() 同期で解放

ストア規約の注意点(ここが一番詰まる)

外部決済の導線は、iOS/Androidともに 制度・地域・プログラム条件 が絡みます。
実装では「いつでも出す」ではなく、OS×国×プランで“出し分けできる”設計がおすすめです。

例:Remote Config等で制御

bool shouldShowExternalCheckoutButton({
  required bool isIos,
  required bool isAndroid,
  required String countryCode,
}) {
  // 例:最初はAndroidだけ / 特定国だけ等、運用で切り替えられる形にする
  if (isIos) return false;
  if (isAndroid && countryCode == "JP") return true;
  return false;
}

まとめ

  • スマホ新法で「決済手段の多様化」が注目されるが、実装は IAP / 外部決済 の整理から始めると迷いにくい
  • RevenueCatで外部決済を扱うなら、最短は Web Purchase Links + アプリ復帰時 getCustomerInfo()
  • ただし「デジタル商品を外部決済へ誘導」は条件が絡むため、最初から 出し分け設計 を入れるのが安全

参考リンク

公正取引委員会

Flutter決済パッケージ

RevenueCat(Web Billing)

お知らせ(採用情報)

最後にお知らせとなりますが、AppTime では一緒に働くメンバーを募集しております。
詳しくは採用情報ページをご確認ください。

AppTime 採用情報

みなさまからのご応募をお待ちしております。


最後までお読みいただきありがとうございました。
質問やフィードバックがあれば、ぜひコメントで教えてください
たくさんのいいね待ってます!

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?