Android(Google Play)にてアプリ内定期購入を実装したときに困ったポイント

## はじめに

* この記事は[オールアバウトアドベントカレンダー](https://qiita.com/advent-calendar/2018/allabout)3日目の記事です（3日目ですが1日と2日はお休みなので実質1日目？）
* Android(Google Play)アプリにて、[アプリ内定期購入](https://developer.android.com/google/play/billing/billing_subscriptions) を実装したときに、困ったポイントがいくつかあったので、それをまとめてみました。
* 2018年12月2日時点での仕様に基づいた困ったポイントです。仕様が変更される場合もあるので、必ず公式のマニュアルを参照しましょう。

## 1. Google Play Billingの公式ドキュメントの和訳が追いついていない箇所がある

開発中に必ずまず最初に見るのが公式ドキュメントだと思うのですが、Google Play Billingのページでは「日本語」と「英語」では内容がかなり違う箇所がありました :sob: 
おそらくまだ和訳が追いついていないようで、公式和訳のページに書かれている情報が古い、というのが見られました…。
最新の仕様を確認する際は、**必ず**ページ左下にある言語を「English」に設定しましょう :muscle: 

* 参考
    * [Add subscription-specific features  |  Android Developers](https://developer.android.com/google/play/billing/billing_subscriptions)


## 2. Google Play ConsoleからGoogle APIの連携設定にハマる

定期購入を実装する前に、Google Play ConsoleからGoogle APIとの連携設定を行う必要があります。
サービスアカウントを利用して連携する場合、下記の手順で設定することができます。

1. Google Play Console の [API アクセス] ページに移動します。
2. [サービス アカウント] で [サービス アカウントを作成] をクリックします。
3. ページの指示に従って、サービス アカウントを作成します。
4. Google Developers Console でサービス アカウントを作成したら、[完了] をクリックします。[API アクセス] ページが自動的に更新され、サービス アカウントがリスト表示されます。
5. [アクセスを許可] をクリックすると、操作を実行するのに必要な権限がサービス アカウントに付与されます。

ですが、なぜかこの設定がいつまでも完了されない、という事象が発生しました。
調査したところ、**Googleアカウントの言語設定を英語**にしたら無事に完了となりました。キャッシュの問題とかだったのでしょうか、今でも謎です…。

* 参考
    * [スタートガイド  |  Google Play Developer API  |  Google Developers](https://developers.google.com/android-publisher/getting_started?hl=ja)

## 3. Purchases.subscriptionsのstartTimeMillisは定期購読を開始した日

ユーザーの定期購入が購入・更新された日を取得するために、[Purchases.subscriptions](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions)のstartTimeMillisというプロパティを使用していました。

> startTimeMillis
> Time at which the subscription was granted, in milliseconds since the Epoch.

しかしこれがとんでもない勘違いで、後にこの`startTimeMillis` は定期購読の購入/更新日ではなく、**定期購読を開始した日**が入ることがわかりました。
つまり、1ヶ月単位の定期購読の場合、最初に定期購読を開始した日時が`startTimeMillis`に入り、その後2ヶ月立って有効期限が更新されても、この値はずっと変わっていませんでした…。

どうやら定期購読が更新された日はレシートからは取得できないようなので、ご注意ください。

## 4. Google Playの消費税設定はテスト購入では反映されない

これは地味にハマったのですが、
定期購入のテスト購入を下記の手順に従い行っていたところ、Google Play Consoleから設定してる消費税が反映されない、という現象が起きていました。

[アプリ内課金のテスト  |  Android Developers](https://developer.android.com/google/play/billing/billing_testing)

下記はテスト購入したときにGoogle Playから届くメールに記載されてる金額です。
<img width="511" alt="スクリーンショット 2018-12-02 14.30.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/42852/c58fc2c9-2cae-8c21-ade3-06df9351b4a6.png">

実はこれ、「1. Google Play Billingの公式ドキュメントの和訳が追いついていない箇所がある」の問題とも関わってくるのですが、テスト購入では消費税設定は含まれないような仕様になっているようでした。

日本語の公式ドキュメントには記載がなかったのですが、英語の方のドキュメントを見てみるとたしかに下記のような記載がありました…。やっぱり英語のドキュメントを確認するようにしないと、こういうところでハマってしまいますね:cry: 

> Taxes are not computed for test purchases.

## 5. 1つのGoogle Playアカウントの支払いで複数アカウントで定期購入のコンテンツが利用できないようにする

これはGoogle Playのシステムの仕様なのですが、自動更新購読の場合、自動更新をキャンセルして再購入する度に、新しい購入として扱われるため、新しいpurchaseTokenとorderIdが発行されます。

そのため、下記のような手順を行うと、1つのアカウントの支払いで複数のアカウントの自動更新購読を反映できる不正行為ができてしまいます。

1. Aのアカウントでログイン
2. Google Playでアプリ内定期購入を行う
3. アプリでAアカウントをログアウト
4. Google Playからアプリ内定期購入を解約
5. Bのアカウントでログイン
6. アプリ内定期購入を行う
7. 有効期限が切れる前に再購入をすると、支払いは発生しない

こちらの対応としては、下記の記事を参考に、`linkedPurchaseToken`のフィールドがある場合、登録エラーとなるように修正しました。また、その場合既存のtokenが次回の更新時に有効期限切れとなってしまうので、新しいトークンに書き換える処理を追加して、対応を行いました。

[ゲームにおける課金システムについて(自動更新購読編) – てっくぼっと！](https://blog.applibot.co.jp/2018/06/25/in-app-purchase-in-game/)

> 2018年1月よりGoogle Play Billingにおける自動更新購読の不正対策のために、Google Play Developer APIに新たにlinkedPurchaseTokenのフィールドが追加されました。
>にはキャンセルした自動更新購読のpurchaseTokenがセットされます。
> linkedPurchaseTokenを利用することで、不正行為を防ぐことができます。
> ※linkedPurchaseTokenは自動更新購読有効期間中に自動更新をキャンセルして再度購入した場合のみ付与されます。

* 参考
    * [Purchases.subscriptions  |  Google Play Developer API  |  Google Developers](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions)


## さいごに
今回、アプリ内定期購入をはじめて実装してみて思ったのは、実際にテスト購入して発行されるレシート情報を確認するのがとても重要だということです。
ドキュメントに書かれているのは主に説明文のみなので、「どんな状況のときに」「どんな値が含まれるのか」はやはり実際に発行される値を見るのが確実だと思います。

テストケースの洗い出し・シナリオ作成については、クックパッドさんの[新規決済手段導入に際し、なるべく丁寧にテストケースを作成した話 - クックパッド開発者ブログ](https://techlife.cookpad.com/entry/2018/07/19/100000)という記事がとても参考になりました。

みなさまがAndroidにおけるアプリ内定期購入を実装する際に、少しでもこの記事が参考になれば幸いです。