質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Google Play

Google Playは、Google社が提供しているAndroid端末向けのデジタルコンテンツ配信サービスです。Google Play Store アプリから、世界中の個人または企業が開発したアプリをダウンロードできます。有料アプリの売り上げは、70%を開発者、30%は通信キャリア等への支払いにあてられます。開発者が登録する場合は、初回のみ25ドルの登録手数料が必要です。

Q&A

解決済

3回答

13262閲覧

Unity IAP + GooglePlay で消費型アイテム購入時に「ライブラリに追加しました」と表示される

HiroshiWatanabe

総合スコア2160

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Google Play

Google Playは、Google社が提供しているAndroid端末向けのデジタルコンテンツ配信サービスです。Google Play Store アプリから、世界中の個人または企業が開発したアプリをダウンロードできます。有料アプリの売り上げは、70%を開発者、30%は通信キャリア等への支払いにあてられます。開発者が登録する場合は、初回のみ25ドルの登録手数料が必要です。

3グッド

3クリップ

投稿2016/06/27 04:21

編集2016/06/27 07:09

Unity 5.3.5p4 で Unity IAP を使い GooglePlay のアイテム課金(消費型)のテストをしていますが

・購入時に GooglePlay から受け取る情報内から orderId が無くなり、TransactionId も空で返ってきます
(SandboxのIDで購入成功時にはどちらも得られるんですが自前の商品のIDだとその情報が欠落します)

・テストアカウントで自前の商品を何度も購入できているので消費型としては機能しているように見えます
(消費型でなければ2回目の購入ができないらしいので)

・購入時に表示される GooglePlay の支払いましたパネル(Sandbox時)が出ず「ライブラリに追加しました」というパネルが表示されます

・Validate() を呼び出すとその中でクラッシュしてしまいます

検索しても原因や対策がわかりそうな情報がみつからず困っています。
似たような症状に遭遇した方や原因に見当がつく方がいましたら解決に向けて情報を頂けると助かります。
よろしくお願い致します。

---以下6/27追記(実際に使っている物から不要箇所削除しID類情報を変更するなど加工して掲載)---

c#

1#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS 2//#define RECEIPT_VALIDATION 3#endif 4 5using System; 6using System.Collections.Generic; 7using UnityEngine; 8using UnityEngine.Purchasing; 9#if RECEIPT_VALIDATION 10using UnityEngine.Purchasing.Security; 11#endif 12 13public class Unity5Purchase : MonoBehaviour, IStoreListener { 14 private static IStoreController m_StoreController; 15 private static IExtensionProvider m_StoreExtensionProvider; 16#if RECEIPT_VALIDATION 17 private CrossPlatformValidator validator; 18#endif 19 20 // GooglePlayライセンスコード. 21 const string API_KEY = "(ないしょ)"; 22 23 void Start() { 24 if (m_StoreController == null) { 25 InitializePurchasing(); 26 } 27 } 28 29 public void InitializePurchasing() { 30 if (IsInitialized()) { 31 return;// 初期化済み. 32 } 33 var module = StandardPurchasingModule.Instance(); 34 var builder = ConfigurationBuilder.Instance(module); 35 builder.Configure<IGooglePlayConfiguration>().SetPublicKey(API_KEY);// GooglePlayのライセンスキー登録. 36 // (以下のID等は実際に使っている物とは違います今回のための仮記載情報です) 37 builder.AddProduct("PRODUCT_ID1", ProductType.Consumable, new IDs { 38 { "test01", GooglePlay.Name }, 39 { "TEST01", AppleApPStore.Name }, 40 { "Test01", MacAppStore.Name }, 41 }); 42 builder.AddProduct("PRODUCT_ID2", ProductType.Consumable, new IDs { 43 { "test02", GooglePlay.Name }, 44 { "TEST02", AppleApPStore.Name }, 45 { "Test02", MacAppStore.Name }, 46 }); 47#if RECEIPT_VALIDATION 48 validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), Application.bundleIdentifier); 49#endif 50 UnityPurchasing.Initialize(this, builder); 51 } 52 53 private bool IsInitialized() { 54 return m_StoreController != null && m_StoreExtensionProvider != null; 55 } 56 57 // 購入ボタン押下時にここを呼び出す. 58 void BuyProductID(string productId) { 59 if (IsInitialized()) { 60 Product product = m_StoreController.products.WithID(productId); 61 if (product != null && product.availableToPurchase) { 62 m_StoreController.InitiatePurchase(product); 63 } 64 } 65 } 66 67 public void RestorePurchases() { 68 } 69 70 // 71 // --- IStoreListener 72 // 73 74 // 初期化成功時. 75 public void OnInitialized(IStoreController controller, IExtensionProvider extensions) { 76 m_StoreController = controller; 77 m_StoreExtensionProvider = extensions; 78 } 79 80 // 初期化失敗. 81 public void OnInitializeFailed(InitializationFailureReason error) { 82 } 83 84 [Serializable] 85 class unityReceipt { 86 public string Store; 87 public string TransactionID; 88 public string Payload; 89 public unityReceipt() { 90 this.Store = null; 91 this.TransactionID = null; 92 this.Payload = null; 93 } 94 } 95 96 [Serializable] 97 class googlePlayPayload { 98 public string json; 99 public string signature; 100 public googlePlayPayload() { 101 this.json = null; 102 this.signature = null; 103 } 104 } 105 [Serializable] 106 class googlePayloadJson { 107 public string orderId; 108 public string packageName; 109 public string productId; 110 public uint purchaseTime; 111 public uint purchaseState; 112 public string purchaseToken; 113 public googlePayloadJson() { 114 this.orderId = null; 115 this.packageName = null; 116 this.productId = null; 117 this.purchaseTime = 0; 118 this.purchaseState = 0; 119 this.purchaseToken = null; 120 } 121 } 122 123 private string getReceiptPayload(string strReceipt) { 124 unityReceipt u5r = JsonUtility.FromJson<unityReceipt>(strReceipt); 125 if (u5r != null) { 126 string receipt = null; 127 googlePlayPayload gpp = JsonUtility.FromJson<googlePlayPayload>(u5r.Payload); 128 if (gpp != null) { 129 receipt = gpp.json; 130 if (!string.IsNullOrEmpty(receipt)) { 131 googlePayloadJson googleJson = JsonUtility.FromJson<googlePayloadJson>(receipt); 132 if (googleJson != null) { 133 receipt = googleJson.orderId;// ←何故かSandboxでしか存在しない. 134 } else { 135 receipt = null; 136 } 137 } 138 } 139#if RECEIPT_VALIDATION 140 if (Application.platform == RuntimePlatform.Android) { 141 try { 142 var result = validator.Validate(strReceipt);// ←この中でクラッシュ. 143 foreach (IPurchaseReceipt productReceipt in result) { 144 GooglePlayReceipt google = productReceipt as GooglePlayReceipt; 145 if (null != google) { 146 147 } 148 } 149 } catch (IAPSecurityException) { 150 receipt = null;// 不正なレシートだったので不成立とする. 151 } 152 } 153#endif 154 return receipt;// OK 155 } 156 return null; 157 } 158 // 購入実行(成功). 159 public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args) { 160 bool given = false; 161 if (String.Equals(args.purchasedProduct.definition.id, "PRODUCT_ID1", StringComparison.Ordinal)) { 162 string receipt = getReceiptPayload(args.purchasedProduct.receipt, "test01"); 163 if (string.IsNullOrEmpty(receipt)) { 164 // 不正?想定外? 165 } else { 166 // (ここで付与) 167 given = true; 168 } 169 } else if (String.Equals(args.purchasedProduct.definition.id, "PRODUCT_ID2", StringComparison.Ordinal)) { 170 string receipt = getReceiptPayload(args.purchasedProduct.receipt, "test02"); 171 if (string.IsNullOrEmpty(receipt)) { 172 // 不正?想定外? 173 } else { 174 // (ここで付与) 175 given = true; 176 } 177 } 178 if (!given) { 179 // (付与失敗) 180 } 181 return PurchaseProcessingResult.Complete; 182 } 183 184 // 購入失敗. 185 public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) { 186 // (付与失敗) 187 } 188} 189

あと、6/20までに何度か購入テストしていた時のレシートメールは日本語の件名で
「テスト:Google Play のご注文明細(ご注文:2016/06/??) - Goole Play ご購入ありがとうご(以下略)」
のようにきていましたが6/24以降に来ているレシートメールは全て英語の件名で
「Test: Your Google Play Order Receipt from Jun ??,2016 - Google Play Thank you. You've made a purchase (以下略)」
のように変わっていました。(メールの内容(本文)は日本語のレシートですが件名だけ英語に変わった状態)

buibui80, Hawn, mondaminZ👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

buibui80

2016/06/27 06:25

UnityIAPは情報が少ないので詳しい内容やソースを明記された方が回答を得られやすいと思います。特にレシート検証については情報がないので。
HiroshiWatanabe

2016/06/27 07:10

追記しました。そのまま全部載せる訳にはいかないので改変してありますが概ねこんな感じです。
buibui80

2016/06/27 07:49

自前の商品とはデベロッパーコンソールのアプリ内アイテムとして登録した商品のことでしょうか?
HiroshiWatanabe

2016/06/27 08:39 編集

そうです。管理対象アイテムと定期購読と選べるので管理対象アイテムの方で登録されています。
guest

回答3

0

ログを見るとAを購入成功後にAの消費処理をしているようなのですがAを何度か連続購入してBを購入してAを購入するという流れだとAの購入に戻った時の消費処理では何故かAの消費ではなくBの消費処理をしようとする…みたいな混乱が生じてしまうようです。そうなると消費できていないので次にそれを買おうとすると所有しているからと購入できなくなります。

こちらは改善されました?
というのも当方でも同様の症状を確認しております。

--- 追記:7/4 15:10 ---

以下確認した問題になります。
誤りや追加がありましたら共有をお願いします。


(1) 消費型プロダクトの購入の際、
ProcessPurchase で PurchaseProcessingResult.Complete を返すか、
ConfirmPendingPurchase で購入トランザクションを完了させた後に
UnityIAPプラグインが自動実行する消費型プロダクトの消費処理にて、
消費対象となるプロダクトではなく購入済み他プロダクトの消費処理を勝手に行っている。
さらに購入済み他プロダクトが消費型プロダクト以外の場合も消費処理を実行しており当然ながら失敗している。
結果として消費対象のプロダクトは消費処理が行われないので再購入できない問題が発生する。


(2) 消費されていない消費型プロダクトを再購入する場合など、
ProcessPurchase で PurchaseProcessingResult.Complete を返した後に
OnPurchaseFailed が呼ばれることがある。
(失敗理由は PurchaseFailureReason.Unknown )
その為 ProcessPurchase 内で購入プロダクトの数量・アンロック管理を行う場合に不整合が発生してしまう。
一般的なエラーの場合は ProcessPurchase が呼ばれず直接 OnPurchaseFailed が呼ばれるので、
OnPurchaseFailed 内で数量・アンロック管理を行うことも不整合が発生する。


(3) 消費型プロダクトの消費処理はUnityIAP側で自動処理され、
その結果用のイベントリスナーが無いため消費の成否及び何を消費したのか把握するすべが無い。

投稿2016/07/04 04:00

編集2016/07/04 06:20
buibui80

総合スコア1033

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HiroshiWatanabe

2016/07/04 06:36

おっしゃる通りの症状が今もでています。Unityサポートに問い合わせもしましたが有効な回答は得られていません。なおこの症状は今の所GooglePlayでのみ起きているようでiOS版では同症状の発生は確認できておりません。
buibui80

2016/07/04 14:00

色々ログを取ってみたら (1) に誤りがあることに気づきました。 「購入済み他プロダクトが消費型プロダクト以外の場合も消費処理を実行しており当然ながら失敗している」ですが、成功しているケースがありました。 非消費型でも消費処理に成功という意味不明な現象です。 Unityサポートから良い回答が得られるのを期待しております。 合わせてこちらからも問い合わせをしておきました。 iOSは簡易なチェックのみ実施しましたが、すぐ気づく様な問題はなかったですね。
HiroshiWatanabe

2016/07/05 07:16

サポートの方は英語圏で同様の問題を報告している人を見つけられていないそうで同様の報告を何処かで見かけたら教えて欲しいと言われました。 で、こちらが本題ですが、バグの情報を社内DBで探してAndroidのみで発生する問題で近い物があったそうです。 もしそれと同じ原因だとすれば社内的には既に修正済みでリリースに向けて確認中だそうです。 そのバージョンは1.6でIAPモジュールの再インポートで更新されるようです。 /Assets/Plugin/UnityPurchasing/Changelog.md でIAPモジュールのバージョンを確認できるそうです。 (手元環境では1.5.0でした) 1.6で治るかどうかはわかりませんがひとまず1.6を首を長くして待ってます。 1.6が出たら(もしくは追加情報があれば)また報告させてもらいます。
buibui80

2016/07/05 07:49

情報共有ありがとうございます。 当方からもログ付きの質問をしているので把握されていると思われます。 いや〜、既に対応中とのことでホッとしています。 とりあえず1.6待ちですね。 ちなみにUnity5.3.5p6でImportしたものは1.5でした。 こちらもUnityサポートの回答に追加情報がありましたらコメントします。
buibui80

2016/07/11 05:50

早速1.6を試してみました。 (1) の致命的な問題が改善されていることを確認しました。 ただし、(2) の問題については残ったままになっています。
HiroshiWatanabe

2016/07/11 08:09

私も1.6.0を再importして確認してみました(Unityはまだ5.3.5p6のままでp7にはあげていません)が、アプリの見た目上の動作としては想定通りの結果になっているように見えます。(2)の問題も今の所は(私の試した範囲内では)発生しなくなっているようです。ただ最初の購入時にエラーログが記載されていました。 I/Unity (32577): AndroidJavaException: java.lang.IllegalArgumentException: Receiver not registered: com.unity.purchasing.googleplay.GooglePlayPurchasing$3@3ee4ca99 I/Unity (32577): java.lang.IllegalArgumentException: Receiver not registered: com.unity.purchasing.googleplay.GooglePlayPurchasing$3@3ee4ca99 I/Unity (32577): at android.app.LoadedApk.forgetReceiverDispatcher(LoadedApk.java:766) I/Unity (32577): at android.app.ContextImpl.unregisterReceiver(ContextImpl.java:1665) I/Unity (32577): at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:510) I/Unity (32577): at com.unity.purchasing.googleplay.GooglePlayPurchasing.OnApplicationPause(GooglePlayPurchasing.java:102) I/Unity (32577): at com.unity3d.player.UnityPlayer.nativePause(Native Method) I/Unity (32577): at com.unity3d.player.UnityPlayer.i(Unknown Source) I/Unity (32577): at com.unity3d.player.UnityPlayer$18.run(Unknown Source) I/Unity (32577): at com.unity3d.player.UnityPlayer.executeGLThreadJobs(Unknown Source) I/Unity (32577): at com.unity3d.player.UnityPlayer$b.run(Unknown Source) I/Unity (32577): at UnityEngine.AndroidJNISafe.CheckException () [0x00000] in <filename unknown>:0 I/Unity (32577): at UnityEngine.AndroidJNISafe.CallVo
HiroshiWatanabe

2016/07/11 08:50 編集

ちなみに1.6.0でもValidateを呼び出すと1.5.0と同じクラッシュが発生するので呼び出せない状態は継続中です
buibui80

2016/07/11 08:52

こちらは5.3.5p7で試しています。 エラーメッセージはこちらでも出力されましたが現在は出力されていないです。 継続してエラーが出力されますか? Validateですが、 getReceiptPayloadへ処理を切り分けていますが、 ProcessPurchaseで実行してもダメでしょうか?
buibui80

2016/07/11 10:13

再インストールして確認しましたが ご指摘の通り初回の購入ダイアログの表示時のみエラーメッセージが出力されますね。 キャンセルしたりそのまま購入した後の 2度目以降の購入ダイアログの表示時には出力されない様です。 そのまま購入した場合も問題なく購入されており、 消費型プロダクトの場合は消費処理も行われておりました。 サポートに問い合わせてみます。
HiroshiWatanabe

2016/07/12 00:25

エラーメッセージは起動後最初の購入時にのみ記録されます。 続けて購入する時にそれ以降エラーは記録されません。 アプリの見た目上の動作的にはエラーが出てもそれ以降の購入も 全部正常に動作しているようには見えています。 >Validateですが、 >getReceiptPayloadへ処理を切り分けていますが、 >ProcessPurchaseで実行してもダメでしょうか? getReceiptPayload が ProcessPurchase から呼び出されていますが getReceiptPayload の内容(Validateの呼び出し)をProcessPurchaseの 中に直接展開すると…って話しでしょうか? それにどんな意図があるのか分からないので教えてください。 ちなみにiOS版ではValidateを呼び出してもクラッシュせずGooglePlay限定です。
buibui80

2016/07/12 02:06

> ProcessPurchaseの中に直接展開する その通りです。 IAPデモの内容だとProcessPurchaseの中に記述があり、 私もそれに合わせてValidateが通っているので、 あえて理由をつけるなら成功している状況にソース形態を合わせてみるですね。 以下は間違っていることを前提としますが、 getReceiptPayloadメソッドに切り分けられたことで Validate中にProcessPurchaseが完了してしまい、 Validateで利用される参照がきれてクラッシュしているのではと想像します。 ただ、getReceiptPayloadメソッドが戻り値を返しているので 同期的な動作をしているとは思いますが正直よくわかりません。
HiroshiWatanabe

2016/07/12 03:13

getReceiptPayloadを呼ばずに直接ProcessPurchaseの中でValidateを呼び出してみましたが同じ結果でした
buibui80

2016/07/12 05:18

ちなみにですが、 UnityIAPデモソースのプロダクトをストアに登録している内容に修正して試してもダメでしょうか?
HiroshiWatanabe

2016/07/12 06:22

課金テストだけのアプリにValidateの呼び出しを追加した状態のアプリでは当方の環境でも落ちない事が確認できました。UnityIAP自体ではValidateに問題ないようです。お騒がせしました。他のSDK類との競合で何かがおかしくなっているようです。エラーログにWebViewと書かれていたのでWebViewに何か問題があるのかも?という事でそっち方向を調べてみる事にします。
buibui80

2016/07/12 06:47

UnityIAPの問題ではなかった様で良かったです。 後学のために何のSDKで問題になったか教えてもらえないでしょうか?
HiroshiWatanabe

2016/07/13 01:35

クラッシュログにはWebViewと記載があるのでWebViewだろうという事しかわかっていません。何か進展があれば追加報告させていただきます。
buibui80

2016/07/13 06:11

初回の購入ダイアログ表示時のみエラー出力される件ですが、 サポートでは把握していない問題とのことで サポート指定のサンプルを試した所、確かにエラー出力はされませんでした。 (https://bitbucket.org/Unity-Technologies/unity-iap-samples) 色々試してみた所、 UnityIAPの初期化をAwake()で行うと出力されないことを確認しました。 HiroshiWatanabeさんの場合、 Start()で初期化している所をAwake()に変更すれば エラー出力されなくなるかもしれません。
HiroshiWatanabe

2016/07/13 09:52

おー!ありがとうございます!試してみます!
HiroshiWatanabe

2016/07/14 00:24

Startでの初期化をやめてAwakeで初期化すると購入最初で発生していたエラーログが出なくなりました!ありがとうございます!
HiroshiWatanabe

2016/07/14 05:40

ValidateでNull Exceptionが出る原因がわかりました。 Stripping Level の問題だったようです。 テスト用に用意したプロジェクトではそこが Disable になっていたため動作していましたが、組み込んで使っていたプロジェクトでは Strip Byte Code に設定してあったため、最適化されて消え去ってしまった未使用と誤認した何かを参照してしまっているという状態になっていたようです。link.xmlでSystem.Security.Cryptographyだけ禁止にしてやるという措置を取るとNullエラー出なくなりました。
buibui80

2016/07/14 07:57

情報ありがとうございます。 マニュアルには Stripping Level を Use micro mscorlib にすると Security が除かれると明記されていますが Strip Byte Code でも同様なんですね。 自分は Stripping Level の存在自体知らなかったので参考になりました。 備忘録的にURL貼っときます。 http://docs.unity3d.com/ja/current/Manual/iphone-playerSizeOptimization.html http://docs.unity3d.com/ja/current/Manual/class-PlayerSettingsAndroid.html http://fspace.hatenablog.com/entry/2016/02/23/180816 ちなみに、 ProcessPurchase で Pending を返して購入を保留した状態で 同じプロダクトを再購入すると ProcessPurchase の後でOnPurchaseFailed が呼ばれ 正常処理が行えない症状がありますが、 サポートからはアプリ側でPending管理を行い ユーザーが購入操作できない様にして欲しい旨の回答がありました。 常にCompleteを返す場合関係無いですがサーバー連携を行う際は注意が必要です。
guest

0

Validate() を呼び出すとその中でクラッシュ件ですが、

C#

1#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS 2//#define RECEIPT_VALIDATION 3#endif

これって RECEIPT_VALIDATION は定義されていますか?
UnityIAPのデモスクリプトではコメントアウトされていたのでそのまま利用していましたが、
常に IAPSecurityException になったので、

C#

1#define RECEIPT_VALIDATION

と常に定義する様にしたらValidateが通る様になりました。
最終的に以下の様にしています。

C#

1#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS 2#define RECEIPT_VALIDATION 3#endif

C#は疎いので正しい記述かわかりませんが
RECEIPT_VALIDATION が定義されているか確認してみては如何でしょうか?

投稿2016/06/30 02:51

buibui80

総合スコア1033

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

buibui80

2016/06/30 02:53

ちなみにクラッシュとはアプリが落ちるのではなく、 IAPSecurityException をキャッチするというので良かったでしょうか?
HiroshiWatanabe

2016/06/30 04:03

RECEIPT_VALIDATION を定義した時にクラッシュします。 (RECEIPT_VALIDATIONを定義している時しかValidate()は呼び出されない) 発生する例外はIAPSecurityExceptionではなくNullReferenceExceptionです。
HiroshiWatanabe

2016/06/30 10:03

残念ながら症状は変わりません。 というか何度も繰り返し購入しているとどんどんおかしくなります。 ログを見るとAを購入成功後にAの消費処理をしているようなのですがAを何度か連続購入してBを購入してAを購入するという流れだとAの購入に戻った時の消費処理では何故かAの消費ではなくBの消費処理をしようとする…みたいな混乱が生じてしまうようです。そうなると消費できていないので次にそれを買おうとすると所有しているからと購入できなくなります。
buibui80

2016/06/30 12:48

それはValidate()を行わない場合も同様でしょうか? (Validate()を行わないことで  必ずPurchaseProcessingResult.Completeをreturnして終わらせる) (連続購入処理とValidate()との問題を切り分け) 「ログを見ると購入成功後の消費処理〜」についてですが、 購入成功後とは ProcessPurchase が呼ばれた時点を指していますか? また、ログで分かる消費処理とは独自処理を指していますか? それともUnityIAPプラグインによる処理を指していますか?
HiroshiWatanabe

2016/07/01 00:30

ValidateをするとクラッシュするのでValidateをしないで購入処理を試しています。 消費処理というのは自前では何もしておりません。 UnityIAPが勝手におこなっているらしい…とログから推察しているだけにすぎません。 購入の開始は I/UnityIAP(13116): onPurchaseProduct: (商品のGooglePlay用ID) というログで購入の成功は I/Unity (13116): Purchase OK: (商品のUnity用ID) というログで消費処理は I/UnityIAP(13116): Consuming (商品のGooglePlay用ID) というログの記録で解釈しています。 2つめのログだけはサンプルのUnityIAPDemo.cs内(ProcessPurchase)に出力が指定されていますが最初と最後の2件はそのファイルには見当たらないので内部的にUnityが処理&ログ出力している部分だと思います。
buibui80

2016/07/01 07:09

実購入テストをクローズド アルファ版テストで検証していると思いますが、 その場合のUnityが内部出力するログの確認方法を教えてもらえないでしょうか? 自分用のログはTextコンポーネントに都度貼り付けて確認しているのですが、 内部出力までは確認していなかったので。。
buibui80

2016/07/01 07:26

NullReferenceExceptionの件ですが、 該当するかわかりませんがAnalytics&UnityIAP絡みの問題を Unity5.3.5p5で1つ対応されているみたいです。 Analytics: Fixed a NullReferenceException when stores inform Unity IAP of purchase events without providing metadata for the purchased product. https://unity3d.com/jp/unity/qa/patch-releases
HiroshiWatanabe

2016/07/01 08:57

ありがとうございます!Unityをアップデートしてみます。 ログはAndroid実機をUSBでPC(Windows)に接続して adb.exe logcat > file でファイルに保存したのを見ています。
buibui80

2016/07/01 11:25

すっかりlogcatのことを忘れてました。 AndroidSDK付属のAndroid Device Monitor使えば実購入テスト中もリアルタイムにロギング出来ますね。
guest

0

ベストアンサー

https://developer.android.com/google/play/billing/billing_reference.html

A unique order identifier for the transaction. This identifier corresponds to the Google payments order ID. If the order is a test purchase made through the In-app Billing Sandbox, orderId is blank.

SandBoxだとorderIdは空になるようです。
よってTransactionIdも空になるのではないでしょうか?

投稿2016/06/27 09:14

buibui80

総合スコア1033

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

HiroshiWatanabe

2016/06/27 09:33

回答ありがとうございます。 [Google Play In-App Billing テスト方法] http://devwalker.blogspot.jp/2013/07/google-play-in-app-billing.html このページによると 1.サンドボックス 2.実購入テスト の2つのテスト方法があると書いてありました。 サンドボックスのテストというのは「予めテスト用に予約されたアイテムID」で購入のテストをすると書いてあり今回の実験で私はその android.test.purchased を指定してテストを実施しました。 この時には「orderId も TransactionId も返ってくる」ので期待通りの動作になっています。 ※但し TransactionID か orderId のいずれかもしくは両方は毎回同一の物なので Unity のログを消す作業をしないと既に購入済みのログを出力して2回目以降の購入ができませんでした(ログを消さない場合はアプリをアンインストールすればまた最初の1回だけ購入できます) そして今回一番困惑しているのは上の2の方式「実機による購入テスト」で orderId も TransactionId も得られないという症状です。(テストアカウントを使っているので実際の支払いは発生しませんがサンドボックス用の予約されたIDではなく実際の商品IDを使っていて、支払われないけど購入処理は実際に行うという流れでレシートメールもやってきます)
buibui80

2016/06/27 12:17 編集

リファレンスでは「SandBoxだとorderIdは空」とあり、 HiroshiWatanabeさんの「1.サンドボックス」結果とは異なるので 「2.実購入テスト」がSandBoxなのではと思いますがどうでしょうか? 「テスト用のアクセス権がある Gmail アカウント」を利用せず実際に購入したら orderIdやTransactionIdはどうなのでしょうね。 ちなみに、予約されたアイテムIDを購入した際は購入メールは届くのでしょうか?
HiroshiWatanabe

2016/06/28 00:35

予約されたアイテムID(android.test.purchased)での購入でメールは来ませんでした。 今しているテストアカウントでの実購入テストが実はSandBoxなのでは…?というのは私も一瞬疑ったんですが、テストではない本当のアカウントで購入を試してみるのはちょっと勇気が要りますね…テストで動いてるから最終確認で本番環境でも1度だけ確認してみる、というのとはニュアンスが違うので本番でもダメな可能性が最初からある程度ある状態ではなかなか…(汗) 今しているテストアカウントでの実購入テストの事がSandBoxである事、予約されたアイテムIDでのSandBoxテストは実はリファレンスで言うSandBoxとは別物である事、の明確な情報がどこかにあればいいんですが…私はまだ見つけられていません。 もしどこかに発見された時はぜひおしえて下さいm(._.)m
buibui80

2016/06/28 02:14

1・2共にサンドボックステストでした。 https://developer.android.com/google/play/billing/billing_testing.html 正しくは、 1は「静的応答テスト」で、 2が「実際のアプリ内購入を行うアプリ内課金の実装テスト」になります。 項目「Test Purchases (In-app Billing Sandbox)」に、 The orderId field for test purchases remains blank, ensuring that there are no actual charges to user accounts. とあり、 テスト購入品のorderIdフィールドは空のままとあります。
buibui80

2016/06/28 09:44

ちなみに、 1の「静的応答テスト」で android.test.purchased を購入した時の orderIdは偽の注文IDとの記載がありました。 The response includes a JSON string, which contains fake purchase information (for example, a fake order ID) よって1・2の結果は正常だと判断できるはずです。
HiroshiWatanabe

2016/06/30 00:11

ありがとうございます! orderIdが得られない件については了解致しました。 本番で課金テストできるようになったら改めて確認しようと思います。 他の問題は解決していませんがBAにさせて頂きます。
buibui80

2016/06/30 02:43

orderIdについての追加です。 Note: For test purchases, leave the orderId field blank. You can use the purchaseToken field to identify test purchases. とあり、 テストの際はorderIdのかわりにpurchaseTokenを代用する旨の記述がありました。 Testing In-app Billingをしっかり読み込むとまだ何かあるかもしれませんね。 「ライブラリに追加しました」の件は仕様変更があったみたいです。 http://mtimsno.hatenablog.jp/entry/2016/06/27/213208
HiroshiWatanabe

2016/06/30 04:14

うぉー!なんと!…情報ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問