无法获取用户安装的原始应用程序版本(收据验证)?
Posted
技术标签:
【中文标题】无法获取用户安装的原始应用程序版本(收据验证)?【英文标题】:Trouble getting the original app version that the user installed (receipt validation)? 【发布时间】:2014-10-19 22:31:00 【问题描述】:我最近更新了一个应用程序,可以在应用程序购买中使用。以前的版本(付费但没有应用内购买)是 1.0,当前版本是 1.1。
由于应用内购买基本上解锁了所有功能(包括在付费版本 1.0 中),我希望为最初下载版本 1.0 的用户按下我的恢复购买按钮提供一种升级方式。
为此,我首先尝试恢复购买,如果响应:
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
如果这为我提供了一个交易计数为 0 的队列,我会检查收据以查看安装的原始版本是否为 1.0。
获取收据的代码是根据 Apple 的文档
- (void)tryRestoreFromOriginalPurchase
// Load the receipt from the app bundle
NSError *error;
NSData *receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
if (receipt == nil)
[self restoreFromOriginalVersionWithReceipt:nil];
return;
// Create the JSON object that describes the request
NSDictionary *requestContents = @@"receipt-data": [receipt base64EncodedStringWithOptions:0];
NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error];
if (!requestData)
[self restoreFromOriginalVersionWithReceipt:nil];
return;
// Create a POST request with the receipt data
NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
[storeRequest setHTTPMethod:@"POST"];
[storeRequest setHTTPBody:requestData];
// Make a connection to the iTunes Store on a background queue
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:storeRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError)
if (!connectionError)
NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
if (jsonResponse) [self restoreFromOriginalVersionWithReceipt:jsonResponse];
else [self restoreFromOriginalVersionWithReceipt:nil];
else
[self restoreFromOriginalVersionWithReceipt:nil];
];
然后调用以下方法:
- (void)restoreFromOriginalVersionWithReceipt:(NSDictionary *)receipt
if (receipt == nil)
// CALL METHOD TO HANDLE FAILED RESTORE
else
NSInteger status = [[receipt valueForKey:@"status"] integerValue];
if (status == 0)
NSString *originalApplicationVersion = [[receipt valueForKey:@"receipt"] valueForKey:@"original_application_version"];
if (originalApplicationVersion != nil && [originalApplicationVersion isEqualToString:@"1.0"])
// CALL METHOD TO HANDLE SUCCESSFUL RESTORE
else
// CALL METHOD TO HANDLE FAILED RESTORE
else
// CALL METHOD TO HANDLE FAILED RESTORE
现在这不起作用。当有人安装 1.1 版并点击恢复购买时,它会在不应该的情况下成功恢复。
我刚刚意识到在我的 Info.plist 中,我的 CFBundleShortVersionString 是 1.1,但我的 CFBundleVersion 是 1.0。
这可能是一个非常愚蠢的问题,但即使更新版本为 1.1,收据是否提供 original_application_version 为 1.0(由于错误的 CFBundleVersion)?
那么,如果我发布一个新的更新,并修正为 1.2 版(对于 CFBundleShortVersionString 和 CFBundleVersion),问题会得到解决吗?
-- 更新--
所以我刚刚向应用商店上传了一个新版本,其中 CGBundleVersion 和 CFBundleShortVersionString 都等于 1.2。但是,我仍然面临同样的问题 - 首次下载 1.2 版并点击恢复购买的用户正在免费升级(由于上述收据检查)。看来 original_application_version 总是要到 1.0。
注意:我正在使用以前未下载过该应用的新 iTunes 帐户下载该应用。
这是我从应用商店安装然后尝试通过 Xcode 获取收据时的收据
2014-08-27 08:46:42.858 AppName[4138:1803]
environment = Production;
receipt =
"adam_id" = AppID;
"application_version" = "1.0";
"bundle_id" = "com.CompanyName.AppName";
"download_id" = 94004873536255;
"in_app" = (
);
"original_application_version" = "1.0";
"original_purchase_date" = "2014-08-26 22:30:49 Etc/GMT";
"original_purchase_date_ms" = 1409092249000;
"original_purchase_date_pst" = "2014-08-26 15:30:49 America/Los_Angeles";
"receipt_type" = Production;
"request_date" = "2014-08-26 22:46:42 Etc/GMT";
"request_date_ms" = 1409093202544;
"request_date_pst" = "2014-08-26 15:46:42 America/Los_Angeles";
;
status = 0;
有什么想法吗?
【问题讨论】:
万一有人遇到了同样的问题,我无法让上面的代码工作。相反,我通过检查 original_purchase_date 得到了想要的结果。 我试过这段代码,但每次都说receipt = nil。 @NCF 运气好吗? @sheefy 你会说即使现在你更喜欢 original_date 而不是版本号?我也要做同样的事情,你的代码是否足够当前可以重复使用? @NCFUSN 是否通过从 Xcode 运行进行本地测试?如果是这样,收据将为零 IIRC。创建一个 TestFlight 构建,你会得到一个收据 【参考方案1】:我偶然发现了同样的问题 - 我将我的应用从付费转换为免费增值,并尝试在应用收据中使用 original_application_version
来决定为谁解锁新的免费增值功能。我也失败了。
但是,我发现我错误地使用了original_application_version
。这个名字误导我认为这个字符串对应于应用程序的版本号。在 ios 上,它没有。 original_application_version
实际上是应用的 build 编号。
原始应用程序版本
这对应于 CFBundleVersion 的值(在 iOS 中)或 CFBundleShortVersionString(在 macOS 中)在 Info.plist 文件中时 最初是购买的。在沙盒环境中,该字段的值始终为“1.0”。
来源:https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html
我认为这可能是您得到一个出乎意料的数字的原因。
使用original_purchase_date
,就像你最后所做的那样,是一个可靠的替代方案。
【讨论】:
我还可以确认original_application_number
是原始版本的内部版本号,这对于确定实际的原始版本几乎没有用处。因此,当我切换到免费增值模式时,我将内部版本号更改为以版本号为前缀。所以对于 2.1.5 版本,构建 1 将是 2.1.5.1。免费增值前的版本始终只有一个数字的内部版本号,因此现在很容易区分原始客户和新客户。【参考方案2】:
这个问题被问到已经有一段时间了,但它提出了一些非常重要的观点:
收据中的原始应用版本字段对应的是CFBundleVersion,而不是CFBundleShortVersionString。在沙盒(开发者构建)环境中,值字符串是always“1.0”。
请注意,从付费应用转换为免费增值应用时,如果原始(付费版本)用户卸载该应用,然后从 iTunes 重新安装,则不会有本地收据。如果该用户从未进行过应用内购买,则调用 SKPaymentQueue restoreCompletedTransactions
不会导致下载新收据。在这种情况下,您需要使用SKReceiptRefreshRequest
请求刷新收据,而不是依赖恢复功能。
【讨论】:
以上是关于无法获取用户安装的原始应用程序版本(收据验证)?的主要内容,如果未能解决你的问题,请参考以下文章