iPhone 应用内购买问题

发布于 2024-10-04 00:54:49 字数 7555 浏览 1 评论 0原文

我在应用程序中使用应用程序内购买,但在测试时遇到问题。我有四种消耗品。有关我在 tableview 中显示的产品的信息。有时,当我单击按钮购买某些产品时,我会在 updatedTransaction 函数中得到交易状态 SKPaymentTransactionStateFailed,但 transaction.error localizedFailureReason 始终为 。 一旦我注意到一笔交易被更新了两次(在具有相同 transactionIdentifierupdatedTransaction 函数交易中,交易状态为 SKPaymentTransactionStatePurchased) - 是那么该产品被购买了两次?

所以我不知道问题出在哪里。请帮我。

我使用该类来管理应用程序内购买:

@implementation InAppPurchaseManager

@synthesize upgradeProducts;
@synthesize productsRequest;
@synthesize delegate;

- (id) init
{
   self = [super init];
   if (!self) return nil;

   if ([SKPaymentQueue canMakePayments]) {
      [self loadStore];
      [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
   }

   upgradeProducts = [[NSMutableArray alloc] init];
   delegate = nil;

   return self;
}

+ (InAppPurchaseManager *) sharedInstance
{
   static InAppPurchaseManager *myInstance = nil;

   if (nil == myInstance) {
      myInstance  = [[[self class] alloc] init];
   }

   return myInstance;
}

- (void) loadStore
{
    NSSet *productsIdentifiers = [[NSSet alloc] initWithObjects:PRODUCT_1_ID, PRODUCT_2_ID, PRODUCT_3_ID, PRODUCT_4_ID, nil];
    [self requestUpgradeProductsData:productsIdentifiers];
        [productsIdentifiers release];
}

- (void) requestUpgradeProductsData:(NSSet *) productIdentifiers
{
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}

- (void) productsRequest:(SKProductsRequest *) request didReceiveResponse:(SKProductsResponse *) response
{
    [upgradeProducts removeAllObjects];

    for (int i = 0; i < [response.products count]; i++) {
        SKProduct *product = [response.products objectAtIndex:i];

        UpgradeProduct *upgradeProduct = [[UpgradeProduct alloc] initWithProductID:product.productIdentifier];
        upgradeProduct.title = product.localizedTitle;
        upgradeProduct.description = product.localizedDescription;

        NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
        [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
        [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        [numberFormatter setLocale:product.priceLocale];
        NSString *price = [numberFormatter stringFromNumber:product.price];
        [numberFormatter release];

        upgradeProduct.price = price;

        [self.upgradeProducts addObject:upgradeProduct];

        [upgradeProduct release];
    }

        [productsRequest release];

    if ([self.delegate respondsToSelector:@selector(didLoadStore:)])
        [self.delegate didLoadStore:self.upgradeProducts];
}

+ (BOOL) canMakePurchases
{
    if ([SKPaymentQueue canMakePayments])
        return YES;
    else {
        [Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title") 
                                            message:NSLocalizedString(@"You are not authorized to purchase from AppStore", @"Payment Error Alert Text when user cannot make payments from store")];
        return NO;
    }
}

- (void) purchaseUpgrade:(NSString *) productIdentifier
{
    if ([InAppPurchaseManager canMakePurchases]) {
        SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    }
}

- (void) recordTransaction:(SKPaymentTransaction *) transaction
{
    [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"upgradeTransactionReceipt" ];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void) finishTransaction:(SKPaymentTransaction *) transaction
{
    [self paymentSucceeded:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void) paymentSucceeded:(SKPaymentTransaction *) transaction
{
    // provide content here

    if ([self.delegate respondsToSelector:@selector(didFinishPaymentTransaction)])
        [self.delegate didFinishPaymentTransaction];
}

- (void) completeTransaction:(SKPaymentTransaction *) transaction
{
    [self recordTransaction:transaction];
    [self finishTransaction:transaction];
}

- (void) restoreTransaction:(SKPaymentTransaction *) transaction
{
    [self recordTransaction:transaction.originalTransaction];
    [self finishTransaction:transaction];
}

- (void) failedTransaction:(SKPaymentTransaction *) transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled) {
        NSMutableString *messageToBeShown = [[NSMutableString alloc] init];

        if ([transaction.error localizedFailureReason] != nil) {
            [messageToBeShown setString:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Reason:", @"Reason Text in alert when payment transaction failed"), [transaction.error localizedFailureReason]]];

            if ([transaction.error localizedRecoverySuggestion] != nil)
                [messageToBeShown appendFormat:@", %@ %@", NSLocalizedString(@"You can try:", @"Text for sugesstion in alert when payment transaction failed"), [transaction.error localizedRecoverySuggestion]];
        }

        [Global showAlertViewWithTitle:NSLocalizedString(@"Unable to complete your purchase", @"Payment transaction failed alert title") 
                                            message:messageToBeShown];

        [messageToBeShown release];

        if ([self.delegate respondsToSelector:@selector(didFailedPaymentTransaction)])
            [self.delegate didFailedPaymentTransaction];
    } else {
        if ([self.delegate respondsToSelector:@selector(didCancelPaymentTransaction)])
            [self.delegate didCancelPaymentTransaction];
    }

    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void) paymentQueue:(SKPaymentQueue *) queue updatedTransactions:(NSArray *) transactions
{
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];

                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];

                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];

                break;
            default:
                break;
        }
    }
}

- (void) request:(SKRequest *) request didFailWithError:(NSError *) error
{
    [Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title") 
        message:[NSString stringWithFormat:@"%@, %@", NSLocalizedString(@"Could not contact App Store properly", @"Alert text when request did fail"),
                 [error localizedDescription]]];
}

- (void) dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

    [upgradeProducts release];

    if (productsRequest)
        productsRequest = nil;

    [super dealloc];
}

@end

在函数 didFinishLaunchingWithOptions 中的 AppDelegate 中,我这样做:

[InAppPurchaseManager sharedInstance];

在购买视图中,当我单击我所做的按钮时:

UpgradeProduct *selectedProduct = [self.faxProducts objectAtIndex:[purchaseButton.identifier intValue]];

if (selectedProduct) {
    [[InAppPurchaseManager sharedInstance] purchaseUpgrade:selectedProduct.productID];
}

I use In App Purchase in my application, but I have problem when I'm testing that. I have four consumable products. Information about that products I show in tableview. Sometimes when I click a button to buy some product I get a transaction state SKPaymentTransactionStateFailed in updatedTransaction function but transaction.error localizedFailureReason is always null.
Once I noticed that one transaction was updated two times (in updatedTransaction function transaction with the same transactionIdentifier comes, state of transaction is SKPaymentTransactionStatePurchased) - is then that product two times purchased?.

So I have no idea where is the problem. Please help me.

I use that class to manage In App Purchase:

@implementation InAppPurchaseManager

@synthesize upgradeProducts;
@synthesize productsRequest;
@synthesize delegate;

- (id) init
{
   self = [super init];
   if (!self) return nil;

   if ([SKPaymentQueue canMakePayments]) {
      [self loadStore];
      [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
   }

   upgradeProducts = [[NSMutableArray alloc] init];
   delegate = nil;

   return self;
}

+ (InAppPurchaseManager *) sharedInstance
{
   static InAppPurchaseManager *myInstance = nil;

   if (nil == myInstance) {
      myInstance  = [[[self class] alloc] init];
   }

   return myInstance;
}

- (void) loadStore
{
    NSSet *productsIdentifiers = [[NSSet alloc] initWithObjects:PRODUCT_1_ID, PRODUCT_2_ID, PRODUCT_3_ID, PRODUCT_4_ID, nil];
    [self requestUpgradeProductsData:productsIdentifiers];
        [productsIdentifiers release];
}

- (void) requestUpgradeProductsData:(NSSet *) productIdentifiers
{
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];
}

- (void) productsRequest:(SKProductsRequest *) request didReceiveResponse:(SKProductsResponse *) response
{
    [upgradeProducts removeAllObjects];

    for (int i = 0; i < [response.products count]; i++) {
        SKProduct *product = [response.products objectAtIndex:i];

        UpgradeProduct *upgradeProduct = [[UpgradeProduct alloc] initWithProductID:product.productIdentifier];
        upgradeProduct.title = product.localizedTitle;
        upgradeProduct.description = product.localizedDescription;

        NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
        [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
        [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        [numberFormatter setLocale:product.priceLocale];
        NSString *price = [numberFormatter stringFromNumber:product.price];
        [numberFormatter release];

        upgradeProduct.price = price;

        [self.upgradeProducts addObject:upgradeProduct];

        [upgradeProduct release];
    }

        [productsRequest release];

    if ([self.delegate respondsToSelector:@selector(didLoadStore:)])
        [self.delegate didLoadStore:self.upgradeProducts];
}

+ (BOOL) canMakePurchases
{
    if ([SKPaymentQueue canMakePayments])
        return YES;
    else {
        [Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title") 
                                            message:NSLocalizedString(@"You are not authorized to purchase from AppStore", @"Payment Error Alert Text when user cannot make payments from store")];
        return NO;
    }
}

- (void) purchaseUpgrade:(NSString *) productIdentifier
{
    if ([InAppPurchaseManager canMakePurchases]) {
        SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
        [[SKPaymentQueue defaultQueue] addPayment:payment];
    }
}

- (void) recordTransaction:(SKPaymentTransaction *) transaction
{
    [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"upgradeTransactionReceipt" ];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

- (void) finishTransaction:(SKPaymentTransaction *) transaction
{
    [self paymentSucceeded:transaction];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void) paymentSucceeded:(SKPaymentTransaction *) transaction
{
    // provide content here

    if ([self.delegate respondsToSelector:@selector(didFinishPaymentTransaction)])
        [self.delegate didFinishPaymentTransaction];
}

- (void) completeTransaction:(SKPaymentTransaction *) transaction
{
    [self recordTransaction:transaction];
    [self finishTransaction:transaction];
}

- (void) restoreTransaction:(SKPaymentTransaction *) transaction
{
    [self recordTransaction:transaction.originalTransaction];
    [self finishTransaction:transaction];
}

- (void) failedTransaction:(SKPaymentTransaction *) transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled) {
        NSMutableString *messageToBeShown = [[NSMutableString alloc] init];

        if ([transaction.error localizedFailureReason] != nil) {
            [messageToBeShown setString:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Reason:", @"Reason Text in alert when payment transaction failed"), [transaction.error localizedFailureReason]]];

            if ([transaction.error localizedRecoverySuggestion] != nil)
                [messageToBeShown appendFormat:@", %@ %@", NSLocalizedString(@"You can try:", @"Text for sugesstion in alert when payment transaction failed"), [transaction.error localizedRecoverySuggestion]];
        }

        [Global showAlertViewWithTitle:NSLocalizedString(@"Unable to complete your purchase", @"Payment transaction failed alert title") 
                                            message:messageToBeShown];

        [messageToBeShown release];

        if ([self.delegate respondsToSelector:@selector(didFailedPaymentTransaction)])
            [self.delegate didFailedPaymentTransaction];
    } else {
        if ([self.delegate respondsToSelector:@selector(didCancelPaymentTransaction)])
            [self.delegate didCancelPaymentTransaction];
    }

    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void) paymentQueue:(SKPaymentQueue *) queue updatedTransactions:(NSArray *) transactions
{
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];

                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];

                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];

                break;
            default:
                break;
        }
    }
}

- (void) request:(SKRequest *) request didFailWithError:(NSError *) error
{
    [Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title") 
        message:[NSString stringWithFormat:@"%@, %@", NSLocalizedString(@"Could not contact App Store properly", @"Alert text when request did fail"),
                 [error localizedDescription]]];
}

- (void) dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

    [upgradeProducts release];

    if (productsRequest)
        productsRequest = nil;

    [super dealloc];
}

@end

In AppDelegate in function didFinishLaunchingWithOptions I make that:

[InAppPurchaseManager sharedInstance];

In Purchase View when I click a button I make:

UpgradeProduct *selectedProduct = [self.faxProducts objectAtIndex:[purchaseButton.identifier intValue]];

if (selectedProduct) {
    [[InAppPurchaseManager sharedInstance] purchaseUpgrade:selectedProduct.productID];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

暖阳 2024-10-11 00:54:49
[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; 

此代码是错误的,您不能多次使用。要知道,如果你添加两次观察者,你会发现一笔交易被更新了两次。

[[SKPaymentQueue defaultQueue] addTransactionObserver:self]; 

This code is wrong, you can't use more than once. You know, if you add the observer for twice , you will find one transaction was updated two times.

追星践月 2024-10-11 00:54:49

我有同样的问题,观察者总是有 2 个事务。即使我删除 [[SKPaymentQueue defaultQueue] addPayment: payment],它仍然有 1 笔交易。所以我怀疑“canMakePayments”

在我删除[SKPaymentQueue canMakePayments]后,问题似乎解决了..不知道为什么,但可能会解决你的问题

I have the same problem, observer always has 2 transaction. Even i remove [[SKPaymentQueue defaultQueue] addPayment:payment], it still have 1 transaction. so i suspect the "canMakePayments"

After i remove [SKPaymentQueue canMakePayments], the problem seem to solve.. not sure why but may be it solve yours

梦回旧景 2024-10-11 00:54:49

如果您只是进行测试,只需确保从您的个人帐户注销并在 iTunesConnect 中创建一个新的测试帐户即可。

奇怪的是,如果我不使用测试用户,它就会失败。该 API 充满了黑魔法,几乎没有解释。

If you're just testing, just make sure you sign out from your personal account and create a new test account in iTunesConnect.

Strangely it would fail if I don't use a test user. The API is full of black magic with little explanation.

世态炎凉 2024-10-11 00:54:49

确保您正确使用 AppID。我遇到了同样的问题“用户已取消”,并且我两次都没有使用正确的 ID 调用交易。我自动将 com.mycompany.product" 前缀附加到我的代码中,但在某些情况下,com.mycompany.product 已经附加了。菜鸟 bug...

Make sure you use the AppID correctly. I had the same issue "User cancelled" and I was not calling the transaction with the correct ID both times. I automatically append the com.mycompany.product" prefix to my code, but in some cases, the com.mycompany.product was already appended. Rookie bug...

吐个泡泡 2024-10-11 00:54:49

我收到此错误是因为我的产品标识符错误。

I got this error because I had the wrong product identifier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文