この記事は Akatsuki Games Advent Calendar 2025 の 20 日目の記事です。
はじめに
実務で Unity アプリケーションの課金実装を担当しているんですが、「反映までのタイムラグ」や「特定条件下での挙動」、 「本番とテスト環境の違い」 などに悩まされることが多かったので今回備忘録として書くことにしました。
今回は、実際のコードの話というよりも、「プラットフォーム(iOS/Android/Steam)のあそこって、実際どういう挙動だっけ?」と迷った時に役立つ、実務的な備忘録・ハマりどころをまとめました。
この記事内で使用するライブラリは以下の通りです
- Unity IAP
- Steamwork.Net
※本記事の内容は 2025 年 12 月 20 日時点での挙動に基づいています。プラットフォーム側の仕様変更により動作が変わる可能性がある点にご注意ください。
💰 海外価格とストア反映の挙動
Android: アプリ内商品のデフォルト国以外の価格確認
Android で、デフォルト設定以外の国・地域の価格が正しく反映されているかを確認したい場合、最低でも「クローズドベータ(内部テスト)」トラックが動いている必要があります。
つまり内部テストだけで確認していると設定した価格が正しく取得できません。
課金処理を確認する場合は 必ずクローズドベータ まで出しておきましょう。
なお地域別の価格は Play Billing Lab を使うことで確認が出来ます。
新規に登録した商品が反映されるタイミング
課金アイテムを新規作成した際、「いつ買えるようになるのか?」はプラットフォームにより異なります。
| OS | 反映のトリガー | 反映までの目安 | 備考 |
|---|---|---|---|
| Android | 保存して有効化 | 半日 〜 1日 | 更新だと最短数分で完了します。 |
| iOS | 審査(sandbox は不要) |
数時間程度 | 本番で有効にする場合は審査が必要です。 |
Android は Google Play Store のキャッシュを削除したりすると反映がされたりすることもありますが、
上記の目安かかる前提でスケジュールを組み、設定をしていきましょう。
🖼️ 決済画面でのアイコン表示
ユーザーが「購入」ボタンを押した際に出るシステム側のポップアップ(または画面)に表示されるアイコンにも違いがあります。
- Android: ストアの掲載情報に設定しているアイコンが表示されます。
- iOS: 最新バージョンのアプリのバイナリに含まれているアイコンが表示されます。
半周年施策とかでアプリアイコンを変えたい!けど決済画面が違うとなった場合はここをチェックです。
💳 決済情報の処理とエッジケース
iOS:未消費レシートと「キャンセル不可」問題
iOS では、購入後にレシート(トランザクション)を消費しない限り、その決済情報は残り続けます。
厄介なのは、「未処理のレシートが残っている間、ユーザー側からその注文をキャンセルしたり、返金フローに進むことができない」(あるいは非常に困難)という点です。
対策:
不整合が起きた場合でも、アプリ側で一度レシートを正しく消費(完了処理)してから、Appleサポート経由での返金などの対応を案内するフローにする必要があります。「処理に失敗したからレシートを放置」すると、ユーザーのアカウントでその購入がスタックしてしまいます。sandbox でも確認が可能なので実装の際はご参考に。
Android:ストアの下位互換性設定について
Unity IAP 4.13 系では Play Billing Library 7 を使用しており、2025 年 12 月現在最新は ver 8 です。
7 の場合 Play Console 上のアプリ内商品設定にある「下位互換性」がないと購入が出来ません。
下位互換性をありに設定しましょう。
👶 ペアレンタルコントロール
未成年者が親の承認を得て購入するフロー(Ask to Buy / ファミリー用お支払い方法)について
対応するにはそこそこ面倒な部分があります。
Android
-
挙動: 「後払い決済(Pending)」の処理フローに則ってコールバックが来ます。
ですので、アプリ側で後払い決済のハンドリングがしっかりしていれば、特に追加対応なくカバーできるかと思います。
iOS
-
挙動: こちらも「後払い(Deferred)」のフローですが、コールバックの仕様にクセがあります。
-
親が承認した場合:
ProcessPurchaseのコールバックが返ってきます。 -
親が拒否した場合: 何もコールバックが返ってきません。
拒否した場合が厄介で、購入失敗として何かしら処理を行うことが出来ません。
全体をそのような設計にするかDeferredが来た時だけ専用で処理するか等実装コストが高めです。
-
親が承認した場合:
🧪 iOS TestFlight で起きた現象
注意: こちらは原因が特定できなかったものになります。
TestFlight で課金をテストした際に、以下の事象に遭遇することがありました。
- 現象: テスターの地域設定(Region)が日本なのに、ゲーム内の通貨単位表示が「ドル ($)」になる。 (システム内部的にも地域が US 扱いになっている)。
-
しかし: いざ購入しようと決済ポップアップを出すと、正しい「円 (¥)」表記になる。
sandbox アカウントを日本にしたもの、Apple アカウントは日本のものでも起きていました。
結論:
これらは本番環境では発生せず、正しくユーザーの地域ごとの通貨になります。
TestFlight 環境特有、あるいは Sandbox アカウント特有の挙動である可能性が高く、原因は完全には特定できていませんが、「本番では直る」ケースが大半です。過度な心配は不要かもしれません。
🎮 Steam (PC)
ゲーム内ブラウザ(オーバーレイ)について
Steam 決済時、ゲーム内オーバーレイ(Web ブラウザ)が開いて決済画面が表示されます。
-
問題: 通信切断時にユーザーが
Escapeキーでオーバーレイを閉じてしまった場合、アプリ側にはキャンセルのコールバックが返ってきません。 -
対策:
ユーザーが誤って閉じてしまった場合や、通信切断(正確には Steam サーバーとの接続断)への対策として、以下の Steamworks API を活用します。
- Steam サーバーとの接続コールバック
-
Steam のオーバーレイを閉じたか開いた時のコールバック
この2つのコールバックを組み合わせて、接続してないときにオーバーレイを閉じたらキャンセル扱いとするのが良いでしょう
おわりに
プラットフォームの決済周りは、細かい部分がドキュメントになかったりハマると時間が溶けていきます。
この記事が、同じ現象に遭遇した誰かの助けになれば幸いです。
明日の Akatsuki Games Advent Calendar 2025 もお楽しみに!