.NET MAUIでGoogle Playの定期購入を実装すると、購入自体は成功しているのに、Playストアの「定期購入」管理ページでプラン一覧が出ず、アップグレード/ダウングレード/解約ができないことがあります。本記事では原因の切り分けと実務的な対策をまとめます。
起きている現象を整理する
相談として多いのは次のようなケースです。
- .NET MAUI(C#)で作成したアプリにサブスクリプションを実装した
- Google Play(実カード決済)で購入自体は完了できる
- 購入後、ユーザーを Play ストアの定期購入管理ページへ遷移させたい(アップグレード/ダウングレード/解約をさせたい)
- しかし、Play ストア側で他のプランが表示されない、解約(Cancel)やプラン変更の導線が出ない
- 同等のことが iOS(App Store)ではできている
典型的には、アプリ側で次のような URL を開いているパターンです。
https://play.google.com/store/account/subscriptions?package=(パッケージ名)&sku=(商品ID)
そして購入処理には Plugin.InAppBilling などのサードパーティ製プラグインを利用している、という構成です。
結論:MAUI固有の不具合というより「プラグイン」と「Play側の状態/仕様」を疑う
まず押さえておきたいのは、「Playストアの定期購入管理画面の表示」はアプリのUIではなく、Google側の画面・仕様・アカウント状態に強く依存するという点です。つまり、.NET MAUI 本体の不具合として再現条件を固定しにくく、MAUI のサポート範囲だけで切り分けるのが難しい領域です。
この手の問題は、実務上は次の2方向で調査を進めるのが最短です。
- 購入処理(課金プラグイン)が最新仕様に追随できているか(Plugin.InAppBilling の Issue/PR、依存している Billing Library の世代、購入の acknowledge など)
- Google Play 側の「サブスク状態」「アカウント状態」「表示仕様」(保留、支払い問題、テスト購入の扱い、UI差分など)
切り分け早見表:どこが原因かを最短で当てにいく
| 観点 | まず見るもの | よくある原因 | 次のアクション |
|---|---|---|---|
| ユーザーの画面 | Playストアアプリの「お支払いと定期購入」 | アカウント違い、Playストアアプリが古い、表示キャッシュ | 購入アカウントでログイン確認、Playストア更新、別端末/別回線で再確認 |
| 購入状態 | Play Console の注文(購入)/サブスク状態 | 保留、支払い失敗、grace期間、未確認(acknowledge未完了) | 購入の状態を「有効」として確認、状態遷移(保留→有効)を追う |
| プラン表示 | 同一サブスク内のプラン構成(ベースプラン/オファー) | ユーザーが条件非該当、別商品ID扱い、UIでの切替非対応 | プラン変更をアプリ内フローで実装する方針に切替 |
| 遷移URL | package/sku 付きURLと、一覧URLの差 | skuの指定が期待通りに動かない、UIの変更 | 一覧(skuなし)へフォールバック、アプリ内ヘルプ文言を追加 |
| ライブラリ互換 | 使用している課金ライブラリの世代 | 古い Billing API、サブスク変更フロー未対応 | プラグイン更新/乗り換え、公式 Billing での実装を検討 |
なぜ「プラン一覧が出ない」「解約ボタンが出ない」ことがあるのか
Playストアの定期購入管理画面は、常に同じ見た目・同じ導線が出るとは限りません。特に以下の要因で、表示される情報が変わることがあります。
購入が「有効化」されていない(保留・要対応・自動キャンセルの前段)
ユーザーが購入した直後に「Order Receipt(領収書)」+「Action needed for your subscription(要対応)」の2通が届くケースがあります。これは、支払い確認・本人確認・銀行側/カード側の承認・Google側の審査/保留など、何らかの理由でサブスクが即時に有効状態になっていない可能性を示唆します。
この状態だと、ユーザーの定期購入管理画面に「通常の解約」や「プラン変更」のUIが出ない、または表示が限定されることがあります。
プラン変更(アップグレード/ダウングレード)が「ストア画面任せ」では出ないことがある
Google Play のサブスクは、同一商品内でもベースプランやオファー、ユーザーの適用条件(新規/復帰/地域/期間など)により、「管理画面で切り替え可能な候補」が出ないことがあります。iOS のようにストア管理画面でのプラン変更が安定していると感じる場合でも、Google Play ではアプリ内でサブスク変更フローを実装する方が確実な場面が多いです。
「package/sku付きURL」が期待通りに動作しないことがある
次のURLは、特定のアプリ/商品に紐づいた定期購入の管理へ近道として使われがちです。
https://play.google.com/store/account/subscriptions?package=...&sku=...
ただし、このURLは「いつでも必ず同じUIを出す」ことを保証するものではなく、Playストア側のUI改修や仕様変更の影響を受けます。結果として、プラン一覧が出ない・解約導線が出ないといった見た目の差が出ることがあります。
まずやるべき確認:購入が本当に「アクティブ」かを確かめる
「購入できた」だけでは判断が難しいため、Play側の購入状態を確認して、表示UIが出ない理由を潰していきます。ユーザー画面と運用側(Play Console)で、同じ結論になるのが理想です。
ユーザー側:Playストアアプリの画面で確認する
- Playストアアプリを開く
- メニューから「お支払いと定期購入」→「定期購入」(表記は端末/言語で差)
- 該当の定期購入が表示されるか、状態が「有効」か、「お支払いの問題」などが出ていないかを見る
Webブラウザで開くよりも、Playストアアプリ内の表示の方が正確なことが多いです。可能なら、アプリからの遷移も「ブラウザ」ではなく「Playストアアプリ」で開く導線を試します。
運用側:Play Console で注文/定期購入の状態を見る
Play Console 側では、該当ユーザーの注文(購入)がどの状態にあるかを確認します。特に次の状態に要注意です。
| 状態 | ユーザー体験 | 起こりやすいこと | 対処の方向性 |
|---|---|---|---|
| 有効(Active) | 通常の利用可能 | 解約は基本的に可能だが、プラン変更UIは出ない場合がある | 変更はアプリ内フロー実装を検討 |
| 保留(Pending) | 支払い確認中/保留 | 管理画面UIが限定される、要対応メールが飛ぶことがある | 支払い完了・確認を待つ/ユーザーへ案内 |
| 支払い失敗/要支払い設定 | 「お支払い方法を更新」などが出る | 解約/変更導線が通常と異なる | 支払い方法更新の案内、復帰フロー |
| キャンセル予定/期限内 | 次回更新で終了 | 一部の変更UIが出ない | 復帰(再開)導線の案内を追加 |
ここで「保留」「要対応」「自動キャンセル」などが見えた場合は、ストア管理画面に期待する操作が出ないのは自然です。まずは購入状態を正常化することが先です。
アプリ側の落とし穴:acknowledge漏れとPurchase Tokenの扱い
Google Play Billing では購入後に acknowledge(承認) が必要になるケースがあります(未承認のままだと、一定期間後に購入が取り消される挙動があるため)。サードパーティ製プラグインを使っている場合、内部で acknowledge をしているつもりでも、特定条件で漏れる/失敗することがあります。
「購入は完了したはずなのに、Play側の管理画面が変」「要対応メールが来る」といった時は、次を確認します。
- 購入後に acknowledge が実行されているか(ログ/プラグイン実装)
- アプリが purchase token を保存できているか(プラン変更フローで必要)
- 購入成功のハンドリングが「UI上の成功」だけで終わっていないか(サーバー検証をしていない等)
特にサブスクは、アプリ再インストールや端末変更でも継続するため、「アプリ内のローカル状態」ではなく、Play側の正の状態を信頼する設計(購入照会、サーバー検証、RTDN活用など)が重要です。
ストア画面に依存しない「確実な対策」:プラン変更はアプリ内フローで実装する
結論として、ユーザーにプラン変更(アップグレード/ダウングレード)を確実に提供したいなら、Playストアの管理画面任せにしないのが最も安定します。Google Play Billing には、既存の購買トークンを指定してサブスクを切り替えるサブスク変更フローが用意されています。
「ストア画面任せ」と「アプリ内フロー」の比較
| 項目 | ストア管理画面任せ | アプリ内フロー |
|---|---|---|
| 確実性 | 端末/アカウント状態/仕様変更でブレる | アプリのUIとして提供でき、挙動が安定しやすい |
| 実装コスト | 低い(URLを開くだけ) | 中〜高(購入照会、切替フロー、テストが必要) |
| ユーザー体験 | 画面遷移が深い/わかりにくいことがある | プラン比較・差分説明をアプリ内で行える |
| 将来の変更耐性 | PlayのUI変更に弱い | Billing APIの追随は必要だが、コントロールしやすい |
.NET MAUIでの実装イメージ(考え方)
MAUI自体はクロスプラットフォームですが、課金はプラットフォーム固有の仕組みに依存します。したがって、次のように整理して設計すると破綻しにくいです。
- 共有プロジェクト:プラン一覧UI、選択、現在プラン表示、説明文
- Android固有:Google Play Billing による「購入」「照会」「サブスク変更」
- iOS固有:StoreKit による同等処理
プラグインを継続利用する場合でも、「サブスク変更フローが実装できるか」を最優先で確認してください。実装できない場合は、Androidのみでも公式 Billing へ寄せる(独自バインディング/別ライブラリ)方が長期的に安全です。
サブスク変更フローに必要な情報
アップグレード/ダウングレードの本質は、旧プランの purchase token を指定して新プランへ切り替えることです。必要なものはシンプルで、次の3点です。
- 現在有効なサブスクの purchase token(旧トークン)
- 切り替え先のプラン(商品ID/オファー)
- 切替時の課金扱い(即時/次回更新時/日割りなど)
ユーザーにとってトラブルが少ないのは、「いつから新プランになるのか」「差額はどうなるのか」をアプリ内で明示することです。ストア画面任せだと、この説明が不足しがちです。
URL遷移は「フォールバック設計」にする
解約だけはストア側でやってもらう(アプリ内で解約はできない)という方針も一般的です。その場合でも、URL1本に依存しない導線にすると、問い合わせ対応が減ります。
推奨する導線の作り方
- まずは sku 付きURLで該当サブスクの管理画面を開く
- 期待する表示が出ない場合に備え、ユーザーに「一覧から選ぶ」手順を併記する
- 最終手段として、定期購入一覧のURL(skuなし)を用意する
例として、一覧URLは次のようなものです。
https://play.google.com/store/account/subscriptions
アプリ内のヘルプ文言では、リンクを出すだけでなく、ユーザーが迷いやすいポイント(どのアカウントで購入したか、定期購入はPlayストア内にあること、見つからない時の検索方法)もセットで案内すると効果的です。
「Plugin.InAppBilling」を使っている場合の現実的な対応
Plugin.InAppBilling のようなサードパーティ製プラグインは、.NET MAUI から課金を扱える手軽さが魅力です。一方で、Google Play Billing は仕様更新が比較的頻繁で、プラグイン側の追随が遅れると、今回のような“購入はできるが運用が不安定”という状態が起きやすくなります。
まず確認するポイント
- プラグインが依存している Billing Library の世代(古いとサブスク変更フローが弱い)
- 購入後の acknowledge が確実に行われる実装になっているか
- サブスクのベースプラン/オファーに対応しているか(設定方法も含め)
- 同様の症状が報告されている Issue があるか
実務では、原因がプラグイン由来かどうかを判断するために、公式のサンプル/最小構成(ネイティブ側)で同じ商品を買って同じ症状が出るかを確認すると一気に進みます。ネイティブ(Androidの BillingClient 直実装)で正常にプラン変更UIが出るなら、プラグイン側の責任範囲が濃厚です。
Issueに投稿する時に書くべき情報(テンプレ)
| 項目 | 記載例 |
|---|---|
| プラグイン/バージョン | Plugin.InAppBilling x.y.z(NuGet) |
| MAUI/Android | .NET MAUI 8/9、Android APIレベル、端末機種 |
| 商品 | サブスク商品ID、ベースプラン/オファー有無、価格、地域 |
| 再現手順 | 購入→URL遷移→プラン一覧が出ない/解約が出ない |
| ログ | 購入成功時のレスポンス、acknowledge実行有無、例外 |
| 期待結果 | 管理画面で解約/変更ができる or アプリ内変更フローが提供できる |
こうした情報が揃うと、プラグイン側で「仕様」「バグ」「未対応」のどれなのかが判断されやすくなり、解決が早まります。
Google Play側に問い合わせるべきケース
次の条件に当てはまるなら、アプリやプラグインではなく、Google Play側の仕様/アカウント状態が原因である可能性が上がります。こうした場合は、Google Play Help Community(公式コミュニティ)や、必要に応じてPlay Console経由のサポートで確認するのが適切です。
- 複数端末・複数回線でも同じアカウントだけ再現する
- 同一アプリでも、別ユーザーでは正常に解約UIが出る
- 「Action needed」など支払い/確認系のメールが発生している
- Play Console 上で購入状態が保留/要対応になっている
問い合わせ時に準備しておくと話が早い情報
| 情報 | 理由 |
|---|---|
| 購入日時(タイムゾーン含む) | 注文の突合に必要 |
| 注文番号/取引ID(可能な範囲で) | 状態確認が速い |
| 定期購入の商品ID | UI/仕様差分の切り分け |
| 端末情報(OS/Playストアバージョン) | 表示差分が出やすい |
| 管理画面のスクリーンショット | 「出ない」を客観化できる |
ユーザー向けの案内を整えると、問い合わせが激減する
この問題は、開発者側がどれだけ頑張っても「ストアの画面がユーザーごとに違う」という事実が残るため、ユーザー向けの案内設計が重要です。特に、解約導線が見つからない問い合わせは、ヘルプページを1枚用意するだけで激減します。
アプリ内ヘルプに入れておくと効果が高い文言例
- 「解約はアプリ内ではなく、Google Play ストアの『定期購入』から行います」
- 「購入に使ったGoogleアカウントでログインしているか確認してください」
- 「見つからない場合は、Playストアアプリの『お支払いと定期購入』→『定期購入』を開いてください」
- 「プラン変更はアプリ内から行えます(または、現在は解約→再契約での変更になります)」
特に最後の一文は重要です。プラン変更がストア管理画面で出ないなら、アプリ内で変更できるようにするか、最低限「解約して再契約」しかないことを明示して、誤解を減らします(ただし二重課金の誤認が起きやすいので説明は丁寧に)。
運用メモ:テスト購入と本番購入の挙動差に注意
Play Console のテスト設定(ライセンステスター、内部テスト、テストカード等)を使うと、購入の状態遷移や表示が本番と完全一致しないことがあります。今回のような「管理画面の導線が出ない」系は、テスト環境の影響を受ける場合があるため、最終的には本番に近い条件(実カード/実アカウント)での再現確認も必要です。
ただし、実カードでの検証が難しい場合は、次のように検証計画を組むと安全です。
- 内部テスト用アカウントを固定し、端末も固定して再現性を確認する
- 同じ商品IDで「別アカウント」でも検証して、アカウント依存かを分ける
- 購入直後/更新直前/更新直後など、タイミングを変えて画面の差を観察する
最終的な落としどころ:今すぐできる現実解
すぐに改善したい場合、優先度としては次の順が現実的です。
| 優先度 | 施策 | 効果 | コスト |
|---|---|---|---|
| 高 | ユーザー案内(一覧URL/手順/アカウント確認)をアプリ内に追加 | 問い合わせ削減、ユーザーが自己解決しやすい | 低 |
| 高 | Play Console で購入状態(有効/保留/要対応)を運用で監視 | 「解約できない」の背景が見える | 中 |
| 中 | プラン変更をアプリ内フローで実装(サブスク変更) | アップグレード/ダウングレードの確実性が上がる | 中〜高 |
| 中 | Plugin.InAppBilling の Issue を追跡し、必要なら代替へ移行 | 根本解決につながる | 中〜高 |
| 低 | URLを変えるだけで解決を狙う | 改善することもあるが再発しやすい | 低 |
まとめ
Google Play の「定期購入」管理ページでプラン一覧が出ない、解約や変更の導線が出ない問題は、.NET MAUI そのものというより、課金プラグインの互換性とGoogle Play 側の状態/仕様が絡み合って発生しがちです。
まずは購入状態が本当にアクティブかを確認し、次に URL 遷移をフォールバック設計にし、それでも「プラン変更」を確実に提供したい場合は、アプリ内でのサブスク変更フロー実装へ寄せるのが長期的に安定します。プラグインの Issue 追跡と、Google Play Community での確認を並行すると、切り分けが一気に進みます。

コメント