In app purchase not fully firing - ios

Whenever I conduct an in-app purchase in a sandbox environment, it acts like it is completing, when it really isn't. To be more specific, I click to buy more coins, I confirm that I want to buy them in the sandbox environment. Then it says "You're all set!" saying that I have completed the purchase. Well when I check my coins, nothing changed!
After looking through the code, I realized that the
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
...is not firing.
Full code:
import UIKit
import StoreKit
import AVFoundation
class InAppPurchases: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {
#IBOutlet weak var noAdsBtn: UIButton!
var product_id: String?
let defaultsAD = UserDefaults.standard
override func viewDidLoad() {
super.viewDidLoad()
product_id = "noads"
SKPaymentQueue.default().add(self)
//Check if product is purchased
if (defaultsAD.bool(forKey: "purchased")){
// Hide a view or show content depends on your requirement
// overlayView.hidden = true
noAdsBtn.backgroundColor = UIColor.red
noAdsBtn.isUserInteractionEnabled = false
} else {
print("false")
// noAds = true
// var NAD = UserDefaults.standard
// NAD.setValue(noAds, forKey: "nad")
// NAD.synchronize()
}
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func backBtnA(_ sender: Any) {
music2()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
#IBAction func Buy600(_ sender: Any) {
print("About to fetch the products")
product_id = "600coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy1500(_ sender: Any) {
print("About to fetch the products")
product_id = "1500coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy3500(_ sender: Any) {
print("About to fetch the products")
product_id = "3500coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy8000(_ sender: Any) {
print("About to fetch the products")
product_id = "8000coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buy25000(_ sender: Any) {
print("About to fetch the products")
product_id = "25000coins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buyTruckload(_ sender: Any) {
print("About to fetch the products")
product_id = "truckloadofcoins"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
#IBAction func buyNoAds(_ sender: Any) {
print("About to fetch the products")
product_id = "noads"
// We check that we are allow to make the purchase.
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
productsRequest.delegate = self;
productsRequest.start();
print("Fetching Products");
} else {
print("can't make purchases");
}
}
func buyProduct(product: SKProduct){
print("Sending the Payment Request to Apple");
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment);
//
SKPaymentQueue.default().add(self)
//^^??
}
func productsRequest (_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let count : Int = response.products.count
if (count>0) {
let validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == self.product_id) {
print(validProduct.localizedTitle)
print(validProduct.localizedDescription)
print(validProduct.price)
buyProduct(product: validProduct);
} else {
print(validProduct.productIdentifier)
}
} else {
print("nothing")
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Error Fetching product information");
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
print("Received Payment Transaction Response from Apple");
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .purchased:
print("Product Purchased");
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
if product_id == "noads"{
defaultsAD.set(true , forKey: "purchased")
noAdsBtn.backgroundColor = UIColor.red
noAdsBtn.isUserInteractionEnabled = false
noAds = true
var NAD = UserDefaults.standard
NAD.setValue(noAds, forKey: "nad")
NAD.synchronize()
}
//add coins
if product_id == "600coins"{
coins += 600
print("just bought 600 coins")
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "1500coins"{
coins += 1500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "3500coins"{
coins += 3500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "8000coins"{
coins += 8000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "25000coins"{
coins += 25000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
print("just boughtn 25k coins")
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
if product_id == "100000coins"{
coins += 100000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
}
// overlayView.hidden = true
break;
case .failed:
print("Purchased Failed");
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break;
case .restored:
print("Already Purchased");
SKPaymentQueue.default().restoreCompletedTransactions()
if product_id == "noads"{
defaultsAD.set(true , forKey: "purchased")
noAdsBtn.backgroundColor = UIColor.red
noAdsBtn.isUserInteractionEnabled = false
noAds = true
var NAD = UserDefaults.standard
NAD.setValue(noAds, forKey: "nad")
NAD.synchronize()
}else{
//add coins
if product_id == "600coins"{
coins += 600
print("already bought")
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "1500coins"{
coins += 1500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "3500coins"{
coins += 3500
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "8000coins"{
coins += 8000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "25000coins"{
coins += 25000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
if product_id == "100000coins"{
coins += 100000
var C = UserDefaults.standard
C.setValue(coins, forKey: "c")
C.synchronize()
}
}
default:
break;
}
}
}
}
func paymentQueue(_ queue: SKPaymentQueue,
updatedTransactions transactions: [SKPaymentTransaction]){
print("updating transactions")
}
func music2(){
// currentlyPlayingAudio = true
// print("\n\n\n\n\n\n\n\n\nview appeared...music??\n\n\n\n\n\n\n\n\n")
if soundFX == true{
let ButtonAudioURL2 = URL(fileURLWithPath: Bundle.main.path(forResource: "Click2", ofType: "mp3")!)
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ {
}
var error: NSError?
do {
audioPlayerClick = try AVAudioPlayer(contentsOf: ButtonAudioURL2)
} catch let error1 as NSError {
error = error1
}
audioPlayerClick.prepareToPlay()
// audioPlayer.volume = 0.3
audioPlayerClick.play()
}
}
func music3(){
// currentlyPlayingAudio = true
// print("\n\n\n\n\n\n\n\n\nview appeared...music??\n\n\n\n\n\n\n\n\n")
if soundFX == true{
let ButtonAudioURL3 = URL(fileURLWithPath: Bundle.main.path(forResource: "Toggle", ofType: "mp3")!)
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch _ {
}
do {
try AVAudioSession.sharedInstance().setActive(true)
} catch _ {
}
var error: NSError?
do {
audioPlayerClick2 = try AVAudioPlayer(contentsOf: ButtonAudioURL3)
} catch let error1 as NSError {
error = error1
}
audioPlayerClick2.prepareToPlay()
// audioPlayer.volume = 0.3
audioPlayerClick2.play()
}
}
}
One last thing; the IAP to remove ads (with id "noads") keeps returning "nothing" in the console. Any ideas why it won't successfully trigger? It is a non-consumable and is labeled in iTunes Connect as "Waiting for Upload".

Related

App crashing on Subscription on live mode in Swift5

I was working on apple subscription and have set two subscription plan on apple store for "monthly" and "yearly" and have set up all the code which is working perfectly on development and adhoc. But after placing build on App Store app crashes.
I have used firebase crashlytic which detected crash I have attached screenshot crash logs.
https://i.stack.imgur.com/e487d.png
Here my code for Subscription:
func getProducts(productIDs: [String]){
//self.showLoader()
print("Start requesting products ...")
//showAlert(text:"Start requesting products ...")
let request = SKProductsRequest(productIdentifiers: Set(productIDs))
request.delegate = self
request.start()
}
func buyProduct(product: SKProduct){
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
if response.products.isEmpty {
NotificationAlert().NotificationAlert(titles: "No subscription plan")
}else{
self.myProducts = response.products
for invalidIdentifier in response.invalidProductIdentifiers {
print(invalidIdentifier)
//NotificationAlert().NotificationAlert(titles:"Invalid Identifire")
}
print("Did receive response")
for fetchedProduct in response.products{
//DispatchQueue.main.async {
print("fetchedProduct:",fetchedProduct)
//showAlert(text:"Product Fetched")
//NotificationAmyProductslert().NotificationAlert(titles: "fetchedProduct:\(fetchedProduct)")
DispatchQueue.main.asyncAfter(deadline: .now()+1.0, execute: {
let price = self.getPrice(item: fetchedProduct)
if price == ""{
} else{
self.myProducts.append(fetchedProduct)
if fetchedProduct.productIdentifier == "com.motivatory.monthly"{
DispatchQueue.main.asyncAfter(deadline: .now()+0.3, execute: {
self.oPriceMonthlyLbl.text = price ?? ""
self.monthlyprice = price ?? ""
print(price ?? "")
self.productIDs.insert("com.motivatory.monthly",at: 0)
self.selectedPrice = price ?? ""
})
} else {
DispatchQueue.main.asyncAfter(deadline: .now()+0.3, execute: {
self.oPriceYearlyLbl.text = price ?? ""
self.selectedPrice = price ?? ""
self.yearlyPrice = price ?? ""
print(price ?? "")
self.productIDs.insert("com.motivatory.yearly",at: 1)
})
}
}
})
}
}
}
func getPrice(item: SKProduct) -> String? {
let numberFormatter = NumberFormatter()
let price = item.price
let locale = item.priceLocale
numberFormatter.numberStyle = .currency
numberFormatter.locale = locale
return numberFormatter.string(from: price)
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
print(transaction)
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .purchased:
purchaseTokenStr = trans.transactionIdentifier ?? ""
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
if self.purchased == true {
print("Product Purchased")
print(purchaseTokenStr)
receiptValidation()
}
break;
case .failed:
purchaseTokenStr = trans.transactionIdentifier ?? ""
NotificationAlert().NotificationAlert(titles: "Payment failed")
print("Purchased Failed");
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
SVProgressHUD.dismiss()
break;
case .restored:
print("Already Purchased")
purchaseTokenStr = trans.transactionIdentifier ?? ""
// receiptValidation()
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
default:
break
}
}
}
}
//added by me
// 4:
func finishTransaction(_ transaction: SKPaymentTransaction) -> Bool {
let productId = transaction.payment.productIdentifier
//print("Product \(productId) successfully purchased”)
print("Product \(productId) successfully purchased")
return true
}
func restorePurchases() {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
//If an error occurs, the code will\ go to this function
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
SVProgressHUD.dismiss()
NotificationAlert().NotificationAlert(titles: error.localizedDescription)
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
if queue.transactions.count == 0{
NotificationAlert().NotificationAlert(titles: "Please purchase a subscription plan")
SVProgressHUD.dismiss()
} else{
for transaction in queue.transactions {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
if self.purchaseTokenStr == t.transactionIdentifier {
switch prodID {
case "com.motivatory.yearly":
print("Your Yearly Plan has Restored Successfully")
NotificationAlert().NotificationAlert(titles: "Your Yearly Plan has Restored Successfully")
receiptValidation()
SVProgressHUD.dismiss()
break
case "com.motivatory.monthly":
print("Your Montly Plan has Restored Successfully")
NotificationAlert().NotificationAlert(titles: "Your Montly Plan has Restored Successfully")
receiptValidation()
SVProgressHUD.dismiss()
break
default:
if queue.transactions.count == 0 {
self.alert(message: "There are no restorable purchases. Only previously bought non-consumable products and auto-renewable subscriptions can be restored.", title: "Inspiration Daily Quotes")
break
}
SVProgressHUD.dismiss()
}
}
}
}
}
func receiptValidation(){
self.HitReceiptApi(Url: "https://buy.itunes.apple.com/verifyReceipt")
}
func HitReceiptApi(Url:String){
SVProgressHUD.setDefaultMaskType(.custom)
SVProgressHUD.setBackgroundLayerColor(#colorLiteral(red: 0, green: 0, blue: 0, alpha: 0.2472442209))
SVProgressHUD.show(withStatus: "Please Wait")
let receiptFileURL = Bundle.main.appStoreReceiptURL
let receiptData = try? Data(contentsOf: receiptFileURL!)
let recieptString = receiptData?.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
let jsonDict: [String: AnyObject] = ["receipt-data" : recieptString! as AnyObject, "password" : "fad24ce1475b4fdd9662a0ec31ef5a7d" as AnyObject]
print(jsonDict)
UserDefaults.standard.set(recieptString!, forKey: "recieptString")
do {
let requestData = try JSONSerialization.data(withJSONObject: jsonDict, options: JSONSerialization.WritingOptions.prettyPrinted)
let storeURL = URL(string: Url)!
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 {
let jsonResponse = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)
print("=======>",jsonResponse)
let json = try JSONSerialization.jsonObject(with: data!) as! Dictionary<String, AnyObject>
DispatchQueue.main.sync {
if json["status"] as? Int == 21007{
print("Sandbox User")
self?.HitReceiptApi(Url: "https://sandbox.itunes.apple.com/verifyReceipt")
return
} else {
print("Production")
if self!.purchaseTokenStr == ""{
} else {
self?.purchaseTokenStr = ""
if let receiptInfo2: NSArray = json["pending_renewal_info"] as? NSArray {
let lastReceipt2 = receiptInfo2.lastObject as! NSDictionary
if let original_transaction_id = lastReceipt2["original_transaction_id"] as? String {
self?.purchaseTokenStr = original_transaction_id
}
}
if let receiptInfo2: NSArray = json["latest_receipt_info"] as? NSArray {
let lastReceipt2 = receiptInfo2.firstObject as! NSDictionary
if let purchase_date = lastReceipt2["purchase_date"] as? String {
if let date = Formatter.customDate.date(from:purchase_date){
var startDate1 = String(describing: date)
startDate1.removeLast(6)
self?.startDate = "\(startDate1)"
}
}
}
self?.buySubscription = true
self?.subscriptionBuy()
}
SVProgressHUD.dismiss()
}
UserDefaults.standard.set(true,forKey:"SubscriptionPurchased")
}
} catch let parseError {
print(parseError)
}
})
task.resume()
} catch let parseError {
print(parseError)
}
}
}

sign in required environment sandbox issue

Everytime I build an adhoc build and runs it on ios 11 it keeps popping up the message saying "Sign-In Required - Enter the password for ***** [Environment:Sandbox]". Thus, this keep activating like a loop and not going away. tried siging out from iCloud also but didn't work.My inAppPurchase code as bellow.
class InAppPurchase: NSObject,SKProductsRequestDelegate,
SKPaymentTransactionObserver {
///Singleton
private static var inappPurChase:InAppPurchase?;
public static var shared:InAppPurchase {
if inappPurChase == nil{
inappPurChase = InAppPurchase()
}
return inappPurChase!
}
override private init() {
//Singleton complete
}
////////////
var productsList = [SKProduct]()
var productToPurchase = SKProduct()
var productID = ""
let PURCHASE_ID_PREFIX = ""//"com.purelightbeta."
var onInAppPurchaseSuccess: (()->Void )? = nil
var onInAppPurchaseError: (()->Void )? = nil
var onNoProductsIDs: (()->Void )? = nil
var appEnvironment: ((String,Bool)->Void )? = nil
var onReceiptVarificationError: (()->Void )? = nil
var onRestorePurchaseError: ((String)->Void )? = nil
var onRestoreProductsIDs: ((NSMutableArray)->Void )? = nil
public func initPayment (productID: String) {
self.productID = PURCHASE_ID_PREFIX + productID
print("Initializing Purchase Product ID: \(self.productID)")
if SKPaymentQueue.canMakePayments() {
let productID: NSSet = NSSet(objects: self.productID)
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
}else {
print("In App Purchases not enabled")
}
}
func buyProduct() {
let payment = SKPayment(product: productToPurchase)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment as SKPayment)
}
public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let myProducts = response.products
print(myProducts)
productsList = []
if myProducts.count == 0 {
print("No products")
if(onNoProductsIDs != nil){
onNoProductsIDs!()
}
}
for product in myProducts {
print("Prod Details :\(product.productIdentifier) \(product.price) \(product.localizedDescription)")
productsList.append(product)
}
for product in productsList {
let productID = product.productIdentifier
if productID == self.productID {
productToPurchase = product
buyProduct()
}
}
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
let productIDs: NSMutableArray = []
for trasacton in queue.transactions {
if trasacton.transactionState == SKPaymentTransactionState.restored
{
let t: SKPaymentTransaction = trasacton as SKPaymentTransaction
let prodID = t.payment.productIdentifier as String
print("prodID:",prodID)
//let appStoreId = prodID.components(separatedBy: "com.purelightbeta.")
productIDs.add(prodID)
SKPaymentQueue .default().finishTransaction(trasacton)
}
}
if onRestoreProductsIDs != nil {
print(productIDs)
onRestoreProductsIDs! (productIDs)
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction: AnyObject in transactions {
let trans = transaction as! SKPaymentTransaction
print(trans.error ?? "No in app error")
switch trans.transactionState {
case .purchased:
print("buy ok, AIP unlocked for item :", productToPurchase.productIdentifier)
let productID = productToPurchase.productIdentifier
switch productID {
case self.productID:
print("Item found")
// startValidatingReceipt()
default:
print("Item not found")
}
queue.finishTransaction(trans)
if self.onInAppPurchaseSuccess != nil {
self.onInAppPurchaseSuccess! ()
self.startValidatingReceipt()
}
case .failed:
print("buy error")
if self.onInAppPurchaseError != nil {
self.onInAppPurchaseError! ()
}
queue.finishTransaction(trans)
break
case .restored:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
// break
default:
print("default")
break
}
}
}
func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
print("ERROR: \(error.localizedDescription)")
if onRestorePurchaseError != nil {
onRestorePurchaseError! (error.localizedDescription)
}
}
func restorePurchase() {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
func startValidatingReceipt() {
if let isExists = try? self.getReceiptURL()?.checkResourceIsReachable(), isExists == true {
do {
let data = try Data(contentsOf: self.getReceiptURL()!)
// self.startValidatingData(data: data)
self.sendReceiptToLocalServer(data: data)
}catch {
let appReceiptRefreshRequest = SKReceiptRefreshRequest(receiptProperties: nil)
appReceiptRefreshRequest.delegate = self
appReceiptRefreshRequest.start()
}
}else {
print("No receipt for this purchase")
}
}
func getReceiptURL() -> URL? {
return Bundle.main.appStoreReceiptURL
}
enum receiptValidationURLs:String {
case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
case production = "https://buy.itunes.apple.com/verifyReceipt"
static var url:URL{
if isDebug {
return URL.init(string: self.sandbox.rawValue)!
}else{
return URL.init(string: self.production.rawValue)!
}
}
}
func sendReceiptToLocalServer(data:Data) {
let base64encodedReceipt = data.base64EncodedString()
if self.appEnvironment != nil {
self.appEnvironment! (base64encodedReceipt,isDebug)
}
}
func startValidatingData(data:Data){
let base64encodedReceipt = data.base64EncodedString()
print(base64encodedReceipt)
let requestDictionary = ["receipt-data":base64encodedReceipt]
guard JSONSerialization.isValidJSONObject(requestDictionary) else { print("requestDictionary is not valid JSON"); return }
do {
let requestData = try JSONSerialization.data(withJSONObject: requestDictionary)
// let validationURLString = "https://sandbox.itunes.apple.com/verifyReceipt" // this works but as noted above it's best to use your own trusted server
NSLog("The Environment is: %#", receiptValidationURLs.url.absoluteString)
guard let validationURL = URL(string: receiptValidationURLs.url.absoluteString) else { print("the validation url could not be created, unlikely error"); return }
let session = URLSession(configuration: URLSessionConfiguration.default)
var request = URLRequest(url: validationURL)
request.httpMethod = "POST"
request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringCacheData
let task = session.uploadTask(with: request, from: requestData) { (data, response, error) in
if let data = data , error == nil {
do {
let appReceiptJSON = try JSONSerialization.jsonObject(with: data)
print((appReceiptJSON as AnyObject).count)
print("success. here is the json representation of the app receipt: \(appReceiptJSON)")
NSLog("Receipt is: %#", appReceiptJSON as! NSDictionary)
if let environment = (appReceiptJSON as? NSDictionary)?["environment"]{
if self.appEnvironment != nil {
self.appEnvironment! (environment as? String ?? "No value",isDebug)
}
}
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
} else {
print("the upload task returned an error: \(error)")
}
}
task.resume()
} catch let error as NSError {
print("json serialization failed with error: \(error)")
}
}
// func requestDidFinish(_ request: SKRequest) {
// // a fresh receipt should now be present at the url
// do {
//
//
//
// } catch {
// // still no receipt, possible but unlikely to occur since this is the "success" delegate method
// }
// }
func request(_ request: SKRequest, didFailWithError error: Error) {
print("app receipt refresh request did fail with error: \(error)")
// for some clues see here: https://samritchie.net/2015/01/29/the-operation-couldnt-be-completed-sserrordomain-error-100/
if self.onReceiptVarificationError != nil {
self.onReceiptVarificationError! ()
}
}
}
This may not be the answer but would be a workaround. Best is to create a new sandbox user, sign out the old one and put the new.

show localized in-app purchase price when I move in my controller

I want to show localized price when I move in my controller.
I use this code:
if (SKPaymentQueue.canMakePayments())
{
let productID:NSSet = NSSet(object: self.product_id!)
let productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
print("Fetching Products")
}else{
print("Can't make purchases")
}
func productsRequest (_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
let count : Int = response.products.count
if (count>0) {
let validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == self.product_id) {
buyProduct(product: validProduct);
} else {
print(validProduct.productIdentifier)
}
} else {
print("nothing")
}
}
func buyProduct(product: SKProduct){
price = localizedPriceForProduct(product)
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment);
self.loading.stopAnimating()
}
func localizedPriceForProduct(_ product:SKProduct) -> String {
let priceFormatter = NumberFormatter()
priceFormatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
priceFormatter.numberStyle = NumberFormatter.Style.currency
priceFormatter.locale = product.priceLocale
return priceFormatter.string(from: product.price)!
}
But in this case I see UIAlertView with login in the store. How to fix it and disappear this UIAlertView?

App Crashes on Buy Subscription when first time launched

I'm working on this subscription system for my app,it took a few days.But as I'm working more on it,it makes more problems.
Sometimes it happens that the app crashes when clicking on buy subscription.
Also I'm having the problem of not knowing when to stop the Please wait.... alert.I need to place the code in:
case .Purchasing:
self.alert_show()
break
But I don't know where to end it,I need to know the information when is the alert from iTunes loaded than to stop the Please wait.... alert.
The biggest problem right now that I'm facing is the crashing sometimes when i click on the Buy Button.
The crashing happens when first time launching the app,and clicking one the Buy Subscription.
Here is the code for the Buy Subscription:
#IBAction func buy_sub(sender: AnyObject) {
let payment:SKPayment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment)
}
Here is the error that I'm getting.
fatal error: unexpectedly found nil while unwrapping an Optional value..
I would like to share with you my source code of the subscription.If you have any advices what to add,or to correct or to correct this problems that i have it would be great.
Here is the full source code of the Subscription View:
class SubscriptionViewController: UIViewController ,SKPaymentTransactionObserver, SKProductsRequestDelegate {
//var productID = ""
var product: SKProduct!
#IBOutlet var buy_trial_button: UIButton!
override func viewDidAppear(animated: Bool) {
if(SKPaymentQueue.canMakePayments()) {
} else {
buy_trial_button.enabled = false
message_alert("Please enable IAPS to continue(Credit card information required in your iTunes account).")
}
//validateReceipt()
let keystore = NSUbiquitousKeyValueStore.defaultStore()
if keystore.objectForKey("expiration_date") != nil{
let expiration: AnyObject? = keystore.objectForKey("expiration_date")
let today = NSDate()
let expiredate = expiration as! NSDate
print("expiredate is %#",expiredate,today)
// var date1 = NSDate()
// var date2 = NSDate()
if(today.compare(expiredate) == NSComparisonResult.OrderedDescending){
print("today is later than expiredate")
validateReceipt()
print("Validating")
}else if(today.compare(expiredate) == NSComparisonResult.OrderedAscending){
print("today is earlier than expiredate")
self.performSegueWithIdentifier("subscriptionPassed", sender: self)
}
}else{
print("First time launch")
}
}
override func viewDidLoad() {
super.viewDidLoad()
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
self.getProductInfo()
//SKPaymentQueue.defaultQueue().addTransactionObserver(self)
//self.getProductInfo()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(animated: Bool) {
}
#IBAction func private_policy(sender: AnyObject) {
let openLink = NSURL(string : "http://arsutech.com/private_policy.php")
UIApplication.sharedApplication().openURL(openLink!)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "subscriptionPassed")
{
}
}
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse){
let products = response.products
if products.count != 0
{
product = products[0] as SKProduct
print(product.localizedTitle + "\n" + product.localizedDescription)
}
}
func getProductInfo(){
if (SKPaymentQueue.canMakePayments()){
let productID:NSSet = NSSet(object: "com.sxxxxxxxxxxxxxxxxx")
let request:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
}
}
#IBAction func buy_sub(sender: AnyObject) {
let payment:SKPayment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment)
}
#IBAction func buy_pro(sender: AnyObject) {
let openLink = NSURL(string : "https://itunes.apple.com/us/app/home-workouts-exercises-mma/id1060747118?mt=8")
UIApplication.sharedApplication().openURL(openLink!)
}
#IBAction func exit(sender: AnyObject) {
exit(0)
}
func validateReceipt(){
alert_show()
let mainBundle = NSBundle.mainBundle() as NSBundle;
let receiptUrl = mainBundle.appStoreReceiptURL;
let isPresent = receiptUrl?.checkResourceIsReachableAndReturnError(NSErrorPointer());
if(isPresent == true){
let data = NSData(contentsOfURL: receiptUrl! );
// Create the JSON object that describes the request
let requestContents = NSMutableDictionary();
//let encodeddata = data!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions());
let encodeddata = data!.base64EncodedString();
//print("encodeddata = \(encodeddata)");
requestContents.setObject(encodeddata, forKey: "receipt-data");
requestContents.setObject("c40f23af1aa44e159aezzzzzzzzzzzzzz", forKey: "password");
var requestData : NSData?
do{
requestData = try NSJSONSerialization.dataWithJSONObject(requestContents, options: NSJSONWritingOptions());
}catch{
// NSLog("Error in json data creation at verifyPaymentReceipt");
}
let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let file = "\(documentsPath)/requestData"
if(NSFileManager.defaultManager().createFileAtPath(file, contents: data, attributes: nil)){
NSLog("File %# ",file);
}
else{
//NSLog("error File %# ",file);
}
if(requestData != nil){
//let strRequestData = NSString(data: requestData!, encoding: NSUTF8StringEncoding);
//print(" strRequestData = \(strRequestData)");
// Create a POST request with the receipt data.
//https://buy.itunes.apple.com/verifyReceipt
//https://sandbox.itunes.apple.com/verifyReceipt
let storeURL = NSURL(string: "https://sandbox.itunes.apple.com/verifyReceipt");
let storeRequest = NSMutableURLRequest(URL: storeURL!);
storeRequest.HTTPMethod = "POST";
storeRequest.HTTPBody = requestData;
// Make a connection to the iTunes Store on a background queue.
let queue = NSOperationQueue();
NSURLConnection.sendAsynchronousRequest(storeRequest, queue: queue, completionHandler: { (response : NSURLResponse?, data : NSData?, error : NSError?) -> Void in
if(error != nil){
//Handle Error
}
else{
let d = NSString(data: data!, encoding: NSUTF8StringEncoding);
// NSLog("DATA:%#", d!);
let dataA = d!.dataUsingEncoding(NSUTF8StringEncoding)
var jsonResponseInternal: NSMutableDictionary?
do{
jsonResponseInternal = try NSJSONSerialization.JSONObjectWithData(dataA!,options: NSJSONReadingOptions.AllowFragments) as? NSMutableDictionary;
//print(jsonResponseInternal);
}catch{
// NSLog("Parsing issue : verifyPaymentReceipt");
}
var jsonResponse: NSMutableDictionary?
do{
jsonResponse = try NSJSONSerialization.JSONObjectWithData(data!,
options: NSJSONReadingOptions.AllowFragments) as? NSMutableDictionary;
//print(jsonResponse);
}catch{
// NSLog("Parsing issue : verifyPaymentReceipt");
}
if(jsonResponse != nil){
if(jsonResponse != nil){
//NSLog("Expiration Date: %#", jsonResponse!);
//print("Passed")
/*
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "Purchase")
NSUserDefaults.standardUserDefaults().synchronize()
*/
//self.performSegueWithIdentifier("subscriptionPassed", sender: self)
if jsonResponse!["status"] as? Int == 0 {
//print("Sucessfully returned internal receipt data")
if let receiptInfo: NSArray = jsonResponse!["latest_receipt_info"] as? NSArray {
let lastReceipt = receiptInfo.lastObject as! NSDictionary
var trial_period: Bool = false
// Get last receipt
//print("LAST RECEIPT INFORMATION \n",lastReceipt)
print("Last from internal memory",lastReceipt["original_transaction_id"])
//var is_trial = lastReceipt["is_trial_period"] as! Bool
//var date_bought =
//var date_expires =
// Format date
//print(is_trial)
// Format date
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
// Get Expiry date as NSDate
let subscriptionExpirationDate: NSDate = formatter.dateFromString(lastReceipt["expires_date"] as! String) as NSDate!
print("\n - DATE SUBSCRIPTION EXPIRES = \(subscriptionExpirationDate)")
let currentDateTime = NSDate()
print(currentDateTime)
if var is_trial:Bool = false{
if(lastReceipt["is_trial_period"] as? String == "Optional(\"true\")"){
is_trial = true
trial_period = is_trial
}else if(lastReceipt["is_trial_period"] as? String == "Optional(\"false\")"){
is_trial = false
trial_period = is_trial
}
}
if (subscriptionExpirationDate.compare(currentDateTime) == NSComparisonResult.OrderedDescending) {
self.alrt_close()
print("Pass");
print("The trial period is \(trial_period)")
let keystore = NSUbiquitousKeyValueStore.defaultStore()
keystore.setObject(subscriptionExpirationDate,forKey:"expiration_date")
keystore.synchronize()
self.performSegueWithIdentifier("subscriptionPassed", sender: self)
} else if (subscriptionExpirationDate.compare(currentDateTime) == NSComparisonResult.OrderedAscending) {
print("Not Pass");
print("Subscription expired")
self.alrt_close()
//self.message_alert("Subscription expired")
}
}
}
}
}
}
});
}
}
}
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .Purchasing:
//self.alrt_close()
break
case .Deferred:
self.alert_show()
break
case .Purchased:
alrt_close()
self.validateReceipt()
//self.setExpirationDate()
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
//dismissViewControllerAnimated(false, completion: nil)
break
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
print("Not called Expired")
message_alert("Error while purchasing!")
break
case .Restored:
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
print("Restored")
break
default:
break
}
}
}
}
//Alrt
func message_alert(let message_A:String){
let alert = UIAlertController(title: "", message: "\(message_A)", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
func alert_show(){
let alert = UIAlertController(title: nil, message: "Please wait...", preferredStyle: .Alert)
alert.view.tintColor = UIColor.blackColor()
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(frame: CGRectMake(10, 5, 50, 50)) as UIActivityIndicatorView
loadingIndicator.hidesWhenStopped = true
loadingIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
loadingIndicator.startAnimating();
alert.view.addSubview(loadingIndicator)
presentViewController(alert, animated: true, completion: nil)
}
func alrt_close(){
self.dismissViewControllerAnimated(false, completion: nil)
}
}

Restore Purchase in Swift

I'm trying to add a restore button to my app, I have a non-consumable inApp purchase and the purchase part works fine. I have a button that calls this two methods:
product_id = "RemoveAdsIAP";
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
and this the purchasing code:
func buyConsumable(){
succssessIAP = false
if (SKPaymentQueue.canMakePayments()) {
var productID:NSSet = NSSet(object: self.product_id!);
var productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID);
productsRequest.delegate = self;
productsRequest.start();
} else {
displayErrorAlert()
}
}
func buyProduct(product: SKProduct){
var payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addPayment(payment);
}
func productsRequest (request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
var count : Int = response.products.count
if (count>0) {
var validProducts = response.products
var validProduct: SKProduct = response.products[0] as SKProduct
if (validProduct.productIdentifier == self.product_id) {
buyProduct(validProduct);
} else { }
} else {
displayErrorAlert()
}
}
func request(request: SKRequest!, didFailWithError error: NSError!) {
activityIndicatorShop.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
displayErrorAlert()
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
succssessIAP = false
for transaction:AnyObject in transactions {
if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
switch trans.transactionState {
case .Purchased, .Restored:
if (product_id == "GetNextFactIAP" && succssessIAP == false) {
startController.getData()
startController.hideContainerView()
succssessIAP = true
}
if (product_id == "RemoveAdsIAP" && succssessIAP == false) {
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "viewAdsBool")
NSUserDefaults.standardUserDefaults().synchronize()
startController.removeOnce()
disableAds(true)
succssessIAP = true
}
SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
break;
case .Failed:
SKPaymentQueue.defaultQueue().finishTransaction(transaction as SKPaymentTransaction)
activityIndicatorShop.stopAnimating()
displayErrorAlert()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
break;
default:
break;
}
}
}
}
When I press the button nothing happens, I've added a log statement to check if the updatedTransactions method was called and it wasn't, What's the problem?
Your products_id has the wrong format.
It should be more like
product_id = "com.xxxxxxxxx.RemoveAdsIAP"

Resources