収益化

Flutterアプリの収益化戦略:AdMob 3種類と内部課金の実装メモ

2026-06-27  ·  SEADICE

自動生成パイプラインで毎日アプリを量産するにあたって、収益化をどうするかを整理した。結論としては当面は広告(AdMob)のみ、内部課金は後から追加する方針にした。その理由と、将来の内部課金実装に必要なことをここにまとめておく。

収益化の選択肢と今回の判断

Flutterアプリの収益化は3パターンありますが、審査リスク最小・実装最速のAdMob広告が量産フェーズの個人開発者には最適です。

方式実装難度審査リスク特徴
AdMob広告ダウンロード数に比例。実装がシンプル
有料アプリなしApp Store側で価格設定のみ。DL数は激減
内部課金(IAP)収益単価高。Apple審査が厳しい

自動生成パイプラインでは毎日アプリを量産する。審査に落ちるリスクを最小化しつつ、とにかく本数を出してロングテールで収益を積み上げる戦略をとる。そのためAdMobを中心に据えた。

AdMob 3種類の広告:テストID一覧

すべてのアプリに以下3種類の広告を実装する。

AdMob テスト用ID(開発・テスト時のみ使用)

種類テストID
App IDca-app-pub-3940256099942544~1458002511
バナーca-app-pub-3940256099942544/2934735716
インタースティシャルca-app-pub-3940256099942544/4411468910
リワードca-app-pub-3940256099942544/1712485313

本番リリース前にAdMobコンソールで実際のユニットIDに差し替えること。

バナー広告

画面下部に常時表示。実装が最もシンプルで、どんなアプリにも馴染む。収益単価は低いが、起動中ずっと表示されるので積み上がりやすい。

// バナー広告の実装例
BannerAd(
  adUnitId: 'ca-app-pub-3940256099942544/2934735716',
  size: AdSize.banner,
  request: const AdRequest(),
  listener: BannerAdListener(
    onAdLoaded: (ad) => setState(() => _bannerAd = ad as BannerAd),
    onAdFailedToLoad: (ad, error) => ad.dispose(),
  ),
)..load();

// ウィジェットとして表示
SizedBox(
  height: 50,
  child: AdWidget(ad: _bannerAd!),
)

インタースティシャル広告

全画面広告。ユーザーがタスクを完了したとき・画面遷移時・クイズの答え合わせ後などに表示する。表示頻度を上げすぎるとUXが下がるので、1セッションに1〜2回が目安。

// インタースティシャル広告のロード
InterstitialAd.load(
  adUnitId: 'ca-app-pub-3940256099942544/4411468910',
  request: const AdRequest(),
  adLoadCallback: InterstitialAdLoadCallback(
    onAdLoaded: (ad) => _interstitialAd = ad,
    onAdFailedToLoad: (error) => print('load failed: $error'),
  ),
);

// 表示
_interstitialAd?.show();
_interstitialAd = null; // 表示後は破棄

リワード広告

ユーザーが動画を最後まで見ると特典を受け取れる広告。「広告を見る」ボタンを設置して、追加コンテンツや機能のアンロックと引き換えにする。単価が最も高く、ユーザーの能動的な行動なのでUXへの影響も少ない。

// リワード広告のロード
RewardedAd.load(
  adUnitId: 'ca-app-pub-3940256099942544/1712485313',
  request: const AdRequest(),
  rewardedAdLoadCallback: RewardedAdLoadCallback(
    onAdLoaded: (ad) => _rewardedAd = ad,
    onAdFailedToLoad: (error) => print('load failed: $error'),
  ),
);

// 表示(報酬コールバックつき)
_rewardedAd?.show(
  onUserEarnedReward: (ad, reward) {
    // ここでコンテンツをアンロック
    setState(() => _isPremiumContent = true);
  },
);

必須:Info.plist への GADApplicationIdentifier 追加

これを忘れると起動直後にクラッシュする。ios/Runner/Info.plist</dict> 直前に追加:

<key>GADApplicationIdentifier</key>
<string>ca-app-pub-3940256099942544~1458002511</string>

pubspec.yaml の設定

dependencies:
  flutter:
    sdk: flutter
  google_mobile_ads: ^5.1.0
  shared_preferences: ^2.3.2
  intl: ^0.19.0

in_app_purchase は今回は入れない。広告のみで運用する。

将来:内部課金(IAP)を追加するときに必要なこと

今はやらないが、ユーザーが付いてきたら追加する。忘れないうちにやることを記録しておく。

① App Store Connect で商品登録

1

サブスクリプショングループを作成

App Store Connect → アプリ → サブスクリプション → 新規グループ。グループ名は「プレミアム」など。

2

商品IDを決める

命名規則の例:com.seadice.kateisaien1.premium_monthly。このIDはコードでも使うので一度決めたら変更不可。

3

価格・説明文を設定

月額180円など。App Store審査用の説明文(英語必須)も入力する。

② pubspec.yaml に追加

dependencies:
  in_app_purchase: ^3.2.0

③ Flutter側の実装フロー

  1. アプリ起動時に InAppPurchase.instance.queryProductDetails() で商品情報を取得
  2. 購入ボタンを押したら InAppPurchase.instance.buyNonConsumable() でAppleの購入フローを呼び出す
  3. purchaseStream をリッスンして購入完了を検知
  4. 購入完了したら SharedPreferencesisPremium = true を保存
  5. アプリ起動時に isPremium を読み込んで広告非表示・機能解放

④ Apple審査で必須の実装

⑤ レシート検証(任意だが推奨)

クライアント側だけで検証するとリスクがあるため、本格運用するならサーバー側でAppleのレシート検証APIを叩く実装が必要になる。ただし個人開発の初期フェーズなら省略して構わない。

今の判断:広告のみで進める理由

リワード広告は単価が高く、ユーザーが自分で「広告を見る」を選ぶので強制感がない。内部課金と広告の中間のような位置づけで、まずここを育てる。