如何使用 SpriteKit 和 Swift 2 中的 Xcode 7 beta 从应用程序中删除 iAd?

How to remove iAd from application, using SpriteKit and Xcode 7 beta in Swift 2?

我使用 Xcode 7 beta 和 Swift 2 中的 SpriteKit 制作了一个具有 iAd 插页式广告的游戏,我尝试使用一个函数来删除它们,但它不起作用。我正在使用两个不同的文件,GameScene.swiftGameViewController.swift.

我在文件中使用的代码,GameScene.swift:

func gameOver() {
    isGameOver = true
    print("Game Over")

    loadAd()
}
//iAd
func close(sender: UIButton) {
    closeButton.removeFromSuperview()
    interAdView.removeFromSuperview()
}


func loadAd() {
    print("load ad")
    interAd = ADInterstitialAd()
    interAd.delegate = self

    closeButton.frame = CGRectMake(15, 15, 22, 22)
    closeButton.layer.cornerRadius = 11
    closeButton.setTitle("x", forState: .Normal)
    closeButton.setTitleColor(UIColor.blackColor(), forState: .Normal)
    closeButton.backgroundColor = UIColor.whiteColor()
    closeButton.layer.borderColor = UIColor.blackColor().CGColor
    closeButton.layer.borderWidth = 1
    closeButton.addTarget(self, action: "close:", forControlEvents: UIControlEvents.TouchDown)

}

func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
    print("ad did load")

    interAdView = UIView()
    interAdView.frame = self.view!.bounds
    view!.addSubview(interAdView)

    interAd.presentInView(interAdView)
    UIViewController.prepareInterstitialAds()

    interAdView.addSubview(closeButton)
}

func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {

}

func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
   print("failed to receive")
    print(error.localizedDescription)

    closeButton.removeFromSuperview()
    interAdView.removeFromSuperview()

}

GameViewController.swift是In-App Purchase去除广告(购买专业版):

@IBAction func removeAds(sender: UIButton) {
    print("Remove Ads Button pressed")
    for product in list {
        let prodID = product.productIdentifier
        if(prodID == "Squares.RemoveAds") {
            p = product
            buyProduct()
            break;
        }
    }
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}


func removeAds() {

}

override func prefersStatusBarHidden() -> Bool {
    return true
}

//Remove Ads Payment
var list = [SKProduct]()
var p = SKProduct()


//Squares.regular.removeAds
//Squares.6Plus.removeAds


func buyProduct() {
    print("Buy" + p.productIdentifier)
    let pay = SKPayment(product: p)
    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    SKPaymentQueue.defaultQueue().addPayment(pay as SKPayment)
}

func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
    print("Product Request")
    let myProduct = response.products

    for product in myProduct {
        print("Product Added")
        print(product.productIdentifier)
        print(product.localizedTitle)
        print(product.localizedDescription)
        print(product.price)

        list.append(product as SKProduct)
    }
    removeAdsButton.enabled = true
    removeAdsIPhone6Plus.enabled = true
}

func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
    print("Transactions Restored")

    var purchasedItemIDS = []
    for transaction in queue.transactions {
        let t: SKPaymentTransaction = transaction as SKPaymentTransaction

        let prodID = t.payment.productIdentifier as String

        switch prodID {
        case "Squares.RemoveAds":
            print("Remove Ads")
            removeAds()
        case "Squares.RemoveAds":
            print("Remove Ads for iPhone 6 Plus")
            removeAds()
        default:
            print("IAP not setup")
        }

    }
}

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 unlock Squares here")
            print(p.productIdentifier)

            let prodID = p.productIdentifier as String
            switch prodID {
                case "Squares.RemoveAds":
                print("Remove Ads")
                removeAds()
                case "Squares.RemoveAds":
                print("Remove Ads for iPhone 6 Plus")
                removeAds()
            default:
                print("IAP not Setup")
            }

            queue.finishTransaction(trans)
            break;
        case .Failed:
            print("Buy Error")
            queue.finishTransaction(trans)
            break;
        default:
            print("Default")
            break;

        }
    }
}

func finishTransaction(trans:SKPaymentTransaction){
    print("Finish Transaction")
}

func paymentQueue(queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
    print("Remove Transaction")
}

如果您阅读文件 GameViewController.swift 中的代码,函数 removeAds() 是空的并且在同一文件中的某些代码中被调用,因此它将删除广告永远,我需要做的是在函数 removeAds() 中放置一个代码,它将永久删除广告,问题是我不知道如何调用它以及以何种方式删除它们,因为函数是在不同的文件中,我尝试了很多方法但没有用。 你能详细告诉我怎么做吗?

您可以使用 NSNotifcationCenter。

所以在您的 viewController 中,您会说

NSNotificationCenter.defaultCenter().addObserver(self, selector: "removeAds", name: "RemoveAdsKey", object: nil)

比任何时候你想调用这个函数你都会说

NSNotificationCenter.defaultCenter().postNotificationName("RemoveAdsKey", object: nil)

关于函数 removeAds() 本身。你需要写这样的东西。

    closeButton.removeFromSuperview()
    interAdView.removeFromSuperview()
    interAd.delegate = nil

您应该尽快添加 SKpayment 交易观察器,并且只添加一次,而不是每次购买。 仅当您的游戏关闭时才移除观察者。很多教程向您展示了 Apple 不推荐的方式。 https://developer.apple.com/library/ios/technotes/tn2387/_index.html

为了让您的生活更轻松,为什么不查看我在 gitHub 上发布的 iAds 和 Admob 助手,它主要是为 SpriteKit 制作的。 https://github.com/crashoverride777/Swift-iAds-and-AdMob-Helper

即使您不想使用它,也应该让您了解如何使用委托等。那里没有什么复杂的,只是使用广告的基本方法。它还向您展示了如何预加载 interAds,以便它们显示得更快。

我用 link 更新了我的第一个答案给 apple。这并不是说你的方法是错误的,而是 Apple 专门给出了一个很好和不好的实施示例,不幸的是,大多数教程都是以错误的方式进行的。 在您的具体情况下,您可以执行以下操作。

将 2 个 NSNotification 中心观察者添加到您的 viewController

 NSNotificationCenter.defaultCenter().addObserver(self, selector: "addTransactionObserver", name: "AddObserverKey", object: nil)
 NSNotificationCenter.defaultCenter().addObserver(self, selector: "removeTransactionObserver", name: "RemoveObserverKey", object: nil)

在您的 viewController.

中创建 2 个函数
func addTransactionObserver() {
 SKPaymentQueue.defaultQueue().addTransactionObserver(self)
 // you could put this in view Did Load but I prefer apples way
}

func removeTransactionObserver() {
 SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
}

比在你的 appDelegate 方法 didFinishLaunching...中使用

NSNotificationCenter.defaultCenter().postNotificationName("AddObserverKey", object: nil)

比在 appWillTerminate 的 appDelegate 中...使用

NSNotificationCenter.defaultCenter().postNotificationName("RemoveObserverKey", object: nil)

您真的应该考虑将您的购买代码放入帮助程序文件中,以使事情变得容易得多。例如,这是一个好的开始。

http://masteringios.com/blog/2015/02/17/in-app-purchase-how-to-retrieve-the-list-of-products-from-the-app-store/

https://github.com/Vitaa/IAPurchaseManager/blob/master/IAPManager.swift

有了广告,只要看看我的助手,它就会让你知道哪里错了。

您的游戏视图控制器可能看起来像这样

    class gameViewController: .....

     struct ProductID {
static let removeAds = "squares.RemoveAds"
static let removeAds6Plus = "squares.RemoveAds6Plus" // really needed?
}

struct NSNotificationKey {
static let addObserver = "AddObserver"
static let removeObserver = "RemoveObserver"
}




    func ViewDidLoad() {


    NSNotificationCenter.defaultCenter().addObserver(self, selector: "addTransactionObserver", name: NSNotificationKey.addObserver, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "removeTransactionObserver", name: NSNotificationKey.removeObserver, object: nil)

        ....
  }

func addTransactionObserver() {
 SKPaymentQueue.defaultQueue().addTransactionObserver(self)
 // you could put this in view Did Load but I prefer apples way
}

func removeTransactionObserver() {
 SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
}



@IBAction func removeAds(sender: UIButton) {
    print("Remove Ads Button pressed")
    for product in list {
        let prodID = product.productIdentifier
        if(prodID == ProductID.removeAds) {
            p = product
            buyProduct()
            break
        }
    }

    SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}

func removeAds() {
     interAd.delegate = nil
     closeButton.removeFromSuperView()
    interAdView.removeFromSuperView()           

 }

override func prefersStatusBarHidden() -> Bool {
    return true
}

//Remove Ads Payment
var list = [SKProduct]()
var p = SKProduct()



//Squares.regular.removeAds
//Squares.6Plus.removeAds


func buyProduct() {
    print("Buy" + p.productIdentifier)
    let pay = SKPayment(product: p)
    SKPaymentQueue.defaultQueue().addPayment(pay as SKPayment)
}

func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
    print("Product Request")
    let myProduct = response.products

    for product in myProduct {
        print("Product Added")
        print(product.productIdentifier)
        print(product.localizedTitle)
        print(product.localizedDescription)
        print(product.price)

        list.append(product as SKProduct)
    }
    removeAdsButton.enabled = true
    removeAdsIPhone6Plus.enabled = true
}

func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
    print("Transactions Restored")

    var purchasedItemIDS = []
    for transaction in queue.transactions {
        let t: SKPaymentTransaction = transaction as SKPaymentTransaction

        let prodID = t.payment.productIdentifier as String

        switch prodID {
        case ProductID.removeAds:
            print("Remove Ads")
            removeAds()
        case ProductID.removeAds6Plus:
            print("Remove Ads for iPhone 6 Plus")
            removeAds()
        default:
            print("IAP not setup")
        }

    }
}

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 unlock Squares here")
            print(p.productIdentifier)

            let prodID = p.productIdentifier as String
            switch prodID {
                case ProductID.removeAds:
                print("Remove Ads")
                removeAds()
                case ProductID.removeAds6Plus: // really needed?
                print("Remove Ads for iPhone 6 Plus")
                removeAds()
            default:
                print("IAP not Setup")
            }

            queue.finishTransaction(trans)
            break;
        case .Failed:
            print("Buy Error")
            queue.finishTransaction(trans)
            break;
        default:
            print("Default")
            break;

        }
    }
}

func finishTransaction(trans:SKPaymentTransaction){
    print("Finish Transaction")
}

func paymentQueue(queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
    print("Remove Transaction")
}

比你在 didFinishLaunchingWithOptions 中的 appDelegate.swift 你说的

NSNotificationCenter.defaultCenter().postNotificationName(GameViewController.NSNotificationKey.addObserver, object: nil)

在 appWillTerminate 中你说

NSNotificationCenter.defaultCenter().postNotificationName(GameViewController.NSNotificationKey.removeObserver, object: nil)

如果仍然无法正常工作,您需要检查您的产品 ID。您正在使用 Squares.RemoveAds 作为产品 ID,但您有这些评论

//Squares.regular.removeAds

//正方形.6Plus.removeAds

仔细检查您的 ID。

好的,这基本上是一种具有更好代码的新方法。 首先复制您的项目,以防万一。 其次,请听我的指示并完全按照我的指示去做。

所以我已经用购买代码向您发布了答案。检查你是否完全按照我说的去做了。比删除 GameScene 中有关广告的所有代码。所有这些都像 NSNotifcationCenter、函数、ADInterstitialAdDelegate(在游戏场景的顶部)等。 然后在项目中创建一个新的 swift 文件并输入此代码。

这是我的帮手的精简版,它现在包括内部广告和横幅广告。要设置横幅,请执行以下操作。在你写的 import UIKit 下的应用委托中

import iAd
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

仍在 class 实现下的 appDelegate 中,您必须创建此 属性

var bannerAdView = ADBannerView()

进入 appDelegate 的原因是因为我们正在创建一个共享的 iAdBanner。对于具有 1 个 viewController 的 spritekit 来说并不是真正需要的,但对于具有多个 viewController 的应用程序来说这是正确的方法,因此您不妨使用它。 而不是像以前一样将其复制到您的项目中。

  import iAd

class Ads: NSObject {

    // MARK: - Properties
    static let sharedInstance = Ads()

    var presentingViewController: UIViewController!

    var interAd = ADInterstitialAd()
    var interAdView = UIView()
    var interAdCloseButton = UIButton.buttonWithType(UIButtonType.System) as! UIButton

    override init() {
        super.init()

        print("Ads Helper init")

        preloadInterAd() // preload first interAd, they will preload automatically afterwards.
    }
        // MARK: - User Methods
        class func showBannerAd() {
        Ads.sharedInstance.loadBannerAd()
       }

        class func showInterAd() {
          Ads.sharedInstance.showInterAd()
        }

        class func removeBannerAds() {
            Ads.sharedInstance.removeBannerAds()
       }

       class func removeAllAds() {
        Ads.sharedInstance.removeAllAds()
      }


      //MARK: - Internal Methods

   // loading banner
   private func loadBannerAd() {
        printDebug("iAd banner loading...")
        appDelegate.bannerAdView = ADBannerView(frame: presentingViewController.view.bounds)
        appDelegate.bannerAdView.delegate = self
        appDelegate.bannerAdView.center = CGPoint(x: CGRectGetMidX(presentingViewController.view.frame), y: CGRectGetMaxY(presentingViewController.view.frame) + (appDelegate.bannerAdView.frame.size.height / 2))
    }

    // preloading inter
    private func preloadInterAd() {
        print("iAds Inter preloading")
        interAd = ADInterstitialAd()
        interAd.delegate = self

        interAdCloseButton.frame = CGRectMake(13, 13, 22, 22)
        interAdCloseButton.layer.cornerRadius = 12
        interAdCloseButton.setTitle("X", forState: .Normal)
        interAdCloseButton.setTitleColor(UIColor.grayColor(), forState: .Normal)
        interAdCloseButton.backgroundColor = UIColor.whiteColor()
        interAdCloseButton.layer.borderColor = UIColor.grayColor().CGColor
        interAdCloseButton.layer.borderWidth = 2
        interAdCloseButton.addTarget(self, action: "pressedCloseButton:", forControlEvents: UIControlEvents.TouchDown) // function such as this with content in brackets need : for selector. VIP
    }

    private func showInterAd() {
        if interAd.loaded {
            print("iAds Inter showing")
            presentingViewController.view.addSubview(interAdView)
            interAd.presentInView(interAdView)
            UIViewController.prepareInterstitialAds()
            interAdView.addSubview(interAdCloseButton)

            // pause game, music etc here
        } else {
            print("iAds Inter cannot be shown, reloading")
            preloadInterAd()
        }
    }

    // closed inter ad 
    func pressedCloseButton(sender: UIButton) {
        interAdCloseButton.removeFromSuperview()
        interAdView.removeFromSuperview()
        interAd.delegate = nil

        preloadInterAd()
    }

    // remove banner ads
    private func removeBannerAds() {
        appDelegate.bannerAdView.delegate = nil
        appDelegate.bannerAdView.removeFromSuperview()
    }

    // remove all ads
    private func removeAllAds() {
        // banners
        appDelegate.bannerAdView.delegate = nil
        appDelegate.bannerAdView.removeFromSuperview()

        // inter
        interAdCloseButton.removeFromSuperview()
        interAdView.removeFromSuperview()
        interAd.delegate = nil
    }
}

// MARK: iAds Banner Delegates 
extension Ads: ADBannerViewDelegate {

    func bannerViewWillLoadAd(banner: ADBannerView!) {
        printDebug("iAds banner will load")
    }

    func bannerViewDidLoadAd(banner: ADBannerView!) {
        printDebug("iAds banner did load, showing")
        presentingViewController.view.addSubview(appDelegate.bannerAdView)
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(1.5)
        appDelegate.bannerAdView.center = CGPoint(x: CGRectGetMidX(presentingViewController.view.frame), y: CGRectGetMaxY(presentingViewController.view.frame) - (appDelegate.bannerAdView.frame.size.height / 2))
        UIView.commitAnimations()
    }

    func bannerViewActionShouldBegin(banner: ADBannerView!, willLeaveApplication willLeave: Bool) -> Bool {
        printDebug("iAds banner clicked")
        // pause game , music etc here
        return true
    }

    func bannerViewActionDidFinish(banner: ADBannerView!) {
        printDebug("iAds banner closed")
        // resume game, music here
    }

    func bannerView(banner: ADBannerView!, didFailToReceiveAdWithError error: NSError!) {
        printDebug("iAds banner error")
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDuration(1.5)
        appDelegate.bannerAdView.center = CGPoint(x: CGRectGetMidX(presentingViewController.view.frame), y: CGRectGetMaxY(presentingViewController.view.frame) + (appDelegate.bannerAdView.frame.size.height / 2))
        appDelegate.bannerAdView.hidden = true
        UIView.commitAnimations()

    }
}


// MARK: - iAds Inter Delegates
extension Ads: ADInterstitialAdDelegate {

    func interstitialAdDidLoad(interstitialAd: ADInterstitialAd!) {
        print("iAds Inter did preload")
        interAdView = UIView()
        interAdView.frame = presentingViewController.view.bounds
    }

    func interstitialAdDidUnload(interstitialAd: ADInterstitialAd!) {
        print("iAds Inter did unload")
    }

    func interstitialAd(interstitialAd: ADInterstitialAd!, didFailWithError error: NSError!) {
        print("iAds Inter error")
        print(error.localizedDescription)
        interAdCloseButton.removeFromSuperview()
        interAdView.removeFromSuperview()
        interAd.delegate = nil

        preloadInterAd()
    }
}

好的。现在你所要做的就是写一行代码来初始化这个Helper并预加载第一个Inter(之后它们会自动预加载。)

在您的 ViewDidLoad 中的 gameViewController 中,您称之为

    // this tells the ad helper that this is the GameViewController that shows ads. 
   // This step also inits the adHelper and preloads the first inter ad. 
    Ads.sharedInstance.presentingViewController = self 

就是这样。在 func gameOver() 的 GameScene 中或任何你想要的地方,你现在只需说

Ads.showInterAd()
Ads.showBannerAd()

您可以随时在控制台中检查广告是否已预加载,因为我为每一步都设置了 prinln。如果广告尚未预加载,则无法显示。这有助于您了解发生了什么。

在你的 gameViewController 中购买代码你现在只需说

Ads.removeAllAds()

并删除所有广告。

如果您只想移除横幅广告,例如在玩游戏期间,只需说

Ads.removeBannerAds()

比你喜欢的时候再次加载它们 Ads.showBannerAd()

要保存购买,请执行此操作。

在函数 removeAllAds() 中,你在最后说得很好

 NSUserDefaults.standardUserDefaults().setBool(true, forKey: "your product ID")

在你的代码中任何你会说 Ads.showInterAd() 或 Ads.showBannerAd() 的地方,比如 func gameOver() 你写这个

// You can use your product Id as a key, and you dont actually have to set a var. So its the easiest this way. If it cannot find a bool for your product ID it will automatically set it to false. Very nice.
   // A reason I made the structs with the product ID is so its easier to reference it so you dont have to type it out every time.
    if NSUserDefaults.standardUserDefaults().boolForKey("your product ID") == false {
         Ads.showInterAd()
    }

完成