Unityでアイテムの課金処理よろしく、と言われた人向け事前知識

#概要
突然開発中のiOS,AndroidマルチプラットフォームUnityアプリでアイテム課金を任された場合に知っておいた方が後々楽できそうな知識をまとめておきます。嘘ついてたら教えてください。
また、ステージ買い切りとかサーバプログラマ無しでのインディーゲームなどは考慮しません。
その場合は普通にUnityIAP sampleを使うのが良い気がします。
普通のUnityIAPはちょっと古いけどこのサンプルプロジェクトが参考になると思います。
https://github.com/unity3d-jp/UnityChanBallRoll

**更新履歴**
3/31 : Autoyaの中の人からフィードバックを受けた情報を追加
4/4 : iOSテスト課金周りの情報を追加

# Unityアイテム課金のための各ストアへのアイテム登録
- AppStoreおよびGooglePlaystoreのアプリ登録を済ませておく(地味に住所入れ忘れとか、アプリ概要欄が「あ」だけだったせいでスパムと思われて登録が完了しないなどのトラップがある）
- AppStoreおよびGooglePlaystoreにアイテムと価格を登録する。本当に重要なのはproductIDと価格だけです。このときに 100_coin_androidや100_coin_iosの様に各プラットフォーム識別が出来る形でアイテム名を登録しましょう。後で購入問い合わせ来るときに有ると無いで全然違う…

軽く「ストアへのアイテム登録」って書いてありますが、結構ハマるポイント多いので下の方の補足も参照ください。

# 購入処理を書く
上に挙げたUnityChanBallRollサンプルみたいなアイテムの課金処理を書いて運用するとどうなるかというと、チートされる余地が結構あったり、ユーザさんから購入失敗問い合わせが来た時にめっちゃつらい目に遭います。

これは何故かというと各ストア(AppStore,GooglePlayStore)に対してUnityIAPのメソッドを叩いて購入処理すると、直接ストアに購入処理が入ってしまうためです。
この記事を読んでいるような人が作るアプリだと

- ユーザ識別子がほしい
- 「購入ボタンを押した」ごとに一意の取引識別子がほしい
- 購入失敗時もその原因込みで情報が欲しい
- それら情報を自社サーバに貯めておきたい

と言う事になりがちです。それは先のサンプルには入っていないので自前で実装する必要があります。つらいっすよね…

# どうすると良いの
Autoya使いましょう。

https://github.com/sassembla/Autoya

AutoyaのPurchaseモジュールが上に挙げたような諸々の処理を含んでいて、後は以下のドキュメントを見ながら作ればクライアントサイドは何とかなります。 実際のIAP購入処理を行う前に各種通信を行い認証を通す（つまり、自社サーバに「買おうとした人」情報を蓄積できる）のが一番便利なところだと思います。 
サーバサイドは誰かに任せましょう。

Autoyaで購入処理前の通信が行われている意図としては、

- 購入処理の前に通信を行うことで購入意図の把握を行う=サーバ側に記録が残るので、お問い合わせに対して確実な判断ができるようになる
- キャンセルや未処理=Appが落ちたりして完結していない購入処理までをサーバ側で把握できる

https://sassembla.github.io/Autoya/docs/en/purchase0.html

Autoyaはチート対策やお問い合わせ対応をする上で欲しい情報や、処理を書き込む口がちゃんと用意されている素敵フレームワークです。

以下の文章が「なんでAutoyaが良いか」を理解する上で役に立つと思います。
http://sassembla.github.io/Public/2017:01:05%2017-46-38/2017:01:05%2017-46-38.html


# Autoya Purchaseモジュール補足
上にあるAutoya Purchaseモジュールのドキュメントは詳しく書いてある+実運用上の知見も詰まっていますが、いくつか（課金処理を初めて触る人向けの）補足説明があった方が読み解きやすいかもしれません。ここで説明します。

## Remote PurchaseとLocal Purchaseはどっちを選ぶの？
アイテムの課金があったら現実的にチート、問い合わせ対応が必要になるので **サーバ有り Remote Purchase** を使いましょう。
Local Purchaseを使うのはサーバエンジニアが居なくて、クライアントエンジニアがチート対策を分かっているかチートを諦める場合だけです。

なので、上のAutoyaドキュメントのRemote部分だけを読みましょう。
問い合わせ件数はLocalでもRemoteでも変わりませんが、問題が起こっているかどうか把握したい、という場合はRemoteを選ぶべき、という感じですね。


## ProductInfoって何を書くの
AutoyaFramework.Purchase.ProductInfoですが
productIDを100_coinみたいな名前で、platformProductIdが100_coin_androidみたいな識別子を付けた名前が来ることを前提としています。

本番稼働だとサーバ側からProductInfoを取得する事になると思いますが、最初の課金テストはこんな感じで書く事になると思います。 ifdefでプラットフォーム分けしておきましょう。(そうしないとAppStoreの方に100_coin_androidがあるか問い合わせてしまい、初期化失敗します)

```cs

 public class PurchaseSettings
    {

        /*
			immutable purchasable item infos.
			*/
        public static readonly ProductInfos IMMUTABLE_PURCHASE_ITEM_INFOS = new ProductInfos
        {
            productInfos = new ProductInfo[] {
          #if UNITY_IOS || UNITY_EDITOR
                new ProductInfo("100_coin", "100_coin_ios", true, "100coin_description"),
          #elif UNITY_ANDROID
                new ProductInfo("100_coin", "100_coin_android", true, "100coin_description"),
          #endif
			}
        };

```

また、

Autoya.Purchase()に入れる商品名の引数は
100_coinのような、**_androidや_iosを入れていない方の名前**が来ることを前提にしています。

```
//こんな感じ！
Autoya.Purchase(
                purchaseId,
                "100_coin",
                pId =>
                {
```

## Autoyaの課金処理を使うときは他のUnity用IAP周りの何か設定しなくて良いの？IAP ButtonとかIAP catalogで商品名作ったりとか…

そういうのは、**やらなくて良いです** 。サーバ側でそういうロジックは作っちゃうのでクライアント側はAPI呼ぶのと返事を処理する口を作るのが大切です。その辺はAutoya Documentを読んでください。

## IAB-DPTLエラーが出て買えない
Android+Autoya で購入時IAB-DPTLエラーが出て買えない→Unity IAPに渡すpayloadが長すぎるエラーです。
Autoyaのサンプルままだとチケット取得時の通信のリクエストヘッダが全部入っているので確かにpayloadの中身が長すぎる気はします。

Autoyaのサンプルからとりあえず動かしたい場合は、
OverridePoint.csの中で認証系処理を追加する部分で決め打ち文字列を入れるのが良いです。

```cs
   private string OnTicketResponse(string ticketData)
        {
            // modify if need.
            //return ticketData;
            return "test_not_auth";
        }
```
本番環境なら実際に運用する場合にはまず認証側を考慮してるはず(つまり AutoyaのOverridePoints.cs の中身が書き換わっている)なのですが、最初のサンプルの時にはハマると思います。


IAB-DPTLエラーについてはこちら
https://stackoverflow.com/questions/10194120/android-in-app-billing-error-this-item-could-no-be-purchased-error-code-iab


# 一般的なUnityIAP課金周りハマりポイント補足

## Android実機テスト時に無言で購入失敗する
https://forum.unity.com/threads/solved-unity-iap-is-not-worked-for-android-device.501881/

GooglePlayのクローズドアルファテストしている時に、開発者アカウントじゃなくてテストアカウントを追加して課金できるかを確認しましょう。僕はこれで半日潰しました。


## 課金テストにはテストアカウントを使おう
上の補足です。課金処理を実装するとき、Androidの場合はテスターアカウントのセット、iOSの場合も同様にテスターアカウントを設定しましょう。どうやら昔は、Apple開発者アカウントを使って課金テストしてたらアカウントロックされてAppStoreで買い物出来なくなったりしたそうです。怖い…


Android「次に、認証済みユーザー用のライセンス テスト アカウントを作成します
https://developer.android.com/google/play/billing/billing_testing.html#testing-purchases

テストアカウントは https://itunesconnect.apple.com/access/users の左下に「 Sandbox テスター」欄があるので、そこから追加します。 **そんな物が出てこない、というときは自分のアカウントの権限をDeveloperじゃなくてAppManager以上にしてください。**


iOS「サンドボックスでお前のアカウントを使うな、テスターアカウント作って使え」
https://developer.apple.com/support/apple-pay-sandbox/


## iOSのテスト課金を通すまでのAppstore側設定
大雑把に言うとテスト課金が通っていれば、本番環境(AppStore+Release+一般AppleID)でも課金が通る仕組みになっています。

1. Mac+Unity+iOS端末で普通のアプリがビルドできるようにする（開発者登録を済ませる。IAPはシミュレーションモードだと動かないのでiOS実機必須）
2. 課金を行うアプリのBundleIDは**ワイルドカード指定ではなく決め打ちの名前**を登録する（IAPはワイルドカード証明書では動きません）
3. Unity上でIAP周りのサービス登録をする（Unity Serviceから指定するやつ） https://unity3d.com/jp/learn/tutorials/topics/ads-analytics/integrating-unity-iap-your-game (テストスクリプトを作成、の手前まで)
4. UnityからビルドしたxcodeprojをXCode上で開いてIn App PurchaseをOnにする![スクリーンショット 2018-04-04 13.08.14.png](https://qiita-image-store.s3.amazonaws.com/0/40627/993642a3-492c-b6c9-8d1a-25ea58936c4d.png)
5. AppleDeveloperアカウントに**銀行口座を紐付ける**（ユーザから課金されたお金を受け取る口座）
6. iTune Connect上でテストアカウントを紐づける
7. iOS実機上で開発者アカウントではなく（サインアウトして）作成したテストアカウントでログインする

気を付けることとしてGooglePlayは口座紐づけが無くてもテスト課金が通りますが、AppStoreはテスト課金時でも口座紐づけが必要という点でしょうか。

sandbox+develop環境でもテスト課金は通る
https://qiita.com/koyopro/items/c6c387b136da1698f666

## iOSのテスト課金を通すまでにやらなくても良い事
- ipaのAppStoreアップロード(XCode上から直接実機Runしてもテスト課金は通る)
- iTuneConnect上の課金アイテムの審査(アイコン未設定でもテスト課金は通る)

↓こういう感じの設定で大丈夫です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/40627/d4b416ae-09c4-aa40-f6c5-2526f094ab5e.png)


## Androidの課金テストを最初に通すまでのイテレーションがめっちゃ面倒くさいので注意
Androidのsandbox課金テストは結構大変です。
何故かというとアイテムを登録した状態でgoogle play console にapkをアップしてないとダメだからです。

つまりReleaseBuild+keystore+ビルド番号を設定してapkビルド→apkを手作業でgoogle play consoleの内部テスター版とかにアップして→反映を待って（だいたい30分いないだけど、最長1日）


そしてgoogle play console経由のgoogle playで開発中バージョンをインストールして

課金テストが出来ます！！！便利！！！（全然便利ではない）
しかもうっかり100MB以上のapkになっていると、わざわざsplitOBBチェック入れてアップロードしなければいけません。ううむ…つらい…

しかもgoogle play consoleにアップするときに横着してリリースノート書かないと、最新版ビルドが反映されたかどうかが分かりにくくてハマります。

勿論、一度課金テストを通した後のアイテム追加して再度テストするときなどはUnityEditorからrelease buildでbuild and runするだけで実行できます。
最初の一度課金テストを「開発初期でアプリサイズが小さいうちに」「スケジュールに余裕があるうちに」やっておきましょう。

## 課金モジュールが入っているプロジェクトをクローンして開いたらめっちゃエラー出るんだけど…
一度UnityEditorを再起動して開き直してみてください。
それでも直らなければ、もしかしたらUnityのOrganizationの設定ミスかもです！