I am trying to integrate a very basic single IAP in my game, here I am calling from my GameScene
let alert = UIAlertController(title: "Upgrade", message: "Would you like to remove ads?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Remove Ads", style: .default, handler: { action in
print("Pressed Remove Ads")
GameViewController().buytheIAP()
}))
alert.addAction(UIAlertAction(title: "Restore Purchases", style: .default, handler: { action in
print("Pressed Restore")
GameViewController().restoretheIAP()
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { action in
print("Pressed Cancel")
}))
view?.window?.rootViewController?.present(alert, animated: true, completion: nil)
}
Those methods are called correctly, and refer to these inside GameViewController.swift
;
func buytheIAP(){
iAPHelper.purchase()
print("OK Lets upgrade")
}
func restoretheIAP(){
iAPHelper.restorePurchase()
print("OK Lets restore")
}
func restoreDidSucceed() {
UserDefaults.setValue(true, forKey: iAPHelper.productID)
//this should have something like hide banner etc.
bannerView.isHidden = true
}
func purchaseDidSucceed() {
UserDefaults.setValue(true, forKey: iAPHelper.productID)
//as above this should have something like hide banner etc.
bannerView.isHidden = true
print("Purchased upgrade ENJOYYYYYYYY")
}
func nothingToRestore() {
}
func paymentCancelled() {
}
The test IAP goes through, it gets the correct information from the app store, and I use my sandbox details to purchase, it goes through correctly with a successful purchase message. However, the bannerView
does not hide, and more importantly, upon restarting the game again, everything is forgotten and the game thinks nothing has been purchased. I am guessing it has to be some sort of check that is missing.
I have this in my viewDidLoad
if userDefaults.bool(forKey: iAPHelper.productID) {
bannerView.isHidden = true
print("It is purchased, so DO NOT show the ads")
} else{
bannerView.adSize = getAdaptiveSize()
bannerView.adUnitID = "ca-app-pub-3940256099942544/2934735716"
bannerView.delegate = self
bannerView.rootViewController = self
bannerView.load(GADRequest())
addBannerViewToView(bannerView)
print("Not purchased, so show the ads")
}
And it ALWAYS shows print("Not purchased, so show the ads")
The IAPHelper
file, for purchasing is;
func purchase() {
SwiftyStoreKit.purchaseProduct(productID, quantity: 1, atomically: true) { [self] result in
switch result {
case .success:
delegate?.purchaseDidSucceed()
print("OK It's purchased")
case .error(let error):
switch error.code {
case .unknown: print("Unknown error. Please contact support")
case .clientInvalid: print("Not allowed to make the payment")
case .paymentCancelled:
delegate?.paymentCancelled()
case .paymentInvalid: print("The purchase identifier was invalid")
case .paymentNotAllowed: print("The device is not allowed to make the payment")
case .storeProductNotAvailable: print("The product is not available in the current storefront")
case .cloudServicePermissionDenied: print("Access to cloud service information is not allowed")
case .cloudServiceNetworkConnectionFailed: print("Could not connect to the network")
case .cloudServiceRevoked: print("User has revoked permission to use this cloud service")
default: print((error as NSError).localizedDescription)
}
}
}
}
}
And the log DOES show print("OK It's purchased")
after the initial purchase - so I am struggling to see what is going wrong.
CodePudding user response:
The IAP delegate functions are not (guaranteed to be) called on the UI/main thread, that's why your view doesn't hide.
Don't you see some iOS warning saying that you try to set a UIView
property on non-main thread?
The fact that your custom purchase info was not saved in UserDefaults
could be caused by killing the app prematurely from Xcode.
(UserDefaults
does take of saving what's being set during normal app flow.)
CodePudding user response:
OK, so I figured the answer, there was a missing line in my AppDelegate.swift
section didFinishLaunchingWithOptions
UserDefaults.standard.register(defaults: ["adRemove" : false])
I renamed userDefaults.bool(forKey: iAPHelper.productID)
to make it easier to use / understand. So in my original post that has been replaced by UserDefaults.standard.register(defaults: ["adRemove" : false])
instead.
You can then use this anywhere to check, such as;
if !userDefaults.bool(forKey: "adRemove") {
// Do something here
}
Hope this helps anyone in future with the same question!