Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
バックエンドのためのアプリ内課金入門 (サブスク編)
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Masaki Hara
January 30, 2025
Programming
2.6k
9
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
バックエンドのためのアプリ内課金入門 (サブスク編)
App StoreやGoogle Playの機能を使ってサブスクを提供するにあたって、バックエンドエンジニアとして理解しておくとよいことをまとめました。
Masaki Hara
January 30, 2025
More Decks by Masaki Hara
See All by Masaki Hara
文字コードの話
qnighy
47
20k
Dockerfileの考え方
qnighy
50
19k
Arm移行タイムアタック
qnighy
1
740
Quine, Polyglot, 良いコード
qnighy
5
910
Prolog入門
qnighy
5
2.9k
Rubyのobject_id
qnighy
8
1.9k
Getting along with YAML comments with Psych
qnighy
2
3.1k
状態設計から「なんとなく」を無くそう
qnighy
90
30k
日付時刻A to Z
qnighy
3
1k
Other Decks in Programming
See All in Programming
AIエージェントで 変わるAndroid開発環境
takahirom
2
660
1B+ /day規模のログを管理する技術
broadleaf
0
140
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
260
フィードバックで育てるAI開発
kotaminato
1
120
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
320
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
0
210
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
230
えっ!!コードを読まずに開発を!?
hananouchi
0
210
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
190
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
2
860
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
570
「正の参照」と 「負の導出」で組む ハーネスエンジニアリング
cottpan
1
140
Featured
See All Featured
Un-Boring Meetings
codingconduct
0
350
Between Models and Reality
mayunak
4
370
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Google's AI Overviews - The New Search
badams
0
1.1k
Navigating Weather and Climate Data
rabernat
0
370
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
350
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
Deep Space Network (abreviated)
tonyrice
0
230
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
2
340
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
Transcript
© 2025 Wantedly, Inc. アプリ内課金入門 (サブスク編) バックエンドのための 2025-01-29 Masaki Hara
@ Tech Lunch
© 2025 Wantedly, Inc. 本発表の目的 • アプリ内課金は特殊なケースが色々ある ◦ 返金された場合、同じApple IDで別のユーザーに課金した場合、
etc… • アプリ内課金ではストアの特性を考慮する必要がある ◦ AppleとGoogleでは課金のモデリングが異なる ◦ 事業者ができること、ユーザーができることも異なる ◦ バックエンドで統合されるマルチプラットフォームのアプリでは、これらをどう統合するか考 える必要がある • これらの罠を知ってもらい、アプリ内課金を開発・保守する上 での参考にしてほしい
© 2025 Wantedly, Inc. アプリ内課金とは
© 2025 Wantedly, Inc. アプリ内課金とは • アプリストアの機能を使って、ユーザーにお金を支払わせる方 法のこと • 英語で
In-App Purchase (IAP) • アプリストアの重要な収入源、すなわち ◦ 手数料率はそれなりに高い、またはかなり高い ◦ ストア外での課金は禁止または制限されている
© 2025 Wantedly, Inc. アプリ内課金とは • OSではなく、アプリストア側の機能として提供される ◦ Android (AOSP)
系OSであっても、Google Play以外のストアを使うならば当該ストア の機能を使って開発することになる たとえばAmazon App Storeなど ◦ ここではApp StoreとGoogle Playについて取り扱う
© 2025 Wantedly, Inc. サブスクリプション
© 2025 Wantedly, Inc. 課金方式 課金報酬の3形態 • 消費可能アイテム ◦ 回復アイテム、ゲーム内通貨など。使うと無くなり、また買う必要がある
• 消費できないアイテム ◦ アイテムボックスを広げる特別なアイテムなど。一度買えば無くならない • サブスクリプション ◦ 広告なしプランなど。支払いをやめると機能は使えなくなる 形態により返金等の挙動が異なる
© 2025 Wantedly, Inc. サブスクリプションのモデル サブスクリプションは以下の3つの組み合わせと考える • 一定期間のサービスを受ける権利に対する購入 • 上記を継続する権利の購入
(複数) • 上記を自動継続するための設定
© 2025 Wantedly, Inc. サブスクリプションの状態 最低でも3状態を考慮する必要がある • アクティブ …… 自動継続が設定されている状態
• キャンセル …… 自動継続が解除されている ◦ ただしサービス自体は、満期が来るまで有効 • 無効 …… 購入の満期が来てサービスが無効になった 月極めの契約一般では、中途解約で即時サービスが無効になるものや、その際に残り期間に応じて返金され るものもあると考えられる。 しかし、App StoreとGoogle Playではどちらも満期まで利用が可能なモデルとなっている。
© 2025 Wantedly, Inc. サブスクリプションの状態 最低でも3状態を考慮する必要がある • アクティブ …… 自動継続が設定されている状態
• キャンセル …… 自動継続が解除されている ◦ ただしサービス自体は、満期が来るまで有効 • 無効 …… 購入の満期が来てサービスが無効になった 月極めの契約一般では、中途解約で即時サービスが無効になるものや、その際に残り期間に応じて返金され るものもあると考えられる。 しかし、App StoreとGoogle Playではどちらも満期まで利用が可能なモデルとなっている。 購入 #1 購入 #2 4月17日 5月17日 6月17日 7月17日 利用開始 自動継続 購入 #3 自動継続 キャンセル サービス 停止
© 2025 Wantedly, Inc. サブスクリプションの状態 加えて以下のようなケースにも注意が必要 • 支払い失敗時の挙動 ◦ 基本的には、継続失敗とみなしてサービスを停止する。
◦ しかし、設定した猶予期間 (grace period) の間サービスを提供し続けることも可能。 • 返金申請された場合 ◦ 返金時はサービス即時停止 • サービス障害等の補償 ◦ 事業者の判断でサービス提供期間を延長することが可能
© 2025 Wantedly, Inc. ストアとの連携
© 2025 Wantedly, Inc. クライアント or サーバー 課金の検証形態には2種類ある • クライアント側で検証を完結させる方法
◦ 特定のサーバー・サービスと紐付いていなければこちらのほうが話が早い ◦ たとえばサードパーティー製のSNSクライアントアプリが広告無しオプションを導入するな らこの方式 • サーバー側で検証し、クライアント側でそれを参照 ◦ 特定のサーバー・サービスと紐付いているならこちらのほうが堅牢で柔軟 ◦ たとえば対戦ゲームや動画視聴サービスであればこちらの方式が良いだろう
© 2025 Wantedly, Inc. クライアント or サーバー サーバーを含む情報の流れ • 端末→ストア
• ストア→サーバー ここさえ抑えておけば何とかな る (サーバーは基本は受信する だけ) 事業者サーバー Google, Apple 利用者端末 通知 課 金 要 求
© 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 基本的に、両方を組み合わせるのが良い
© 2025 Wantedly, Inc. ユーザー サービスを「誰に対して」付与するのか? • ストア側のユーザーIDに対して? ◦ App
Store なら Apple ID ◦ Google Play なら Googleアカウント • 自社サービスのユーザーIDに対して? ◦ Wantedly なら Wantedlyユーザー この2つは、複数端末利用時の挙動が異なる
© 2025 Wantedly, Inc. ユーザー 自社サービスのユーザーIDに紐付ける場合 • 購入にユーザーIDを紐付けることができる ◦ App
Store → appAccountToken ◦ Google Play → obfuscatedExternalAccountId • サーバー側でユーザーIDをデコードして紐付けを永続化
© 2025 Wantedly, Inc. ユーザー ストアユーザーと自社ユーザーは「多対多」の関係にある • 1つの自社ユーザーに、iPhoneとAndroidの両方からログイ ンしている場合はどうする? ◦
たとえば …… 片方でサブスクリプション契約していれば両方で有効 • 1つのGoogleアカウントで複数の自社ユーザーにログインし ている場合はどうする? ◦ たとえば …… 片方でサブスクリプション契約するともう一方では契約できない
© 2025 Wantedly, Inc. ストア別の仕様
© 2025 Wantedly, Inc. サブスクリプション階層 サブスクリプションの基本は2階層 • サブスクリプション契約 …… 連続した購入の列
• 1回分の購入
© 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があり、これで区別できる。
© 2025 Wantedly, Inc. 契約の承認 • 全ユーザーに一律に購入権を与えたくないこともある ◦ たとえばメールアドレス認証済みであることを要求するなど •
一般論として、サービスのサブスクであればバックエンドで商 品情報を制御するのが望ましい ◦ まずバックエンドがモバイルアプリに対して商品 IDの一覧を返す ◦ モバイルアプリは商品IDを使ってストアに商品情報を問い合わせる
© 2025 Wantedly, Inc. 契約の承認 それでも意図しない商品購入があった場合……? • App Store: 事業者からはどうしようもない
◦ ユーザーが自主的にキャンセルないし返金申請するのを待つしかない • Google Play: 「承認」しなければOK ◦ 「承認」は事業者側から専用のAPIを叩くことで購入を確定させる処理 ◦ Google Playでは、承認されなかった購入は自動的にキャンセルされる ◦ サーバーサイドで承認を行うアーキテクチャであれば、意図しない購入を承認しないこと によって実質的に拒否できる
© 2025 Wantedly, Inc. キャンセル 契約をキャンセルする場合 • App Store: Apple
IDを使ってキャンセル申請 ◦ 具体的にはApp Store側または、SDKを組み込んだアプリ内からキャンセルする ◦ 事業者側でキャンセルすることはできない • Google Play: 2つの方法がある ◦ ユーザーがGoogle Playからキャンセル ◦ 事業者がAPIを使ってキャンセル
© 2025 Wantedly, Inc. 返金 ユーザーが返金を申請した場合の挙動 • App Store: ユーザーはAppleに返金を申請する
◦ Appleは独自の基準で返金可否を判断する ◦ 事業者はAppleに参考情報を提供できるが、最終的な判断は Appleが行う • Google Play: 返金申請先は2つある ◦ Googleに返金申請を行うと、決められた基準により返金可否が決定される (契約してか らの時間で決まる) ◦ ユーザーが事業者に返金依頼を行い、事業者判断で返金を申請することも可能
© 2025 Wantedly, Inc. API • App StoreのAPIはJWTで認証を行う ◦ 特にApp
Store側が発行するJWTの検証は大変なので実装者は覚悟すること ▪ ルート証明書を取得して証明証チェインを検証し、さらに OCSPをサポートする必要がある ◦ AppleのSDKがある言語であれば使ったほうがいい • Google Playの通知はGoogle Cloud Pub/Subを利用 ◦ Pub/Sub側の設定でWebhookのようにも運用できる
© 2025 Wantedly, Inc. まとめ
© 2025 Wantedly, Inc. まとめ まとめ • サブスク = 購入
× n + 自動継続設定 • 端末 → アプリストア → 事業者サーバーの流れが重要 • App StoreとGoogle Playのモデリング差異や仕様差異に 気をつけよう