Studyplus Engineering Blog

スタディプラスの開発者が発信するブログ

Studyplus iOS/Androidのサブスクリプションをサーバーサイドに実装した話

こんにちは、サーバーグループの中村です。
Horizon Forbidden Westを先日クリアしました!
とても面白かったのですが大作オープンワールドゲームをがっつりプレイするのが最近しんどくなってきました。
ですが懲りずにELDEN RINGを買おうか悩んでおります。
(クリアできずに詰んでいるメトロイドドレッドもどうにかしなくてはですが)

今回は1月25日にリリースした、 Studyplus有料版のサーバーサイドを担当した時の話をさせてもらいます。

Studyplus有料版とは

元々Studyplus Proという名前で、サブスクリプションサービスは存在していました。
ですが今回のStudyplusブックがリリースするにあたり、
Studyplus有料版としてコースを増やし拡充することになりました。
拡充にあたりお試し機能の追加などもされており、より便利にお得になっています!

お試し機能やStudyplusブックについてはこちらのブログ記事に詳しく書かれていますので、よかったらご覧ください。

tech.studyplus.co.jp

今回の要件

実装にあたって要件はとてもシンプルでした。

  • Studyplusブック用のコースを追加
  • お試し機能を追加

以上です。
さらに元々Studyplus Pro用のサブスクリプション機能が実装されていたため、
そちらを活かした実装にしていけば工数も膨らまず実装できるはずだったのですが、
それほど簡単にはいきませんでした。

iOS側のサーバーサイド課金処理の流れ

まずサーバー側の課金全般の処理について軽く説明したいと思います。

iOS側のサーバーサイド側の処理の流れは大まかに説明しますと、 以下になります。

  1. アプリがレシートを送ってくる

  2. レシートの中身をAppleサーバーに問い合わせて情報を取得

  3. 取得した情報の通りにサーバーのデータを更新

  4. アプリに処理完了を通知

ios課金フロー

課金の処理をAppleサーバーが行い、その状態を確認して同期させるイメージです。

Android側のサーバーサイド課金処理の流れ

Android側のサーバーサイド側の処理の大まかな流れは以下になります。

  1. アプリがレシート取得に必要な情報やトークンを送ってくる

  2. トークンをGoogleサーバーに問い合わせてレシート情報を取得

  3. 取得した情報の通りにサーバーのデータを更新

  4. レシートの承認

  5. アプリに処理完了を通知

Android課金フロー

Androidの場合は、iOSと違いサーバー側でレシートの承認をしないと有効にならないといった違いがあります。

苦労した点その1 アップグレードとダウングレードを考慮しなくてはいけなかった

上記のiOS、Androidのサブスクリプション処理自体はすでに実装済みではあったので、
新しいStudyplusブックのサービスを利用できるコースの実装もスムーズに行うことはできました。

しかし、2つのコースを行き来できるようにするアップグレードやダウングレードの考慮をしておらず、実装後大変苦労しました。

また、アップグレードの処理がiOSとAndroidで結構異なっていたため、サーバー内で処理を実装するのに苦労をしました。
今までは多少の違いはあっても「アプリから来たレシートをプラットフォームのサーバーに通信して情報を取得し、登録する」という流れは共通でした。
ですがiOSは、アップグレード時にはアップグレード前のレシートとアップグレード後のレシート両方が通知されるという仕様。 AndroidはlinkedPurchaseTokenというキーがレシートに追加されることにより、以前の定期購入を確認して判定するという仕様にそれぞれなっていました。

これらの仕様の違いにより以下の問題に対処する必要がでました。

  • iOSは最新のレシートを取得し比較判定するという処理の見直し
  • Androidはレシート取得処理自体の見直し
  • 共通化していたデータベース登録処理自体のリファクタリング

ですが、元の実装と今回の仕様、要件をしっかり確認し、データベースを変更しない。課金処理のコアな部分は元の実装を生かす。
という設計ですすめることができたため、既存の機能は稼働させたまま手戻りや大きなトラブルもなくリリースまで進めることができました。

苦労した点その2 大量のテストパターンを網羅しなくてはいけなかった

上記に関連してくるのですが、アップグレードとダウングレードを考慮すると、
通常の課金に加えて多くのパターンのテストを考慮しなくてはなりませんでした。

- ベーシックコース月額の人がプレミアムコース月額にアップグレードした場合
- ベーシックコース年額の人がプレミアムコース年額にアップグレードした場合
- プレミアムコース月額の人がベーシックコース月額にダウングレードした場合
- プレミアムコース年額の人がベーシックコース年額にダウングレードした場合
など

さらにiOS、Android各プラットフォームごとにも別途書かなくてはいけなかったため、
用意するのが大変でした。

ただ、RSpecWebMockVCRを組み合わせることで、
実際のレスポンスを利用したテストを実装できました。
これにより効率的に最適なユニットテストを書くことができました。

最後に

今回はStudyplusアプリの新しいサブスクリプションを追加するにあたって、
サーバーサイドの実装で苦労した点を紹介させていただきました。
実装前の仕様確認の大切さ、効率よくテストを行う仕組みがあるRubyのエコシステムの豊富さなどを改めて感じることができました。

今回の件を通して、今後も基本を大事に日々開発をしようと決心しました!