我为这件事挣扎了很长一段时间。首先,我们的问题是:在我们的应用程序中,我们有可更新的订阅和一次性购买。如果订阅仍然有效,或者是一次性购买(这是有效的生命周期),我想从收据中读取。首先有一个问题:这个文件包含什么?
NSData* receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];我只需要检查这个文件是否存在,如果没有,我要求刷新正确吗?但是,如果订阅已经自动更新,我也需要刷新这个文件吗?或者,当我在苹果服务器上验证收据时,收据会被更新吗?
现在,我的流程如下所示,并从支付队列开始:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
if(SANDBOX_TESTING) NSLog(@"updated transaction");
[self refreshReceipt];
self.transactionCount = [transactions count];
if(SANDBOX_TESTING) NSLog(@"Number of transactions: %ld", (long)self.transactionCount);
for (SKPaymentTransaction * transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction restore:NO];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPProductPurchaseStateChangedNotification object:nil];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(@"Restore transaction started received");
//Only restore transactions that haven't been restored yet AND if they have a still supported identifier
//IMPORTANT: Original Transaction is only set (transaction.originalTransaction.transactionIdentifier) if it is a restore!
//This first if only helps in a restore case, that not all subscription renewals get looped. If a valid subscription is found for one subscription type, the loop runs only once
if(![self.restoredTransactions containsObject:transaction.payment.productIdentifier] && [[self getAllPurchaseIDsForPlatformType:PURCHASESONPLATFORM_IOS] containsObject:transaction.payment.productIdentifier]){
[self completeTransaction:transaction restore:YES];
} else {
self.transactionCount--;
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//Moved from paymentQueueRestoreCompletedTransactionsFinished
if(self.transactionCount == 0){
[self.delegate restoredTransactions:[self.restoredTransactions count] withReceipt:self.appleReceipt];
}
break;
default:
break;
}
};
}因此,在刷新收据时,我只需这样做:
-(void)refreshReceipt{
//TODO: Check if this file exists - if not refresh receipt (and only then...)
NSData* receiptData = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\", \"password\" : \"%s\"}",
[receiptData base64EncodedStringWithOptions:0], "xxx"];
NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
//Sending the data to store URL based on the kind of build.
NSURL *storeURL;
if(SANDBOX_TESTING){
storeURL = [[NSURL alloc] initWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
} else {
storeURL = [[NSURL alloc] initWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
}
//Sending the POST request.
NSMutableURLRequest *storeRequest = [[NSMutableURLRequest alloc] initWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:payloadData];
NSError *error;
NSURLResponse *response;
NSData *data = [[NSURLSession sharedSession] sendSynchronousRequest:storeRequest returningResponse:&response error:&error];
if(error) {
_appleReceipt = [NSArray arrayWithObjects: error, nil];
}
NSError *localError = nil;
//Parsing the response as JSON.
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&localError];
//Getting the latest_receipt_info field value.
_appleReceipt = jsonResponse[@"latest_receipt_info"];
if(SANDBOX_TESTING) NSLog(@"Refresh Apple receipt: %@", _appleReceipt);
}在我有收据之后,我翻看它,找出正确的购买和提取到期日,如果它是终身购买。
但是:我们有一些用户收到一条错误消息,上面说没有返回苹果收据(如果self.appleReceipt =0)是由我触发的,或者在这张收据中没有找到任何购买。但是很少的用户和我看不出他们有什么共同点,错误在哪里。在测试中,我从不出错。我也看到了一个用户的生活,谁做了终身购买,没有收据被退回,我不知道为什么。
那我的错误在哪里?我每次都要刷新收据吗?或者为什么有时我的self.appleReceipt是空的?我的过程有问题吗?
发布于 2021-03-05 16:44:51
当您向Apple服务器验证时,您确实会得到最新的更新,包括任何取消或过期。
有时,在购买之后生成收据可能需要一段时间,这就是为什么有时您会看到空收据数据,特别是如果您只在购买之后立即检查收据数据的话。或者,它甚至可能是用户试图黑客您的应用程序,但实际上没有收据数据。
您还应该做的是解析接收数据Apple返回,查看IAP项,以便您的可更新订阅检查它们何时到期,或者查看您一次性购买的IAP条目--您可以在这里找到关于收据中存在的数据的详细指南(以及您可能遇到的代码):
https://www.namiml.com/blog/app-store-verify-receipt-definitive-guide
请注意,您确实应该让服务器进行此收据检查和处理,因为潜在的黑客可能会拦截对Apple的调用以进行收据验证。
https://stackoverflow.com/questions/62914470
复制相似问题