0

そのため、アプリケーション内でアプリ購入を設定しようとしていて、解決方法がわからない問題に遭遇しました。私は xamarin を使用しており、消耗品の購入方法に関するアプリ内購入ガイドに従いました。

アップルからトランザクションの領収書を返してもらうまで、すべてが順調に進んでいました。SKPaymentTransaction オブジェクト (プロジェクト内の任意の場所) からこのプロパティにアクセスするたびに、一部の人によるとメモリ リークであるこのエラーが発生します。これは、このプロパティ (SKPaymentTransaction.TransactionReceipt) にアクセスするたびに発生します。

エラー:

*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

私のコードは、以前に説明したガイドにあるものとよく似ています。まず最初に、製品情報を取得するために Apple にリクエストを送信するアプリ内購入マネージャーを作成し (これはうまく機能します)、トランザクションが成功または失敗するたびに UI を更新します。

public class InAppPurchaseManager : SKProductsRequestDelegate
{
    IMobileServiceTable receiptTable = AppDelegate.MobileService.GetTable("Receipt");

    public InAppPurchaseManager ()
    {
        SKPaymentQueue.DefaultQueue.AddTransactionObserver (new TransactionObserver(this));
    }

    public void RequestProductData (List<NSString> productIds)
    {
        var array = new NSString[productIds.Count];
        for (var i = 0; i < productIds.Count; i++) {
            array[i] = productIds[i];
        }
        NSSet productIdentifiers = NSSet.MakeNSObjectSet<NSString>(array);
        var productsRequest = new SKProductsRequest(productIdentifiers);
        productsRequest.Delegate = this; // for SKProductsRequestDelegate.ReceivedResponse
        productsRequest.Start();
    }

    public override void ReceivedResponse (SKProductsRequest request, SKProductsResponse response)
    {
        SKProduct[] 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);
    }

    public override void RequestFailed (SKRequest request, NSError error)
    {
        Console.WriteLine (" ** InAppPurchaseManager RequestFailed() " + error.LocalizedDescription);
    }

    public void PuchaseProduct (SKProduct product)
    {
            SKPayment payment = SKPayment.PaymentWithProduct (product);
            SKPaymentQueue.DefaultQueue.AddPayment (payment);
    }

    public void CompleteTransaction (SKPaymentTransaction transaction)
    {
        var productId = transaction.Payment.ProductIdentifier;
        // Register the purchase, so it is remembered for next time
        FinishTransaction(transaction, true);
    }

    public void FinishTransaction(SKPaymentTransaction transaction, bool wasSuccessful)
    {
        // remove the transaction from the payment queue.
        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 (new NSString("InAppPurchaseManagerTransactionSuccedeedNotification"), this, userInfo);
            } else {
                // send out a notification for the failed transaction
                NSNotificationCenter.DefaultCenter.PostNotificationName (new NSString("InAppPurchaseManagerTransacionFailedNotification"), this, userInfo);
            }
        }
    }

    public void FailedTransaction (SKPaymentTransaction transaction)
    {
        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);
    }
}}

メソッド FinishTransaction で、トランザクションが成功した場合、返された領収書をサーバーに挿入したいと思います (挿入する前に、もちろん Apple サーバーに対して確認します)。この時点で、SKPaymentTransaction.TransactionReceipt にアクセスし、このレシートを base64 にエンコードして、サーバーに送信する必要があります。これは機能しません。その理由はわかりません。

私のトランザクションオブザーバー:

public class TransactionObserver : SKPaymentTransactionObserver
{
    private InAppPurchaseManager iap;

    public TransactionObserver (InAppPurchaseManager manager) : base()
    {
        iap = manager;
    }

    public override void UpdatedTransactions (SKPaymentQueue queue, SKPaymentTransaction[] transactions)
    {
        foreach (SKPaymentTransaction transaction in transactions)
        {
            switch (transaction.TransactionState)
            {
            case SKPaymentTransactionState.Purchased:
                iap.CompleteTransaction (transaction);
                break;
                case SKPaymentTransactionState.Failed:
                iap.FailedTransaction(transaction);
                break;
                default:
                break;
            }
        }

    }
}

したがって、私が提供できるもう 1 つの情報は、プロジェクトがコンパイルされ、アプリをデバイスにデプロイしようとするとクラッシュするということです。

また、私はすでに async と await を使用しているため、xamarin ベータ チャネルを使用しています。

ですから、何か間違っていることがあれば教えてください。

アップデート

プロジェクトをクリーンアップするたびに、それが機能し、そのエラーが発生しなくなります!!! なぜこれがこのように動作するのかわかりません!

4

1 に答える 1

2

これは既知のバグです。

バグ レポートにも回避策があります。プロジェクトの iOS ビルド オプション ページで、追加の mtouch 引数に「-f」を追加します。

于 2013-05-20T10:03:13.213 に答える