| title | tags |
|---|---|
Unity IAPを試してみた (Yet Another Purchaser.cs) |
Unity UnityIAP Android iOS C# |
- Unity & Purchasing
- Unity 6000.0.56f1
- com.unity.purchasing 4.13.0
- IAP 5.x では動作しません。 → Upgrade to IAP version 5
- Apple App Store、Google Play Store アカウント
- この記事では、Unity IAPの一部機能を限定的に使用し、汎用性のない部分があります。
- サーバレス、消費/非消費タイプ使用、購読タイプ未使用
- この記事のソースは、実際のストアでテストしていますが、製品版での使用実績はありません。
- ソース中のIDは実際と異なり、そのまま使用できるものではありません。
- マニュアル
- スクリプトリファレンス
- Unity In-App Purchasing をスクリプトから使います。
- 購入、消費、リストア(iOS)
- スクリプトレスで使うのでしたら、より簡易な方法が用意されています。公式ドキュメントや他の記事を参照してください。
- ストアの開発アカウントが必要です。
- アプリを登録してください。
- アプリ内購入アイテムを登録してください。
- パッケージ「In App Purchasing (
com.unity.purchasing)」が必要です。- あらかじめ、パッケージマネージャで導入してください。
- プロジェクトにサービスを導入します。
Project Settings>Services>In-App Purchasingを「ON」にします。Receipt Obfuscatorで、レシート検証のコードを生成します。- 処理を進めると、
Assets/Scripts/UnityPurchasing/generated/にコードが生成されます。
Assets/Scripts/UnityPurchasing/generatedの生成後、Assets/Scripts/UnityPurchasingにUnityPurchasingGenerated.asmdef(Assembly Definition)を生成してください。- この情報を使って、外部のアセンブリから生成コードが参照されます。
{
"name": "UnityPurchasing.Generated",
"rootNamespace": "UnityEngine.Purchasing.Security",
"references": [
"UnityEngine.Purchasing.Security",
"UnityEngine.Purchasing.SecurityCore",
"UnityEngine.Purchasing.SecurityStub"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
Package Manager>Add package from git URL...で以下を入力します。
https://github.com/tetr4lab/UnityIAP-Test.git?path=/Assets/UnityIAP
- 以下のネームスペースを使用します。
using Tetr4lab.UnityEngine.InAppPuchaser;Package Manager>Add package from git URL...で、順に以下を入力します。
https://github.com/tetr4lab/Tetr4labNugetPackages.git?path=/Tetr4lab
https://github.com/tetr4lab/Tetr4labUnityUtilities.git?path=/Assets/Utilities
UnityEngine.Purchasing- 必須のネームスペースです。
UnityEngine.Purchasing.Security- レシートの検証で必要なネームスペースです。
UnityEngine.Purchasing.Default- この記事では扱いません。
UnityEngine.Purchasing.Extension- この記事では扱いません。
UnityEngine.Purchasing.MiniJSON- この記事では扱いません。
- 初期化のために製品定義が必要です。
- 製品定義は製品のIDとタイプのセットです。
var products = new [] {
new ProductDefinition ("jp.nyanta.tetr4lab.unityiaptest.item1", ProductType.Consumable),
new ProductDefinition ("jp.nyanta.tetr4lab.unityiaptest.item2", ProductType.NonConsumable),
new ProductDefinition ("jp.nyanta.tetr4lab.unityiaptest.item3", ProductType.NonConsumable),
};- これらはストア・コンソールでの設定と正しく呼応している必要があります。
- Apple App Storeでは、IDと製品タイプの双方が設定されます。
- 消費と非消費(恒久)は明確に区別されます。
- Google Play Storeでは、IDが設定されますが、消費の有無についての設定はありません。
- ストア側には消費と非消費(恒久)といった種別がなく、アプリ側で製品定義して消費を申告することで区別されています。
- Apple App Storeでは、IDと製品タイプの双方が設定されます。
- ここでは、消費タイプ
Consumableと非消費タイプNonConsumableだけを扱い、購読タイプは扱いません。
- 製品定義を渡して初期化を行います。
Purchaser.Initialize(products, null)の形では、初期化を開始するのみでブロックされません。Purchaser.Initialize(products, success => Debug.Log (success))とすると、結果のコールバックを受けることができます。
var success = await Purchaser.InitializeAsync (products)とすれば、同期的に成否を得られます。
- 例えば、以下のように書くことで、初期化の完了を待って課金アイテム一覧を表示するようなことことが可能です。
- この
Purchaser.Productsは、ストアから得た製品目録IStoreController.productsを参照します。
- この
private async Task CreateCatalog () {
if (await Purchaser.InitializeAsync (products)) {
Catalog.Create (CatalogHolder);
foreach (var product in Purchaser.Products.all) {
CatalogItem.Create (Catalog.ScrollRect.content, product);
}
}
}- 他に、以下のプロパティをポーリングすることも可能です。
Purchaser.Validで初期化の完了を取得できます。Purchaser.Statusで初期化の状況を取得できます。
- 初期化に成功すると、
Purchaser.Products.allで、ストアから得た製品情報を参照できます。
foreach (var product in Purchaser.Products.all) {
Debug.Log (product.GetProductProperties ());
}Purchaser.Products.GetProduct (string id)で、個別に製品情報を取得できます。idが見つからない場合はnullが返ります。
((Product) product).Valid ()で、製品がストアに登録されているか確認できます。((Product) product).metadata.shortTitle ()で、アプリ名を含まない製品(アイテム)名を取得できます。
- 初期化時に定義を渡さなかった製品は、ストアにあっても製品目録には載りません。
- ストアから製品のカタログが得られるわけではありません。つまり、ストアに新製品を登録しただけでは、製品に組み込むことはできません。
Product.definition.enabledは、ストアのコンソールで設定されている有効/無効状態に関わりなく常にtrueになります。Product.availableToPurchaseは、ストアにアイテムがない場合とストアで無効になっている場合にFalseになります。- ストアでの製品の有効/無効は、アプリの使用する製品定義に連動させ、緊急時以外は、ストア独自に製品を無効化しないようにしてください。
- 「非消費アイテムが購入済み」あるいは「消費アイテムが購入済みで未消費」であることを取得するには、
bool? Purchaser.IsStocked (Product product)またはbool? Purchaser.IsStocked (string productID)を使用します。- 指定した製品が無効だったり、
Purchaserが未初期化の場合はnullを返します。
- 指定した製品が無効だったり、
- あるいは、
Purchaser.Inventoryを参照することもできます。Purchaser.Inventoryを書き換えて所有状態を変化させることはできません。外部から書き換えると不整合が生じます。
Purchaser.Inventory [Product product]またはPurchaser.Inventory [string productID]で、所有状態を取得できます。- 存在しない製品を指定すると例外が発生します。
Purchaser.Inventory.ContainsKey (Product product)またはPurchaser.Inventory.ContainsKey (string productID)で、製品の存在を確認できます。
Purchaser.Purchase (Product product)またはPurchaser.Purchase (string productID)により、課金処理が開始されます。Purchaser.Purchase (Product product, Action<bool> onPurchased)またはPurchaser.Purchase (string productID, Action<bool> onPurchased)とすると、結果のコールバックを受けることができます。
await Purchaser.PurchaseAsync (Product product)またはawait Purchaser.PurchaseAsync (string sku)により、同期的に成否を得られます。Purchaser.PurchaseValidをポーリングすることで、課金処理が進行中であることを確認できます。- ただし、課金処理を開始したものの、エラーのために進行中にならない場合もあります。
Purchaser.Resultにより、直前の課金処理の失敗の理由を取得できます。
- 課金処理に成功すると、非消耗品では購入が完了し、消耗品では「購入済みで未消費(所有している)」状態になります。
- 未消費状態は、アプリの中断時にも保持されます。
Purchaser.ConfirmPendingPurchase (Product product)またはPurchaser.ConfirmPendingPurchase (string productID)で消耗品を消費できます。- 消費に成功すると真が返されて「未所有」状態になります。
Purchaser.Restore (Action<bool, string> onRestored = null)で、課金情報の復元を行い、結果のコールバックを得ることができます。- Google Play Storeでは、何も処理されず、常に成功します。