【问题标题】:RMStore Receipt Verification Failure FlowRMStore 收据验证失败流程
【发布时间】:2014-08-25 19:46:50
【问题描述】:

我正在使用 RMStore 来验证收据。请注意,我没有将 RMStore 用于实际购买部分。如果收据无效,则该过程成功地处理了抛出错误和不交付内容方面的成功和失败。我故意更改捆绑包以强制失败作为测试。不过,我的问题是失败过程和 Apple 发送的确认信息。

问题在于,虽然此过程确实检测到验证失败,因此确实阻止了将内容发送给用户,但 Apple 之后仍会返回一个关于购买成功的对话框。好消息是购买不成功且内容未交付,但我希望 Apple 的这个对话框不要显示,因为它会造成混乱。

这是我的检查实现。现在我只是在测试失败场景之前在失败块中做更多的事情。

- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"completeTransaction...");

    RMStoreAppReceiptVerificator *verifyReceipt = [[RMStoreAppReceiptVerificator alloc]init];

    [verifyReceipt verifyTransaction:transaction success:^{
        [self provideContentForProductIdentifier:transaction.payment.productIdentifier];
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }failure:^(NSError *error){
        NSLog(@"failure to verify: %@",error.description);
    }];
}

是否有办法在失败块中停止 Apple 创建成功对话框的进程,还是我需要在更早的阶段执行此检查?

更新:

进一步看,上面的方法被状态SKPaymentTransactionStatePurchased调用。每个Apple对该状态的定义是:

“App Store 已成功处理付款。您的应用程序应提供用户购买的内容。”

这告诉我阻止对话可能为时已晚。有一个更早的状态,但是,我认为收据验证必须在购买之后但在内容交付之前进行(否则将不会进行购买验证)。那么这只是必须处理相互矛盾的信息还是我错过了什么?

更新 2:在 cmets 中为每个请求添加更多方法

@interface IAPHelper () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@end

@implementation IAPHelper
{
    SKProductsRequest * _productsRequest;
    RequestProductsCompletionHandler _completionHandler;

    NSSet * _productIdentifiers;
    NSMutableSet * _purchasedProductIdentifiers;
    NSDictionary *_mappingDict;
}

- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers andMappings:(NSDictionary *)mappingDict
{

    if ((self = [super init])) {

        // Store product identifiers & mappings
        _productIdentifiers = productIdentifiers;
        _mappingDict = mappingDict;

        // Add self as transaction observer
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    }
    return self;

}

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {


    // 1
    _completionHandler = [completionHandler copy];

    // 2
    _productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
    _productsRequest.delegate = self;
    [_productsRequest start];

}

- (BOOL)productPurchased:(NSString *)productIdentifier {
    return [_purchasedProductIdentifiers containsObject:productIdentifier];
}

- (void)buyProduct:(SKProduct *)product {

    NSLog(@"Buying %@...", product.productIdentifier);

    SKPayment * payment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addPayment:payment];

}

#pragma mark - SKProductsRequestDelegate

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {

    NSLog(@"Loaded list of products...");
    _productsRequest = nil;

    NSArray * skProducts = response.products;
    for (SKProduct * skProduct in skProducts) {
        NSLog(@"Found product: %@ %@ %0.2f",
              skProduct.productIdentifier,
              skProduct.localizedTitle,
              skProduct.price.floatValue);
    }

    if (_completionHandler)
    {
        _completionHandler(YES, skProducts);
        _completionHandler = nil;
    }
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {

    NSLog(@"Failed to load list of products.");
    _productsRequest = nil;

    if (_completionHandler)
    {
        _completionHandler(NO, nil);
        _completionHandler = nil;
    }
}

这里是调用completeTransaction的具体方法

- (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];
            default:
                break;
        }
    };
}

【问题讨论】:

  • 能贴出调用completeTransaction的代码吗?另外,您是否尝试过使用 RMStore 进行购买部分,看看是否仍然出现对话框?
  • 感谢您的回复并为此创建了 SDK!我在 OP 的“更新 2”中粘贴了其他方法。我根据您的要求专门调用了调用 completeTransaction 的方法,但我还包括了上面的其他方法,以防您需要查看更多内容。我没有尝试购买 RMStore,因为在找到您的 SDK 之前我已经调整了另一个用于购买。他们也有一个验证过程,但不适用于 iOS7。
  • 基于这些附加方法还有什么进一步的吗?
  • 我能一眼看出的唯一一件事是,它看起来不像是 RMStore 导致了这个问题。此外,您应该仅在下载内容后完成交易。让 RMStore 处理购买将为您解决这个问题,顺便说一句。
  • 没有可下载的内容。成功购买后,我可以解锁应用程序中已有的内容。我上面描述的问题仅在使用收据验证时发生。我认为这可能是由于苹果认为交易已经完成,因为从它的角度来看,它是。我假设我在代码中执行此检查之前无法进行此检查?

标签: objective-c in-app-purchase rmstore


【解决方案1】:

我们在 cmets 中确定这个问题与 RMStore 没有任何关系。

您不是在测试真实的欺诈场景,因此 Apple 是否显示警报并不重要。

这将涉及使用虚假收据,或向 Store Kit 交易观察者发送虚假调用。在这两种情况下,您都不会收到警报。

当使用有效交易来模拟失败场景时,您不能指望 Apple 也会认为交易无效。没有 API 可以告诉 Apple 交易是欺诈性的。您只能完成或不完成交易。

【讨论】:

  • 我认为收据验证过程属于“RMStore”(需要包含其文件以进行验证)。如果有不同的标签,请告诉我。至于“失败”场景,我认为提供不正确的包名称/版本可能是强制无效案例的好方法(这是验证检查的一部分)。无论如何,由于测试是在“completeTransaction”中进行的,无论哪种方式都为时已晚。为了不完成反式,我必须事先知道它是无效的。这就是为什么我想知道是否可以比我更早地调用 verifyTransaction?
猜你喜欢
  • 1970-01-01
  • 2012-07-14
  • 2014-10-17
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 2018-12-02
  • 1970-01-01
  • 2016-07-31
相关资源
最近更新 更多