【①クライアントの実装】
GooglePlay Billing Libraryを使って実装します。
https://developer.android.com/google/play/billing/billing_library_overview
半日ぐらいで簡単に作れました。ライブラリ自体の使い方が(v3だけあって)かなり洗練されていることに加え、ググれば十分に情報が出てくるので、初心者でも簡単に実装できるかと思います。
つまり、クライアントの実装ネタ自体は十分にあるので本記事では割愛します。
【②サーバ実装】
subscription IABでは、購入時に発行されるreceiptをサーバへ送信し、サーバでGooglePlayへのverification(REST API)を行い、有効な状態ならコンテンツ閲覧などの機能を開放するといった形で実装します。
実装時に注意すべき点としては、APIの実行上限が20万件/日に制限されている(引き上げは出来るけど恐らく有料になる)ので、verificationが完了した状態のreceiptデータをRedisやDB等にキャッシュしておく必要がある(要するに無闇にポンポンGoogleへリクエストを投げてはいけない)事ぐらいでしょうか。
【③verification API】
GooglePlay developer APIのPurchases.proudcts:getを用いて検証します。
https://developer.android.com/google/play/developer-api?hl=ja
https://developers.google.com/android-publisher/api-ref/purchases/products/get
Requires AuthorizationなAPIなので、予めGooglePlay developer consoleでサービスアカウントを作成して、JWT認証できるようにしておく必要があります。
APIは普通にHTTP clientで書いても良いかと思いますが、様々なサーバ言語向けライブラリが用意されていて、少なくともauth系のAPIはライブラリを使用することが(Googleから)推奨されています。
https://developers.google.com/android-publisher/libraries
上記ページには、現時点でJavaとPhytonしかありませんが、ページを辿っていくとNode.jsのライブラリもありました。ただし、Alpha版(この時点で嵐の予感)。
https://github.com/google/google-api-nodejs-client
とりあえず、上記ライブラリでJWT認証+purchases APIを実装してみた。ところが、JWT認証は上手くいったのですが、purchases APIが全然上手く動かない。「Invalid Value」というエラーで失敗するのですが、何処がinvalidなのやら...。
StackOverflow等で調べてもv2以前の情報しか載っていなくて、一応v3の実装自体は入っているけどexampleとか一切無い状態。
https://github.com/google/google-api-nodejs-client/tree/master/src/apis/androidpublisher
やる気が感じられない...せめてどうやって実装するか切り口となる説明ぐらいREADME.mdに書いて欲しい。なので、JWT認証はライブラリで行いつつnode-rest-clientで直にpurchases APIを実行するのが、現時点で最も無難な選択肢だろうと判断しました。
以下、上記の方式で実装したコードを晒します。
【④必要なパッケージ】
npm install --save googleapis
npm install --save node-rest-client
npm install --save xml2js
※xml2jsを入れないとnode-rest-clientのコンストラクタでモジュール不整合が起きる
【⑤実装】
const RestClient = require('node-rest-client');
const { google } = require('googleapis');
const authClient = new google.auth.JWT({
email: サービスアカウントのEメール,
key: サービスアカウントのプライベートキー,
scopes: ['https://www.googleapis.com/auth/androidpublisher']
});
const restClient = new RestClient.Client();
authClient.authorize((error, tokens) => {
if (error) {
略(認証エラー時の処理)
return;
}
const url =
"https://www.googleapis.com/androidpublisher/v3/applications/"
+ receipt.packageName + "/purchases/subscriptions/"
+ receipt.productId + "/tokens/" + receipt.purchaseToken
+ "?access_token=" + tokens.access_token;
restClient.get(url, {
headers: {
'Content-Type': 'application/json'
}
}, (data, response) => {
if (200 != response.statusCode) {
略(APIエラー時の処理)
} else {
receiptExpire = data.expiryTimeMillis;
略(成功時の処理)
}
});
});
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。