Unity IAPの実装まとめ

# UnityIAPとは
Unity5.3より公式でサポートされた、アプリ内課金機能。
比較的容易に実装できる。


# 実装前準備
Unity IAPを有効にする必要があります。

Unityのメニューから
Window > Services
でServicesを開きます。
*自分の環境では最初Inspectorと同じウィンドウで開こうとしようとしましたが画像のようにServicesの内容が表示されませんでした
![temp.png](https://qiita-image-store.s3.amazonaws.com/0/6955/7eb73f75-3915-2863-1362-7db17e126f4f.png)

そこでInspectorと同じウィンドウではなく別のウィンドウで開くと内容が表示されたので、
もし同じ問題が発生した方は試して見てください。


Servicesウィンドウが以下のように表示されていると思います。
<img width="309" alt="スクリーンショット 2016-11-21 10.48.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/6955/1bdb6160-ea74-9407-aed8-d516f17d72f6.png">

UnityProjectIDを作成して次に進むと
<img width="155" alt="スクリーンショット 2016-11-21 10.51.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/6955/943f440e-b9db-6b70-f5d0-02a7712d5a77.png">

のようなメニューになるので
In-App Purchasing
を選択します。

<img width="155" alt="スクリーンショット 2016-11-21 10.55.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/6955/a5dcded7-f028-f8bd-8e76-16a5796eae20.png">

そうするとIAPを有効にすると、Analyticsも有効になるよ、的なメッセージが出るので、
Enableを選択して先にすすみます。

![temp.png](https://qiita-image-store.s3.amazonaws.com/0/6955/64bc6d72-ce17-70aa-4cdf-cd976ba15f5b.png)

次は、作成するプロダクトは13向け（対象？）かどうかの選択がでるので、必要ならチェックしてContinue。

これでIAPが有効になりました。
Importボタンが出てくると思うので、IAPのコード等をImportします。
PluginsフォルダにUnityPurchasingフォルダが作成されているかと思います。
これで実装準備が完了になります。



# 実装
準備でimportしたUnityPurchasingのscriptにIAPDemo.csがあります。
わからないことがあればこちらも参考にするのが良いと思います。

##ストアクラス実装
　
Unity IAPはIStoreListenerを継承したストアクラスで様々なコールバックを受け取ります。
詳しいメソッドは以下になります。

```csharp:StoreTest.cs
public class StoreTest : IStoreListener {

	/// <summary>
	/// IAP初期化完了コールバック
	/// </summary>
	public void OnInitialized( IStoreController controller, IExtensionProvider extensions )
	{
		
	}

	/// <summary>
	/// IAP初期化失敗コールバック
	/// </summary>
	public  void OnInitializeFailed( InitializationFailureReason error )
	{
		
	}

	/// <summary>
	/// 購入失敗コールバック
	/// </summary>
	public void OnPurchaseFailed( Product i, PurchaseFailureReason p )
	{
		
	}

	/// <summary>
	/// 購入成功コールバック
	/// </summary>
	public PurchaseProcessingResult ProcessPurchase( PurchaseEventArgs e )
	{
		return PurchaseProcessingResult.Complete;
	}
}
```

このようなコールバックで処理を行なっていきます。



##IAPの初期化
ここまできたらあとはIAPの実装を行うだけでです。
まずはIAP機能を初期化を行います。
ItunesConnectやGoogle Play Developer Consoleで設定する
製品IDを登録したりします。


```csharp:
public void Initialize()
{
	var module = StandardPurchasingModule.Instance();
	module.useFakeStoreUIMode = FakeStoreUIMode.StandardUser; //Unityエディタでのダミー表示
	var builder = ConfigurationBuilder.Instance(module);

	builder.AddProduct(product.ID, product.Type);

	//製品IDがプラットフォーム毎に違う場合
	builder.AddProduct("100.gold.coins", ProductType.Consumable, new IDs
	{
		{"100.gold.coins.mac", MacAppStore.Name},		//IOS
		{"100.gold.coins.Android", GooglePlay.Name},	//Android

	});
	//製品IDが同じ場合
	builder.AddProduct("100.gold.coins", ProductType.Consumable);

	//初期化
	//第一引数にIStoreListenerを継承したクラス
	UnityPurchasing.Initialize (this, builder);
		
}

```

製品の登録は
プラットフォーム毎に登録したり共通のものを登録したりできます。
個人的には共通にした方が色々と都合がいいと思います。

製品のタイプは
AddProductの第２引数
ProductType.Consumable
の部分で設定できます
詳細はこちらで確認できます。
https://docs.unity3d.com/jp/current/ScriptReference/Purchasing.ProductType.html


# 購入の実行

購入にはIStoreControllerを使用します。
上記の、IStoreListenerを継承したクラスでコールされる初期化完了メソッド

```csharp:
public void OnInitialized( IStoreController controller, IExtensionProvider extensions )
```

の引数で渡されます。
なので、

```csharp:
IStoreController Controller{ get; set; }
IExtensionProvider Extensions{ get; set; }

/// <summary>
/// 初期化完了コールバック
/// </summary>
public void OnInitialized( IStoreController controller, IExtensionProvider extensions )
{
	Controller = controller;
	Extensions = extensions;
}
```

のように保持するのが良いかと思います。
ちなみにIStoreControllerは購入の様に,UnityIAPを制御するのに、
IExtensionProviderはストア特定の拡張機能へのアクセスで使用します。
例えばIOSのリストア等ですね。

さて、実際の購入処理は簡単で

```csharp:
/// <summary>
/// 購入
/// </summary>
/// <param name="ProductID">製品ID</param>
public void Purchase(string productID)
{
	var product = Controller.products.WithID(productID);
	Controller.InitiatePurchase(productID);
}
```
とするだけで可能です。
購入結果はIStoreListenerの継承クラスでコールされ、

成功した場合は、

```csharp:
public PurchaseProcessingResult ProcessPurchase( PurchaseEventArgs e )
```

失敗した場合は

```csharp:
public void OnPurchaseFailed( Product i, PurchaseFailureReason p )
```

がコールされるので
ここからそれぞれ処理をしてあげれば良いかと思います。

# レシートの取得

これまでの流れで購入まではできましたが、
購入したあとはレシートの検証が必要かと思います。
レシートの検証方法は他で調べていただくとして、ここでは
レシートの検証に必要なレシートの取得方法をまとめます


レシート等の情報は、

```csharp:
public PurchaseProcessingResult ProcessPurchase( PurchaseEventArgs e )
```

の

**purchaseEvents.purchasedProduct.receipt**
に入っています。
内容の詳しい説明は以下の公式リファレンスにも書かれていますが、
https://docs.unity3d.com/ja/current/Manual/UnityIAPPurchaseReceipts.html
json形式のstringで格納されています。
そのためこのデータを扱うためにはデシリアライズしなくてはいけないことに注意してください。

jsonの内容は公式リファレンスそのままになりますが以下の通りです

| key | Value |
|:-:|:-:|
| Store  | GooglePlay や AppleAppStore のストア名  |
|  TransactionID | このトランザクションのユニーク ID は、ストアが発行します。  |
|  Payload |  プラットフォームによって異なるため、詳細は以下を参照してください |

レシート検証には各プラットフォームで内容が違う**Payload**の中身を主に使用します。
Payloadの内容は以下にまとめます

## IOSの場合


Payloadにはレシートがbase64されたものが入っています。
そのままレシート検証に使用できます。


## Androidの場合

Androidの場合は少し面倒で、
Payloadにjson形式で

| key | Value |
|:-:|:-:|
| json  | Google によって提供される文字列にエンコードされた JSON |
|  signature |Google によって提供される JSON パラメーターの署名  |

が格納されています。
面倒なのがこれも文字列のため、
扱うにはさらにPayloadの内容をデシリアライズしないといけない事に注意してください。
あとはそれぞれ取り出してレシート検証にしようしてください。

*＊Unity IAPとは関係ありませんが、Andoridのテスト購入にはorderIdが入ってきません。
代わりに purchaseTokenを使用しなくてはいけないようです。
自分の場合はここで若干ハマったので注意してください。
さらに詳細は以下を参照
https://developer.android.com/google/play/billing/billing_testing.html#billing-testing-static*


以上となります。
使用した感想としては、
今までUnityでの課金処理は自前で実装するかSoomla等のアセットを使用するのが主流でしたが、
それに比べたらかなり実装は容易かと思います。
公式にサポートしている機能なのでバグがあった場合はきちんと修正してもらえるという安心感も大きいです。
Unityで課金が必要な場合は選択肢の一つとして考えてみたはいかがでしょうか。


# 参考
http://techtechnolog.com/blog/archives/1500
http://blog.applibot.co.jp/blog/2016/04/20/unity-iap/