In my auto renewable subscription, I am always checking expires_date
of latest_receipt_info
from my validation receipt. If the expires_date
is greater than my current time then I am giving my users all the premium facilities of my application, if not then I bring him to the purchase view controller.
Now my concern is:
- What if user cancel his Auto Renewable subscription from apple support?
- What if he turns off the auto renewing subscription of my application?
- What If user upgrade from one subscription to another subscription (Either upgrade or downgrade)
In the above three cases should I do some additional checking besides comparing expires_date
with current date
?
My receipt validation:
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)")
if let expiresDate = self?.getPurchaseAndExpirationDateFromResponse(jsonResponse) {
//print("expiresDate \(expiresDate)")
let purchaseStatus = self?.isSubscriptionActive(expireDate: expiresDate)
if let purchaseStatus = purchaseStatus {
completion(purchaseStatus, nil)
}
}
}
} catch let parseError {
completion(false, parseError)
}
})
task.resume()
} catch let parseError {
completion(false, parseError)
}
}
My JSON response:
json response {
environment = Sandbox;
"latest_receipt" = "***";
"latest_receipt_info" = (
{
"expires_date" = "2022-02-15 07:33:27 Etc/GMT";
"expires_date_ms" = 1644910407000;
"expires_date_pst" = "2022-02-14 23:33:27 America/Los_Angeles";
"in_app_ownership_type" = PURCHASED;
"is_in_intro_offer_period" = false;
"is_trial_period" = false;
"original_purchase_date" = "2022-02-15 06:29:29 Etc/GMT";
"original_purchase_date_ms" = 1644906569000;
"original_purchase_date_pst" = "2022-02-14 22:29:29 America/Los_Angeles";
"original_transaction_id" = 1000000968987899;
"product_id" = "com.test66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
"purchase_date" = "2022-02-15 06:33:27 Etc/GMT";
"purchase_date_ms" = 1644906807000;
"purchase_date_pst" = "2022-02-14 22:33:27 America/Los_Angeles";
quantity = 1;
"subscription_group_identifier" = 20915143;
"transaction_id" = 1000000968989231;
"web_order_line_item_id" = 1000000072680194;
},
{
"expires_date" = "2022-02-15 06:33:27 Etc/GMT";
"expires_date_ms" = 1644906807000;
"expires_date_pst" = "2022-02-14 22:33:27 America/Los_Angeles";
"in_app_ownership_type" = PURCHASED;
"is_in_intro_offer_period" = false;
"is_trial_period" = true;
"original_purchase_date" = "2022-02-15 06:29:29 Etc/GMT";
"original_purchase_date_ms" = 1644906569000;
"original_purchase_date_pst" = "2022-02-14 22:29:29 America/Los_Angeles";
"original_transaction_id" = 1000000968987899;
"product_id" = "com.test66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
"purchase_date" = "2022-02-15 06:29:27 Etc/GMT";
"purchase_date_ms" = 1644906567000;
"purchase_date_pst" = "2022-02-14 22:29:27 America/Los_Angeles";
quantity = 1;
"subscription_group_identifier" = 20915143;
"transaction_id" = 1000000968987899;
"web_order_line_item_id" = 1000000072680193;
}
);
"pending_renewal_info" = (
{
"auto_renew_product_id" = "com.test66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
"auto_renew_status" = 1;
"original_transaction_id" = 1000000968987899;
"product_id" = "com.test66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
}
);
receipt = {
"adam_id" = 0;
"app_item_id" = 0;
"application_version" = 1;
"bundle_id" = "com.test66.InAppPurchasePT";
"download_id" = 0;
"in_app" = (
{
"expires_date" = "2022-02-15 07:33:27 Etc/GMT";
"expires_date_ms" = 1644910407000;
"expires_date_pst" = "2022-02-14 23:33:27 America/Los_Angeles";
"in_app_ownership_type" = PURCHASED;
"is_in_intro_offer_period" = false;
"is_trial_period" = false;
"original_purchase_date" = "2022-02-15 06:29:29 Etc/GMT";
"original_purchase_date_ms" = 1644906569000;
"original_purchase_date_pst" = "2022-02-14 22:29:29 America/Los_Angeles";
"original_transaction_id" = 1000000968987899;
"product_id" = "com.test66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
"purchase_date" = "2022-02-15 06:33:27 Etc/GMT";
"purchase_date_ms" = 1644906807000;
"purchase_date_pst" = "2022-02-14 22:33:27 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000968989231;
"web_order_line_item_id" = 1000000072680194;
},
{
"expires_date" = "2022-02-15 06:33:27 Etc/GMT";
"expires_date_ms" = 1644906807000;
"expires_date_pst" = "2022-02-14 22:33:27 America/Los_Angeles";
"in_app_ownership_type" = PURCHASED;
"is_in_intro_offer_period" = false;
"is_trial_period" = true;
"original_purchase_date" = "2022-02-15 06:29:29 Etc/GMT";
"original_purchase_date_ms" = 1644906569000;
"original_purchase_date_pst" = "2022-02-14 22:29:29 America/Los_Angeles";
"original_transaction_id" = 1000000968987899;
"product_id" = "com.test66.InAppPurchasePT.AutoRenewableGroup.ARenewable6";
"purchase_date" = "2022-02-15 06:29:27 Etc/GMT";
"purchase_date_ms" = 1644906567000;
"purchase_date_pst" = "2022-02-14 22:29:27 America/Los_Angeles";
quantity = 1;
"transaction_id" = 1000000968987899;
"web_order_line_item_id" = 1000000072680193;
}
);
"original_application_version" = "1.0";
"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";
"receipt_creation_date" = "2022-02-15 06:33:20 Etc/GMT";
"receipt_creation_date_ms" = 1644906800000;
"receipt_creation_date_pst" = "2022-02-14 22:33:20 America/Los_Angeles";
"receipt_type" = ProductionSandbox;
"request_date" = "2022-02-15 06:33:21 Etc/GMT";
"request_date_ms" = 1644906801424;
"request_date_pst" = "2022-02-14 22:33:21 America/Los_Angeles";
"version_external_identifier" = 0;
};
status = 0;
}
json response
. I saw in the below post that I need to checkcancellation_date_ms
but it's not available in my json response. Will it appear If somebody cancel in production? How am I checking this case If I haven't set up server side configuration? Thanks! #5120677 – Draytoncancellation_date_ms
if the purchase has been cancelled, but you are vulnerable to main-in-the-middle attacks – Giovannigipvalidation end point
? Thanks! – Draytoncancellation_date_ms
in the response? Am I missing something? – Draytoncancellation_date_ms
be in thelatest_receipt_info
if user cancel from apple support? Then I will write the code to handle it as well in my code, although I haven't configured the server listening configuration. Thanks! – Drayton