I am having some difficulties with removing ads from my app.
The issue is when I click the remove ads button, the application crashes with the message fatal error: unexpectedly found nil while unwrapping an Optional value
.
I have looked online, however, they seem to be outdated.
I have looked at my console and I may have found the error product = (SKProduct)nil
The funny thing is I had implemented this method once before and had the same issue, and out the blue it worked. So I just re-used the code and change the productID
.
I thought maybe it needed time to actually register the id of the in-app purchase. However, I've woken up to the same issue. Could someone please help me and tell me what the issue may be?
My game crashes once I tap the Remove Ads button. The action/method for my remove button is removeAds_TouchUpInside
.
import UIKit
import SpriteKit
import GameplayKit
import GoogleMobileAds
import StoreKit
class GameViewController: UIViewController, GADInterstitialDelegate, SKPaymentTransactionObserver, SKProductsRequestDelegate {
var fullScreenAds : GADInterstitial!
@IBOutlet weak var removeAdsButton: UIButton!
var product: SKProduct?
var productID = "com.USER.GAME.removeAds"
override func viewDidLoad() {
super.viewDidLoad()
let save = UserDefaults.standard
if save.value(forKey: "Purchase") == nil {
let request = GADRequest()
request.testDevices = [kGADSimulatorID]
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadAds"), object: nil)
} else {
}
if let view = self.view as! SKView? {
if let scene = SKScene(fileNamed: "GameMenuScene") {
scene.scaleMode = .aspectFill
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = false
view.showsNodeCount = false
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
@IBAction func removeAds_TouchUpInside(_ sender: Any) {
let payment = SKPayment(product: product!)
SKPaymentQueue.default().add(payment)
}
override func viewWillLayoutSubviews() {
NotificationCenter.default.addObserver(self, selector: #selector(self.loadAds), name: NSNotification.Name(rawValue: "loadAds"), object: nil)
}
func loadAds() {
self.fullScreenAds = createAndLoadInterstitials()
}
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if UIDevice.current.userInterfaceIdiom == .phone {
return .allButUpsideDown
} else {
return .all
}
}
override var prefersStatusBarHidden: Bool {
return true
}
func createAndLoadInterstitials() -> GADInterstitial? {
fullScreenAds = GADInterstitial(adUnitID: "ca-app-pub-7212561254132738/9424537183")
guard let fullScreenAds = fullScreenAds else {
return nil
}
let request = GADRequest()
request.testDevices = [kGADSimulatorID]
fullScreenAds.load(request)
fullScreenAds.delegate = self
return fullScreenAds
}
func interstitialDidReceiveAd(_ ad: GADInterstitial) {
print("Ad received")
ad.present(fromRootViewController: self)
}
func interstitialDidFail(toPresentScreen ad: GADInterstitial) {
print("No ad can be loaded")
}
func getPurchaseInfo() {
if SKPaymentQueue.canMakePayments() {
let request = SKProductsRequest(productIdentifiers: NSSet(objects: self.productID) as! Set<String>)
request.delegate = self
request.start()
} else {
print("Enable in app purchase!")
return
}
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
var products = response.products
if (products.count == 0) {
print("Error")
return
} else {
product = products[0]
removeAdsButton.isEnabled = true
print("Succes!")
}
let invalids = response.invalidProductIdentifiers
for product in invalids {
print("Product not found \(product)")
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case SKPaymentTransactionState.purchased:
SKPaymentQueue.default().finishTransaction(transaction)
print("SuccessPayementQeue!")
removeAdsButton.isEnabled = false
let save = UserDefaults.standard
save.set(true, forKey: "Purchase")
save.synchronize()
case SKPaymentTransactionState.failed:
SKPaymentQueue.default().finishTransaction(transaction)
print("Failed transaction state")
default:
break
}
}
}
}