在我的iOS应用程序中,我使用了自动续订订阅.我们需要一个跨平台的解决方案.我在iOS中使用RMStore购买产品.
在当前场景中:我从服务器获取最新收据didFinishLaunchingWithOptions
并向AppStore验证,而RMStoreAppReceiptVerifier
不是服务器的更新到期日期.我们始终从两个平台(iOS和Android)更新服务器数据.从iOS方面来说,我们必须在应用程序启动时始终检查收据.当我在续订付款时收到推送通知?如果可能,那么我们当时已经更新了服务器数据
Q-1)如何检查我的新续订流程是否完成?
Q-2)如果用户从iTunes取消了他们的自动续订订阅,我如何通知我以便更新我的数据库?我是否需要一个检查过期订阅的守护程序,以查看用户是否续订?
Q-3)在iOS中.如果我从其他设备登录,那么如何验证来自其他设备的收据?
请建议我如何使用服务器数据库在跨平台处理自动续订订阅.我希望有人可以帮助我.谢谢!
我的应用目前是付费应用.我想将应用程序转换为免费的应用程序与IAP和祖父(给所有付费应用程序的用户)免费的IAP功能.我认为我可以使用收据验证(1)确定应用程序的原始购买日期 - 但这似乎仅适用于IAP或(2)使用原始应用程序版本(似乎是构建版本而不是应用程序版本).但是,当我在testflight中测试时,原始版本号始终为"1.0".各种消息来源称这是一个testflight问题,发布应用程序将在购买应用程序的日期正确识别构建.https://forums.developer.apple.com/message/42107#42107 我还没有在stackoverflow上看到这个问题 - 许多关于找到应用购买日期的问题都在iOS 7中的收据验证之前或者适用于In-应用程序购买,而不是最初购买的应用程序
我有3个相关的问题,看我是否正在走向正确的轨道:
问题1:我可以使用原始应用程序版本来识别在我的应用程序转换之前购买的用户.也就是说,购买版本1.30或更早版本的用户可以通过将它们与最新版本2.0进行比较来识别,然后我可以授予任何原始版本号<2.0,免费访问IAP功能的用户.
问题2:有没有办法在应用程序发布之前测试代码,例如使用testflight?
问题3.有没有其他方法可以将应用程序转换为免费增值而不让现有用户偿还(即使他们在新设备上下载应用程序)?
我使用Receigen获取收据数据并测试我的模型 - Receigen指出测试原始版本号是零还是零但是没有说明在应用程序发布时这是否已修复.
为什么我的应用程序在开发过程中缺少收据?
我从Xcode 7.3.1运行我的iOS(7,8,9)应用程序.该应用程序的收据似乎丢失了.此应用程序目前在App Store中发布,因此我有我的开发人员凭据和"沙盒"用户登录.
运行以下代码时:
NSURL* url = [[NSBundle mainBundle] appStoreReceiptURL];
NSLog(@"url: %@", url);
Run Code Online (Sandbox Code Playgroud)
适用于iPhone 6s Plus的Simulator 9.3的结果:
文件:///用户/布尔克/库/开发商/ CoreSimulator /设备/ 7F32850A-CC1A-45A3-8ED6-95C75CD9DD44 /数据/集装箱/数据/应用/ 46BDF021-D2A3-418E-91E1-61A15215942B/StoreKit /收据
然而,当我导航到以第二个UUID命名的文件夹时,我找不到任何StoreKit
文件夹.
要在真正的iOS iPod touch上进行测试,我将该代码扩展为......
...查看应该找到收据的位置.
NSURL* url = [[NSBundle mainBundle] appStoreReceiptURL];
NSLog(@"url: %@", url);
Run Code Online (Sandbox Code Playgroud)
...尝试加载这样的文件.
NSString* urlContents = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSLog(@"urlContents: %@", urlContents);
Run Code Online (Sandbox Code Playgroud)
...验证文件是否存在.
NSError *err;
if ( [url checkResourceIsReachableAndReturnError:&err] == NO ) {
NSLog(@"BAD No receipt found for url: %@" , url );
} else {
NSLog(@"GOOD Receipt …
Run Code Online (Sandbox Code Playgroud) 我正在Swift 3中开发一个iOS应用程序,并尝试按照本教程实现收据验证:http://savvyapps.com/blog/how-setup-test-auto-renewable-subscription-ios-app.但是,该教程似乎是使用早期版本的Swift编写的,因此我不得不进行一些更改.这是我的receiptValidation()函数:
func receiptValidation() {
let receiptPath = Bundle.main.appStoreReceiptURL?.path
if FileManager.default.fileExists(atPath: receiptPath!){
var receiptData:NSData?
do{
receiptData = try NSData(contentsOf: Bundle.main.appStoreReceiptURL!, options: NSData.ReadingOptions.alwaysMapped)
}
catch{
print("ERROR: " + error.localizedDescription)
}
let receiptString = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
let postString = "receipt-data=" + receiptString! + "&password=" + SUBSCRIPTION_SECRET
let storeURL = NSURL(string:"https://sandbox.itunes.apple.com/verifyReceipt")!
let storeRequest = NSMutableURLRequest(url: storeURL as URL)
storeRequest.httpMethod = "POST"
storeRequest.httpBody = postString.data(using: .utf8)
let session = URLSession(configuration:URLSessionConfiguration.default)
let task = session.dataTask(with: storeRequest as URLRequest) { data, …
Run Code Online (Sandbox Code Playgroud) 我对此有点困惑.因此,按照这种方法,我得到了包含一堆解密字段的json.其中original_purchase_date.
我需要的是跟踪在新版本免费之前是否购买了应用程序,我认为我需要使用此字段.但由于沙盒环境的某些原因,它显示日期
"original_purchase_date"="2013-08-01 07:00:00 Etc/GMT";
在申请之前几年.
所以现在我不确定
为什么它显示日期.
original_purchase_date确实是我需要跟踪的字段.
我们有一项服务器端服务,我们只想向付费 iOS 应用程序的有效用户提供该服务。(请注意,这是付费的 iOS 应用程序,而不是带有 IAP 的免费应用程序。)
当我们appStoreReceiptURL
用来检查沙盒应用收据并将其发送到我们的服务器端时,我们会看到这样的收据:
{
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "com.example.myapp",
"application_version": "1.1.1",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2018-04-16 23:53:58 Etc/GMT",
"receipt_creation_date_ms": "1523922838000",
"receipt_creation_date_pst": "2018-04-16 16:53:58 America/Los_Angeles",
"request_date": "2018-04-17 03:25:42 Etc/GMT",
"request_date_ms": "1523935542798",
"request_date_pst": "2018-04-16 20:25:42 America/Los_Angeles",
"original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
"original_purchase_date_ms": "1375340400000",
"original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
"original_application_version": "1.0",
"in_app": []
}
Run Code Online (Sandbox Code Playgroud)
我担心此收据的重放攻击。在重放攻击中,一个设备购买了应用程序并提交了有效收据,但另一台未经授权的设备存储并传输了第一个收据的精确副本。由于第一张收据由 Apple 签署,因此副本似乎有效。
理想情况下,我们会通过观察收据中的唯一标识符来击败重放攻击;如果有人试图重新传输相同的收据 ID,我们就会知道它是重复的。transaction_identifier
正是出于这个原因,IAP 收据包含一个字段。
但似乎没有唯一标识符可用于识别付费应用收据的重放攻击。黑客可以从不同的设备向我们重新传输此收据,我们将无法知道它是复制的收据还是新的原始收据。
话虽如此,我的眼睛被吸引到那些_id
在沙箱中收到的0号:adam_id
,app_item_id
,和download_id
。我们可以使用其中任何一个来识别重复收据吗?或者有没有其他更好的方法来处理这个问题?
我正在准备从我的服务器验证 App Store 应用程序内购买收据,一切似乎都运行良好,除了我看不到任何方法可以为 Apple 的 Sandbox 和生产环境创建单独的共享机密。
我希望共享的秘密是分开的,这样我就可以安全地将 Sandbox 放在代码存储库的配置文件中,例如用于单元测试。我只会在我们的生产环境的配置文件中保留生产共享的秘密。
我似乎找不到任何方法来做到这一点。我只是错过了什么吗?
I have a one year auto-renewable subscription in my app with a three day free trial. According to Apple, while testing in the sandbox, a one year subscription is equivalent to one hour but it says nothing about how long the free trial is. Add to this, when I'm testing and I sign-up for the free trial, the receipt doesn't list a separate transaction for a free trial, it simply lists the first hour long subscription:
transactionIdentifier: 1000000408088544
purchaseDate: Sat …
我们最近将可购买的应用程序转换为“免费增值”模式。我们正在使用 Bundle.main.appStoreReceiptURL 来拉取收据,然后检查“original_application_version”以查看用户是否从 App Store 下载了较旧的付费版本,或者他们是否下载了较新的免费版本,并且在应用内购买了非消耗品升级到完整版。
这在测试 Sandbox 时非常有效,但在生产中,旧版本的应用程序无法正确验证它们是否在免费增值版本之前下载。
以下代码使用 productionStoreURL 和从 Bundle.main.appStoreReceiptURL 获得的收据调用:
private let productionStoreURL = URL(string: "https://buy.itunes.apple.com/verifyReceipt")
private let sandboxStoreURL = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")
private func verifyIfPurchasedBeforeFreemium(_ storeURL: URL, _ receipt: Data) {
do {
let requestContents:Dictionary = ["receipt-data": receipt.base64EncodedString()]
let requestData = try JSONSerialization.data(withJSONObject: requestContents, options: [])
var storeRequest = URLRequest(url: storeURL)
storeRequest.httpMethod = "POST"
storeRequest.httpBody = requestData
URLSession.shared.dataTask(with: storeRequest) { (data, response, error) in
DispatchQueue.main.async {
if data != nil {
do {
let jsonResponse = …
Run Code Online (Sandbox Code Playgroud) Apple 提供了一个端点来验证收据:https : //buy.itunes.apple.com/verifyReceipt并警告不要从应用程序调用端点
无法直接在用户设备和 App Store 之间建立可信连接,因为您无法控制该连接的任何一端,因此容易受到中间人攻击。
据说,安全的方法是先将收据发送到“我自己的”服务器,然后从自己的服务器与Apple端点通信。
老实说,我不明白它如何帮助提高安全级别。是的,我不控制/verifyReceipt
端点,但 Apple 希望能做到。为什么
手机 <-> 我的服务器 <-> 苹果服务器比手机好 <-> 苹果服务器?
您能否从黑客(或中间人)的角度详细说明这一点?在后一种情况下,他将如何篡改收据/回复,而在前一种情况下,是什么让他感到困难?
ios ×9
storekit ×3
app-store ×2
objective-c ×2
swift ×2
testing ×2
itunes-store ×1
rmstore ×1
sandbox ×1
swift3 ×1
testflight ×1