Customizing an existing view controller by subclassing the default implementation

Subclassing an existing view controller helps when:

The following view controllers can be subclassed:

The following examples illustrate this customization option:

Subclassing SelectorViewController to display an advertisement banner at the top of the screen.

Follow the prerequisite to import the Google Mobile Ads SDK dependency and set up the mandatory configuration.

The info.plist looks like that:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>GADApplicationIdentifier</key>
	<string>ca-app-pub-3940256099942544~1458002511</string>
	<key>SKAdNetworkItems</key>
	<array>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>cstr6suwn9.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>4fzdc2evr5.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>2fnua5tdw4.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>ydx93a7ass.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>p78axxw29g.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>v72qych5uu.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>ludvb6z3bs.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>cp8zw746q7.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>3sh42y64q3.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>c6k4g5qg8m.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>s39g8k73mm.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>3qy4746246.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>hs6bdukanm.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>mlmmfzh3r3.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>v4nxqhlyqp.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>wzmmz9fp6w.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>su67r6k2v3.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>yclnxrl5pm.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>7ug5zh24hu.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>gta9lk7p23.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>vutu7akeur.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>y5ghdn5j9k.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>v9wttpbfk9.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>n38lu8286q.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>47vhws6wlr.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>kbd757ywx3.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>9t245vhmpl.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>a2p9lx4jpn.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>22mmun2rn5.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>4468km3ulz.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>2u9pt9hc89.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>8s468mfl3y.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>ppxm28t8ap.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>uw77j35x4d.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>pwa73g5rt2.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>578prtvx9j.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>4dzt52r2t5.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>tl55sbb4fm.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>e5fvkxwrpn.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>8c4e2ghe7u.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>3rd42ekr43.skadnetwork</string>
		</dict>
		<dict>
			<key>SKAdNetworkIdentifier</key>
			<string>3qcr597p9d.skadnetwork</string>
		</dict>
	</array>
</dict>
</plist>

In your AppDelegate, the Mobile Ads SDK has to be configured as demonstrated in the following snippet.

import GoogleMobileAds

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
		func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // GoogleMobileAds
        MobileAds.shared.start(completionHandler: nil)
        return true
    }
}

Create a subclass of SelectorViewController that will display a banner Ads as demonstrated below.

import Foundation
import IdsvrHaapiUIKit
import GoogleMobileAds

class AdsSelectorViewController: SelectorViewController {
    var bannerView: AdManagerBannerView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let adSize = currentOrientationAnchoredAdaptiveBanner(width: view.bounds.width)
        bannerView = AdManagerBannerView(adSize: adSize)
        bannerView.adUnitID = "ca-app-pub-3940256099942544/2435281174"
        bannerView.rootViewController = self
        bannerView.load(Request())

        insertView(bannerView, aboveView: messagesStackView)
    }
}

In your AppDelegate, create an instance of ViewControllerFactoryRegistry and set to your HaapiUIKitApplicationBuilder as demonstrated below:

import GoogleMobileAds
import IdsvrHaapiUIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
      // GoogleMobileAds
      MobileAds.shared.start(completionHandler: nil)
      // Registering the custom SelectorViewController to render SelectorModel
      let resolver = ViewControllerFactoryRegistry()
          .registerViewControllerFactorySelectorModel { model, style, commonStyle in
              return AdsSelectorViewController(model, style: style, commonStyle: commonStyle)
          }

      do {
          haapiUIKitApplication = try HaapiUIKitApplicationBuilder(haapiUIKitConfiguration: haapiUIKitConfiguration)
              .setViewControllerFactoryRegistry(registry: resolver)
              .buildOrThrow()
      } catch {
          print("An exception was thrown and it should be handled.: \(error)")
      }
      return true
  	}
}

When starting the HAAPI flow and the SelectorModel is displayed, a banner view is presented at the top of the screen as demonstrated below.

Banner ad with subclass selectorFragment

Subclassing FormViewController to trigger reCAPTCHA when a button is pushed.

Follow the prerequisite to import reCAPTCHA dependency and set up the mandatory configuration.

Create a subclass of FormViewController that will handle reCaptcha when the user submits an action.

import Foundation
import IdsvrHaapiUIKit
import RecaptchaEnterprise

class ReCaptchaFormViewController: FormViewController {
    var recaptchaClient: RecaptchaClient!

    override func viewDidLoad() {
        super.viewDidLoad()

        Task {
            do {
                self.recaptchaClient = try await Recaptcha.fetchClient(withSiteKey: "6LfqguwqADAAADw4QGR3arg4q0SfB4Y6wtu4kHaf")
            } catch let error as RecaptchaError {
                print(error)
            }
        }
    }

    override func preSubmit(interactionActionModel: any InteractionActionModel,
                            parameters: [String : Any],
                            closure: @escaping (Bool, [String : Any]) -> Void)
    {
        recaptchaClient.execute(withAction: RecaptchaAction.login) { token, error in
            let willSubmit: Bool                                                        
            if let token = token {
                print(token)
                willSubmit = true
            }
            if let error = error {
                print(error)
                willSubmit = false
            }
            closure(willSubmit, parameters)                                                        
        }
    }
}

In your AppDelegate, create an instance of ViewControllerFactoryRegistry and set to your HaapiUIKitApplicationBuilder as demonstrated below:

import IdsvrHaapiUIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
      // Registering the custom ReCaptchaFormViewController to render FormModel
      let resolver = ViewControllerFactoryRegistry()
          .registerViewControllerFactoryFormModel { model, style, commonStyle in
              return ReCaptchaFormViewController(model, style: style, commonStyle: commonStyle)
          }

      do {
          haapiUIKitApplication = try HaapiUIKitApplicationBuilder(haapiUIKitConfiguration: haapiUIKitConfiguration)
              .setViewControllerFactoryRegistry(registry: resolver)
              .buildOrThrow()
      } catch {
          print("An exception was thrown and it should be handled.: \(error)")
      }
      return true
  	}
}

When ReCaptchaFormViewController is presented and the button is pressed. Before submiting the form, a reCAPTCHA flow is triggered. When identifying successfully as a human, then the block of the submitting button is sent.