【问题标题】:How do I use the Google Mobile Ads SDK in SwiftUI, or use the UIKit UIViewController within a SwiftUI view?如何在 SwiftUI 中使用 Google Mobile Ads SDK,或在 SwiftUI 视图中使用 UIKit UIViewController?
【发布时间】:2020-06-16 18:48:40
【问题描述】:

我有一个 SwiftUI 视图,我想在按下按钮时从 Google 移动广告 SDK 打开一个奖励广告。加载广告的说明 (https://developers.google.com/admob/ios/rewarded-ads#create_rewarded_ad) 在 UIKit 中,我正在努力在我的 SwiftUI 应用程序中使用它们。有没有办法使用 SwiftUI 加载广告,或者如果我使用 UIKit,如何将其集成到 SwiftUI 中?

这是 SwiftUI 父视图:

struct AdMenu: View {

    var body: some View {
   NavigationView {
       NavigationLink(destination: Ads())
        {
            Text("Watch Ad")
        }
    }
}
}

我不知道 UIKit,但我认为这是我想在 SwiftUI 中使用的代码:

    class ViewController: UIViewController, GADRewardedAdDelegate {

    var rewardedAd: GADRewardedAd?

var adRequestInProgress = false

  @IBAction func doSomething(sender: UIButton) {
    if rewardedAd?.isReady == true {
       rewardedAd?.present(fromRootViewController: self, delegate:self)
    }else {
      let alert = UIAlertController(
        title: "Rewarded video not ready",
        message: "The rewarded video didn't finish loading or failed to load",
        preferredStyle: .alert)
      let alertAction = UIAlertAction(
        title: "OK",
        style: .cancel,
        handler: { [weak self] action in
            // redirect to AdMenu SwiftUI view somehow?
        })
      alert.addAction(alertAction)
      self.present(alert, animated: true, completion: nil)
    }
}

func createAndLoadRewardedAd() {
    rewardedAd = GADRewardedAd(adUnitID: "ca-app-pub-3940256099942544/1712485313")
    adRequestInProgress = true
    rewardedAd?.load(GADRequest()) { error in
      self.adRequestInProgress = false
      if let error = error {
        print("Loading failed: \(error)")
      } else {
        print("Loading Succeeded")
      }
    }
  return rewardedAd
}

// Tells the delegate that the user earned a reward
func rewardedAd(_ rewardedAd: GADRewardedAd, userDidEarn reward: GADAdReward) {
  print("Reward received with currency: \(reward.type), amount \(reward.amount).")
}
// Tells the delegate that the rewarded ad was presented
func rewardedAdDidPresent(_ rewardedAd: GADRewardedAd) {
  print("Rewarded ad presented.")
}
// Tells the delegate that the rewarded ad was dismissed
func rewardedAdDidDismiss(_ rewardedAd: GADRewardedAd) {
  print("Rewarded ad dismissed.")
}
// Tells the delegate that the rewarded ad failed to present
func rewardedAd(_ rewardedAd: GADRewardedAd, didFailToPresentWithError error: Error) {
    rewardedAd = createAndLoadRewardedAd()
    print("Rewarded ad failed to present.")
}

    override func viewDidLoad() {
        super.viewDidLoad()
    if !adRequestInProgress && !(rewardedAd?.isReady ?? false) {
    rewardedAd = createAndLoadRewardedAd()
}

【问题讨论】:

    标签: swift uiviewcontroller uikit swiftui googlemobileads


    【解决方案1】:

    我使用了一种非常简单的方法。我有一个委托类,它加载奖励广告并通知视图它已加载,因此视图呈现它。当用户观看完整的广告时,相同的代理会收到成功回调并将其通知视图。

    委托的代码如下:-

    class RewardedAdDelegate: NSObject, GADRewardedAdDelegate, ObservableObject {
    @Published var adLoaded: Bool = false
    @Published var adFullyWatched: Bool = false
    
    var rewardedAd: GADRewardedAd? = nil
    
    func loadAd() {
        rewardedAd = GADRewardedAd(adUnitID: "ca-app-pub-3940256099942544/1712485313")
            rewardedAd!.load(GADRequest()) { error in
              if error != nil {
                self.adLoaded = false
              } else {
                self.adLoaded = true
              }
            }
    }
    
    /// Tells the delegate that the user earned a reward.
    func rewardedAd(_ rewardedAd: GADRewardedAd, userDidEarn reward: GADAdReward) {
        adFullyWatched = true
    }
    
    /// Tells the delegate that the rewarded ad was presented.
    func rewardedAdDidPresent(_ rewardedAd: GADRewardedAd) {
         self.adLoaded = false
    }
    
    /// Tells the delegate that the rewarded ad was dismissed.
    func rewardedAdDidDismiss(_ rewardedAd: GADRewardedAd) {}
    
    /// Tells the delegate that the rewarded ad failed to present.
    func rewardedAd(_ rewardedAd: GADRewardedAd, didFailToPresentWithError error: Error) {}
    }
    

    现在您需要一个视图来启动和展示 RewardedAd:-

    struct RewardedAd: View {
    @ObservedObject var adDelegate = RewardedAdDelegate()
    
    var body: some View {
        if adDelegate.adLoaded && !adDelegate.adFullyWatched {
            let root = UIApplication.shared.windows.first?.rootViewController
            self.adDelegate.rewardedAd!.present(fromRootViewController: root!, delegate: adDelegate)
        }
        
        return Text("Load ad").onTapGesture {
            self.adDelegate.loadAd()
        }
    }
    }
    

    解释:- 在上面的视图中,当用户点击Load Ad 时,我们启动加载,然后委托更新已发布的布尔值。这通知我们认为广告已加载,我们调用:-

    让 root = UIApplication.shared.windows.first?.rootViewController self.adDelegate.rewardedAd!.present(fromRootViewController: root!, delegate: adDelegate)

    广告现在正在屏幕上播放,如果用户观看完毕,代理将收到成功回调,并更新另一个已发布布尔值。这将通知我们现在需要奖励用户(您可以添加处理/奖励用户的方式)。

    【讨论】:

    • 你知道如何判断用户在获得奖励后点击X的时间吗?我得到 adFullyWatched=true 但随后我的游戏继续进行,并且用户看不到游戏现在在后台进行,直到他们真正关闭广告。有回调吗?仅当他们过早关闭它时才会调用rewardedAdDidDismiss()。
    【解决方案2】:

    我想出了一种方法,如何将 AdMob 页面中的 Objective-c 代码很好地转换为您可以在 SwiftUI 中轻松使用的代码。

    
    final class RewardedAd {
        private let rewardId = "ca-app-pub-3940256099942544/1712485313" // TODO: replace this with your own Ad ID
        
        var rewardedAd: GADRewardedAd?
        
        init() {
            load()
        }
        
        func load(){
            let request = GADRequest()
            // add extras here to the request, for example, for not presonalized Ads
            GADRewardedAd.load(withAdUnitID: rewardId, request: request, completionHandler: {rewardedAd, error in
                if error != nil {
                    // loading the rewarded Ad failed :( 
                    return
                }
                self.rewardedAd = rewardedAd
            })
        }
        
        func showAd(rewardFunction: @escaping () -> Void) -> Bool {
            guard let rewardedAd = rewardedAd else {
                return false
            }
            
            guard let root = UIApplication.shared.keyWindowPresentedController else {
                return false
            }
            rewardedAd.present(fromRootViewController: root, userDidEarnRewardHandler: rewardFunction)
            return true
        }
    }
    

    我还添加了一个扩展来简化根视图:

    extension UIApplication {
        
        var keyWindow: UIWindow? {
            return UIApplication.shared.connectedScenes
                .filter { $0.activationState == .foregroundActive }
                .first(where: { $0 is UIWindowScene })
                .flatMap({ $0 as? UIWindowScene })?.windows
                .first(where: \.isKeyWindow)
        }
        
        var keyWindowPresentedController: UIViewController? {
            var viewController = self.keyWindow?.rootViewController
            
            if let presentedController = viewController as? UITabBarController {
                viewController = presentedController.selectedViewController
            }
            
            while let presentedController = viewController?.presentedViewController {
                if let presentedController = presentedController as? UITabBarController {
                    viewController = presentedController.selectedViewController
                } else {
                    viewController = presentedController
                }
            }
            return viewController
        }
    }
    

    如果你将它添加到你的项目中,你可以在你的 SwiftUI 代码中这样调用它:

    var rewardAd: RewardedAd
            
        init(){
            self.rewardAd = RewardedAd()
            rewardAd.load()
        }
        
        var body: some View {
            Button(action: {
                self.rewardAd.showAd(rewardFunction: {
                  // TODO: give the user a reward for watching
                  self.collectedDiamonds += 1
                })
            }) {
                Text("Watch Ad - Earn ?")
                    .foregroundColor(.white)
                    .padding()
            }
            .background(Capsule().fill(Color.blue))
        }
    

    【讨论】:

      猜你喜欢
      • 2020-06-03
      • 1970-01-01
      • 2022-11-07
      • 1970-01-01
      • 2021-07-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-05
      相关资源
      最近更新 更多