1

在我以前的应用程序中,只有一个 IAP,所以我没有意识到我的代码有问题。今天我有一个包含多个 IAP 产品的应用程序,我发现了问题。

我遵循了Troy 的 IAP 教程,并且几乎复制了他的代码。这对我以前的应用程序很有效,因为每个应用程序中只有一个 IAP 产品。本教程也使用一个 IAP 产品作为示例。我试图在他的博客上发帖问我的问题,但是我的帖子太长而且没有格式,而且我认为这里的专家可以帮助我了解更多,并检查我是否误解了某些内容或遗漏了某些内容。

现在有两件事我必须处理(除非我错过了,本教程没有提到多个 IAP 产品的案例)。

1、不知道是不是我理解错了,教程里有一个loadStore方法的注释,像这样

//
// call this method once on startup
//
- (void)loadStore {
    // restarts any purchases if they were interrupted last time the app was open
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    // get the product description (defined in early sections)
    [self requestProUpgradeProductData];
}

所以我在我的应用程序开头的 ViewController.m 文件中调用了这个方法。我的理解是,此方法需要检查是否有任何先前的交易挂在那里,并且需要在应用程序重新启动时处理它。这是这个 loadStore 方法的第一条语句。该方法继续调用 requestProUpgradeProductData,如下所示:

- (void)requestProUpgradeProductData {
   NSSet *productIdentifiers = [NSSet setWithObject:@"com.runmonster.runmonsterfree.upgradetopro" ];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

    // we will release the request object in the delegate callback
}

注意这里,该方法中的第一条语句是获取 IAP 产品 ID。这对于单 IAP 产品应用程序来说一切都很好,因为产品 ID 是固定的,并且可以在应用程序开始运行时调用 loadStore。实际上, loadStore 可能必须在运行应用程序的开始时运行,因为这是第二个问题。

2、如果 loadStore 在用户想要购买 IAP 的时候运行,而不是在应用程序开始时运行,那么问题是当 [productRequest start] 运行时,会运行以下方法:

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *products = response.products;
    proUpgradeProduct = [products count] == 1 ? [[products firstObject] retain] : nil;
    if (proUpgradeProduct)
    {
    NSLog(@"Product title: %@" , proUpgradeProduct.localizedTitle);
    NSLog(@"Product description: %@" , proUpgradeProduct.localizedDescription);
    NSLog(@"Product price: %@" , proUpgradeProduct.price);
    NSLog(@"Product id: %@" , proUpgradeProduct.productIdentifier);
    }

    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    {
    NSLog(@"Invalid product id: %@" , invalidProductId);
    }

   // finally release the reqest we alloc/init’ed in requestProUpgradeProductData
   [productsRequest release]; //I didn't do this because of ARC

    [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
}

这将运行并返回产品响应。然后我需要开始付款,但我不确定 HRER 应该如何调用以下方法。这是启动 IAP 付款的方法。正如我所提到的,一旦 loadStore 在应用程序的开头运行,productRequest..response 方法(右上方)有“充足”的时间来完成并发送回通知,因为用户点击这里和那里一秒钟。正如我所说,对于单一 IAP 产品应用程序,这很好,我可以在开头指定产品 ID。现在对于具有多个 IAP 产品的应用程序,我需要向用户展示多个产品,并且用户选择其中一个。在此之后,我需要按顺序做两件事:A,通过 loadStore -> productRequest 方法(右上方)指定哪个 IAP 产品,以及 B,调用以下方法来发起付款。

- (void)purchaseProUpgrade
{
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppPurchaseProUpgradeProductId];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

但是,在我调用付款发起方法时,productRequest.....response 方法可能还没有返回。我将无法开始付款。我想在大约一秒钟之间放置一个延迟功能,但我认为这种方法从根本上是错误的。然而,如何解决问题?

有人可以在这里帮忙吗?

4

1 回答 1

1

关键是您不能允许用户购买任何东西,直到您从productsRequest. 首先,initWithProductIdentifiers:采用一组标识符。因此,在应用程序启动时或在向用户提供购买选项之前的任何其他时间,您可以使用您可能允许用户购买的所有产品的标识符/skus 调用它。在启动时调用它对我来说似乎很浪费,但它也应该可以工作,并且可能是某些应用程序的唯一选择。

只有在您获得productsRequest:didReceiveResponse:包含产品对象的回调后,您才允许用户单击/触摸或以其他方式调用该产品的购买操作。在允许用户尝试购买之前,您必须检查响应以确保产品存在。我有一个购买屏幕,当用户进入它时,我会调用productsRequest与应用程序当前状态相关的所有产品(例如,忽略已购买的项目或按级别限制产品)。我还创建了购买屏幕,但我没有使用任何产品填充它。在响应委托中,我实际上用可购买的对象填充了屏幕。这样,用户就不能尝试购买无效产品。

当用户点击/点击时,您使用响应中的产品对象来创建支付对象:

[SKPayment paymentWithProduct:product]

请注意,这是对您当前使用的设置的更改paymentWithProductIdentifier:- 不推荐使用的方法。

于 2013-02-14T17:39:27.217 回答