Unity IAP サーバ側で検証~みたいなのを実装してた


概要

簡単だった。いや~~楽になったなあ。

もうSoomlaもPrime31も要らないと思う。


困るのは使い方を知るための情報が足りなかったりとかそのへんだ。


一番悩んだのが、payloadっていう引数があったんだけど、これがどう扱われるのかまったくドキュメントがないところ。


Mac/iOSのreceiptにはそんなの入る枠ないし、となるとAndroidでのpurchase receiptにのみ関連するんだろうか、、?


入っているのか入っていないのか、というめんどくさいけど確認しないとわからなかったのでそのまとめ。



Unity IAP API

なんかこう書くとややこしいんだけど、十分実用に耐える感じ。


・ストアの初期化

・Purchaseの発行

・ユーザーアクションのハンドリング

・Purchase完了時の同期的完了処理

・Purchase完了後の非同期的完了処理

・その他 プラットフォーム独自の要素の設定とかいろいろ


といった物事が綺麗にハンドリングできる。



サンプルを作るにあたって苦労したこと

今作っているAutoya フレームワークにエッセンシャル的な実装をぶち込んだ。

payloadの次に悩んだのが、Purchase完了後の非同期的完了処理。


いやドキュメントが足りなくて。具体的には次のことをするための情報がなかった。

・非同期に処理するには、まずPendingする必要がある

・サーバの応答を待って、対象のProductをcontroller.ConfirmPendingPurchase(e.purchasedProduct)する必要がある

・今PurchaseしたProductと、過去PurchaseしていてStore処理が未完だから流れてきたProductを綺麗に見分ける必要がある

・payloadがどんなデータになるのかよくわからん



綺麗に見分けるという動作のニーズ

UnityのIAP APIでは、購入が完了していないProductはOS(iOS, Android)が適当なタイミングでその情報を流してくるのをラップしているので、

PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e){} 

がいつでも呼ばれる可能性がある。


これは、たった今購入したProductに対しても呼ばれるし、先ほど行ってまだ完了していないProductに関しても呼ばれたり、

あまつさえ別端末で同じIDでログインしてたりすると、そちらで完了していなければ別端末で受ける、みたいなのもある。


つまり「アカウントに紐づいて、今買ったProductも、こないだ買った未完了のProductも、このメソッドを呼び出す」のだ。

これがめんどうくさい。綺麗に見分けないといけない。

「Productは購入されてるんだけど、今買ったの? それともこないだ買ったの?」というのを判断しないといけない。

綺麗に見分けるという動作の実装

で、ProductにはtransactionIdというパラメータがあるんだけど、

このパラメータは「購入処理が開始されてからセットされる」。


つまり事前に設定できるパラメータではない。


・購入用のIdを適当に用意する

・そのIdをProductとまとめてStoreに流して、Product情報から取り出す


ということができれば、他のProductと明確に区別できるんだけど、まあ、クライアント側でそれらを処理間で共有するようなキーはAPIに存在しなかった。

唯一、

controller.InitiatePurchase(product, payload);

のpayloadがなんかそれっぽかったんだけど、このパラメータはまあ、御察しの通り、Androidのreceiptの内部に入れられるパラメータだった。

んでこのpayload、具体的なreceiptに入るよ~~とか説明一切ないの。なんかpayloadだよってだけで。困る。


最終的にどうやったかというと、Productのインスタンスを自分で保持する、ということにした。


購入前

-> ProductIdでProduct召喚

-> オンメモリでProductを保持(グローバルなパラメータとして保持)

-> 購入処理

-> 購入成功でProcessPurchaseが呼ばれる

-> オンメモリに保持していたProductのインスタンスのtransactionIdが処理を経て変わっているので、そのtransactionIdと、ProcessPurchaseで渡ってきたProduct(オンメモリのものと同一)のtransactionIdを内容比較

-> 一致すればたった今購入したProduct、一致しなければ今買ったのではないけれどまだ未処理のProduct という区別ができる。


はーー。これだけのことをするために「どうすればいいんだろ。。?」ってなってた。

ちなみに public void OnPurchaseFailed (Product i, PurchaseFailureReason failReason) メソッドも似たような呼ばれ方するので、やはり判別する必要がある。



おねがいドキュメント。オンメモリで購入中のProductのインスタンスを保持すればいいですよ、ってどっか書いといて。

パラメータの内容が動的に変わるからそれ使ってトレースできるよ、っていうのはちょっと、、、ノールックはちょっと、、、、まあ、、、はい、、、