I am working in autorenewable subscriptions in app purchases with swiftystorekit but i am facing the issue Reciept validation error. I verify all the products in home screen during verify i am facing this issue. I get help from https://github.com/bizz84/SwiftyStoreKit and Videos series https://youtu.be/6ekX7FK0OTY
but i unable to resolve this issue please help me.
Please help.
Code is given below
its go to in error section.
Check error
image
//MARK: - Verify Subscription
func verifyPurchases(id:String,secretkey:String,type: SubscriptionType,validDuration:TimeInterval? = nil){
DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
self.showIndicator(caption: "Loading...")
}
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: secretkey)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
// Verify the purchase of a Subscription
switch type {
case .simple:
// Verify the purchase of Consumable or NonConsumable
let purchaseResult = SwiftyStoreKit.verifyPurchase(
productId: id,
inReceipt: receipt)
switch purchaseResult {
case .purchased(let receiptItem):
print("\(id) is purchased: \(receiptItem)")
self.hideIndicator()
case .notPurchased:
print("The user has never purchased \(id)")
self.hideIndicator()
}
case .autoRenewable:
let purchaseResult = SwiftyStoreKit.verifySubscription(
ofType: .autoRenewable, // or .nonRenewing (see below)
productId: id,
inReceipt: receipt)
switch purchaseResult {
case .purchased(let expiryDate, let items):
print("\(id) is valid until \(expiryDate)\n\(items)\n")
if id == self.purchasesIds[0]{
self.subsStatus = "Monthly"
self.uploadData(expiryDate:expiryDate)
}else if id == self.purchasesIds[1]{
self.subsStatus = "Yearly"
self.uploadData(expiryDate: expiryDate)
}
self.hideIndicator()
case .expired(let expiryDate, let items):
print("\(id) is expired since \(expiryDate)\n\(items)\n")
self.setData()
self.hideIndicator()
case .notPurchased:
print("The user has never purchased \(id)")
self.setData()
self.hideIndicator()
}
case .nonRenewing:
// validDuration: time interval in seconds
guard let validDuration = validDuration else {return}
let purchaseResult = SwiftyStoreKit.verifySubscription(
ofType: .nonRenewing(validDuration: validDuration),
productId: id,
inReceipt: receipt)
switch purchaseResult {
case .purchased(let expiryDate, let items):
print("\(id) is valid until \(expiryDate)\n\(items)\n")
self.hideIndicator()
case .expired(let expiryDate, let items):
print("\(id) is expired since \(expiryDate)\n\(items)\n")
self.hideIndicator()
case .notPurchased:
print("The user has never purchased \(id)")
self.hideIndicator()
}
}
case .error(let error):
print("Receipt verification failed: \(error)")
self.errorWithMsgTitle(title: "Receipt verification failed", message: "Receipt verification failed: \(error)")
self.hideIndicator()
}
}
}
Related
I am having issues utilizing a pay function given by the stripe documentation
Stripe documentation: https://stripe.com/docs/payments/accept-a-payment
All my server side & client side keys are the same testing keys.
I have successfully retrieved a payment intent with the value
pi_1ITiM3KCSIKL5fqUAMGk32Do_secret_cJfvlRxtnnTuU8VIScj8NCz12
Error message:
No such payment_intent: \ 'pi_1ITiM3KCSIKL5fqUAMGk32Do \ '
Not sure why the error message includes: (possibly json issue)
\ '
Any help would be much appreciated on why this is happening.
var paymentIntentClientSecret: String?
func pay() {
guard let paymentIntentClientSecret = paymentIntentClientSecret else {
return;
}
print(paymentIntentClientSecret) // pi_1ITiM3KCSIKL5fqUAMGk32Do_secret_cJfvlRxtnnTuU8VIScj8NCz12
// Collect card details
let cardParams = creditCardField.cardParams//cardTextField.cardParams
let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: nil, metadata: nil)
let paymentIntentParams = STPPaymentIntentParams(clientSecret: paymentIntentClientSecret)
print(paymentIntentParams)
paymentIntentParams.paymentMethodParams = paymentMethodParams
// Submit the payment
let paymentHandler = STPPaymentHandler.shared()
paymentHandler.confirmPayment(paymentIntentParams, with: self) { (status, paymentIntent, error) in
switch (status) {
case .failed:
//self.displayAlert(title: "Payment failed", message: error?.localizedDescription ?? "")
print("failed: \(String(describing: error?.localizedDescription))")
break
case .canceled:
//self.displayAlert(title: "Payment canceled", message: error?.localizedDescription ?? "")
print("cancled: \(String(describing: error?.localizedDescription))")
break
case .succeeded:
//self.displayAlert(title: "Payment succeeded", message: paymentIntent?.description ?? "", restartDemo: true)
print("succeeded: \(String(describing: error?.localizedDescription))")
break
#unknown default:
fatalError()
break
}
}
}
Response body:
{
"error": {
"code": "resource_missing",
"doc_url": "https://stripe.com/docs/error-codes/resource-missing",
"message": "No such payment_intent: 'pi_1ITh8QKCSIKL5fqU7VjJqHH0'",
"param": "intent",
"type": "invalid_request_error"
}
}
“No such...” errors are usually caused by either a mismatch in API keys (e.g. using a mixture of your test plus live keys) or by trying to access objects that exist on a different account (e.g. trying to perform an operation from your platform account on an object that was created on a connected account).
Most likely you're using a publishable key from one account and a secret key from another (assuming you're not using Connect).
i did all the code regarding to the Stripe and i followed the documentation of the stripe in which i i am calling one api to get the secret key from the server n which is coming..and after that i am passing it ot the "STPPaymentHandler.shared()"..but i am getting the error STPPaymentHandlerActionStatus error Optional("No such setupintent: (null)") a..please help me if you know thank you in advance
below the code which i did
i followed this documentation
https://stripe.com/docs/payments/accept-a-payment
//method to get secrete key
func checkout() {
let apikey = UserDefaults.standard.value(forKey: keyParameter.apikey.rawValue) as! String
let dic = ["apikey":apikey,"amount":"5000"]
Webhelper.sharedInstance.apiPostRequest(apiUrl: GlobalConstant.stripe_token, parameter: dic, success: { (success) in
print("success from the server is \(success)")
do{
let responseResult = try Global.sharedInstance.decode(jwtToken: success)
let message = Global.sharedInstance.getStringValue(responseResult["Message"] as AnyObject)
if let status = responseResult["result"] as? NSNumber {
if status == 1{
let responseDic = responseResult["Secrate"] as! NSDictionary
self.setupIntentClientSecret = responseDic.value(forKey: "clientSecret") as! String
let apikey = responseDic.value(forKey: "publishableKey") as! String
Stripe.setDefaultPublishableKey(apikey)
print(" self.setupIntentClientSecret self.setupIntentClientSecret \(self.setupIntentClientSecret)")
}else if status == 0{
Global.sharedInstance.ShowMessagePopup(Viewobj: self, title: "", Message: message)
}
}
}catch{
print("cought error in the catch \(error.localizedDescription)")
}
}) { (error) in
print("error for the server is \(error.localizedDescription)")
}
}
///this is the method to complete the payment
#objc func pay() {
// Collect card details
let cardParams = self.paymentTextField.cardParams
// Collect the customer's email to know which customer the PaymentMethod belongs to.
let billingDetails = STPPaymentMethodBillingDetails()
billingDetails.email = "sunil#gmial.com"//emailTextField.text
// Create SetupIntent confirm parameters with the above
let paymentMethodParams = STPPaymentMethodParams(card: cardParams, billingDetails: billingDetails, metadata: nil)
print("setupIntentClientSecret inside method\(setupIntentClientSecret)")
let setupIntentParams = STPSetupIntentConfirmParams(clientSecret: setupIntentClientSecret)
setupIntentParams.paymentMethodParams = paymentMethodParams
print("secrete \(setupIntentClientSecret)")
// Complete the setup
let paymentHandler = STPPaymentHandler.shared()
paymentHandler.confirmSetupIntent(withParams: setupIntentParams, authenticationContext: self) { status, setupIntent, error in
print("success from the server is setupIntent\(setupIntent) status \(status) error \(error?.localizedDescription)")
switch (status) {
case .failed:
self.displayAlert(title: "Setup failed", message: error?.localizedDescription ?? "")
// print("\(error?.localizedDescription)")
break
case .canceled:
self.displayAlert(title: "Setup canceled", message: error?.localizedDescription ?? "")
break
case .succeeded:
self.displayAlert(title: "Setup succeeded", message: setupIntent?.description ?? "", restartDemo: true)
break
#unknown default:
fatalError()
break
}
}
}
How can I use SwiftyStoreKit to check if a user purchased a product with product ID com.X.X? I want to use the SwiftyStoreKit code to check if a user already purchased a product using inapp purchase system? I want to do that to determine whether I should show them a feature. How can I use Apple's inapp purchase system to check if a user already purchased a product? using swift
func checkIfPurchaed () {
let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
let productId = "com.app.name.productID"
// Verify the purchase of a Subscription
let purchaseResult = SwiftyStoreKit.verifySubscription(
ofType: .renewing //or .nonRenewing
productId: productId,
inReceipt: receipt)
switch purchaseResult {
case .purchased(let expiryDate, let items):
print("\(productId) is valid until \(expiryDate)\n\(items)\n")
case .expired(let expiryDate, let items):
print("\(productId) is expired since \(expiryDate)\n\(items)\n")
case .notPurchased:
print("The user has never purchased \(productId)")
}
case .error(let error):
print("Receipt verification failed: \(error)")
}
}
}
My VC like this:
var coins = 50 // coins
override func viewDidLoad() {
super.viewDidLoad()
if(SKPaymentQueue.canMakePayments()) {
//print("enabled, loading")
let productID: NSSet = NSSet(objects: "com.tahabuyruk.taha.coinsal", "com.tahabuyruk.taha.reklam") // my products Id
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
} else {
print("please enable IAPS")
}
}
//I have 2 products on itunesconnect
#IBAction func btnRemoveAds(_ sender: Any) {
print("rem ads")
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.tahabuyruk.taha.reklam") {
// ad product id
p = product
buyProduct()
}
}
}
// my bundle id is com.tahabuyruk.taha
// my product id is com.tahabuyruk.taha.coins
#IBAction func satinAl(_ sender: Any) { // addCoin Button
for product in list {
let prodID = product.productIdentifier
if(prodID == "com.tahabuyruk.taha.coinsal") {
p = product
buyProduct()
}
}
}
func buyProduct() {
print("buy " + p.productIdentifier)
let pay = SKPayment(product: p)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(pay as SKPayment)
}
func removeAds() {
lblAd.removeFromSuperview()
}
func addCoins() {
coins += 50
lblCoinAmount.text = "\(coins)"
}
var list = [SKProduct]()
var p = SKProduct()
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("product request")
let myProduct = response.products // myProduct is always be 0 . I don't know why .
for product in myProduct {
print("product added")
print(product.productIdentifier)
print(product.localizedTitle)
print(product.localizedDescription)
print(product.price)
list.append(product)
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
print("transactions restored")
for transaction in queue.transactions {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
switch prodID {
case "com.tahabuyruk.taha.reklam":// ad product id
print("remove ads")
removeAds()
case "com.tahabuyruk.taha.coinsal":
print("add coins to account")
addCoins()
default:
print("IAP not found")
}
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
print("add payment")
for transaction: AnyObject in transactions {
let trans = transaction as! SKPaymentTransaction
print(trans.error)
switch trans.transactionState {
case .purchased:
print("buy ok")
print(p.productIdentifier)
let prodID = p.productIdentifier
switch prodID {
case "com.tahabuyruk.taha.reklam":// ad product id
print("remove ads")
removeAds()
case "com.tahabuyruk.taha.coinsal":
print("add coins to account")
addCoins()
default:
print("IAP not found")
}
queue.finishTransaction(trans)
case .failed:
print("buy error")
queue.finishTransaction(trans)
break
default:
print("Default")
break
}
}
}
Always myProduct is 0.
What's wrong with this code?
I want to know why always be 0?
I handle this problem , look for Agreements , Tax and Banking and check that your banking, contact and tax information has been filled up
I am doing simple in app purchase application. At the time of product load I simply restore all my previous purchase, so I start loading indicator when I start loading product but in some device I already used inapp id so every time I load the product in that device some type of alert come and if I press cancel then nothing happen and my loading indicator goes infinite.
Here I have screenshot too.
extension IAPHelper: SKPaymentTransactionObserver {
public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
if productIdentifiers.contains(transaction.payment.productIdentifier) {
switch (transaction.transactionState) {
case .purchased:
complete(transaction: transaction)
break
case .failed:
fail(transaction: transaction)
break
case .restored:
restore(transaction: transaction)
break
case .deferred:
print("denied")
break
case .purchasing:
break
}
}
}
if productsRestoreCompletionHandler != nil
{
productsRestoreCompletionHandler = nil
}
}
private func complete(transaction: SKPaymentTransaction) {
print("complete...")
// deliverPurchaseNotificationFor(identifier: transaction.payment.productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
productsPurchaseCompletionHandler?(true, transaction)
if productsPurchaseCompletionHandler != nil
{
productsPurchaseCompletionHandler = nil
}
}
private func restore(transaction: SKPaymentTransaction) {
guard let productIdentifier = transaction.original?.payment.productIdentifier else { return }
print("restore... \(productIdentifier)")
// deliverPurchaseNotificationFor(identifier: productIdentifier)
SKPaymentQueue.default().finishTransaction(transaction)
productsRestoreCompletionHandler?(true, transaction)
}
private func fail(transaction: SKPaymentTransaction) {
print("fail...")
if let transactionError = transaction.error as? NSError {
if transactionError.code != SKError.paymentCancelled.rawValue {
print("Transaction Error: \(transaction.error?.localizedDescription)")
}
}
SKPaymentQueue.default().finishTransaction(transaction)
if productsRestoreCompletionHandler != nil
{
productsRestoreCompletionHandler?(false, transaction)
productsRestoreCompletionHandler = nil
}
if productsPurchaseCompletionHandler != nil
{
productsPurchaseCompletionHandler?(false, transaction)
productsPurchaseCompletionHandler = nil
}
}
private func deliverPurchaseNotificationFor(identifier: String?) {
guard let identifier = identifier else { return }
purchasedProductIdentifiers.insert(identifier)
// UserDefaults.standard.set(true, forKey: identifier)
// UserDefaults.standard.synchronize()
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: IAPHelper.IAPHelperPurchaseNotification), object: identifier)
}
}
When product load
//MARK:
//MARK: load the product
func getProduct()
{
let userData = getUserDataFromFile()
obj = IAPHelper(productIds: NetFishProducts.productIdentifiers)
if checkInternetConnection()
{
SINGLETON.startLoadingActivity(self.view)
obj.requestProducts { (isSuccess, arrProduct) in
if isSuccess == true
{
self.setProduct = Set<SKProduct>(arrProduct! as [SKProduct])
self.btnSignup.isUserInteractionEnabled = true
for p in arrProduct! {
print("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
if p.productIdentifier == NetFishProducts.monthlyPlan
{
self.setupLblMonth(withMothPrice: "\(p.price.floatValue)")
}
else
{
self.setupLblYear(withYearPrice: "\(p.price.floatValue)")
}
}
self.obj.requestRestoreProducts(completionHandler: { (isSuccess, transation) in
SINGLETON.stopLoadingActivity(self.view)
if isSuccess == true
{
let orignalTI = transation?.original?.transactionIdentifier
let userEmail = transation?.payment.applicationUsername
print("orignalTI:\(orignalTI)")
print("username:\(userEmail)")
if userEmail != nil && userData?.userEmail != userEmail
{
self.btnSignup.isUserInteractionEnabled = false
self.showAlertToUser("Information", MsgDesc: "You are login with different appstore account so login with correct appstore account")
return
}
}
else
{
self.btnSignup.isUserInteractionEnabled = false
}
},withUserName: (userData?.userEmail)!)
}
else
{
SINGLETON.stopLoadingActivity(self.view)
self.btnSignup.isUserInteractionEnabled = false
}
}
}
}