- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
苹果终于推出了所谓的auto-renewable subscriptions昨天。由于我在应用内购买方面的经验很少(仅限沙盒),所以我不确定我在这里是否一切顺利。似乎需要对收据进行服务器端验证。找出订阅是否仍然有效的唯一方法似乎是将原始交易数据存储在服务器端。关于这个主题的苹果编程指南对我来说都是神秘的。
我的期望是,我只能使用 iOS 客户端,只需通过 store kit api 询问 iTunes,他/她是否已经购买了这个(订阅)产品并收到了是/否的答案以及到期日期。
有没有人有过自动更新订阅或(因为它们看起来有点相似)非消耗性产品的经验?有没有关于这个的好教程?
谢谢你。
最佳答案
我让它在沙箱中运行,几乎要上线了......
应该使用服务器来验证收据。
在服务器上,您可以使用收据数据记录设备 udid,因为收据总是新生成的,并且它可以跨多个设备工作,因为收据总是新生成的。
在设备上不需要存储任何敏感数据,也不应该:)
每当应用程序出现时,应该检查商店的最后一张收据。应用程序调用服务器,服务器与商店进行验证。只要商店返回有效的收据应用程序就可以使用该功能。
我开发了一个 Rails3.x 应用程序来处理服务器端,验证的实际代码如下所示:
APPLE_SHARED_PASS = "enter_yours"
APPLE_RECEIPT_VERIFY_URL = "https://sandbox.itunes.apple.com/verifyReceipt" #test
# APPLE_RECEIPT_VERIFY_URL = "https://buy.itunes.apple.com/verifyReceipt" #real
def self.verify_receipt(b64_receipt)
json_resp = nil
url = URI.parse(APPLE_RECEIPT_VERIFY_URL)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
json_request = {'receipt-data' => b64_receipt, 'password' => APPLE_SHARED_PASS}.to_json
resp, resp_body = http.post(url.path, json_request.to_s, {'Content-Type' => 'application/x-www-form-urlencoded'})
if resp.code == '200'
json_resp = JSON.parse(resp_body)
logger.info "verify_receipt response: #{json_resp}"
end
json_resp
end
#App Store error responses
#21000 The App Store could not read the JSON object you provided.
#21002 The data in the receipt-data property was malformed.
#21003 The receipt could not be authenticated.
#21004 The shared secret you provided does not match the shared secret on file for your account.
#21005 The receipt server is not currently available.
#21006 This receipt is valid but the subscription has expired.
In your meta data at iTunes Connect (in your app description): You need to clearly and conspicuously disclose to users the following information regarding Your auto-renewing subscription:
- Title of publication or service
- Length of subscription (time period and/or number of deliveries during each subscription period)
- Price of subscription, and price per issue if appropriate
- Payment will be charged to iTunes Account at confirmation of purchase
- Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period
- Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal
- Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user’s Account Settings after purchase
- No cancellation of the current subscription is allowed during active subscription period
- Links to Your Privacy Policy and Terms of Use
- Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication."
#21007 This receipt is a sandbox receipt, but it was sent to the production service for verification.
#21008 This receipt is a production receipt, but it was sent to the sandbox service for verification.
Application initiates the In App Purchase process in a non-standard manner. We have included the following details to help explain the issue and hope you’ll consider revising and resubmitting your application.
iTunes username & password are being asked for immediately on application launch. Please refer to the attached screenshot for more information.
//make the payment
SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
- (void)applicationWillResignActive:(UIApplication *)application
- (void)applicationDidBecomeActive:(UIApplication *)application
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased: {
[self completeTransaction:transaction];
break;
}
case SKPaymentTransactionStateFailed: {
[self failedTransaction:transaction];
break;
}
case SKPaymentTransactionStateRestored: {
[self restoreTransaction:transaction];
break;
}
default:
break;
}
}
}
//a fresh purchase
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
[self recordTransaction: transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
finishTransaction
将收到的交易传递给
recordTransaction
,然后调用应用服务器并与 App Store 进行订阅回执验证。像这样:
- (void)recordTransaction: (SKPaymentTransaction *)transaction
{
[self subscribeWithTransaction:transaction];
}
- (void)subscribeWithTransaction:(SKPaymentTransaction*)transaction {
NSData *receiptData = [transaction transactionReceipt];
NSString *receiptEncoded = [Kriya base64encode:(uint8_t*)receiptData.bytes length:receiptData.length];//encode to base64 before sending
NSString *urlString = [NSString stringWithFormat:@"%@/api/%@/%@/subscribe", [Kriya server_url], APP_ID, [Kriya deviceId]];
NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:[[transaction payment] productIdentifier] forKey:@"product"];
[request setPostValue:receiptEncoded forKey:@"receipt"];
[request setPostValue:[Kriya deviceModelString] forKey:@"model"];
[request setPostValue:[Kriya deviceiOSString] forKey:@"ios"];
[request setPostValue:[appDelegate version] forKey:@"v"];
[request setDidFinishSelector:@selector(subscribeWithTransactionFinished:)];
[request setDidFailSelector:@selector(subscribeWithTransactionFailed:)];
[request setDelegate:self];
[request startAsynchronous];
}
finishTransaction
只有在我的服务器验证了收据之后,但到那时,交易已经不知何故丢失了。所以只要确保
finishTransaction
尽早。
APPLE_SHARED_PASS = "83f1ec5e7d864e89beef4d2402091cd0" #you can get this in iTunes Connect
APPLE_RECEIPT_VERIFY_URL_SANDBOX = "https://sandbox.itunes.apple.com/verifyReceipt"
APPLE_RECEIPT_VERIFY_URL_PRODUCTION = "https://buy.itunes.apple.com/verifyReceipt"
def self.verify_receipt_for(b64_receipt, receipt_verify_url)
json_resp = nil
url = URI.parse(receipt_verify_url)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
json_request = {'receipt-data' => b64_receipt, 'password' => APPLE_SHARED_PASS}.to_json
resp, resp_body = http.post(url.path, json_request.to_s, {'Content-Type' => 'application/x-www-form-urlencoded'})
if resp.code == '200'
json_resp = JSON.parse(resp_body)
end
json_resp
end
def self.verify_receipt(b64_receipt)
json_resp = Subscription.verify_receipt_for(b64_receipt, APPLE_RECEIPT_VERIFY_URL_PRODUCTION)
if json_resp!=nil
if json_resp.kind_of? Hash
if json_resp['status']==21007
#try the sandbox then
json_resp = Subscription.verify_receipt_for(b64_receipt, APPLE_RECEIPT_VERIFY_URL_SANDBOX)
end
end
end
json_resp
end
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
并且应用程序将与恢复的交易(如果有)一起交付。
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
[self recordTransaction: transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
if (transaction.error.code == SKErrorPaymentCancelled)
{
//present error to user here
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
关于iphone - iOS 自动续订订阅的任何(早期)体验,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5017731/
我正在为从 API 级别 8 到 14 的 android 开发一个应用程序。我正在尝试在早期版本中获得与 android 4(请参阅联系人应用程序)相同的快速滚动行为(右侧固定的时尚滚动条)边)。有
早期(编译期)优化 jvm的编译器可以分为三个编译器: 前端编译器:把*.java转变为*.class的过程。如sun的javac、eclipse jdt中的增量式编译器(ecj)
苹果终于推出了所谓的auto-renewable subscriptions昨天。由于我在应用内购买方面的经验很少(仅限沙盒),所以我不确定我在这里是否一切顺利。似乎需要对收据进行服务器端验证。找出订
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 要求代码的问题必须表明对正在解决的问题的最低理解。包括尝试的解决方案、它们为什么不起作用以及预期结果。另
在 Wagner 的“Effective C#”第 23 项中,他解释说 interface methods are not virtual...they are a declaration of a
我最近遵循了本指南 Installing a Git Server using Apache (WebDAV) on Ubuntu Server 12.04使用 Apache (WebDAV) 设置本
这是我之前的问题 jQuery UI hiding not taking effect for early DOM elements 的后续问题。我几乎刚刚编辑了那个,但不想使 the accepte
我正在尝试替换 ZonedDateTime.toInstant方法,因为它仅从 API 26 for Android 开始可用。 但我的应用程序应该支持 API 19。 我想将 ZonedDateTi
我的电脑正确配置了 SSH,我在尝试克隆存储库时遇到了这个错误: 我运行这个命令来克隆存储库 git clone ssh://git-codecommit.us-west-2.amazonaws.co
我是一名优秀的程序员,十分优秀!