Swift: 如何将 Date() 转换为 Apple 服务器的时区以验证收据?

Swift: How to convert Date() to timezone of Apple's server to validate receipt?

使用Swift 3

当我调用这段代码时,它显示为我的时区

let date = Date()
let todayDate = formatter.string(from: date)
print(todayDate)

我调用了 StoreKit 收据的 JSON 响应来检查 original_purchase_dateexpires_date 将其与 todayDate 进行比较以验证收据。

我想做的,比如

if (todayDate > expires_date ) {
    cancel subscription
}

如果 Apple 的 purchase_date 和 expires_date 在 GMT 时区,而 todayDate 在用户所在的任何时区,我无法匹配日期。

所以我只需要在调用 Date() 时转换用户所在的任何时区,并将其转换为 GMT,就像 Apple 的服务器一样,这样我就可以检查 todayDate 是否已通过自动更新订阅的过期数据。

此外,这是防止应用内黑客攻击的好方法吗?我使用 php 从我的服务器获得了收据,它从 Apple 验证了它。

if parseJSON["status"] as? Int == 0 {

print("Status Code for Receipt = 0!")

// Checking "latest_receipt_info"
if let receiptInfo: NSArray = parseJSON["latest_receipt_info"] as? NSArray {
    let lastReceipt = receiptInfo.lastObject as! NSDictionary

    // Get last receipt
    print("\nLAST RECEIPT INFORMATION: \n", lastReceipt)

    // Format date
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
    formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") as Locale!

    // Get "original_purchase_date" as NSDate
    let subscriptionBoughtDate: NSDate = formatter.date(from: lastReceipt["original_purchase_date"] as! String) as NSDate!
    print("\n   - DATE BOUGHT SUBSCRIPTION = \(subscriptionBoughtDate)\n")

    // Get "expires_date" as NSDate
    let subscriptionExpirationDate: NSDate = formatter.date(from: lastReceipt["expires_date"] as! String) as NSDate!
    print("\n   - DATE SUBSCRIPTION EXPIRES = \(subscriptionExpirationDate)\n")

    // Get Todays Date
    let date = Date()
    let todayDate = formatter.string(from: date)
    print("\n   - DATE TODAY = \(todayDate)\n")

    // See if current date has passed expired date
}

JSON 回应

LAST RECEIPT INFORMATION: 
{
"expires_date" = "2017-08-03 04:50:08 Etc/GMT";
"expires_date_ms" = 1501735808000;
"expires_date_pst" = "2017-08-02 21:50:08 America/Los_Angeles";
"is_trial_period" = false;
"original_purchase_date" = "2017-08-02 15:27:27 Etc/GMT";
"original_purchase_date_ms" = 1501687647000;
"original_purchase_date_pst" = "2017-08-02 08:27:27 America/Los_Angeles";
"original_transaction_id" = 1000000552288255;
"product_id" = "com.example.gg.month";
"purchase_date" = "2017-08-03 04:45:08 Etc/GMT";
"purchase_date_ms" = 1501735508000;
"purchase_date_pst" = "2017-08-02 21:45:08 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000568853433;
"web_order_line_item_id" = 1000000055887122;
}

- DATE BOUGHT SUBSCRIPTION = 2017-08-02 15:27:27 +0000


- DATE SUBSCRIPTION EXPIRES = 2017-08-03 04:50:08 +0000


- DATE TODAY = 2017-08-04 17:26:51 America/New_York

谢谢!

您只需将 DateFormatterTimeZone 属性 设置为 GMT。

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
formatter.timeZone = TimeZone(secondsFromGMT: 0)

一般性建议:当原生 Swift 替代项可用时,不要在 Swift 中使用 Foundation 类型,例如 ArrayDictionaryLocaleDate。使用这些代替 NSArrayNSDictionaryNSLocaleNSDate.

我根本不会乱用日期格式化程序。 JSON 中有各种日期,后缀为“_ms”。这些是基于 Unix "epoch date" 的日期,但乘以 1000。

如果您需要做的只是查看当前日期是否在订阅开始日期和结束日期之间,您可以直接比较那些以“_ms”结尾的日期值,作为整数值。

如果您需要将这些日期之一转换为 Date 对象,那很容易。

这是一个例子:

let expiresDateValue = Double(lastReceipt["expires_date_ms"]) / 1000
let expiresDate = Date(timeIntervalSince1970: expiresDateValue)

编辑:

Swift 严格的类型转换使这比它应该的更痛苦。

这样做:

var expiresSeconds: Double = 0
if let expiresString = lastReceipt["expires_date_ms"] as? String,
  let expiresMS = Double(expiresString) {
  expiresSeconds = expiresMS / 1000
}