Xamarin.InAppBilling - "Error available inventory: System.NullReferenceException"



注意:我主要是在这里发布这个问题,这样它就可以在谷歌上进行索引,让一些可怜的人省去了深入挖掘这个烂摊子却发现这不是他们自己的错的麻烦。这个问题的一个可接受的答案是我可以使用的变通方法,或者Xamarin/SimpleJson的某个人确认这是一个错误,它会被修复。

我已经成功使用Xamarin.InAppBilling一年多了(在真正的Google Play商店购买效果良好)。我们最近开始重新测试此功能(由于重构),并且在查询产品库存时(甚至在使用静态响应测试produkt Skus时)遇到此异常:

Error Available Inventory: System.NullReferenceException: Object reference not set to an instance of an object
  at Xamarin.InAppBilling.PocoJsonSerializerStrategy.DeserializeObject (System.Object value, System.Type type) [0x0047a] in <filename unknown>:0 
  at Xamarin.InAppBilling.SimpleJson.DeserializeObject (System.String json, System.Type type, IJsonSerializerStrategy jsonSerializerStrategy) [0x0003d] in <filename unknown>:0 
  at Xamarin.InAppBilling.SimpleJson.DeserializeObject[T] (System.String json) [0x00000] in <filename unknown>:0 
  at System.Linq.Enumerable+WhereSelectEnumerableIterator`2[TSource,TResult].MoveNext () [0x00064] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/external/referencesource/System.Core/System/Linq/Enumerable.cs:285 
  at System.Collections.Generic.List`1[T]..ctor (IEnumerable`1 collection) [0x0008b] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/external/referencesource/mscorlib/system/collections/generic/list.cs:105 
  at System.Linq.Enumerable.ToList[TSource] (IEnumerable`1 source) [0x00011] in /Users/builder/data/lanes/2098/3efa14c4/source/mono/external/referencesource/System.Core/System/Linq/Enumerable.cs:835 
  at Xamarin.InAppBilling.InAppBillingHandler+<QueryInventoryAsync>c__AnonStorey0.<>m__0 () [0x00092] in <filename unknown>:0 

我已经颠倒了Xamarin的应用内计费代码,尤其是Xamarin.InAppBilling.InAppBillingHandler.QueryInventoryAsync(IList<string> skuList, string itemType)方法。

它所做的是查询Google Play Billing API中的sku详细信息,然后反序列化返回的DETAILS_LIST json对象。这就是代码抛出NullReferenceException的地方。所有这些都超出了我的控制范围,所以我使用了这段代码的修改副本来获得原始json,毫无疑问,它对我来说非常好。代码:

var service = _serviceConnection.Service;
Task.Factory.StartNew<IList<Product>>( () => {
    IList<Product> result;
    try
    {
        Bundle bundle = new Bundle();
        bundle.PutStringArrayList( "ITEM_ID_LIST", skus );
        Bundle skuDetails = service.GetSkuDetails( 3, this.Activity.PackageName, ItemType.Product, bundle );
        int responseCode = skuDetails.GetInt( "RESPONSE_CODE" );
        if (responseCode != 0)
        {
            ViewModel.ShowTransactionError( "Error querying inventory: " + TranslateResponseCode( responseCode ) );
            result = null;
        }
        else
        {
            IList<string> stringArrayList = skuDetails.GetStringArrayList( "DETAILS_LIST" );
            result = null;
            if (stringArrayList != null)
            {
                Console.WriteLine("DETAILS_LIST: " + string.Join("n - ", stringArrayList));
                result = stringArrayList.Select(x => JsonConvert.DeserializeObject<Product>(x)).ToList();
            }                        
        }
    } catch (Exception ex)
    {
        ViewModel.ShowTransactionError( "Error querying inventory: " + ex.ToString() );
        result = null;
    }
    return result;
} )

Json:

DETAILS_LIST: {"title":"Sample Title","price":"0,93 €","type":"inapp","description":"Sample description for product: android.test.canceled.","price_amount_micros":933038,"price_currency_code":"EUR","productId":"android.test.canceled"}
 - {"title":"Sample Title","price":"0,93 €","type":"inapp","description":"Sample description for product: android.test.item_unavailable.","price_amount_micros":933038,"price_currency_code":"EUR","productId":"android.test.item_unavailable"}
 - {"title":"Sample Title","price":"0,93 €","type":"inapp","description":"Sample description for product: android.test.purchased.","price_amount_micros":933038,"price_currency_code":"EUR","productId":"android.test.purchased"}
 - {"title":"Sample Title","price":"0,93 €","type":"inapp","description":"Sample description for product: android.test.refunded.","price_amount_micros":933038,"price_currency_code":"EUR","productId":"android.test.refunded"}
 - {"title":"Boat Upgrade (Rowing in Motion - Solo)","price":"69,90 €","type":"inapp","description":"Analyze and Record an unlimited number of strokes per rowing session.","price_amount_micros":69900000,"price_currency_code":"EUR","productId":"com.rowinginmotion.mobile.boatapp.droid.solo.boat"}
 - {"title":"Coach Upgrade (Rowing in Motion - Solo)","price":"98,77 €","type":"inapp","description":"Receive unlimited live data from a boat using a mobile WiFi.","price_amount_micros":98770000,"price_currency_code":"EUR","productId":"com.rowinginmotion.mobile.boatapp.droid.solo.coach"}

所以我认为SimpleJson/PocoJson(不管他们有什么序列化程序)出了问题。对我来说,这看起来像是图书馆里的一个bug,而不是我这边的一个错误(仔细查看了他们的清单和这里的一切)。

我使用JSON.NET的问题是,他们的Product类显然没有默认构造函数(什么?!,我在IL工作了很多年,从来没有看到过这样的东西),但上面有一个CompilerGeneratedAttribute。不过,我的产品需要是该类的实例,这样我才能将它们传递回他们的API。。。

链接器再次命中。PocoJsonSerializerStrategy使用了大量的反思,所以这是我的第二个猜测,在完成了IAP工作所需的一长串事情之后。

把这个添加到你的.csproj中,你就可以开始了。

<AndroidLinkSkip>Xamarin.InAppBilling</AndroidLinkSkip>

这是一个真正的失望Xamarin没有使自己的图书馆链接器证明。。。

这个问题很容易让我花了一两天的时间,特别是因为应用内计费有很多微妙的方式可以中断,你应该先检查一下(特别是,我们将大部分IAP逻辑从活动转移到片段,所以这也必须进行测试)。

旁注:我徒劳地等待了3x2h,等待Google Play Alpha频道更新我的测试设备。对于me,我可以使用从Xamarin Studio部署的构建(甚至是调试构建)成功测试和运行IAP。这并不意味着这对你也有效。

相关内容

最新更新