iOS 7本地(设备上)收据验证和应用内购买检查

21
我使用OpenSSL和asn1c编译器在设备上本地实现了收据验证,帮助我完成了苹果的“Receipt Validation Programming Guide”。我的应用只支持iOS 7及以上版本。
按照苹果的建议,我调用[[NSBundle mainBundle] appStoreReceiptURL]来获取应用商店收据。在显示任何UI之前,我也会在应用程序“首次”启动时执行此操作。这个首次启动的调用是必需的,因为苹果建议在第一次尝试时刷新收据,如果没有找到收据。由于这个调用(SKReceiptRefreshRequest),应用程序会要求用户输入他们的iTunes登录信息。
现在的问题是苹果一直拒绝我的应用程序,并称我正在向他们的生产服务器而不是沙盒服务器发出请求。但根据我从“Receipt Validation Programming Guide”中理解的内容,这只适用于您使用第二种验证方法并通过自己的安全服务器向苹果发送数据。然而,我正在本地完成所有操作,对如何区分生产环境和沙盒环境感到非常困惑,以使我的应用程序能够通过审核。
如果有什么建议或指针,将非常有帮助。

这没有意义。为什么苹果会抱怨你提交审核的应用程序正在使用生产服务器?为什么他们会建议在生产应用程序中使用沙盒服务器? - rmaddy
我认为我不被允许在外部发布苹果的解决中心消息,否则我会在这里发布它。 - Anuj Seth
如果出现失败的情况,例如用户在iTunes登录提示框中按下取消按钮,只需加载基本免费版本的应用程序。不要阻塞或做任何其他操作。 - Anuj Seth
Anuj,你和苹果公司的问题解决了吗? - platypus
在我们的“商店”页面中,除非用户点击“恢复”按钮,否则我们不会刷新任何收据或尝试进行收据验证。我很高兴我们和其他人站在同一条船上。请问您所说的“不刷新收据”是什么意思?我猜想如果收据丢失,您会完全跳过收据验证阶段而不会使应用程序崩溃? - platypus
显示剩余4条评论
5个回答

13

好的,以下是对我有效的操作:经过多轮审查申诉和重新提交,苹果在昨晚批准了该应用程序,这个过程跨度将近一个月。

不要在应用程序启动时尝试刷新收据,也不要阻止用户界面。我的做法是在启动时不显示任何UI,直到找到收据,因此在启动时提示输入iTunes密码时,按取消将显示应用程序的限制版本;输入正确的密码后,将尝试下载新的收据并根据是否找到收据进行操作。

因此,在启动时如果找到收据很好,如果没有,请不要尝试刷新它。

然而,当用户按下“恢复购买”选项时请确实刷新它。

希望这有所帮助。


2
那些一直在给答案投反对票的人,如果能说明原因会更有帮助。 - Anuj Seth
这是事实。如果收据无效或不存在,则会显示输入用户密码的对话框。因此,与其在开始时要求密码(对用户来说很困惑,因为他刚刚启动应用程序,而它没有任何原因要求密码),不如提供必须提供的“恢复”按钮,并等待用户按下它。 - Jakub Truhlář

5
我已删除之前的回复,我误解了问题。
我认为您做得很对,苹果公司对自己的指南感到困惑,老实说。毕竟,在“收据验证编程指南”中,他们明确建议:“如果在iOS中验证失败,请使用SKReceiptRefreshRequest类刷新收据”,并且无法影响此调用所连接的服务器(SKReceiptRefreshRequest reference)。
根据http://asciiwwdc.com/2013/sessions/308,所调用的服务器取决于应用程序的签名方式,并且需要在提交时进行生产签名。

4
生产环境和沙盒环境的区别在于您调用的链接。
#define ITMS_PROD_VERIFY_RECEIPT_URL        @"https://buy.itunes.apple.com/verifyReceipt"
#define ITMS_SANDBOX_VERIFY_RECEIPT_URL     @"https://sandbox.itunes.apple.com/verifyReceipt";

ITMS_PROD_VERIFY_RECEIPT_URL是生产服务器。ITMS_SANDBOX_VERIFY_RECEIPT_URL是沙盒服务器。

  1. 确保从Apple provisioning portal创建正确的证书。了解Ad-Hoc与Distribution之间的区别。
  2. 当您使用从iTunes Connect创建的测试iTunes用户帐户购买时,您将需要在沙盒服务器下进行测试。在Code Signing IdentityRelease下,您应该选择Ad-Hoc provisioning而不是distribution provisioning
  3. 但是,当您想要发布到应用商店时,您必须选择distribution provisioningproduction server(ITMS_PROD_VERIFY_RECEIPT_URL)。您不能在此服务器上使用测试用户帐户。您将需要使用真实的iTune用户帐户购买它(在Apple批准后)以进行真正的购买。

要了解如何在本地实现IAP并在本地验证收据,请参考以下内容:- 1.http://www.raywenderlich.com/21081/introduction-to-in-app-purchases-in-ios-6-tutorial

2.http://www.raywenderlich.com/23266/in-app-purchases-in-ios-6-tutorial-consumables-and-receipt-validation

您可以在此处下载完成的示例项目:- 3. http://cdn1.raywenderlich.com/downloads/InAppRagePart2Finished.zip

注意:可能还有其他验证收据的方法,我不知道。

我发现了一些可能有用的东西:- 1. https://developer.apple.com/library/ios/documentation/StoreKit/Reference/SKReceiptRefreshRequest_ClassRef/SKReceiptRefreshRequest_ClassRef.pdf

- (id)initWithReceiptProperties:(NSDictionary *)properties

它说:“在生产环境中,将此参数设置为nil。” 属性 在测试环境中,新收据应具有的属性。对于键,请参阅“收据属性”(第4页)。 在生产环境中,将此参数设置为nil。


不,这不是问题的关键,这些内容仅适用于使用苹果服务器进行收据验证和应用内购买解析的情况。当在设备上完全本地执行时,无法确定您是否处于沙盒或生产环境中。 - Anuj Seth
你能给我展示验证收据的代码吗?据我所知,有两种验证收据的方式。1. 在设备上本地验证,是的,我们使用设备调用收据验证URL,就像我上面说的那样。2. 在服务器上验证。服务器将验证收据并将参数传递回设备。我已经尝试过这两种方法。如果您想要本地验证,可以参考这个好的教程:http://www.raywenderlich.com/21081/introduction-to-in-app-purchases-in-ios-6-tutorial 当我第一次学习移动端(本地)验证收据时,我曾经使用过它。 - Ricky
在学完第一个教程之后,可以学习这个:http://www.raywenderlich.com/23266/in-app-purchases-in-ios-6-tutorial-consumables-and-receipt-validation - Ricky
找到了一个可能有用的链接:https://developer.apple.com/library/ios/documentation/StoreKit/Reference/SKReceiptRefreshRequest_ClassRef/SKReceiptRefreshRequest_ClassRef.pdf 属性 在测试环境中,新收据应该具有的属性。有关键,请参见“收据属性”(第4页)。在生产环境中,将此参数设置为nil。 - Ricky
@voyage11,当我们谈论本地验证收据时,没有一个可以直接调用的URL。我们只需使用SKReceiptRefreshRequest。因此,您对如何进行本地收据验证的理解与提问者不在同一页。 - platypus
是的,我知道。我已经在注意事项中提到了:“可能还有其他验证收据的方法,我不知道。”之后,我发现了第三种验证收据的方法。我还找到了一个链接,应该可以帮助用户区分生产环境和测试环境。 - Ricky

1
如果收据无效或不存在,则会显示输入用户密码的对话框。因此,不要在收据不存在时一开始就要求密码(因为这会让用户感到困惑,因为他刚刚启动应用程序,但却没有任何原因要求密码),而是提供恢复按钮,你必须提供它,并等待你可以合理验证的收据。
因此,请将您的刷新代码放入if语句中:
if([[NSFileManager defaultManager] fileExistsAtPath:[[[NSBundle mainBundle] appStoreReceiptURL] path]] == YES) {

        self.receiptRefreshRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
        self.receiptRefreshRequest.delegate = self;
        [self.receiptRefreshRequest start];
}

0

我想分享我的经验。我一直在沙盒中工作,在删除应用后,应用收据丢失。(然后重新Command-R) 我不知道这是否会在生产环境中发生,但听起来好像会。在第一次启动应用时要求刷新,并提示用户输入密码是令人震惊的。当然,这是个问题。

似乎[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]也会在没有弹出对话框的情况下静默刷新应用收据。意思是,在还原了交易之后,请求appReceiptURL + Data将返回一个非空值。这只是我进行短时间测试得出的结论。请自行进行测试。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接