Title says it all. I ran into an issue whilst trying to purchase a monthly autorenewable subscription, but the productsRequest callback never happened. The system status page for apple says Sandbox is all good, but I'm fairly confident that's not up to date.I manually made a post request with Postman to verify a receipt, and did not get any response. Moreover, I tried to sign in as a different sandbox user, and I was unable to do so.Any reason for this? Is there an expected duration for this down time?Any particular reason the System Status page is displaying Sandbox as up and running when it is clearly not?
Post not yet marked as solved
Objective:I would like to redeem a subscription offer while an autorenewable subscription is currently active and not expired.What I've tried:I set up a Store Kit demo project on Xcode 10.2 in order to test out the new subscription offers. After following the WWDC 2019 keynotes and much troubleshooting I was able to achieve the following:Successfully set up a 1-month autorenewable subscription using StoreKit.Hit the /verifyReceipt endpoint and successfully decrypted the receipt data.Set up local server and successfully generated signature.Set up subscription offer (1 month free) on Appstore Connect.Successfully redeemed subscription offer after renewable subscription has expired.My current issue:Whenever I try to claim the subscription offer and my autorenewable subscription is still active, I get the following error from StoreKit on my logs:Error Domain=SKErrorDomain Code=0 "Cannot connect to iTunes Store" UserInfo={NSLocalizedDescription=Cannot connect to iTunes Store}Surprisingly, however, an alert box pops up upon trying to claim the offer saying "You're all set. Your purchase was successful. [Environment: Sandbox]" despite getting the above error message in the logs. According to the Apple Documentation on SKErrorDomain (link: https://developer.apple.com/documentation/storekit/skerror/code), Code 0 is an "Unknown Error". This is the brick wall I've hit.During the development process of this demo project, I received other error codes, such as ErrorCode=12, which means "invalid signature", which I resolved, so I'm sure there is nothing wrong with the signature. Check out my setup below for more context.I urge you to disregard my non-optimal coding practices here. I hacked this together as a proof of concept, not for production.This is the action for tapping the 'Claim Reward' button, which tries to redeem the subscription offer:// PrimaryVC.swift
@IBAction func aClaimReward(_ sender: UIButton) {
// Hard code offer information
let username = "mail@mysandbox.com" // sandbox username
guard let usernameData = username.data(using: .utf8) else { return }
let usernameHash = usernameData.md5().toHexString()
// Enums for simplifying the product identifiers.
let productIdentifier = IAPProduct.autoRenewable.rawValue
let offerIdentifier = IAPProduct.reward.rawValue
// Call prepare offer method and get discount in completion block
IAPService.shared.prepareOffer(usernameHash: usernameHash, productIdentifier: productIdentifier, offerIdentifier: offerIdentifier) { (discount) in
// Find the autorenewable subscription in products set
guard let product = IAPService.shared.products.filter({ $0.productIdentifier == IAPProduct.autoRenewable.rawValue }).first else {
return
}
// Complete transaction
self.buyProduct(product: product, forApplicationUsername: usernameHash, withOffer: discount)
}
}This is the code for the buyProduct() method, used at the end of the action above:// PrimaryVC.swift
func buyProduct(product: SKProduct, forApplicationUsername usernameHash: String, withOffer offer: SKPaymentDiscount) {
// Create payment object
let payment = SKMutablePayment(product: product)
// Apply username and offer to the payment
payment.applicationUsername = usernameHash
payment.paymentDiscount = offer
// Add payment to paymentQueue
IAPService.shared.paymentQueue.add(payment)
}I created an In-app purchases service class where much of the in-app purchase logic lives. This singleton is used in the button action detailed above, and the method used there follows:// IAPService.swift
import SwiftyJSON
import Alamofire
// ...
func prepareOffer(usernameHash: String, productIdentifier: String, offerIdentifier: String, completion: @escaping (SKPaymentDiscount) -> Void) {
// Create parameters dictionary
let parameters: Parameters = [
"appBundleID": "my.bundle.id",
"productIdentifier": productIdentifier, // "my.product.id",
"offerID": offerIdentifier, // "REFERRALBONUSMONTH"
"applicationUsername": usernameHash
]
// Generate new signature by making get request to local server.
// I used the starter code from the wwdc2019 lecture on subscription offers
AF.request("https://mylocalserver/offer", parameters: parameters).responseJSON { response in
var signature: String?
var keyID: String?
var timestamp: NSNumber?
var nonce: UUID?
switch response.result {
case let .success(value):
let json = JSON(value)
// Get required parameters for creating offer
signature = json["signature"].stringValue
keyID = json["keyID"].stringValue
timestamp = json["timestamp"].numberValue
nonce = UUID(uuidString: json["nonce"].stringValue)
case let .failure(error):
print(error)
return
}
// Create offer
let discountOffer = SKPaymentDiscount(identifier: offerIdentifier, keyIdentifier: keyID!, nonce: nonce!, signature: signature!, timestamp: timestamp!)
// Pass offer in completion block
completion(discountOffer)
}
}Conclusion:According to the WWDC2019 subscription offers lecture, users should be able to redeem a subscription offer even during an active subscription, but I continue to get SKErrorCode=0 when I try to redeem a subscription offer during an active subscription. I am able to redeem the subscription after the autorenewable subscription has expired, and I have verified the receipt and have seen the data for the subscription offer on the receipt.Any ideas on where I might be going wrong?