我只有一个订阅组,它有 3 种产品:
1 week
1 month
1 year
在自动续订订阅中,如果用户降级到另一个方案,新的降级计划将在下一次续订中激活。(完成目前的高等方案后)
对于升级,新升级的计划在取消旧的降级计划后立即激活,并退还之前的降级计划。
对于取消,如果用户取消了一个计划,那么
latest_receipt_info
我们会通过这个名称获得当天的日期cancellation_date
。通常这里不会显示。
基于这 3 个条件,我正在处理isSubscriptionActive
升级、降级和取消状态的状态。
在这里,我在(购买产品)和(恢复产品)委托的receiptValidation
每笔成功交易后调用该函数。updatedTransactions
paymentQueueRestoreCompletedTransactionsFinished
在receiptValidation
函数内部获得 JSON 响应后,这就是我检查升级、降级和取消订阅的方式。
latest_receipt_info
在一个单独的函数中,我从该 JSON中创建了一个所有可用的对象数组。在这里我也添加cancellation_date
属性如果它在latest_receipt_info
字典中可用。这是因为此属性仅在用户从苹果支持取消订阅时才会出现。正常响应不包含此内容。然后在另一个函数中,我传递这个数组并根据这些检查返回一个布尔值(isSubscriptionActive):
a) Get the highest `expire_date` from that `latest_receipt_info` object array and find out that object. b) Compare the `expire_date` of this object with `current_date` c) If it is greater or equal to `current_date` then set `isSubscriptionActive = true` otherwise `isSubscriptionActive = false` d) If it's true then check if the `cancel_date` of that object is `nil` or not. e) If its `nil` then `isSubscriptionActive = true` otherwise `isSubscriptionActive = false`
代码:
latest_receipt_info
对象:
struct LatestReceiptInfo {
var productId: String?
var expiresDate: Date? = nil
var isInIntroOffer_period: Bool?
var isTrialPeriod: Bool?
var cancellationDate: Date? = nil
}
func receiptValidation
:
func receiptValidation(completion: @escaping(_ isPurchaseSchemeActive: Bool, _ error: Error?) -> ()) {
let receiptFileURL = Bundle.main.appStoreReceiptURL
guard let receiptData = try? Data(contentsOf: receiptFileURL!) else {
//This is the First launch app VC pointer call
completion(false, nil)
return
}
let recieptString = receiptData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
let jsonDict: [String: AnyObject] = ["receipt-data" : recieptString as AnyObject, "password" : AppSpecificSharedSecret as AnyObject]
do {
let requestData = try JSONSerialization.data(withJSONObject: jsonDict, options: JSONSerialization.WritingOptions.prettyPrinted)
let storeURL = URL(string: self.verifyReceiptURL)!
var storeRequest = URLRequest(url: storeURL)
storeRequest.httpMethod = "POST"
storeRequest.httpBody = requestData
let session = URLSession(configuration: URLSessionConfiguration.default)
let task = session.dataTask(with: storeRequest, completionHandler: { [weak self] (data, response, error) in
do {
if let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary {
//print("json response \(jsonResponse)")
//1. Get all latestInfoReceiptObjects in an array
//2. Get the object of highest expire_date from latestInfoReceiptObjects array
//3. Compare this highest expire_date with current time
//4. If it is greater or equal to current time then set isActivePurchase = true otherwise isActivePurchase = false
//5. If it's true then check if the cancel_date of that object which has highest expire date is nil. If its nil then isActivePurchase = true otherwise isActivePurchase = false
//1. Get all latestInfoReceiptObjects in an array
if let latestInfoReceiptObjects = self?.getLatestInfoReceiptObjects(jsonResponse: jsonResponse) {
let purchaseStatus = self?.isPurchaseActive(latestReceiptInfoArray: latestInfoReceiptObjects)
completion(purchaseStatus!, nil)
}
}
} catch let parseError {
completion(false, parseError)
}
})
task.resume()
} catch let parseError {
completion(false, parseError)
}
}
制作一个数组latest_receipt_info
:
func getLatestInfoReceiptObjects(jsonResponse: NSDictionary) -> [LatestReceiptInfo]? {
if let receiptInfo: NSArray = jsonResponse["latest_receipt_info"] as? NSArray {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
var latestReceiptInfoArray = [LatestReceiptInfo]()
for receiptInf in receiptInfo {
let recInf = receiptInf as! NSDictionary
var productId: String?
if let product_id = recInf["product_id"] as? String {
productId = product_id
} else {
productId = nil
}
var expiresDate: Date? = nil
if let expires_date = recInf["expires_date"] as? String {
expiresDate = formatter.date(from: expires_date)!
} else {
expiresDate = nil
}
var isInIntroOfferPeriod: Bool? = nil
if let is_in_intro_offer_period = recInf["is_in_intro_offer_period"] as? String {
if is_in_intro_offer_period.contains("true") {
isInIntroOfferPeriod = true
} else {
isInIntroOfferPeriod = false
}
} else {
isInIntroOfferPeriod = nil
}
var isTrialPeriod: Bool? = nil
if let is_trial_period = recInf["is_trial_period"] as? String {
if is_trial_period.contains("true") {
isTrialPeriod = true
} else {
isTrialPeriod = false
}
} else {
isTrialPeriod = nil
}
var cancelDate: Date? = nil
if let cancellation_date = recInf["cancellation_date"] as? String {
cancelDate = formatter.date(from: cancellation_date)!
} else {
cancelDate = nil
}
latestReceiptInfoArray.append(LatestReceiptInfo(productId: productId, expiresDate: expiresDate, isInIntroOffer_period: isInIntroOfferPeriod, isTrialPeriod: isTrialPeriod, cancellationDate: cancelDate))
}
return latestReceiptInfoArray
} else {
return nil
}
}
a), b), c), d), e) 检查:
func isPurchaseActive(latestReceiptInfoArray: [LatestReceiptInfo]) -> Bool {
var isSubsActive = true
//2. Get the object of highest expire_date from latestInfoReceiptObjects array
//3. Compare this highest expire_date with current time
//4. If it is greater or equal to current time then set isActivePurchase = true otherwise isActivePurchase = false
//5. If it's true then check if the cancel_date of that object which has highest expire date is nil. If its nil then isActivePurchase = true otherwise isActivePurchase = false
//2. Get the object of highest expire_date from latestInfoReceiptObjects array
let latestReceiptInfoForHighestExpireDate = latestReceiptInfoArray
.filter { $0.expiresDate != nil }
.max { $0.expiresDate! < $1.expiresDate! }
isIntroductoryOfferActive = latestReceiptInfoForHighestExpireDate?.isInIntroOffer_period
//3. Compare this highest expire_date with current time
let currDate = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
let currentDateString = formatter.string(from: currDate)
let currentDate = formatter.date(from: currentDateString)
print("expireDate \(String(describing: latestReceiptInfoForHighestExpireDate?.expiresDate))")
print("currentDate \(String(describing: currentDate!))")
//4. If it is greater or equal to current time then set isActivePurchase = true otherwise isActivePurchase = false
if currentDate!.compare((latestReceiptInfoForHighestExpireDate?.expiresDate)!) == .orderedAscending {
isSubsActive = true
} else if currentDate!.compare((latestReceiptInfoForHighestExpireDate?.expiresDate)!) == .orderedDescending {
isSubsActive = false
} else if currentDate!.compare((latestReceiptInfoForHighestExpireDate?.expiresDate)!) == .orderedSame {
isSubsActive = true
}
//5. If it's true then check if the cancel_date of that object which has highest expire date is nil. If its nil then isActivePurchase = true otherwise isActivePurchase = false
if isSubsActive == true {
if latestReceiptInfoForHighestExpireDate?.cancellationDate == nil {
isSubsActive = true
} else {
isSubsActive = false
}
}
return isSubsActive
}
我知道如果我只使用苹果通知会容易得多,但现在我需要像上面那样做。请分享你的想法。
谢谢!