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

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

ただいまの
回答率

90.53%

  • C#

    8774questions

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

  • Unity

    5286questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • Google Play

    85questions

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

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

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 7,877

HiroshiWatanabe

score 1949

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

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

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

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

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

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

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

#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS
//#define RECEIPT_VALIDATION
#endif

using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Purchasing;
#if RECEIPT_VALIDATION
using UnityEngine.Purchasing.Security;
#endif

public class Unity5Purchase : MonoBehaviour, IStoreListener {
    private static IStoreController m_StoreController;
    private static IExtensionProvider m_StoreExtensionProvider;
#if RECEIPT_VALIDATION
    private CrossPlatformValidator validator;
#endif

    // GooglePlayライセンスコード.
    const string API_KEY = "(ないしょ)";

    void Start() {
        if (m_StoreController == null) {
            InitializePurchasing();
        }
    }

    public void InitializePurchasing() {
        if (IsInitialized()) {
            return;// 初期化済み.
        }
        var module = StandardPurchasingModule.Instance();
        var builder = ConfigurationBuilder.Instance(module);
        builder.Configure<IGooglePlayConfiguration>().SetPublicKey(API_KEY);// GooglePlayのライセンスキー登録.
        // (以下のID等は実際に使っている物とは違います今回のための仮記載情報です)
        builder.AddProduct("PRODUCT_ID1", ProductType.Consumable, new IDs {
            { "test01", GooglePlay.Name },
            { "TEST01", AppleApPStore.Name },
            { "Test01", MacAppStore.Name },
        });
        builder.AddProduct("PRODUCT_ID2", ProductType.Consumable, new IDs {
            { "test02", GooglePlay.Name },
            { "TEST02", AppleApPStore.Name },
            { "Test02", MacAppStore.Name },
        });
#if RECEIPT_VALIDATION
        validator = new CrossPlatformValidator(GooglePlayTangle.Data(), AppleTangle.Data(), Application.bundleIdentifier);
#endif
        UnityPurchasing.Initialize(this, builder);
    }

    private bool IsInitialized() {
        return m_StoreController != null && m_StoreExtensionProvider != null;
    }

    // 購入ボタン押下時にここを呼び出す.
    void BuyProductID(string productId) {
        if (IsInitialized()) {
            Product product = m_StoreController.products.WithID(productId);
            if (product != null && product.availableToPurchase) {
                m_StoreController.InitiatePurchase(product);
            }
        }
    }

    public void RestorePurchases() {
    }

    // 
    // --- IStoreListener
    // 

    // 初期化成功時.
    public void OnInitialized(IStoreController controller, IExtensionProvider extensions) {
        m_StoreController = controller;
        m_StoreExtensionProvider = extensions;
    }

    // 初期化失敗.
    public void OnInitializeFailed(InitializationFailureReason error) {
    }

    [Serializable]
    class unityReceipt {
        public string Store;
        public string TransactionID;
        public string Payload;
        public unityReceipt() {
            this.Store = null;
            this.TransactionID = null;
            this.Payload = null;
        }
    }

    [Serializable]
    class googlePlayPayload {
        public string json;
        public string signature;
        public googlePlayPayload() {
            this.json = null;
            this.signature = null;
        }
    }
    [Serializable]
    class googlePayloadJson {
        public string orderId;
        public string packageName;
        public string productId;
        public uint purchaseTime;
        public uint purchaseState;
        public string purchaseToken;
        public googlePayloadJson() {
            this.orderId = null;
            this.packageName = null;
            this.productId = null;
            this.purchaseTime = 0;
            this.purchaseState = 0;
            this.purchaseToken = null;
        }
    }

    private string getReceiptPayload(string strReceipt) {
        unityReceipt u5r = JsonUtility.FromJson<unityReceipt>(strReceipt);
        if (u5r != null) {
            string receipt = null;
            googlePlayPayload gpp = JsonUtility.FromJson<googlePlayPayload>(u5r.Payload);
            if (gpp != null) {
                receipt = gpp.json;
                if (!string.IsNullOrEmpty(receipt)) {
                    googlePayloadJson googleJson = JsonUtility.FromJson<googlePayloadJson>(receipt);
                    if (googleJson != null) {
                        receipt = googleJson.orderId;// ←何故かSandboxでしか存在しない.
                    } else {
                        receipt = null;
                    }
                }
            }
#if RECEIPT_VALIDATION
            if (Application.platform == RuntimePlatform.Android) {
                try {
                    var result = validator.Validate(strReceipt);// ←この中でクラッシュ.
                    foreach (IPurchaseReceipt productReceipt in result) {
                        GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
                        if (null != google) {

                        }
                    }
                } catch (IAPSecurityException) {
                    receipt = null;// 不正なレシートだったので不成立とする.
                }
            }
#endif
            return receipt;// OK
        }
        return null;
    }
    // 購入実行(成功).
    public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args) {
        bool given = false;
        if (String.Equals(args.purchasedProduct.definition.id, "PRODUCT_ID1", StringComparison.Ordinal)) {
            string receipt = getReceiptPayload(args.purchasedProduct.receipt, "test01");
            if (string.IsNullOrEmpty(receipt)) {
                // 不正?想定外?
            } else {
                // (ここで付与)
                given = true;
            }
        } else if (String.Equals(args.purchasedProduct.definition.id, "PRODUCT_ID2", StringComparison.Ordinal)) {
            string receipt = getReceiptPayload(args.purchasedProduct.receipt, "test02");
            if (string.IsNullOrEmpty(receipt)) {
                // 不正?想定外?
            } else {
                // (ここで付与)
                given = true;
            }
        }
        if (!given) {
            // (付与失敗)
        }
        return PurchaseProcessingResult.Complete;
    }

    // 購入失敗.
    public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason) {
        // (付与失敗)
    }
}

あと、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 (以下略)」
のように変わっていました。(メールの内容(本文)は日本語のレシートですが件名だけ英語に変わった状態)

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • buibui80

    2016/06/27 15:25

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

    キャンセル

  • HiroshiWatanabe

    2016/06/27 16:10

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

    キャンセル

  • buibui80

    2016/06/27 16:49

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

    キャンセル

  • HiroshiWatanabe

    2016/06/27 17:37 編集

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

    キャンセル

回答 3

checkベストアンサー

+1

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 18: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を使っていて、支払われないけど購入処理は実際に行うという流れでレシートメールもやってきます)

    キャンセル

  • 2016/06/27 21:16 編集

    リファレンスでは「SandBoxだとorderIdは空」とあり、
    HiroshiWatanabeさんの「1.サンドボックス」結果とは異なるので
    「2.実購入テスト」がSandBoxなのではと思いますがどうでしょうか?

    「テスト用のアクセス権がある Gmail アカウント」を利用せず実際に購入したら
    orderIdやTransactionIdはどうなのでしょうね。

    ちなみに、予約されたアイテムIDを購入した際は購入メールは届くのでしょうか?

    キャンセル

  • 2016/06/28 09:35

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

    キャンセル

  • 2016/06/28 11: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フィールドは空のままとあります。

    キャンセル

  • 2016/06/28 18: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の結果は正常だと判断できるはずです。

    キャンセル

  • 2016/06/30 09:11

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

    キャンセル

  • 2016/06/30 11: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

    キャンセル

  • 2016/06/30 13:14

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

    キャンセル

+1

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

#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS
//#define RECEIPT_VALIDATION
#endif


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

#define RECEIPT_VALIDATION


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

#if UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_OSX || UNITY_TVOS
#define RECEIPT_VALIDATION
#endif

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/06/30 11:53

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

    キャンセル

  • 2016/06/30 13:03

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

    キャンセル

  • 2016/06/30 14:06

    NullReferenceExceptionエラーになったことが無いので分かりませんが、
    ・UnityIAPの再インポート
    ・SetPublicKeyでパブリックキーを設定せず、マニュアルに沿って設定する。
     http://docs.unity3d.com/jp/current/Manual/UnityIAPValidatingReceipts.html
    を試してみてはどうでしょうか?

    キャンセル

  • 2016/06/30 19:03

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

    キャンセル

  • 2016/06/30 21:48

    それはValidate()を行わない場合も同様でしょうか?
    (Validate()を行わないことで
     必ずPurchaseProcessingResult.Completeをreturnして終わらせる)
    (連続購入処理とValidate()との問題を切り分け)

    「ログを見ると購入成功後の消費処理〜」についてですが、
    購入成功後とは ProcessPurchase が呼ばれた時点を指していますか?
    また、ログで分かる消費処理とは独自処理を指していますか?
    それともUnityIAPプラグインによる処理を指していますか?

    キャンセル

  • 2016/07/01 09: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が処理&ログ出力している部分だと思います。

    キャンセル

  • 2016/07/01 16:09

    実購入テストをクローズド アルファ版テストで検証していると思いますが、
    その場合のUnityが内部出力するログの確認方法を教えてもらえないでしょうか?

    自分用のログはTextコンポーネントに都度貼り付けて確認しているのですが、
    内部出力までは確認していなかったので。。

    キャンセル

  • 2016/07/01 16: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

    キャンセル

  • 2016/07/01 17:57

    ありがとうございます!Unityをアップデートしてみます。

    ログはAndroid実機をUSBでPC(Windows)に接続して adb.exe logcat > file でファイルに保存したのを見ています。

    キャンセル

  • 2016/07/01 20:25

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

    キャンセル

+1

ログを見ると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 15:36

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

    キャンセル

  • 2016/07/04 23:00

    色々ログを取ってみたら (1) に誤りがあることに気づきました。
    「購入済み他プロダクトが消費型プロダクト以外の場合も消費処理を実行しており当然ながら失敗している」ですが、成功しているケースがありました。
    非消費型でも消費処理に成功という意味不明な現象です。

    Unityサポートから良い回答が得られるのを期待しております。
    合わせてこちらからも問い合わせをしておきました。

    iOSは簡易なチェックのみ実施しましたが、すぐ気づく様な問題はなかったですね。

    キャンセル

  • 2016/07/05 16:16

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

    キャンセル

  • 2016/07/05 16:49

    情報共有ありがとうございます。
    当方からもログ付きの質問をしているので把握されていると思われます。

    いや〜、既に対応中とのことでホッとしています。
    とりあえず1.6待ちですね。
    ちなみにUnity5.3.5p6でImportしたものは1.5でした。

    こちらもUnityサポートの回答に追加情報がありましたらコメントします。

    キャンセル

  • 2016/07/11 14:50

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

    キャンセル

  • 2016/07/11 17: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

    キャンセル

  • 2016/07/11 17:18 編集

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

    キャンセル

  • 2016/07/11 17:52

    こちらは5.3.5p7で試しています。
    エラーメッセージはこちらでも出力されましたが現在は出力されていないです。
    継続してエラーが出力されますか?

    Validateですが、
    getReceiptPayloadへ処理を切り分けていますが、
    ProcessPurchaseで実行してもダメでしょうか?

    キャンセル

  • 2016/07/11 19:13

    再インストールして確認しましたが
    ご指摘の通り初回の購入ダイアログの表示時のみエラーメッセージが出力されますね。

    キャンセルしたりそのまま購入した後の
    2度目以降の購入ダイアログの表示時には出力されない様です。

    そのまま購入した場合も問題なく購入されており、
    消費型プロダクトの場合は消費処理も行われておりました。

    サポートに問い合わせてみます。

    キャンセル

  • 2016/07/12 09:25

    エラーメッセージは起動後最初の購入時にのみ記録されます。
    続けて購入する時にそれ以降エラーは記録されません。
    アプリの見た目上の動作的にはエラーが出てもそれ以降の購入も
    全部正常に動作しているようには見えています。

    >Validateですが、
    >getReceiptPayloadへ処理を切り分けていますが、
    >ProcessPurchaseで実行してもダメでしょうか?

    getReceiptPayload が ProcessPurchase から呼び出されていますが
    getReceiptPayload の内容(Validateの呼び出し)をProcessPurchaseの
    中に直接展開すると…って話しでしょうか?
    それにどんな意図があるのか分からないので教えてください。
    ちなみにiOS版ではValidateを呼び出してもクラッシュせずGooglePlay限定です。

    キャンセル

  • 2016/07/12 11:06

    > ProcessPurchaseの中に直接展開する
    その通りです。
    IAPデモの内容だとProcessPurchaseの中に記述があり、
    私もそれに合わせてValidateが通っているので、
    あえて理由をつけるなら成功している状況にソース形態を合わせてみるですね。

    以下は間違っていることを前提としますが、
    getReceiptPayloadメソッドに切り分けられたことで
    Validate中にProcessPurchaseが完了してしまい、
    Validateで利用される参照がきれてクラッシュしているのではと想像します。
    ただ、getReceiptPayloadメソッドが戻り値を返しているので
    同期的な動作をしているとは思いますが正直よくわかりません。

    キャンセル

  • 2016/07/12 12:13

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

    キャンセル

  • 2016/07/12 14:18

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

    キャンセル

  • 2016/07/12 15:22

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

    キャンセル

  • 2016/07/12 15:47

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

    キャンセル

  • 2016/07/13 10:35

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

    キャンセル

  • 2016/07/13 15:11

    初回の購入ダイアログ表示時のみエラー出力される件ですが、
    サポートでは把握していない問題とのことで
    サポート指定のサンプルを試した所、確かにエラー出力はされませんでした。
    https://bitbucket.org/Unity-Technologies/unity-iap-samples

    色々試してみた所、
    UnityIAPの初期化をAwake()で行うと出力されないことを確認しました。

    HiroshiWatanabeさんの場合、
    Start()で初期化している所をAwake()に変更すれば
    エラー出力されなくなるかもしれません。

    キャンセル

  • 2016/07/13 18:52

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

    キャンセル

  • 2016/07/14 09:24

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

    キャンセル

  • 2016/07/14 14:40

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

    キャンセル

  • 2016/07/14 16: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を返す場合関係無いですがサーバー連携を行う際は注意が必要です。

    キャンセル

同じタグがついた質問を見る

  • C#

    8774questions

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

  • Unity

    5286questions

    Unityは、ユニティテクノロジーが開発したゲームエンジンです。 主にモバイルやブラウザ向けのゲーム製作に利用されていましたが、3Dの重力付きゲームが簡単に作成できることから需要が増え、現在はマルチプラットフォームに対応しています。 言語はC言語/C++で書かれていますが、C#、JavaScript、Booで書かれたコードにも対応しています。

  • Google Play

    85questions

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

  • トップ
  • C#に関する質問
  • Unity IAP + GooglePlay で消費型アイテム購入時に「ライブラリに追加しました」と表示される