2020年12月13日PR運営しているアプリ(iOSとAndroid)に月額のサブスクリプション機能を追加しました。調査した結果、現時点で一番良さげなアーキテクチャを実装したのですが、その過程で色々と悩むことが多かったです。今回の記事では、サーバーサイドを含めた全体的なアーキテクチャを記載します。(iOS、Androidのそれぞれの詳細なコードは記載していません。)アーキテクチャのポイントは以下の2点です。AppleやGoogleが提供する通知機能を用いて、最新のレシート情報を常にサーバー側に持たせる。モバイルアプリでの立ち上げ時に、サーバー側で保管しているレシート(支払い情報)を確認し、サブスクリプションを契約しているかどうかを、モバイルにレスポンスする。参考情報になりますが、今回のアプリでのサブスクリプションの特典は以下の2点です。翻訳機能などの機能制限開放サブスクリプションのアーキテクチャ概要これまでのサブスクリプションでは、モバイル側でアプリ立ち上げ時等にサブスクリプションの状態を確認し、最新情報をサーバーサイドに送信する必要がありました。(サーバーサイドで色々するなら、というかユーザーからの問い合わせに対応するには、どこかにレシート情報を保管する必要があった。)しかし、2020年時点では、サブスクリプションが更新されると、通知を直接サーバー側に送ってくれるというサービスがiOS、Androidともにありました!確認してみると、どうやらここ1~2年ぐらいで追加された機能のようです。このサービスを用いて、常に最新の支払い情報をサーバー側にもたせておくことで、モバイルでいろいろやる必要がなくなりました。用いて、最新のレシートを常にサーバーサイドに保管する。false”をレスポンスする。いうアーキテクチャになります。これにより最新のレシート情報が常にサーバーに保管されていることになり、モバイルはその情報を確認するだけでよくなります。このアーキテクチャを実現するために、以下のAppleとGoogleの2つのサービスを使用します。POSTによりJSONを飛ばしてくるサービスです。この記事は、「モバイルのサブスクリプションのアーキテクチャ」の参考記事になります。Notificationと同等のサービスがあります。Pub/Subにメッセージが飛んでくるため、その通知を受信することで、レシート情報を更新します。この記事は、「モバイルのサブスクリプションのアーキテクチャ」の参考記事になります。定期購読に関する処理には、主に1新規購読、2継続更新、3解約の3つのプロセスがあります。それぞれのプロセスを図を用いて解説します。1新規購読プロセスモバイル内で新規購読ボタンタップで、AppleやGoogleとの通信で定期購読処理を実行します。成功すると、最新のレシート情報をサービスのサーバーに格納します。この時、レシート情報を一意に判別する値はiOSでは”original_transaction_id”、Androidでは、”purchace_token”となります。これらのデータを、ユーザーと紐付けてDBに保存します。新規購読処理が完了し、サーバーへのレシート情報保存が完了すると、購読済みユーザーとして利用できるように、モバイルでのUIの更新等を行います。Notificationを用いて、定期購読の更新のたびに通知を受け取り、最新のレシート情報をDBに保存します。その結果、モバイルでは、アプリ立ち上げ時にサーバー内のレシート期限を確認するだけで、購読済みか否かを判別することが可能になります。Pub/Subが入ることになります。詳細は以下の記事を参照してください。この記事は、「モバイルのサブスクリプションのアーキテクチャ」の参考記事になります。https://hiromiick.com...3解約プロセス解約は、iOS、Androidともに、アプリ内で行うことは出来ません。Storeからの解約処理が必要となります。解約処理がなされると、それ以降はレシート情報が更新されなくなるので、自動的に期限が切れ、時間とともに無料ユーザーに戻るという流れです。処理は必要ありません。最新のレシート情報を保存するテーブルサービスのサーバーに最低限保持しておく必要のあるデータは以下の通りです。user_id(どのユーザーのレシートか)expired_date(レシートの有効期限)receipt_id(レシートを一意に判別する)加えて、iosかandroidかというdevice情報やレシートのオリジナルデータ等も含めると管理が楽になるかもしれません。適宜要件に併せて、データベースにtableを実装してください。懸念点と対処法このアーキテクチャでいくと、サーバーから送られてくる、premiumのbool値のみを元に、購読済みかどうかを判断することができるので、モバイルの実装が楽になります。確実にサービスのサーバー内に最新のレシート情報を保存出来ているということが必要条件になってきます。懸念1:AppleやGoogleから購読更新の通知が飛んで来なかったら?もし仮に、AppleやGoogleの課金サーバーが(落ちることはさすがにないと思うが)レスポンスに時間がかかりすぎるなどなんらかの原因で疎通がうまく行かなかった場合どうなるか?お金を支払っているにも関わらず、無料アカウントとして認識されてしまうユーザーが出てくる可能性があります。懸念1の対応:期限切れのレシートも念の為に最新レシートを確認するバッチ処理を行う何があるかはわかりませんので、この懸念に対して「期限切れのレシートの最新情報を念の為取得する」という処理を1日に1回バッチで回すことにしました。懸念2:Androidで課金していてiOSに乗り換えた場合はどうなる?例えば、Androidで課金していて、iOSに乗り換えるユーザーがいた場合はどうなるのか考えてみました。結論は、対策の必要なしと判断しました。Andoridでの課金が終了したとしても、最初のうちはレシート期限が残っているので、iOSに変わってもそのまま購読済みユーザーとしてアプリを利用することが出来ます。期限が切れると自動的に無料会員に戻るので、その後必要であればiOSで再度課金処理を行なっていただくのみ、という流れです。アプリや公式サイトにて、サブスクリプションの解約手順を明確に記載する、ぐらいかなと思います。これはすでに行なっていたので、特に対応は不要と判断しました。モバイルアプリのサブスクリプション実装のまとめ以上、iOSとAndroidでの定期購読を、サーバーサイドを含めたアーキテクチャを紹介してきました。実装するにあたって、非常に調査に時間を使ってしまったことや、AppleのSnadboxがドキュメント通りに動かないこと、リリースしてからもAndoridでのacknowledge処理を忘れてしまい、すべて自動でシステムによる解約処理が行われてしまうなど、様々なトラブルがありましたが、現在なんとか運用出来ています。定期購読処理をどのように実装していくのかを自分の中で整理するために纏めていたパワポも使って今回記事にしてみました。参考になりましたら幸いです。