Upgrade to Pro — share decks privately, control downloads, hide ads and more …

バックエンドのためのアプリ内課金入門 (サブスク編)

バックエンドのためのアプリ内課金入門 (サブスク編)

App StoreやGoogle Playの機能を使ってサブスクを提供するにあたって、バックエンドエンジニアとして理解しておくとよいことをまとめました。

Masaki Hara

January 30, 2025
Tweet

More Decks by Masaki Hara

Other Decks in Programming

Transcript

  1. © 2025 Wantedly, Inc. 本発表の目的 • アプリ内課金は特殊なケースが色々ある ◦ 返金された場合、同じApple IDで別のユーザーに課金した場合、

    etc… • アプリ内課金ではストアの特性を考慮する必要がある ◦ AppleとGoogleでは課金のモデリングが異なる ◦ 事業者ができること、ユーザーができることも異なる ◦ バックエンドで統合されるマルチプラットフォームのアプリでは、これらをどう統合するか考 える必要がある • これらの罠を知ってもらい、アプリ内課金を開発・保守する上 での参考にしてほしい
  2. © 2025 Wantedly, Inc. アプリ内課金とは • アプリストアの機能を使って、ユーザーにお金を支払わせる方 法のこと • 英語で

    In-App Purchase (IAP) • アプリストアの重要な収入源、すなわち ◦ 手数料率はそれなりに高い、またはかなり高い ◦ ストア外での課金は禁止または制限されている
  3. © 2025 Wantedly, Inc. アプリ内課金とは • OSではなく、アプリストア側の機能として提供される ◦ Android (AOSP)

    系OSであっても、Google Play以外のストアを使うならば当該ストア の機能を使って開発することになる たとえばAmazon App Storeなど ◦ ここではApp StoreとGoogle Playについて取り扱う
  4. © 2025 Wantedly, Inc. 課金方式 課金報酬の3形態 • 消費可能アイテム ◦ 回復アイテム、ゲーム内通貨など。使うと無くなり、また買う必要がある

    • 消費できないアイテム ◦ アイテムボックスを広げる特別なアイテムなど。一度買えば無くならない • サブスクリプション ◦ 広告なしプランなど。支払いをやめると機能は使えなくなる 形態により返金等の挙動が異なる
  5. © 2025 Wantedly, Inc. サブスクリプションの状態 最低でも3状態を考慮する必要がある • アクティブ …… 自動継続が設定されている状態

    • キャンセル …… 自動継続が解除されている ◦ ただしサービス自体は、満期が来るまで有効 • 無効 …… 購入の満期が来てサービスが無効になった 月極めの契約一般では、中途解約で即時サービスが無効になるものや、その際に残り期間に応じて返金され るものもあると考えられる。 しかし、App StoreとGoogle Playではどちらも満期まで利用が可能なモデルとなっている。
  6. © 2025 Wantedly, Inc. サブスクリプションの状態 最低でも3状態を考慮する必要がある • アクティブ …… 自動継続が設定されている状態

    • キャンセル …… 自動継続が解除されている ◦ ただしサービス自体は、満期が来るまで有効 • 無効 …… 購入の満期が来てサービスが無効になった 月極めの契約一般では、中途解約で即時サービスが無効になるものや、その際に残り期間に応じて返金され るものもあると考えられる。 しかし、App StoreとGoogle Playではどちらも満期まで利用が可能なモデルとなっている。 購入 #1 購入 #2 4月17日 5月17日 6月17日 7月17日 利用開始 自動継続 購入 #3 自動継続 キャンセル サービス 停止
  7. © 2025 Wantedly, Inc. サブスクリプションの状態 加えて以下のようなケースにも注意が必要 • 支払い失敗時の挙動 ◦ 基本的には、継続失敗とみなしてサービスを停止する。

    ◦ しかし、設定した猶予期間 (grace period) の間サービスを提供し続けることも可能。 • 返金申請された場合 ◦ 返金時はサービス即時停止 • サービス障害等の補償 ◦ 事業者の判断でサービス提供期間を延長することが可能
  8. © 2025 Wantedly, Inc. クライアント or サーバー 課金の検証形態には2種類ある • クライアント側で検証を完結させる方法

    ◦ 特定のサーバー・サービスと紐付いていなければこちらのほうが話が早い ◦ たとえばサードパーティー製のSNSクライアントアプリが広告無しオプションを導入するな らこの方式 • サーバー側で検証し、クライアント側でそれを参照 ◦ 特定のサーバー・サービスと紐付いているならこちらのほうが堅牢で柔軟 ◦ たとえば対戦ゲームや動画視聴サービスであればこちらの方式が良いだろう
  9. © 2025 Wantedly, Inc. クライアント or サーバー サーバーを含む情報の流れ • 端末→ストア

    • ストア→サーバー ここさえ抑えておけば何とかな る (サーバーは基本は受信する だけ) 事業者サーバー Google, Apple 利用者端末 通知 課 金 要 求
  10. © 2025 Wantedly, Inc. サーバー通信 事業者サーバーがストアから情報を得る方法は2つある • Push型 ◦ App

    Store: App Store Server Notification ◦ Google Play: Real-Time Developer Notification • Pull型 ◦ App Store: App Store Server API ◦ Google Play: Google Play Developer API 基本的に、両方を組み合わせるのが良い
  11. © 2025 Wantedly, Inc. ユーザー サービスを「誰に対して」付与するのか? • ストア側のユーザーIDに対して? ◦ App

    Store なら Apple ID ◦ Google Play なら Googleアカウント • 自社サービスのユーザーIDに対して? ◦ Wantedly なら Wantedlyユーザー この2つは、複数端末利用時の挙動が異なる
  12. © 2025 Wantedly, Inc. ユーザー 自社サービスのユーザーIDに紐付ける場合 • 購入にユーザーIDを紐付けることができる ◦ App

    Store → appAccountToken ◦ Google Play → obfuscatedExternalAccountId • サーバー側でユーザーIDをデコードして紐付けを永続化
  13. © 2025 Wantedly, Inc. ユーザー ストアユーザーと自社ユーザーは「多対多」の関係にある • 1つの自社ユーザーに、iPhoneとAndroidの両方からログイ ンしている場合はどうする? ◦

    たとえば …… 片方でサブスクリプション契約していれば両方で有効 • 1つのGoogleアカウントで複数の自社ユーザーにログインし ている場合はどうする? ◦ たとえば …… 片方でサブスクリプション契約するともう一方では契約できない
  14. © 2025 Wantedly, Inc. サブスクリプション階層 App Store と Google Play

    のモデリング差異 階層 App Store Google Play (上位)※1 originalTransactionId - サブスクリプション (transactionReason = PURCHASE) SubscriptionPurchaseV2※2 1回分 Transaction (transactionId) Order※3 ※1 originalTransactionId は、同一Apple IDの同一商品の購入に対して 1つだけ発行される。そのため、一度解約して再度契約し ても同じIDが返ってくる。サブスクリプション単位を知るには transactionReason を参照する必要がある。 ※3 SubscriptionPurchaseV2のプライマリキーは (packageName, purchaseToken) ※3 SubscriptionPurchaseV2内にorderIdがあり、これで区別できる。
  15. © 2025 Wantedly, Inc. 契約の承認 • 全ユーザーに一律に購入権を与えたくないこともある ◦ たとえばメールアドレス認証済みであることを要求するなど •

    一般論として、サービスのサブスクであればバックエンドで商 品情報を制御するのが望ましい ◦ まずバックエンドがモバイルアプリに対して商品 IDの一覧を返す ◦ モバイルアプリは商品IDを使ってストアに商品情報を問い合わせる
  16. © 2025 Wantedly, Inc. 契約の承認 それでも意図しない商品購入があった場合……? • App Store: 事業者からはどうしようもない

    ◦ ユーザーが自主的にキャンセルないし返金申請するのを待つしかない • Google Play: 「承認」しなければOK ◦ 「承認」は事業者側から専用のAPIを叩くことで購入を確定させる処理 ◦ Google Playでは、承認されなかった購入は自動的にキャンセルされる ◦ サーバーサイドで承認を行うアーキテクチャであれば、意図しない購入を承認しないこと によって実質的に拒否できる
  17. © 2025 Wantedly, Inc. キャンセル 契約をキャンセルする場合 • App Store: Apple

    IDを使ってキャンセル申請 ◦ 具体的にはApp Store側または、SDKを組み込んだアプリ内からキャンセルする ◦ 事業者側でキャンセルすることはできない • Google Play: 2つの方法がある ◦ ユーザーがGoogle Playからキャンセル ◦ 事業者がAPIを使ってキャンセル
  18. © 2025 Wantedly, Inc. 返金 ユーザーが返金を申請した場合の挙動 • App Store: ユーザーはAppleに返金を申請する

    ◦ Appleは独自の基準で返金可否を判断する ◦ 事業者はAppleに参考情報を提供できるが、最終的な判断は Appleが行う • Google Play: 返金申請先は2つある ◦ Googleに返金申請を行うと、決められた基準により返金可否が決定される (契約してか らの時間で決まる) ◦ ユーザーが事業者に返金依頼を行い、事業者判断で返金を申請することも可能
  19. © 2025 Wantedly, Inc. API • App StoreのAPIはJWTで認証を行う ◦ 特にApp

    Store側が発行するJWTの検証は大変なので実装者は覚悟すること ▪ ルート証明書を取得して証明証チェインを検証し、さらに OCSPをサポートする必要がある ◦ AppleのSDKがある言語であれば使ったほうがいい • Google Playの通知はGoogle Cloud Pub/Subを利用 ◦ Pub/Sub側の設定でWebhookのようにも運用できる
  20. © 2025 Wantedly, Inc. まとめ まとめ • サブスク = 購入

    × n + 自動継続設定 • 端末 → アプリストア → 事業者サーバーの流れが重要 • App StoreとGoogle Playのモデリング差異や仕様差異に 気をつけよう