Posts

Post marked as solved
4 Replies
1.1k Views
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?
Posted Last updated
.
Post not yet marked as solved
2 Replies
3.1k Views
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?
Posted Last updated
.