我的应用在购买应用内购买时有时崩溃。购买应用内购买应用时崩溃
大部分时间它工作正常,但有时应用程序崩溃没有任何错误(我在调试模式下测试)。
要建立的应用程序内购买(非消耗品),我用下面的例子: 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[] 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();
}
}
什么可能导致崩溃?
仅供参考:我正在使用Xamarin iOS版本6.3.4.36(测试版)。现在我使用这个测试版,因为它解决了我在Game Center中遇到的一个问题。 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: 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.
=================================================================
另一次我得到这个错误:
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.
=================================================================
第二次更新
我刚刚发现出现问题的方式。购买和恢复应用程序内购买的按钮以模态视图显示。当我重新打开模式视图并点击购买或恢复按钮时,似乎应用程序崩溃。因此,当我第一次打开模式视图并点击购买和恢复按钮时(大多数情况下)可以正常工作。但是,当我重新打开模式视图,并点击购买或恢复按钮时,该应用程序崩溃,出现上述错误。
有人熟悉这个吗?
感谢您的回复。我试过你说的,但不幸的是问题没有解决。 – StackFlower 2013-05-01 10:18:16
我刚发现问题出现的方式。看到我的第二个更新。 – StackFlower 2013-05-01 10:33:24
好的,太好了。如果您将设备置于Flight Mode并尝试购买,则会发生我的问题。类似的没有细胞服务等 – jonathanpeppers 2013-05-01 11:50:51