PWA が Google Play に掲載されていて、アプリ内アイテムや定期購入を販売して収益化する場合は、Google Play のポリシーに準拠するため、Google Play 請求サービスを実装する必要があります。PWA に実装する必要がある API は、Digital Goods API と Payment Request API の 2 つです。
Digital Goods API
Digital Goods API は、アプリと Google Play の間のインターフェースです。この API を使用すると、Play Console でアプリ内アイテムと定期購入について入力したデジタル アイテムとその詳細を取得できるほか、ユーザーが過去に行った購入も取得できます。Google Play Console でアプリ内アイテムや定期購入をまだ追加していない場合は、Google Play 課金サービスの Google Play Console での設定に沿って設定してください。
2021 年 11 月 30 日に、ChromeOS 96 が Digital Goods API 2.0 の実装とともにリリースされました。
Digital Goods API の最初のバージョンのオリジン トライアルは、2022 年 1 月 30 日に終了しました。そのため、この API は非推奨となり、API の v2 のみが利用可能になりました。
2022 年 6 月 23 日に、ChromeOS 103 がリリースされ、Digital Goods API 2.1 が実装されました。今回のリリースには、破壊的な変更はなく、新しいメソッドと追加のフィールド(listPurchaseHistory() と itemType)のみが含まれています。
オリジン トライアルに登録する
注: 現在、Digital Goods API はオリジン トライアル(デベロッパーが新しいウェブ API に早期アクセスできるメカニズム)を通じて利用できます。Digital Goods API v2 のオリジン トライアルに登録してトークンをリクエストする必要があります。このトークンは、オリジンのすべてのページで提供する必要があります。
オリジン トライアルに登録すると、「有効期限」が表示されます。この日付まではトークンが確実に機能します。トライアルへの参加を継続するには、期限が近づいたらトークンを更新してください。オリジン トライアルとして提供される API は変更される可能性があるため、参加しているオリジン トライアルの最新の変更を常に把握するようにしてください。問題が発生した場合は、デジタル商品 API ドキュメントを参照してください。
Payment Request API
購入が行われると、Payment Request API が実際の支払いトランザクションを処理します。この API は、Digital Goods API が提供するアイテムの詳細を利用して、適切な支払い方法(この場合は Google Play 請求)を使用してアプリ内購入を行います。
Digital Goods API の機能検出
オリジン トライアルでウェブサイトで API が正しく有効になっているかどうかを検出するには、window オブジェクトで getDigitalGoodsService メソッドを確認します。
if ('getDigitalGoodsService' in window) { // Digital Goods API is supported! } else { console.log('DigitalGoodsService is not available.'); // Use another payment method }
Google Play 請求サービスに接続する
Digital Goods API は、Payment Request API がブラウザに依存せず、さまざまな決済機関で使用できるのと同様に、さまざまなブラウザやデジタル ストアと互換性を持つように設計されています。Google Play 請求サービスに関連付けられたサービスのインスタンスを取得するには、getDigitalGoodsService() にお支払い方法として文字列 "https://play.google.com/billing" を渡します。
メソッドがエラーをスローした場合、Google Play 請求サービスのお支払い方法は利用できません(ユーザーがブラウザから PWA にアクセスしている場合など)。代わりに、取引に別のお支払い方法を提供する必要があります。
if ('getDigitalGoodsService' in window) { // Digital Goods API is supported! try { const service = await window.getDigitalGoodsService('https://play.google.com/billing'); // Google Play Billing service is available } catch (error) { // Google Play Billing service is not available. Use another payment flow. } }
アイテムの詳細を取得する
デジタル商品サービスを Google Play に接続すると、API を使用して商品と購入に関する情報を取得できます。
getDetails() メソッドを使用すると、Google Play Console で設定したアイテムに関する情報を取得できます。アプリの UI に商品のタイトル、説明、価格などの情報を表示して、購入可能な商品とその価格をユーザーに知らせる必要があります。
getDetails() メソッドには、Play Console で作成したアプリ内アイテムと定期購入のアイテム ID に対応するアイテム ID のリストが必要です。
const itemDetails = await service.getDetails(['product_1', 'product_2', 'product_3']); for (const item of itemDetails) { // Display item information to user displayItem(item.title, item.description, item.price); }
ユーザーのロケールに適した価格を取得するには、追加の書式設定を行う必要があります。
const localePrice = new Intl.NumberFormat(navigator.language, { style: 'currency', currency: item.price.currency, }).format(item.price.value);
注: Digital Goods API には、アイテム ID のリストを取得するメソッドは用意されていません。代わりに、クライアントにハードコードするか、バックエンド サーバーから取得する必要があります。Google Play Developer API では、バックエンドからアイテム ID のリストをクエリできます。(バックエンド サーバーでの Play 請求サービスの主要コンポーネントの実装の詳細もご覧ください)。どのソリューションを選択する場合でも、アイテム ID が Google Play Console のものと一致するようにしてください。
API の v2.1 では、getDetails() によって返されるフィールドの 1 つが itemType です。値が ”product” または ”subscription” の列挙型で、それぞれ対応するアイテムがアプリ内アイテムか定期購入かを示します。2 種類のプロダクトを区別できると、プロダクトの種類ごとに異なる処理を適用する必要がある場合に便利です。たとえば、ユーザーが定期購入するための専用のページと、定期購入以外の商品のための別のページがある場合があります。また、バックエンドで使用する適切な Google Play Developer API REST リソース(purchases.products または purchases.subscriptions)を把握するうえでも役立ちます。
アイテムを購入する
商品と詳細がユーザーに表示されたら、Payment Request API を使用して購入フローを構築できます。Digital Goods API と組み合わせて使用する場合、必要な入力パラメータは methodData のみです。
Google Play 請求サービスでは、一度に 1 つのアイテムしか購入できません。アイテムの価格と詳細は Google Play サーバーですでに把握されているため、details パラメータは必要ありません。詳しくは、説明をご覧ください。
PaymentRequest の methodData パラメータの supportedMethods メンバーを使用して、文字列 "https://play.google.com/billing" で Google Play 請求サービスを支払い方法として識別します。次に、data メンバーで、アイテム ID を sku として渡します。
const paymentMethodData = [ { supportedMethods: 'https://play.google.com/billing', data: { sku: item.itemId, }, }, ];
次に、支払いリクエストを作成し、show() を呼び出して支払いフローを開始します。
const request = new PaymentRequest(paymentMethodData); const paymentResponse = await request.show();
これにより、Google Play の購入 UI がユーザーに表示され、購入しようとしている商品の詳細を確認できます。取引を破棄するか、支払いを続行するかを選択できます。ユーザーが支払いをキャンセルすると、show() によって返される Promise はエラーで拒否されます。支払いが正常に完了すると、Promise は PaymentResponse で解決されます。支払いレスポンスの details プロパティで、購入トークンが返されます。
不正行為を防ぐには、バックエンド サーバーで購入と購入トークンを検証することが重要です。ユーザーと関連する購入トークンを追跡することをおすすめします。バックエンド サーバーで確認を実装する方法をご覧ください。
購入を検証したら、支払いレスポンスで complete() を呼び出して支払いフローを終了し、請求 UI を閉じます。オプションの result 文字列を渡して、支払いプロセスの状態を示すこともできます。この結果をユーザーに表示するかどうかは、ブラウザによって異なります。Chrome ではユーザーに表示されるキューは作成されないため、PWA で独自のエラー メッセージや成功メッセージを表示することをおすすめします。
/* Changes were recently made so that the PaymentResponse `details` property returns the purchase token as `purchaseToken` instead of `token`. Note that `token` will be deprecated at some point in the future. To ensure that your app won't be affected by this, make the change to `purchaseToken` in your client code and use the latest version of Bubblewrap (v1.13.5 and later) to update and generate a new app package to upload to the Play Console. */ const { purchaseToken } = paymentResponse.details; let paymentComplete; if (validatePurchaseOnBackend(purchaseToken)) { paymentComplete = await paymentResponse.complete('success'); // Let user know their purchase transaction has successfully completed and been verified } else { paymentComplete = await paymentResponse.complete('fail'); // Let user know their purchase transaction failed to verify }
サブスクリプションのアップグレードとダウングレード
この購入フローは、アプリ内アイテムと定期購入の両方で同じです。ただし、定期購入については、アップグレードとダウングレードという追加の購入オプションを実装できます。お支払い方法の data をビルドする際に、アップグレードまたはダウングレードのフローを開始するために、次の情報を渡す必要があります。
sku: アップグレードまたはダウングレードする新しいサブスクリプションのアイテム ID。oldSku: ユーザーの現在の定期購入のアイテム ID。purchaseToken: ユーザーの現在の定期購入の購入トークンです。前述のとおり、購入トークンをバックエンドで追跡することをおすすめします。このシナリオや他のシナリオでも、ユーザーを現在の購入や購入トークンに関連付ける必要があります。prorationMode: 新しい定期購入がユーザーの現在の定期購入に置き換わる際の請求方法。
| 比例配分モード | 説明 |
|---|---|
immediateAndChargeProratedPrice |
定期購入は直ちにアップグレードされますが、請求期間は変わりません。ユーザーには残りの期間の差額が請求されます。 |
immediateAndChargeFullPrice |
定期購入がアップグレードまたはダウングレードされると、ユーザーには新しい利用資格の全額が直ちに課金されます。以前の定期購入の残額は、新しい定期購入の期間内で比例配分されます。この日割り計算モードは、Google Play Billing Library 4.0 のリリースで最近追加されました。バージョン 1.13.5 以降の Bubblewrap で利用できるようになりました。 |
immediateWithoutProration |
一時的に無効: この日割り計算モードでは、ユーザーが 1 回の請求サイクルで追加料金を支払うことなくアップグレードされたサブスクリプションを利用できる不正行為の可能性がありました。なお、修正に取り組んでいる間、このモードは一時的に無効になっています。 |
immediateWithTimeProration |
定期購入は直ちにアップグレードまたはダウングレードされます。残りの期間は価格の差に応じて調整され、次回の請求日との差分が新しい定期購入に充当されます。これはデフォルトの動作です。 |
deferred |
定期購入は、更新時にのみアップグレードまたはダウングレードされます。これは、特にダウングレードに役立ちます。 |
unknownSubscriptionUpgradeDowngradePolicy |
ポリシーが設定されていません。この方法はおすすめしません。 |
Google Play Billing Library のリファレンス ドキュメントで、さまざまな日割り計算モードについてご確認ください。定期購入のアップグレードとダウングレード、日割り計算モードの推奨事項について詳しくは、Android デベロッパー向けドキュメントをご覧ください。
これらの追加フィールドの使用方法は次のようになります。
const paymentMethod = [ { supportedMethods: 'https://play.google.com/billing', data: { sku: item.itemId, oldSku: oldPurchase.itemId, purchaseToken: oldPurchase.purchaseToken, prorationMode: 'immediateAndChargeProratedPrice', }, }, ];
ここで、item はユーザーがアップグレードまたはダウングレードしようとしている新しい定期購入の ItemDetails で、oldPurchase はユーザーの現在の定期購入の PurchaseDetails です。
購入を承認する
ユーザーがアイテムを購入したら、適切な利用資格(購入したアイテムやコンテンツへのアクセス権)を付与する必要があります。その後、購入を承認します。購入を承認すると、購入を適切に受け取って処理したことが Google Play に通知されます。
注: 購入から 72 時間以内に購入が承認されなかった場合、ユーザーに支払いが払い戻され、購入は取り消されます。購入トークンは無効になるため、既存の購入をクエリしても、取り消された購入は返されません。これにより、ネットワーク エラーが発生してアイテムの利用資格が付与されなかった場合に、ユーザーに不当な請求が行われるのを防ぐことができます。
Google Play Developer API を使用して、バックエンド サーバーから購入を承認する必要があります。利用権の付与と購入の承認は、バックエンド サーバーでまとめて行うことをおすすめします。
- ユーザーがクライアントサイドで購入を行った後、購入トークンとアイテム ID をリクエストでバックエンド サーバーに送信します。
- バックエンドで、購入の詳細を取得して検証するには、次の呼び出しを行います。
- アプリ内アイテムの purchases.products.get。
- サブスクリプションの場合は purchases.subscriptions.get。
- バックエンド データベースで適切な利用資格を付与します。
- 次に、次の呼び出しで購入を承認します。
- アプリ内アイテムの場合は purchases.products.acknowledge。
- サブスクリプションの場合は purchases.subscriptions.acknowledge。
購入を消費する
購入を承認すると、ユーザーがアイテムを所有しており、再購入できないことを Google Play に通知できます。ユーザーが一度購入すれば永久に所有できるアイテム(ゲームのキャラクター スキンなど)は、消費型アイテムではありません。
また、ユーザーが一度に 1 つしか利用できないアイテムもあります。ユーザーは、別のアイテムを購入する前に、そのアイテムを使用する必要があります。ユーザーがアイテムを「使用」したときに、ユーザーがアイテムを消費したことを Google Play に通知するには、consume() メソッドを呼び出す必要があります。Google Play は、ユーザーがアイテムを再度購入できるようにします。
ユーザーが複数所有できるアイテムの場合、まず使用しなくても繰り返し購入できる必要があります(このようなアイテムを「リピート可能なアイテム」と呼びます)。同様に、Google Play でユーザーが再度購入できるようにするには、これらのアイテムを「消費」する必要があります。そのため、ユーザーがアイテムをまだ使用していない場合でも、consume() メソッドを呼び出してアイテムを消費済みとしてマークする必要があります。
// After the user purchases the item, send the purchase token and item ID to your backend to grant the entitlement and acknowledge it right away . . . // When the user uses the item or if it is a repeatable item, consume it so it’s available for purchase again. service.consume(purchaseToken); }
既存の購入を確認する
最後の重要なユーザーフローは、既存の購入(まだ消費されていないアプリ内アイテムと継続中の定期購入)を確認して、ユーザーが現在所有している定期購入やアイテムをユーザーに知らせることです。既存の購入は、アプリ内または Play ストアで、任意のデバイスで以前に Google Play で購入したものが対象となります。Google Play ストアでアプリ外から行われた購入は、アプリ外購入と呼ばれます。
既存の購入を取得する際は、承認ステータスも確認し、以前に購入されたものの、適切に承認されなかった購入を承認する必要があります。購入はできるだけ早く確認し、ユーザーの利用資格が最新の状態になり、アプリに適切に反映されるようにすることをおすすめします。
Digital Goods API の listPurchases() メソッドは、購入ごとに itemId と purchaseToken を含む PurchaseDetails のリストを返します。バックエンド サーバーで Google Play Developer API を使用して、購入のステータスを確認し、適切に承認する必要があります。このセッションを修了すると、次のことができるようになります。
- クライアントサイドで Digital Goods API の
listPurchases()メソッドを呼び出して、ユーザーの購入リストを取得します。 - 購入ごとに、
purchaseTokenとitemIdをバックエンドに渡します。 - 必要に応じて、バックエンド データベースで利用資格を付与します。
- 次に、を呼び出して、
acknowledgementStateを確認します。- アプリ内アイテムの purchases.products.get。
- サブスクリプションの場合は purchases.subscriptions.get。
- 値が 0(まだ確認されていない)の場合は、次を呼び出します。
- アプリ内アイテムの場合は purchases.products.acknowledge。
- サブスクリプションの場合は purchases.subscriptions.acknowledge。
利用権を付与する前にバックエンド サーバーで購入を確認する方法について詳しくは、こちらをご覧ください。
購入履歴
listPurchases はユーザーの既存の購入に関する情報を返しますが、listPurchaseHistory() メソッド(API の v2.1)は、購入が期限切れ、キャンセル済み、消費済みであるかどうかにかかわらず、ユーザーが各アイテムに対して行った最新の購入を返します。listPurchaseHistory() メソッドは、各購入の itemId と purchaseToken を含む PurchaseDetails のリストを返します。このリストは、バックエンド サーバーで Google Play Developer API を使用して詳細情報を取得するために必要になります。
アプリ外で行われた購入
アプリ外で行われた購入とは、通常のアプリ内購入フローで行われなかった購入のことです。通常、アプリ内ではなく Google Play ストアで行われます。ユーザーがアプリ外で購入を行う主な方法は次の 2 つです。
- プロモーション コードの利用: Play ストアのユーザー メニューで、[特典と通知] -> [プロモーション コードを利用]、または [お支払いと定期購入] -> [ギフトコードの利用] を選択します。
- 再登録: Google Play ストアのユーザー メニューの [お支払いと定期購入] -> [定期購入] で、ユーザーはさまざまなアプリのすべての定期購入を管理できます。期限切れまたは解約済みの定期購入については、[再度定期購入] オプションが表示されます。
ユーザーが Play ストアから再登録した場合、購入は自動的に承認されず、払い戻しが行われる可能性があります。この動作は意図的なものです。ユーザーがアプリを開いて使用した場合にのみ、定期購入の料金が請求されるようにするためです。ユーザーには「定期購入を確認」というメッセージが表示され、アプリを開くよう促されます。
ユーザーがアプリを起動したときにこれらの確認応答を実装するかどうかは、デベロッパーの判断に委ねられています。そのため、既存の購入を確認し(通常はアプリの初回起動時)、まだ確認応答されていない購入を確認応答することをおすすめします。
ユーザーが定期購入を管理できるようにする
ユーザー エクスペリエンスを向上させるには、ユーザーがアプリ内で定期購入を管理、解約できる方法を提供することが重要です。設定ページまたはメニューに、ユーザーをアプリの Google Play ストアの定期購入管理ページにリダイレクトするディープリンクを作成することをおすすめします。次の URL を適切な「sub-product-id」と「app-package-name」に置き換えてください。
https://play.google.com/store/account/subscriptions?sku=sub-product-id&package=app-package-name次のステップ
これらのユーザーフローとコード スニペットは、PWA で Digital Goods API と Payment Request API を使用して Google Play 請求サービスを実装する方法を示す基本的な実装です。アプリのコンテキストとユースケースで意味のある API を使用する必要があります。エンドツーエンドの実装例については、オープンソース サンプルをご覧ください。
次に、バックエンド サーバーに重要な Play Billing コンポーネントを実装する方法を確認して、アプリのセキュリティを維持し、ユーザーの利用資格を常に最新の状態に保ちましょう。