gpt4 book ai didi

iOS 收据验证 - 自动续订订阅

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:36:49 28 4
gpt4 key购买 nike

我在验证自动续订 IAP 的收据时遇到问题。以下是我验证订阅的代码摘要。我正在使用 Parse 作为后端,并且还包含一些代码。在开发模式下,一切正常,没有任何问题。它在 App Store 中上线,我所有的 TestFlight 测试人员和一些真实用户在应用程序尝试验证后立即遇到崩溃。当我尝试将数据保存回 Parse 时,我看到崩溃来自函数的最后,它告诉我我保存的键是空的。 (base64, info, expirationDate)

在我的设备上,我有一张沙盒购买收据,并且我收到了来自 Apple 的 21007 响应,试图根据实时 URL 进行验证。当我切换到沙箱 url 时,它每次都会验证并正常工作。

另外,我知道以这种方式验证购买并不安全,我通过我的服务器执行验证,所以没有问题。

我想弄清楚我是否遗漏了一个步骤,是否应该做一些不同的事情?

伪代码:

Get the receipt from NSBundle
Get the receipt from Parse database
If neither of them exist:
end the function
else:
if Parse receipt exists:
use it, but first just check the expirationDate stored in Parse
else:
use NSBundle receipt for validation,
If expired based on date from Parse:
build request to send to Apple (my server in production)
Get JSON response, and perform switch statement for response codes
Check for errors or expiration
Save new data to Parse // <-- Cause of the crash is here because the keys are null for some users

这是一段实际代码:

PFUser *user = [PFUser currentUser];

//Load the receipt from the app bundle
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

//Load the receipt from Parse, already encoded
NSString *saved64 = user[@"base64"];

//Check for at least one instance of a receipt... Either Parse or appBundle
if (!receipt && saved64.length == 0) {
//if (!receipt) {
//No receipt
NSLog(@"No Receipt");
return;
}

//Base 64 encode appBundle receipt
NSString *receipt64 = [receipt base64EncodedStringWithOptions:0];

//String to hold base64 receipt (either from Parse or appBundle)
NSString *temp64;

//See if Parse base64 exists
if (saved64.length == 0) {
//Not a receipt in Parse yet, use appBundle
NSLog(@"Using appBundle receipt.");
temp64 = receipt64;
} else {
//Receipt in Parse, use it
NSLog(@"Using Parse receipt.");
temp64 = saved64;

//Check expiration date stored in Parse
NSDate *parseExpDate = user[@"expirationDate"];
if ([[self todayGMT] compare:parseExpDate] == NSOrderedAscending) {
//Active based on Parse, no need to validate...
NSLog(@"Active based on Parse receipt... No need to validate!");
return;
}
}

//Base 64 encode appBundle receipt
NSString *receipt64 = [receipt base64EncodedStringWithOptions:0];


//Create the request
NSString *sharedSecret = @"[shared-secret]";
NSError *error;
//Request with receipt data and shared secret from iTunesConnect
NSDictionary *requestContents = @{@"receipt-data":receipt64, @"password": sharedSecret};
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error];
if (!requestData) {
//Handle error
NSLog(@"Error: %@", error);

return;
}

//Create a POST request with the receipt data.
NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
//NSURL *sandboxURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];

//Make a connection to the iTunes Store
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (connectionError) {
//Error
} else {
//Success
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (!jsonResponse) {
//Error
NSLog(@"Error at !jsonResponse: %@", error);
return;
}

NSString *base64 = jsonResponse[@"latest_receipt"];
NSArray *info = jsonResponse[@"latest_receipt_info"];
BOOL isPro;

//Switch statement for subscription status
switch ([jsonResponse[@"status"] intValue]) {
case 21002: {
//The data in the receipt-data property was malformed or missing.
NSLog(@"21002 : The data in the receipt-data property was malformed or missing.");
isPro = NO;
break;
}
case 21003: {
//The receipt could not be authenticated.
NSLog(@"21003 : The receipt could not be authenticated.");
isPro = NO;
break;
}
case 21004: {
//The shared secret you provided does not match the shared secret on file for your account.
NSLog(@"21004 : The shared secret you provided does not match the shared secret on file for your account.");
isPro = NO;
break;
}
case 21005: {
//The receipt server is not currently available.
NSLog(@"21005 : The receipt server is not currently available.");
isPro = NO;
break;
}
case 21006: {
//This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.
NSLog(@"21006 : This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.");
isPro = NO;
break;
}
case 21007: {
//This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.
NSLog(@"21007 : This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead..");
isPro = NO;
break;
}
case 21008: {
//This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.
NSLog(@"21008 : This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead..");
isPro = NO;
break;
}
case 0: {
//Valid and active
NSLog(@"0 : Valid and active subscription.");
isPro = YES;
break;
}
default: {
isPro = NO;
break;
}
}

//Set user info to database (Parse)
user[@"base64"] = base64;
user[@"info"] = info;
user[@"expirationDate"] = expirationDate;
user[@"isPro"] = [NSNumber numberWithBool:isPro];
[user saveEventually];
}
}];

最佳答案

沙盒 URL - https://sandbox.itunes.apple.com/verifyReceipt

Sandbox URL 仅在开发者证书的情况下在开发模式下工作,因此它从服务器获得响应。

实时网址 - https://buy.itunes.apple.com/verifyReceipt

Live URL 在分发模式下仅使用分发证书工作,因此在开发模式下不起作用,无法返回响应。

所以如果你想在 Debug模式下使用实时 URL,你应该处理异常。

如果您将 Swift 与可选绑定(bind)一起使用,则可以在不发生崩溃的情况下进行解析。

关于iOS 收据验证 - 自动续订订阅,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29282341/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com