应用程式内购买时应用程式崩溃 [英] App crashing when buying in-app purchase

查看:250
本文介绍了应用程式内购买时应用程式崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



大多数情况下,它工作正常,但有时应用程序崩溃,没有任何错误(我正在测试



要设置应用内购买(非消费品),我使用以下示例:
https://github.com/conceptdev/xamarin-samples/tree/master/InAppPurchase/NonConsumables



处理应用内购买的类如下所示:

  public class InAppPurchaseManager:SKProductsRequestDelegate {
public static NSString InAppPurchaseManagerProductsFetchedNotification = new NSString(InAppPurchaseManagerProductsFetchedNotification);
public static NSString InAppPurchaseManagerTransactionFailedNotification = new NSString(InAppPurchaseManagerTransactionFailedNotification);
public static NSString InAppPurchaseManagerTransactionSucceededNotification = new NSString(InAppPurchaseManagerTransactionSucceededNotification);
public static NSString InAppPurchaseManagerRequestFailedNotification = new NSString(InAppPurchaseManagerRequestFailedNotification);

SKProductsRequest productsRequest;
CustomPaymentObserver theObserver;
SKProduct []产品;

public static NSAction Done {get; set;}

public InAppPurchaseManager()
{
theObserver = new CustomPaymentObserver(this);
SKPaymentQueue.DefaultQueue.AddTransactionObserver(theObserver);
}

//接收对RequestProductData的响应 - 包含价格,标题和描述信息
public override void ReceivedResponse(SKProductsRequest请求,SKProductsResponse响应)
{
products = response.Products;

NSDictionary userInfo = null;
if(products.Length> 0){
NSObject [] productIdsArray = new NSObject [response.Products.Length];
NSObject [] productsArray = new NSObject [response.Products.Length];
for(int i = 0; i< response.Products.Length; i ++){
productIdsArray [i] = new NSString(response.Products [i] .ProductIdentifier);
productsArray [i] = response.Products [i];
}
userInfo = NSDictionary.FromObjectsAndKeys(productsArray,productIdsArray);
}
NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerProductsFetchedNotification,this,userInfo);

foreach(response.InvalidProducts中的string invalidProductId){
Console.WriteLine(Invalid product id:+ invalidProductId);
}
}

//一次请求多个产品
public void RequestProductData(List< string> productIds)
{
var array = new NSString [productIds.Count];
for(var i = 0; i< productIds.Count; i ++){
array [i] = new NSString(productIds [i]);
}
NSSet productIdentifiers = NSSet.MakeNSObjectSet< NSString>(array);

//设置应用内购买的产品请求
productsRequest = new SKProductsRequest(productIdentifiers);
productsRequest.Delegate = this; // SKProductsRequestDelegate.ReceivedResponse
productsRequest.Start();
Console.WriteLine(BEREIKT);
}



//验证iTunes帐户是否可以为此应用程序进行此购买
public bool CanMakePayments()
{
return SKPaymentQueue.CanMakePayments;
}

public void PurchaseProduct(string appStoreProductId)
{
Console.WriteLine(PurchaseProduct+ appStoreProductId);

SKPayment payment = SKPayment.PaymentWithProduct(appStoreProductId);

SKPaymentQueue.DefaultQueue.AddPayment(payment);
}


public void CompleteTransaction(SKPaymentTransaction transaction)
{
Console.WriteLine(CompleteTransaction+ transaction.TransactionIdentifier);
var productId = transaction.Payment.productIdentifier;
//注册购买,所以下次记住它
//PhotoFilterManager.Purchase(productId);
UserDefaults.Purchase(productId);

FinishTransaction(transaction,true);

//显示对话框
new UIAlertView(Succes,De aankoop is gelukt。+
\\\
Je kunt de gekozencategorieënnu spelen。 ,OK,null).Show();
/ *
if(ReceiptValidation.VerificationController.SharedInstance.VerifyPurchase(transaction)){
Console.WriteLine(Verified!
//注册购买,所以下次记住它
PhotoFilterManager.Purchase(productId);
FinishTransaction(transaction,true);
} else {
Console.WriteLine(NOT Verified :();
FinishTransaction(transaction,false);
}
* /
}
public void RestoreTransaction(SKPaymentTransaction transaction)
{
//恢复的事务总是有一个'原始事务'
Console.WriteLine(RestoreTransaction+ transaction.TransactionIdentifier +;原始事务+ transaction.OriginalTransaction.TransactionIdentifier);
var productId = transaction.OriginalTransaction.Payment.ProductIdentifier;
//注册购买,因此下次记住
// PhotoFilterManager。购买(productId); //它就像是再次购买
UserDefaults.Purchase(productId);
FinishTransaction(transaction,true);
}

void FailedTransaction(SKPaymentTransaction transaction)
{
// SKErrorPaymentCancelled == 2
if(transaction.Error.Code == 2)//用户取消
Console.WriteLine CANCELLED FailedTransaction Code =+ transaction.Error.Code ++ transaction.Error.LocalizedDescription);
else //错误!
Console.WriteLine(FailedTransaction Code =+ transaction.Error.Code ++ transaction.Error.LocalizedDescription);

FinishTransaction(transaction,false);

//显示对话框
new UIAlertView(Helaas,De aankoop is mislukt。+
\\\
Probeer het openen tijdstip nogmaals aub,null ,OK,null).Show();
}

public void FinishTransaction(SKPaymentTransaction transaction,bool wasSuccessful)
{
Console.WriteLine(FinishTransaction+ wasSuccessful);
//从支付队列中删除事务。
SKPaymentQueue.DefaultQueue.FinishTransaction(transaction); //这是重要的 - 让苹果知道我们要完成!

using(var pool = new NSAutoreleasePool()){
NSDictionary userInfo = NSDictionary.FromObjectsAndKeys(new NSObject [] {transaction},new NSObject [] {new NSString(transaction) });
if(wasSuccessful){
//发出一个通知我们完成了事务
NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerTransactionSucceededNotification,this,userInfo);
} else {
//发送失败事务的通知
NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerTransactionFailedNotification,this,userInfo);
}
}
}

///< summary>
///可能无法连接到App Store(网络不可用?)
///< / summary>
public override void RequestFailed(SKRequest request,NSError error)
{
Console.WriteLine(** InAppPurchaseManager RequestFailed()+ error.LocalizedDescription);
using(var pool = new NSAutoreleasePool()){
NSDictionary userInfo = NSDictionary.FromObjectsAndKeys(new NSObject [] {error},new NSObject [] {new NSString(error)});
//发送失败事务的通知
NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerRequestFailedNotification,this,userInfo);
}
}

///< summary>
///恢复对此Apple ID发生的任何事务,无论是在
///此设备或使用该帐户登录的任何其他。
///< / summary>
public void Restore()
{
Console.WriteLine(** InAppPurchaseManager Restore());
//将通知Observer恢复的事务何时开始到达< - AppStore
SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions();
}
}

会导致崩溃的原因是什么?



FYI:我使用Xamarin iOS版本6.3.4.36(测试版)。现在我使用这个测试版,因为它解决了我与游戏中心的问题。 Xamarin的稳定版本并没有解决这个问题。



PS。我读了我使用的示例没有实现RECEIPT VERIFICATION。



>有时候我会收到这个错误。

  mono-rt:Stacktrace:


mono -rt:at< unknown> < 0xffffffff>

mono-rt:at(wrapper managed-to-native)MonoTouch.UIKit.UIApplication.UIApplicationMain(int,string [],intptr,intptr)< IL 0x0009f,0xffffffff>

mono-rt:在MonoTouch.UIKit.UIApplication.Main(string [],string,string)[0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs: 38

mono-rt:at PP_IOS.Application.Main(string [])[0x00001] in /Users/Mac01/Projects/PP/PP_IOS/Main.cs:19

mono-rt:at(wrapper runtime-invoke)< Module> .runtime_invoke_void_object(object,intptr,intptr,intptr)< IL 0x00050,0xffffffff>

mono-rt:


本机堆栈跟踪:
mono-rt:
=========== ==================================================== ====
执行本地代码时遇到SIGSEGV。这通常表示
在单一运行时或您的应用程序使用的本机库之一
中的致命错误。
============================================== ===================

时间我得到这个错误:

  mono-rt:Stacktrace:


rt:at< unknown> < 0xffffffff>

mono-rt:at(wrapper managed-to-native)MonoTouch.ObjCRuntime.Messaging.void_objc_msgSend_IntPtr(intptr,intptr,intptr)< IL 0x00025,0xffffffff>

mono-rt:在MonoTouch.StoreKit.SKPaymentQueue.AddPayment(MonoTouch.StoreKit.SKPayment)[0x0001c] in /Developer/MonoTouch/Source/monotouch/src/StoreKit/SKPaymentQueue.g.cs: 107

mono-rt:at PP_IOS.InAppPurchaseManager.PurchaseProduct(string)[0x0001f] in /Users/Mac01/Projects/PP/PP_IOS/Utils/InAppPurchase/InAppPurchaseManager.cs:109

mono-rt:at PP_IOS.UpgradeScreen。< BuyCategoryArtistsAndSports> m__21()[0x0003d] in /Users/Mac01/Projects/PP/PP_IOS/ControllersUniversal/UpgradeScreen.cs:171

mono-rt:在MonoTouch.Foundation.NSAsyncActionDispatcher.Apply()[0x00000]在/Developer/MonoTouch/Source/monotouch/src/shared/Foundation/NSAction.cs:87

mono-rt: at(wrapper runtime-invoke)object.runtime_invoke_void__this__(object,intptr,intptr,intptr)< IL 0x0004e,0xffffffff>

mono-rt:at< unknown> < 0xffffffff>

mono-rt:at(wrapper managed-to-native)MonoTouch.UIKit.UIApplication.UIApplicationMain(int,string [],intptr,intptr)< IL 0x0009f,0xffffffff>

mono-rt:在MonoTouch.UIKit.UIApplication.Main(string [],string,string)[0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs: 38

mono-rt:at PP_IOS.Application.Main(string [])[0x00001] in /Users/Mac01/Projects/PP/PP_IOS/Main.cs:19

mono-rt:at(wrapper runtime-invoke)< Module> .runtime_invoke_void_object(object,intptr,intptr,intptr)< IL 0x00050,0xffffffff>

mono-rt:
本机栈跟踪:


mono-rt:
=========== ==================================================== ====
执行本地代码时遇到SIGSEGV。这通常表示
在单一运行时或您的应用程序使用的本机库之一
中的致命错误。
============================================== ===================

第二次更新



我刚刚找到问题的发生方式。用于购买和恢复应用内购买的按钮以模态视图显示。似乎应用程序崩溃时,我重新打开模态视图,点击购买或恢复按钮。所以当我第一次打开模态视图,我点击购买和恢复按钮(大部分时间)工作正常。但是当我重新打开模态视图,我点击购买或恢复按钮,应用崩溃与上面的错误显示。



有人熟悉这个? >

解决方案

问题解决了!



我在关闭视图时删除了TransactionObserver 。

  public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear

//重新打开视图时防止崩溃
SKPaymentQueue.DefaultQueue.RemoveTransactionObserver(theObserver);
}


My app crashes sometimes when buying something with in-app purchase.

Most of the time it works fine but sometimes the app crashes without any error (I am testing in debug mode).

To set-up the in-app purchase (non-consumable), I used the following example: https://github.com/conceptdev/xamarin-samples/tree/master/InAppPurchase/NonConsumables

The class which handles the in-app purchase looks like this:

public class InAppPurchaseManager : SKProductsRequestDelegate {
    public static NSString InAppPurchaseManagerProductsFetchedNotification = new NSString("InAppPurchaseManagerProductsFetchedNotification");
    public static NSString InAppPurchaseManagerTransactionFailedNotification = new NSString("InAppPurchaseManagerTransactionFailedNotification");
    public static NSString InAppPurchaseManagerTransactionSucceededNotification = new NSString("InAppPurchaseManagerTransactionSucceededNotification");
    public static NSString InAppPurchaseManagerRequestFailedNotification = new NSString("InAppPurchaseManagerRequestFailedNotification");

    SKProductsRequest productsRequest;
    CustomPaymentObserver theObserver;
    SKProduct[] products;

    public static NSAction Done {get;set;}

    public InAppPurchaseManager ()
    {
        theObserver = new CustomPaymentObserver(this);
        SKPaymentQueue.DefaultQueue.AddTransactionObserver(theObserver);
    }

    // received response to RequestProductData - with price,title,description info
    public override void ReceivedResponse (SKProductsRequest request, SKProductsResponse response)
    {
        products = response.Products;

        NSDictionary userInfo = null;
        if (products.Length > 0) {
            NSObject[] productIdsArray = new NSObject[response.Products.Length];
            NSObject[] productsArray = new NSObject[response.Products.Length];
            for (int i = 0; i < response.Products.Length; i++) {
                productIdsArray[i] = new NSString(response.Products[i].ProductIdentifier);
                productsArray[i] = response.Products[i];
            }
            userInfo = NSDictionary.FromObjectsAndKeys (productsArray, productIdsArray);
        }
        NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerProductsFetchedNotification,this,userInfo);

        foreach (string invalidProductId in response.InvalidProducts) {
            Console.WriteLine("Invalid product id: " + invalidProductId );
        }
    }

    // request multiple products at once
    public void RequestProductData (List<string> productIds)
    {
        var array = new NSString[productIds.Count];
        for (var i = 0; i < productIds.Count; i++) {
            array[i] = new NSString(productIds[i]);
        }
        NSSet productIdentifiers = NSSet.MakeNSObjectSet<NSString>(array);          

        //set up product request for in-app purchase
        productsRequest  = new SKProductsRequest(productIdentifiers);
        productsRequest.Delegate = this; // SKProductsRequestDelegate.ReceivedResponse
        productsRequest.Start();
        Console.WriteLine ("BEREIKT");
    }



    // Verify that the iTunes account can make this purchase for this application
    public bool CanMakePayments()
    {
        return SKPaymentQueue.CanMakePayments;  
    }

    public void PurchaseProduct(string appStoreProductId)
    {
        Console.WriteLine("PurchaseProduct " + appStoreProductId);

        SKPayment payment = SKPayment.PaymentWithProduct (appStoreProductId);   

        SKPaymentQueue.DefaultQueue.AddPayment (payment);
    }


    public void CompleteTransaction (SKPaymentTransaction transaction)
    {
        Console.WriteLine ("CompleteTransaction " + transaction.TransactionIdentifier);
        var productId = transaction.Payment.ProductIdentifier;
        // Register the purchase, so it is remembered for next time
        //PhotoFilterManager.Purchase(productId);
        UserDefaults.Purchase(productId);

        FinishTransaction (transaction, true);

        //Show Dialog
        new UIAlertView("Succes", "De aankoop is gelukt." +
                        "\n Je kunt de gekozen categorieën nu spelen.", null, "OK", null).Show();
    /*
        if (ReceiptValidation.VerificationController.SharedInstance.VerifyPurchase (transaction)) {
            Console.WriteLine ("Verified!");
            // Register the purchase, so it is remembered for next time
            PhotoFilterManager.Purchase(productId);
            FinishTransaction (transaction, true);
        } else {
            Console.WriteLine ("NOT Verified :(");
            FinishTransaction (transaction, false);
        }
            */
    }
    public void RestoreTransaction (SKPaymentTransaction transaction)
    {
        // Restored Transactions always have an 'original transaction' attached
        Console.WriteLine("RestoreTransaction " + transaction.TransactionIdentifier + "; OriginalTransaction " + transaction.OriginalTransaction.TransactionIdentifier);
        var productId = transaction.OriginalTransaction.Payment.ProductIdentifier;
        // Register the purchase, so it is remembered for next time
        //PhotoFilterManager.Purchase(productId); // it's as though it was purchased again
        UserDefaults.Purchase(productId);
        FinishTransaction(transaction, true);
    }

    public void FailedTransaction (SKPaymentTransaction transaction)
    {
        //SKErrorPaymentCancelled == 2
        if (transaction.Error.Code == 2) // user cancelled
            Console.WriteLine("User CANCELLED FailedTransaction Code=" + transaction.Error.Code + " " + transaction.Error.LocalizedDescription);
        else // error!
            Console.WriteLine("FailedTransaction Code=" + transaction.Error.Code + " " + transaction.Error.LocalizedDescription);

        FinishTransaction(transaction,false);

        //Show Dialog
        new UIAlertView("Helaas", "De aankoop is mislukt." +
                        "\n Probeer het op een later tijdstip nogmaals a.u.b.", null, "OK", null).Show();
    }

    public void FinishTransaction(SKPaymentTransaction transaction, bool wasSuccessful)
    {
        Console.WriteLine("FinishTransaction " + wasSuccessful);
        // remove the transaction from the payment queue.
        SKPaymentQueue.DefaultQueue.FinishTransaction(transaction);     // THIS IS IMPORTANT - LET'S APPLE KNOW WE'RE DONE !!!!

        using (var pool = new NSAutoreleasePool()) {
            NSDictionary userInfo = NSDictionary.FromObjectsAndKeys(new NSObject[] {transaction},new NSObject[] {new NSString("transaction")});
            if (wasSuccessful) {
                // send out a notification that we’ve finished the transaction
                NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerTransactionSucceededNotification,this,userInfo);
            } else {
                // send out a notification for the failed transaction
                NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerTransactionFailedNotification,this,userInfo);
            }
        }
    }

    /// <summary>
    /// Probably could not connect to the App Store (network unavailable?)
    /// </summary>
    public override void RequestFailed (SKRequest request, NSError error)
    {
        Console.WriteLine (" ** InAppPurchaseManager RequestFailed() " + error.LocalizedDescription);
        using (var pool = new NSAutoreleasePool()) {
            NSDictionary userInfo = NSDictionary.FromObjectsAndKeys(new NSObject[] {error},new NSObject[] {new NSString("error")});
            // send out a notification for the failed transaction
            NSNotificationCenter.DefaultCenter.PostNotificationName(InAppPurchaseManagerRequestFailedNotification,this,userInfo);
        }
    }

    /// <summary>
    /// Restore any transactions that occurred for this Apple ID, either on 
    /// this device or any other logged in with that account.
    /// </summary>
    public void Restore()
    {
        Console.WriteLine (" ** InAppPurchaseManager Restore()");
        // theObserver will be notified of when the restored transactions start arriving <- AppStore
        SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions();         
    }
}

What could cause the crash?

FYI: I am using Xamarin iOS version 6.3.4.36 (beta). For now I use this beta version because it solves a problem I have with Game Center. The stable version of Xamarin does not solve this yet.

PS. I read that the example I used not implemented RECEIPT VERIFICATION. What does this mean and is this necessary to implement?

FIRST UPDATE:

Sometimes I get this error.

    mono-rt: Stacktrace:


    mono-rt:   at <unknown> <0xffffffff>

    mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x0009f, 0xffffffff>

    mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38

    mono-rt:   at PP_IOS.Application.Main (string[]) [0x00001] in /Users/Mac01/Projects/PP/PP_IOS/Main.cs:19

    mono-rt:   at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00050, 0xffffffff>

    mono-rt: 


    Native stacktrace:
    mono-rt: 
    =================================================================
    Got a SIGSEGV while executing native code. This usually indicates
    a fatal error in the mono runtime or one of the native libraries 
    used by your application.
    =================================================================

And another time I get this error:

    mono-rt: Stacktrace:


    mono-rt:   at <unknown> <0xffffffff>

    mono-rt:   at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging.void_objc_msgSend_IntPtr (intptr,intptr,intptr) <IL 0x00025, 0xffffffff>

    mono-rt:   at MonoTouch.StoreKit.SKPaymentQueue.AddPayment (MonoTouch.StoreKit.SKPayment) [0x0001c] in /Developer/MonoTouch/Source/monotouch/src/StoreKit/SKPaymentQueue.g.cs:107

    mono-rt:   at PP_IOS.InAppPurchaseManager.PurchaseProduct (string) [0x0001f] in /Users/Mac01/Projects/PP/PP_IOS/Utils/InAppPurchase/InAppPurchaseManager.cs:109

    mono-rt:   at PP_IOS.UpgradeScreen.<BuyCategoryArtistsAndSports>m__21 () [0x0003d] in /Users/Mac01/Projects/PP/PP_IOS/ControllersUniversal/UpgradeScreen.cs:171

    mono-rt:   at MonoTouch.Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Developer/MonoTouch/Source/monotouch/src/shared/Foundation/NSAction.cs:87

    mono-rt:   at (wrapper runtime-invoke) object.runtime_invoke_void__this__ (object,intptr,intptr,intptr) <IL 0x0004e, 0xffffffff>

    mono-rt:   at <unknown> <0xffffffff>

    mono-rt:   at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication.UIApplicationMain (int,string[],intptr,intptr) <IL 0x0009f, 0xffffffff>

    mono-rt:   at MonoTouch.UIKit.UIApplication.Main (string[],string,string) [0x0004c] in /Developer/MonoTouch/Source/monotouch/src/UIKit/UIApplication.cs:38

    mono-rt:   at PP_IOS.Application.Main (string[]) [0x00001] in /Users/Mac01/Projects/PP/PP_IOS/Main.cs:19

    mono-rt:   at (wrapper runtime-invoke) <Module>.runtime_invoke_void_object (object,intptr,intptr,intptr) <IL 0x00050, 0xffffffff>

    mono-rt: 
    Native stacktrace:


    mono-rt: 
    =================================================================
    Got a SIGSEGV while executing native code. This usually indicates
    a fatal error in the mono runtime or one of the native libraries 
    used by your application.
    =================================================================

SECOND UPDATE

I just found the way the problem occurs. The buttons to buy and restore an in-app purchase are displayed in a modal view. It seems that the app crashes when I reopen the modal view and tap at the buy or restore button. So when I open the modal view for the first time and I tap at the buy and restore buttons it (most of the time) works fine. But when I reopen the modal view, and I tap at the buy or restore button, the app crashes with the error showed above.

Somebody familiar with this?

解决方案

Problem solved!

I had to remove the TransactionObserver when closing the view.

    public override void ViewWillDisappear (bool animated)
    {
        base.ViewWillDisappear (animated);

        //Prevents crash when re-opening view
        SKPaymentQueue.DefaultQueue.RemoveTransactionObserver (theObserver);
    }

这篇关于应用程式内购买时应用程式崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆