アプリに組み込む

Google Play サブスクリプション

Google Play でサブスクリプションを販売していて、独自のバックエンドを持たない Android アプリ向けです。アプリは API キーを使って購入トークンをゲートウェイに送り、ゲートウェイがお客様のサービスアカウントで Google に問い合わせ、サブスクリプションが有効かどうかを返します。チェックは無料です。

#始める前に

  • ユーザーを招待できる、アカウント所有者または管理者の Play Console ログイン。
  • Google Cloud コンソールでプロジェクトを作成できる Google アカウント(どの Google アカウントでも可)。
  • アプリのパッケージ名(applicationId、例:com.example.app)と、Play Console で作成済みのサブスクリプション商品 1 つ以上。
  • 操作は約 15 分。その後、Google が権限を有効にするまで最大 1 日かかります。

#1. サービスアカウントの JSON を取得する

この JSON ファイルはサービスアカウントのキーです。ゲートウェイはこれを使ってアプリの購入について Google に問い合わせるだけで、それ以外には使いません。Google ではサービスアカウントキーと呼ばれ、OAuth クライアントのファイル(client_secret_….json)とは別物です。

  1. 1

    Google Cloud コンソールを開いてプロジェクトを選ぶ

    console.cloud.google.com

    上部のプロジェクト選択ツールを使います。どのプロジェクトでも構いませんが、Play のチェック専用に新しく作成すると管理しやすくなります。

  2. 2

    Play API を有効にする

    API とサービス(APIs & Services)→ ライブラリ(Library)→ Google Play Android Developer API → 有効にする(Enable)

    名前を正確に入力して検索してください。ボタンが「管理(Manage)」になっていれば、すでに有効です。

  3. 3

    サービスアカウントを作成する

    IAM と管理(IAM & Admin)→ サービス アカウント(Service accounts)→ サービス アカウントを作成(Create service account)

    名前は play-verify など自由に付けて構いません。プロジェクトのロールやユーザーアクセスを付与する任意の手順はスキップしてください:Cloud のロールは不要です。「完了(Done)」をクリックします。

  4. 4

    JSON キーをダウンロードする

    サービスアカウントを開く → キー(Keys)→ 鍵を追加(Add key)→ 新しい鍵を作成(Create new key)→ JSON → 作成(Create)

    ブラウザに .json ファイルがダウンロードされます。大切に保管してください:Google は二度と表示せず、このファイルを持つ人は誰でもアプリの購入情報を読み取れます。

  5. 5

    サービスアカウントのメールアドレスをコピーする

    play-verify@your-project.iam.gserviceaccount.com のような形式で、サービスアカウントのページと、ファイル内の client_email に表示されています。次の手順で使います。

「新しい鍵を作成」がグレーアウトしている、または拒否される場合

Google Cloud の組織が iam.disableServiceAccountKeyCreation ポリシー(新しい組織ではデフォルトで有効)でキーのダウンロードをブロックしています。組織の管理者が「IAM と管理 → 組織のポリシー(Organization policies)」でこのプロジェクトについて無効にするか、組織外のプロジェクトを使ってください。

#2. Play Console でアクセス権を付与する

  1. 1

    サービスアカウントを招待する

    play.google.com/console → ユーザーと権限(Users and permissions)→ 新しいユーザーを招待(Invite new users)

    メールアドレス欄にサービスアカウントのメールアドレスを貼り付けます。サービスアカウントは招待を承諾する必要はありません。

  2. 2

    次の 2 つの権限を付与する

    アプリの権限(App permissions)→ アプリを追加(Add app)→ 自分のアプリを選択

    「財務データ、注文、解約理由アンケートへの回答の表示(View financial data, orders, and cancellation survey responses)」と「注文と定期購入の管理(Manage orders and subscriptions)」にチェックを入れます。それ以外はオフのままにします。代わりに「アカウントの権限(Account permissions)」で同じ 2 つにチェックを入れると、すべてのアプリが対象になります。

  3. 3

    招待を送信する

    適用(Apply)→ ユーザーを招待(Invite user)

    サービスアカウントが「ユーザーと権限」に「有効(Active)」として表示されます。

これらの権限が必要な理由

ゲートウェイは Google の purchases.subscriptionsv2.get でサブスクリプションを読み取るだけです。Google はこの読み取りに財務データと注文の権限を求めます。ゲートウェイが確認、返金、キャンセルを行うことは一切ありません。

Google での有効化には最大 1 日かかる

それまでは、チェックに google_play_permission_denied が返ります。Play Console でいずれかのサブスクリプション商品を編集する(説明を変更して保存し、元に戻す)と、新しい権限が早く反映されることがよくあります。

#3. API キーに設定する

  1. 1

    アプリで使うキーを開く

    コンソール → API キー → 編集

    アプリ専用のキーを使ってください(下記参照)。

  2. 2

    「Google Play サブスクリプションの確認」を入力する

    Google Play チェックを設定

    パッケージ名をアプリの build.gradle(applicationId)と完全に同じに入力し、手順 1 の JSON ファイルを選んで保存します。

  3. 3

    保存時のメッセージを確認する

    ゲートウェイは保存する前に、そのファイルで Google への問い合わせを試します。それでも Google が拒否する場合は、何が足りないかがダイアログに表示されます。多くは手順 1 の API か手順 2 の権限です。ファイルは暗号化して保存され、再表示されることはありません。置き換えるには再度アップロードしてください。

アプリ専用のキーを使う

Google Play の設定は 1 つのキーに属します。アプリ用に別のキーを作成し、アプリが使うモデルだけに制限して、利用枠の上限を設定してください。

#4. アプリからチェックする

購入直後にチェックし、アプリを開いたときにも保存したトークンで再度チェックしてください。アプリの起動を結果待ちでブロックしないでください:前回保存した結果を表示し、チェックが返ってきたら更新します。同じトークンには 1 分間のキャッシュから応答します。各キーはデフォルトで 1 分あたり 120 回までチェックでき、現在の上限はキーの Google Play 設定に表示されます。サポートがキーごとに引き上げることもできます。上限を超えた呼び出しは 429 を返し、ログに記録されないため、前回保存した結果を使い続けてください。

google_play.dart
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:in_app_purchase/in_app_purchase.dart';

const apiKey = 'sk-YOUR_KEY';

Future<Map<String, dynamic>?> checkSubscription(String purchaseToken) async {
  final res = await http.post(
    Uri.parse('https://www.aisplice.store/v1/google-play/verify'),
    headers: {
      'Authorization': 'Bearer $apiKey',
      'Content-Type': 'application/json',
      // Request signing on for this key? Then this call must be signed too:
      // ...signedHeaders('POST', '/v1/google-play/verify'),
    },
    body: jsonEncode({'purchase_token': purchaseToken}),
  );
  if (res.statusCode != 200) return null; // keep the last saved answer
  return jsonDecode(res.body) as Map<String, dynamic>;
}

// In your purchaseStream listener:
Future<void> onPurchase(PurchaseDetails purchase) async {
  if (purchase.status != PurchaseStatus.purchased &&
      purchase.status != PurchaseStatus.restored) return;
  final token = purchase.verificationData.serverVerificationData;
  final status = await checkSubscription(token);
  if (status != null && status['active'] == true) {
    await saveEntitlement(token, status); // your local storage
    unlockPaidFeatures();
  }
  if (purchase.pendingCompletePurchase) {
    await InAppPurchase.instance.completePurchase(purchase); // acknowledges on Android
  }
}

#5. 解放する内容を決める

チェック結果アプリの対応よくある原因
active: true, in_trial: true解放し、expiry_time で「トライアル終了日」を表示します。無料トライアル
active: trueexpiry_time まで解放します。支払い済み(キャンセル済みでまだ期限が切れていないサブスクリプションを含む)
subscribed: true, active: falseロックして更新画面を表示します。期限切れ、一時停止、保留中
subscribed: falseロックして購読画面を表示します。不明なトークン、支払い保留中
HTTP 502 / 503保存済みの前回の結果を使い、後で再試行します。Google またはサービスアカウントが応答していない

結果と一緒に expiry_time を保存してください。チェックとチェックの間はその時刻までサブスクリプションを利用可能として扱えば、オフラインの端末でも動作し続けます。

#6. すべての購入を確認する

確認されていない購入は 3 日後に返金される

ゲートウェイはサブスクリプションを読み取るだけで、確認(acknowledge)は行いません。アプリが completePurchase(Flutter)または acknowledgePurchase(Play Billing)を呼び出す必要があります。数分以上前の購入でチェックが acknowledged: false を返す場合、アプリはまだ確認を行っていません。

#7. アプリ内のキーを保護する

アプリ内のキーは、キャプチャした通信から読み取られる可能性があります。そのキーでリクエスト署名を有効にしてコピーされたキー単体では使えないようにし、ビルドを難読化し、キーに利用枠の上限を設定してください。

署名はキーによるすべての呼び出しに適用される

署名を有効にすると、/v1/google-play/verify もそのキーの他のリクエストと同様に X-Timestamp、X-Nonce、X-Signature が必要になり、ない場合は 401 signature_required が返ります。署名には専用のパスを使います:signedHeaders('POST', '/v1/google-play/verify')。署名を有効にするのは、署名に対応したアプリのバージョンをリリースしてからにしてください。

アプリ向けのリクエスト署名 →

#8. 結果を確認する

キャッシュ済みの応答や失敗も含め、すべてのチェックはコンソール → リクエストログ に、そのキーの無料の「Google Play チェック」として表示されます。購入トークン全体、末尾の数文字、またはユーザーが Google の領収書メールから送ってきた注文 ID(GPA.…)で検索できます。

  • google_play_api_disabled:JSON ファイルが属するプロジェクトで、手順 1 の Play API が有効になっていません。
  • google_play_permission_denied:手順 2 の招待がない、2 つの権限が付与されていない、別のアプリに対する招待である、またはまだ有効になっていません。
  • google_play_credentials_invalid:JSON キーが Google Cloud で削除または無効化されています。新しいキーを作成し、API キーにアップロードしてください。
  • 保存時にサービスアカウントキーではないと表示される場合:OAuth クライアントのファイルを選んでいます。代わりにサービスアカウントの「キー」タブからキーをダウンロードしてください。
  • すべてのチェックで購入が見つからないと表示される場合:キーのパッケージ名がアプリの applicationId と異なるか、トークンが別のアプリのものです。
  • ライセンステスターによるテスト購入では test_purchase: true が返ります。

すべてのフィールドとエラーコード →

まだ解決しませんか?

リクエスト ID かエラーメッセージを送っていただければ、こちらで調査します。