【发布时间】:2020-07-15 12:07:08
【问题描述】:
我为此苦苦挣扎了很长一段时间。首先是我们的问题:在我们的应用程序中,我们有可更新的订阅和一次性购买。我想从收据中读取订阅是否仍然有效或者是一次性购买(这是有效的生命周期)。首先提出一个问题: 此文件包含什么内容?
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 = nil)或者在此收据中没有发现任何购买。但是很少有用户,我无法真正看到他们的共同点以及错误在哪里。在测试中,我从来没有出错。我还看到一位终身购买的用户在现场看到没有退回任何收据,我不知道为什么。
那么我的错误在哪里?我每次都必须刷新收据吗?或者为什么有时我的 self.appleReceipt 是空的?我的流程有问题吗?
【问题讨论】:
标签: ios objective-c storekit