0

I have build a SwiftUI .sheet() that appears so the user can see their statistics and can click on a button that then will show a rewarded video to give the user some extra points. The code is as follows:

import SwiftUI
import GoogleMobileAds

struct Scoresheet: View {

   @State private var rewardedadd = ViewController()

   var body: some View {
      VStack {
          // all sorts of content.
          // if a user clicks on a specific button it will call func loadadd()
      }
      .onAppear {
         rewardedadd.loadRewardedAd()
      }
   }
   func loadadd() {
      rewardedadd.show()
   }
}

In another file I have the following:

import UIKit
import GoogleMobileAds

class ViewController: UIViewController, GADFullScreenContentDelegate {
   var rewardedAd: GADRewardedAd?

   func loadRewardedAd() {
      let request = GADRequest()
      GADRewardedAd.load(withAdUnitID:"ca-app-pub-3940256099942544/1712485313",
                       request: request,
                       completionHandler: { [self] ad, error in
         if let error = error {
            print("Failed to load rewarded ad with error: \(error.localizedDescription)")
            return
         }
         rewardedAd = ad
         print("Rewarded ad loaded.")
         rewardedAd?.fullScreenContentDelegate = self
      })
   }

   func show() {
      if let ad = rewardedAd {
         ad.present(fromRootViewController: self) {
            let reward = ad.adReward
            print("Reward received with currency \(reward.amount), amount \(reward.amount.doubleValue)")
            // TODO: Reward the user.
           }
       } else {
          print("Ad wasn't ready")
       }
   }

   func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
      print("Ad did fail to present full screen content. Error: \(error.localizedDescription)")
   }

   func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
      print("Ad will present full screen content.")
   }

   func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
      print("Ad did dismiss full screen content.")
   }
}

I keep getting the following error:

Ad did fail to present full screen content. Error: The provided view controller is not being presented.

That is the error from func ad in class ViewController. Does anyone know what I can do to fix this issue?

---- edit ---- I have rebuild my viewcontroller class to the following:

import SwiftUI
import GoogleMobileAds

struct RewardedAd: UIViewRepresentable {
    @State private var rewardedAd: GADRewardedAd
    let adUnitId = "ca-app-pub-3940256099942544/1712485313"

    func makeCoordinator() -> CoordinatorVideoAd {
        return CoordinatorVideoAd()
    }

    func makeUIView(context: Context) -> GADRewardedAd {
        let request = GADRequest()
        rewardedAd.load(withAdUnitID: adUnitId,
                         request: request, completionHandler: { [self] ad, error in
            if let error = error {
                print("Failed to load rewarded ad with error: \(error.localizedDescription)")
                return
            }
            rewardedAd = ad
            print("Rewarded ad loaded.")
            rewardedAd?.fullScreenContentDelegate = self
        })
        return rewardedAd
    }

    func updateUIView(_ uiView: GADRewardedAd, context: Context) { }

    class CoordinatorVideoAd: NSObject, GADFullScreenContentDelegate {
        func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
            print("Ad did fail to present full screen content.")
        }

        func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
            print("Ad will present full screen content.")
        }

        func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
           print("Ad did dismiss full screen content.")
       }
    }
}

I new have two error's:

Type 'RewardedAd' does not conform to protocol 'UIViewRepresentable' Static member 'load' cannot be used on instance of type 'GADRewardedAd'

How can I fix this?

chrispsv
  • 503
  • 1
  • 3
  • 21
  • Your view controller needs to be in a uiviewcontrollerrepresentable https://stackoverflow.com/questions/69942854/how-to-pass-textfield-value-to-view-controller-through-button-click-in-swift-ui/69945806#69945806 – lorem ipsum May 11 '22 at 14:09
  • i dont think that's how you present an UIKit component into a swiftUI, try looking for https://developer.apple.com/documentation/swiftui/uiviewcontrollerrepresentable – Farhandika May 11 '22 at 14:43
  • here's also a tutorial in medium https://medium.com/@max.codes/use-uiviewcontrollers-in-swiftui-views-with-uiviewcontrollerrepresentable-coordinator-5b5f75e45caf – Farhandika May 11 '22 at 14:44

1 Answers1

0

I believe that's now how you present a UIKit component to a swiftUI. You should read it in the apple docs about how to do it.

Here's an example how to do it :

First, create a struct that inherit the UIViewControllerRepresentable protocol

it'll look like this

struct SomethingViewController: UIViewControllerRepresentable {
    typealias UIViewControllerType = [enter your UIViewController type]
    
    
}

add the type, for example, here i;m creating a FakeViewController

typealias UIViewControllerType = FakeViewController

it'll generate the nescessary method

Last, just customize it whahtever you want

struct SomethingViewController: UIViewControllerRepresentable {
    @Binding var colorIDX: Int
    let colors: [UIColor] = [.red,.blue,.green]

    func makeUIViewController(context: Context) -> FakeViewController {
        //Construct your ViewController
        let viewController = FakeViewController()
        viewController.bgColor = .systemPink
        return viewController
    }

    func updateUIViewController(_ uiViewController: FakeViewController, context: Context) {
        // Update your ViewController
        uiViewController.view.backgroundColor = colors[colorIDX]
    }

}

and setup in the SwiftUIView to look like this (depending on how do you want it, navigate to UIViewController or present it)

struct ContentView: View {
    @State var isShow: Bool = false
    @State var colorIDX: Int = 0
    var body: some View {
        VStack {
            Button("show") {
                if colorIDX >= 2 {
                    colorIDX = 0
                } else {
                    colorIDX += 1
                }
                isShow.toggle()
            }
        }.sheet(isPresented: $isShow) {
        } content: {
            SomethingViewController(colorIDX: $colorIDX)
        }

    }
}

you see, every time i update something in the swiftUI View, it updates my ViewController and everytime I push the button, it'll present the ViewController

if you want to use a navigationController, just use it like any other swiftUI component/views

And that;s how you use a UIViewController in SwiftUI

Farhandika
  • 437
  • 1
  • 3
  • 16
  • i believe you have enough knowledge about the viewcontroller lifecycle to make everything works. cherios – Farhandika May 11 '22 at 15:11
  • Thank you for all your effort! I am completely new new to the viewcontroller lifecycle. I edited my post. Am going I in the right direction? – chrispsv May 11 '22 at 17:29
  • tbh, i do not know how you would like to present your viewController, but I assume it's in presentation mode. try to do .sheet rather than onAppear. and could you please upvote my answer if it answer your question. thanks – Farhandika May 12 '22 at 07:40
  • and please do call your loadrewardApp on viewdidLoad or any other method provided by UIviewcontroller (depending on your need and when will it load) – Farhandika May 12 '22 at 07:41
  • last but not least, could you provide a detailed information on what you're trying to do? thanks – Farhandika May 12 '22 at 07:41
  • i think that view is the sheet view and within the sheetview you want to load the uiviewcontroller right? then put the viewloader inside the view variable – Farhandika May 12 '22 at 07:42
  • Yes, so Scoresheet() is the struct that is the .sheet (so the parentview calls .sheet(Scoresheet())). In the ScoreSheet there is a button which calls the function loadadd(). This function should display the fullscreen video add. This is what I can't get to work. – chrispsv May 12 '22 at 11:06