[interactive_media_ads] Adds internal wrapper for iOS native `IMACompanionAd` (#7873)

diff --git a/packages/interactive_media_ads/CHANGELOG.md b/packages/interactive_media_ads/CHANGELOG.md
index 96eccd9..51ff513 100644
--- a/packages/interactive_media_ads/CHANGELOG.md
+++ b/packages/interactive_media_ads/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.2+12
+
+* Adds internal wrapper for iOS native `IMACompanionAd`.
+
 ## 0.2.2+11
 
 * Adds internal wrapper for Android native `UniversalAdId`.
diff --git a/packages/interactive_media_ads/CONTRIBUTING.md b/packages/interactive_media_ads/CONTRIBUTING.md
index 1578ce8..0578595 100644
--- a/packages/interactive_media_ads/CONTRIBUTING.md
+++ b/packages/interactive_media_ads/CONTRIBUTING.md
@@ -135,40 +135,21 @@
 * Android: Run `flutter build apk --debug` in `example/`.
 * iOS: Run `flutter build ios --simulator` in `example/`
 
-##### 2. Ensure the correct `pigeon` package is added to `dev_dependencies` in the `pubspec.yaml` and run `pub upgrade`
+##### 2. Make changes to the respective pigeon file that matches the native SDK
 
-Android:
+* Android:
+    - [Android SDK]
+    - Pigeon file to update: `pigeons/interactive_media_ads_android.dart`
+* iOS:
+    - [iOS SDK]
+    - Pigeon file to update: `pigeons/interactive_media_ads_ios.dart`
 
-```yaml
-pigeon: ^22.2.0
-```
-
-iOS:
-
-```yaml
-pigeon:
-  git:
-    url: git@github.com:bparrishMines/packages.git
-    ref: pigeon_wrapper_swift
-    path: packages/pigeon
-```
-
-##### 3. Uncomment the multiline comments in the pigeon file
-
-* Android: `pigeons/interactive_media_ads_android.dart`
-* iOS: `pigeons/interactive_media_ads_ios.dart`
-
-##### 4. Make changes that match the native SDK
-
-* [Android SDK]
-* [iOS SDK]
-
-##### 5. Run the code generator from the terminal
+##### 3. Run the code generator from the terminal
 
 * Android: `dart run pigeon --input pigeons/interactive_media_ads_android.dart`
 * iOS: `dart run pigeon --input pigeons/interactive_media_ads_ios.dart`
 
-##### 6. Update the generated APIs in native code
+##### 4. Update the generated APIs in native code
 
 Running the `flutter build` step from step 1 again should provide build errors and indicate what
 needs to be done. Alternatively, it can be easier to update native code with the platform's specific
@@ -177,7 +158,7 @@
 * Android: Open `example/android/` in a separate Android Studio project.
 * iOS: Open `example/ios/` in Xcode.
 
-##### 7. Write API tests
+##### 5. Write API tests
 
 Assuming a non-static method or constructor was added to the native wrapper, a native test will need
 to be added.
diff --git a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt
index b414bba..89de44c 100644
--- a/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt
+++ b/packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt
@@ -21,7 +21,7 @@
      *
      * This must match the version in pubspec.yaml.
      */
-    const val pluginVersion = "0.2.2+11"
+    const val pluginVersion = "0.2.2+12"
   }
 
   override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) {
diff --git a/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj b/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj
index 76decbf..545e2e9 100644
--- a/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj
@@ -20,6 +20,7 @@
 		8F599BBB2C332C010090A0DF /* AdsRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F599BBA2C332C010090A0DF /* AdsRequestTests.swift */; };
 		8F599BBD2C332CFE0090A0DF /* ContentPlayheadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */; };
 		8F599BBF2C3335B40090A0DF /* ViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */; };
+		8F8382A32CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */; };
 		8F977DCF2C2B99C600A90D4B /* AdDisplayContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DCE2C2B99C600A90D4B /* AdDisplayContainerTests.swift */; };
 		8F977DD32C2BA15100A90D4B /* TestProxyApiRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DD22C2BA15100A90D4B /* TestProxyApiRegistrar.swift */; };
 		8F977DD52C2C777600A90D4B /* AdErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DD42C2C777600A90D4B /* AdErrorTests.swift */; };
@@ -78,6 +79,7 @@
 		8F599BBA2C332C010090A0DF /* AdsRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsRequestTests.swift; sourceTree = "<group>"; };
 		8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPlayheadTests.swift; sourceTree = "<group>"; };
 		8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerTests.swift; sourceTree = "<group>"; };
+		8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanionAdProxyApiTests.swift; sourceTree = "<group>"; };
 		8F977DCE2C2B99C600A90D4B /* AdDisplayContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdDisplayContainerTests.swift; sourceTree = "<group>"; };
 		8F977DD22C2BA15100A90D4B /* TestProxyApiRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProxyApiRegistrar.swift; sourceTree = "<group>"; };
 		8F977DD42C2C777600A90D4B /* AdErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdErrorTests.swift; sourceTree = "<group>"; };
@@ -133,6 +135,7 @@
 				8F599BBA2C332C010090A0DF /* AdsRequestTests.swift */,
 				8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */,
 				8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */,
+				8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */,
 			);
 			path = RunnerTests;
 			sourceTree = "<group>";
@@ -411,6 +414,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				8F599BBF2C3335B40090A0DF /* ViewControllerTests.swift in Sources */,
+				8F8382A32CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift in Sources */,
 				8FC919922CA5D86F00188068 /* FriendlyObstructionTests.swift in Sources */,
 				8F977DD92C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift in Sources */,
 				8F599BB32C2DD87D0090A0DF /* AdsLoaderTests.swift in Sources */,
diff --git a/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdProxyApiTests.swift b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdProxyApiTests.swift
new file mode 100644
index 0000000..59391c3
--- /dev/null
+++ b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdProxyApiTests.swift
@@ -0,0 +1,77 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import Flutter
+import GoogleInteractiveMediaAds
+import XCTest
+
+@testable import interactive_media_ads
+
+class CompanionAdProxyApiTests: XCTestCase {
+  func testResourceValue() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
+
+    let instance = TestCompanionAd.customInit()
+    let value = try? api.pigeonDelegate.resourceValue(pigeonApi: api, pigeonInstance: instance)
+
+    XCTAssertEqual(value, instance.resourceValue)
+  }
+
+  func testApiFramework() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
+
+    let instance = TestCompanionAd.customInit()
+    let value = try? api.pigeonDelegate.apiFramework(pigeonApi: api, pigeonInstance: instance)
+
+    XCTAssertEqual(value, instance.apiFramework)
+  }
+
+  func testWidth() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
+
+    let instance = TestCompanionAd.customInit()
+    let value = try? api.pigeonDelegate.width(pigeonApi: api, pigeonInstance: instance)
+
+    XCTAssertEqual(value, Int64(instance.width))
+  }
+
+  func testHeight() {
+    let registrar = TestProxyApiRegistrar()
+    let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
+
+    let instance = TestCompanionAd.customInit()
+    let value = try? api.pigeonDelegate.height(pigeonApi: api, pigeonInstance: instance)
+
+    XCTAssertEqual(value, Int64(instance.height))
+  }
+
+}
+
+class TestCompanionAd: IMACompanionAd {
+  // Workaround to subclass an Objective-C class that has an `init` constructor with NS_UNAVAILABLE
+  static func customInit() -> TestCompanionAd {
+    let instance =
+      TestCompanionAd.perform(NSSelectorFromString("new")).takeRetainedValue() as! TestCompanionAd
+    return instance
+  }
+
+  override var resourceValue: String? {
+    return "resourceValue"
+  }
+
+  override var apiFramework: String? {
+    return "apiFramework"
+  }
+
+  override var width: Int {
+    return 0
+  }
+
+  override var height: Int {
+    return 1
+  }
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift
index a4a790a..2fc5186 100644
--- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift
@@ -13,7 +13,7 @@
   /// The current version of the `interactive_media_ads` plugin.
   ///
   /// This must match the version in pubspec.yaml.
-  static let pluginVersion = "0.2.2+11"
+  static let pluginVersion = "0.2.2+12"
 
   func pigeonDefaultConstructor(
     pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer,
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdProxyAPIDelegate.swift
new file mode 100644
index 0000000..b58ad8b
--- /dev/null
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdProxyAPIDelegate.swift
@@ -0,0 +1,32 @@
+// Copyright 2013 The Flutter Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import Foundation
+import GoogleInteractiveMediaAds
+
+/// ProxyApi implementation for [IMACompanionAd].
+///
+/// This class may handle instantiating native object instances that are attached to a Dart instance
+/// or handle method calls on the associated native class or an instance of that class.
+class CompanionAdProxyAPIDelegate: PigeonApiDelegateIMACompanionAd {
+  func resourceValue(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
+    -> String?
+  {
+    return pigeonInstance.resourceValue
+  }
+
+  func apiFramework(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
+    -> String?
+  {
+    return pigeonInstance.apiFramework
+  }
+
+  func width(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64 {
+    return Int64(pigeonInstance.width)
+  }
+
+  func height(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64 {
+    return Int64(pigeonInstance.height)
+  }
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift
index ae9d85c..3100f77 100644
--- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift
@@ -445,6 +445,10 @@
   func pigeonApiIMAFriendlyObstruction(
     _ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
   ) -> PigeonApiIMAFriendlyObstruction
+  /// An implementation of [PigeonApiIMACompanionAd] used to add a new Dart instance of
+  /// `IMACompanionAd` to the Dart `InstanceManager` and make calls to Dart.
+  func pigeonApiIMACompanionAd(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
+    -> PigeonApiIMACompanionAd
 }
 
 extension InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
@@ -769,8 +773,20 @@
         return
       }
 
-      if let instance = value as? NSObject {
-        pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar).pigeonNewInstance(
+      if let instance = value as? IMAFriendlyObstruction {
+        pigeonRegistrar.apiDelegate.pigeonApiIMAFriendlyObstruction(pigeonRegistrar)
+          .pigeonNewInstance(
+            pigeonInstance: instance
+          ) { _ in }
+        super.writeByte(128)
+        super.writeValue(
+          pigeonRegistrar.instanceManager.identifierWithStrongReference(
+            forInstance: instance as AnyObject)!)
+        return
+      }
+
+      if let instance = value as? IMACompanionAd {
+        pigeonRegistrar.apiDelegate.pigeonApiIMACompanionAd(pigeonRegistrar).pigeonNewInstance(
           pigeonInstance: instance
         ) { _ in }
         super.writeByte(128)
@@ -780,11 +796,10 @@
         return
       }
 
-      if let instance = value as? IMAFriendlyObstruction {
-        pigeonRegistrar.apiDelegate.pigeonApiIMAFriendlyObstruction(pigeonRegistrar)
-          .pigeonNewInstance(
-            pigeonInstance: instance
-          ) { _ in }
+      if let instance = value as? NSObject {
+        pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar).pigeonNewInstance(
+          pigeonInstance: instance
+        ) { _ in }
         super.writeByte(128)
         super.writeValue(
           pigeonRegistrar.instanceManager.identifierWithStrongReference(
@@ -3156,6 +3171,11 @@
 final class PigeonApiIMAFriendlyObstruction: PigeonApiProtocolIMAFriendlyObstruction {
   unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
   let pigeonDelegate: PigeonApiDelegateIMAFriendlyObstruction
+  ///An implementation of [NSObject] used to access callback methods
+  var pigeonApiNSObject: PigeonApiNSObject {
+    return pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar)
+  }
+
   init(
     pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
     delegate: PigeonApiDelegateIMAFriendlyObstruction
@@ -3244,3 +3264,86 @@
     }
   }
 }
+protocol PigeonApiDelegateIMACompanionAd {
+  /// The value for the resource of this companion.
+  func resourceValue(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
+    -> String?
+  /// The API needed to execute this ad, or nil if unavailable.
+  func apiFramework(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
+    -> String?
+  /// The width of the companion in pixels.
+  ///
+  /// 0 if unavailable.
+  func width(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64
+  /// The height of the companion in pixels.
+  ///
+  /// 0 if unavailable.
+  func height(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64
+}
+
+protocol PigeonApiProtocolIMACompanionAd {
+}
+
+final class PigeonApiIMACompanionAd: PigeonApiProtocolIMACompanionAd {
+  unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
+  let pigeonDelegate: PigeonApiDelegateIMACompanionAd
+  ///An implementation of [NSObject] used to access callback methods
+  var pigeonApiNSObject: PigeonApiNSObject {
+    return pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar)
+  }
+
+  init(
+    pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
+    delegate: PigeonApiDelegateIMACompanionAd
+  ) {
+    self.pigeonRegistrar = pigeonRegistrar
+    self.pigeonDelegate = delegate
+  }
+  ///Creates a Dart instance of IMACompanionAd and attaches it to [pigeonInstance].
+  func pigeonNewInstance(
+    pigeonInstance: IMACompanionAd, completion: @escaping (Result<Void, PigeonError>) -> Void
+  ) {
+    if pigeonRegistrar.ignoreCallsToDart {
+      completion(
+        .failure(
+          PigeonError(
+            code: "ignore-calls-error",
+            message: "Calls to Dart are being ignored.", details: "")))
+      return
+    }
+    if pigeonRegistrar.instanceManager.containsInstance(pigeonInstance as AnyObject) {
+      completion(.success(Void()))
+      return
+    }
+    let pigeonIdentifierArg = pigeonRegistrar.instanceManager.addHostCreatedInstance(
+      pigeonInstance as AnyObject)
+    let resourceValueArg = try! pigeonDelegate.resourceValue(
+      pigeonApi: self, pigeonInstance: pigeonInstance)
+    let apiFrameworkArg = try! pigeonDelegate.apiFramework(
+      pigeonApi: self, pigeonInstance: pigeonInstance)
+    let widthArg = try! pigeonDelegate.width(pigeonApi: self, pigeonInstance: pigeonInstance)
+    let heightArg = try! pigeonDelegate.height(pigeonApi: self, pigeonInstance: pigeonInstance)
+    let binaryMessenger = pigeonRegistrar.binaryMessenger
+    let codec = pigeonRegistrar.codec
+    let channelName: String =
+      "dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance"
+    let channel = FlutterBasicMessageChannel(
+      name: channelName, binaryMessenger: binaryMessenger, codec: codec)
+    channel.sendMessage(
+      [pigeonIdentifierArg, resourceValueArg, apiFrameworkArg, widthArg, heightArg] as [Any?]
+    ) { response in
+      guard let listResponse = response as? [Any?] else {
+        completion(.failure(createConnectionError(withChannelName: channelName)))
+        return
+      }
+      if listResponse.count > 1 {
+        let code: String = listResponse[0] as! String
+        let message: String? = nilOrValue(listResponse[1])
+        let details: String? = nilOrValue(listResponse[2])
+        completion(.failure(PigeonError(code: code, message: message, details: details)))
+      } else {
+        completion(.success(Void()))
+      }
+    }
+  }
+}
diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift
index b20ae2f..3c9a26c 100644
--- a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift
+++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/ProxyApiDelegate.swift
@@ -112,7 +112,7 @@
   )
     -> PigeonApiIMAAdsRenderingSettings
   {
-    PigeonApiIMAAdsRenderingSettings(
+    return PigeonApiIMAAdsRenderingSettings(
       pigeonRegistrar: registrar, delegate: AdsRenderingSettingsProxyAPIDelegate())
   }
 
@@ -121,7 +121,14 @@
   )
     -> PigeonApiIMAFriendlyObstruction
   {
-    PigeonApiIMAFriendlyObstruction(
+    return PigeonApiIMAFriendlyObstruction(
       pigeonRegistrar: registrar, delegate: FriendlyObstructionProxyAPIDelegate())
   }
+
+  func pigeonApiIMACompanionAd(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
+    -> PigeonApiIMACompanionAd
+  {
+    return PigeonApiIMACompanionAd(
+      pigeonRegistrar: registrar, delegate: CompanionAdProxyAPIDelegate())
+  }
 }
diff --git a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart
index 2e6d58a..b3ac074 100644
--- a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart
+++ b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads.g.dart
@@ -171,6 +171,8 @@
         pigeon_instanceManager: instanceManager);
     IMAFriendlyObstruction.pigeon_setUpMessageHandlers(
         pigeon_instanceManager: instanceManager);
+    IMACompanionAd.pigeon_setUpMessageHandlers(
+        pigeon_instanceManager: instanceManager);
     return instanceManager;
   }
 
@@ -3342,7 +3344,7 @@
 /// purposes.
 ///
 /// See https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/ios/reference/Classes/IMAFriendlyObstruction.html.
-class IMAFriendlyObstruction extends PigeonInternalProxyApiBaseClass {
+class IMAFriendlyObstruction extends NSObject {
   /// Initializes a friendly obstruction.
   IMAFriendlyObstruction({
     super.pigeon_binaryMessenger,
@@ -3350,7 +3352,7 @@
     required this.view,
     required this.purpose,
     this.detailedReason,
-  }) {
+  }) : super.pigeon_detached() {
     final int pigeonVar_instanceIdentifier =
         pigeon_instanceManager.addDartCreatedInstance(this);
     final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
@@ -3397,7 +3399,7 @@
     required this.view,
     required this.purpose,
     this.detailedReason,
-  });
+  }) : super.pigeon_detached();
 
   late final _PigeonInternalProxyApiBaseCodec
       _pigeonVar_codecIMAFriendlyObstruction =
@@ -3492,3 +3494,117 @@
     );
   }
 }
+
+/// An object that holds data corresponding to the companion ad.
+///
+/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Classes/IMACompanionAd.
+class IMACompanionAd extends NSObject {
+  /// Constructs [IMACompanionAd] without creating the associated native object.
+  ///
+  /// This should only be used by subclasses created by this library or to
+  /// create copies for an [PigeonInstanceManager].
+  @protected
+  IMACompanionAd.pigeon_detached({
+    super.pigeon_binaryMessenger,
+    super.pigeon_instanceManager,
+    this.resourceValue,
+    this.apiFramework,
+    required this.width,
+    required this.height,
+  }) : super.pigeon_detached();
+
+  /// The value for the resource of this companion.
+  final String? resourceValue;
+
+  /// The API needed to execute this ad, or nil if unavailable.
+  final String? apiFramework;
+
+  /// The width of the companion in pixels.
+  ///
+  /// 0 if unavailable.
+  final int width;
+
+  /// The height of the companion in pixels.
+  ///
+  /// 0 if unavailable.
+  final int height;
+
+  static void pigeon_setUpMessageHandlers({
+    bool pigeon_clearHandlers = false,
+    BinaryMessenger? pigeon_binaryMessenger,
+    PigeonInstanceManager? pigeon_instanceManager,
+    IMACompanionAd Function(
+      String? resourceValue,
+      String? apiFramework,
+      int width,
+      int height,
+    )? pigeon_newInstance,
+  }) {
+    final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec =
+        _PigeonInternalProxyApiBaseCodec(
+            pigeon_instanceManager ?? PigeonInstanceManager.instance);
+    final BinaryMessenger? binaryMessenger = pigeon_binaryMessenger;
+    {
+      final BasicMessageChannel<
+          Object?> pigeonVar_channel = BasicMessageChannel<
+              Object?>(
+          'dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance',
+          pigeonChannelCodec,
+          binaryMessenger: binaryMessenger);
+      if (pigeon_clearHandlers) {
+        pigeonVar_channel.setMessageHandler(null);
+      } else {
+        pigeonVar_channel.setMessageHandler((Object? message) async {
+          assert(message != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance was null.');
+          final List<Object?> args = (message as List<Object?>?)!;
+          final int? arg_pigeon_instanceIdentifier = (args[0] as int?);
+          assert(arg_pigeon_instanceIdentifier != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance was null, expected non-null int.');
+          final String? arg_resourceValue = (args[1] as String?);
+          final String? arg_apiFramework = (args[2] as String?);
+          final int? arg_width = (args[3] as int?);
+          assert(arg_width != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance was null, expected non-null int.');
+          final int? arg_height = (args[4] as int?);
+          assert(arg_height != null,
+              'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance was null, expected non-null int.');
+          try {
+            (pigeon_instanceManager ?? PigeonInstanceManager.instance)
+                .addHostCreatedInstance(
+              pigeon_newInstance?.call(arg_resourceValue, arg_apiFramework,
+                      arg_width!, arg_height!) ??
+                  IMACompanionAd.pigeon_detached(
+                    pigeon_binaryMessenger: pigeon_binaryMessenger,
+                    pigeon_instanceManager: pigeon_instanceManager,
+                    resourceValue: arg_resourceValue,
+                    apiFramework: arg_apiFramework,
+                    width: arg_width!,
+                    height: arg_height!,
+                  ),
+              arg_pigeon_instanceIdentifier!,
+            );
+            return wrapResponse(empty: true);
+          } on PlatformException catch (e) {
+            return wrapResponse(error: e);
+          } catch (e) {
+            return wrapResponse(
+                error: PlatformException(code: 'error', message: e.toString()));
+          }
+        });
+      }
+    }
+  }
+
+  @override
+  IMACompanionAd pigeon_copy() {
+    return IMACompanionAd.pigeon_detached(
+      pigeon_binaryMessenger: pigeon_binaryMessenger,
+      pigeon_instanceManager: pigeon_instanceManager,
+      resourceValue: resourceValue,
+      apiFramework: apiFramework,
+      width: width,
+      height: height,
+    );
+  }
+}
diff --git a/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart b/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart
index 5b87858..ff34c8e 100644
--- a/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart
+++ b/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart
@@ -2,12 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// TODO(bparrishMines): Uncomment this file once
-// https://github.com/flutter/packages/pull/6602 lands. This file uses the
-// Swift ProxyApi feature from pigeon.
 // ignore_for_file: avoid_unused_constructor_parameters
 
-/*
 import 'package:pigeon/pigeon.dart';
 
 @ConfigurePigeon(
@@ -573,7 +569,7 @@
 ///
 /// See https://developers.google.com/ad-manager/dynamic-ad-insertion/sdk/ios/reference/Classes/IMAFriendlyObstruction.html.
 @ProxyApi()
-abstract class IMAFriendlyObstruction {
+abstract class IMAFriendlyObstruction extends NSObject {
   /// Initializes a friendly obstruction.
   IMAFriendlyObstruction();
 
@@ -590,4 +586,25 @@
   /// spaces.
   late final String? detailedReason;
 }
-*/
+
+/// An object that holds data corresponding to the companion ad.
+///
+/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Classes/IMACompanionAd.
+@ProxyApi()
+abstract class IMACompanionAd extends NSObject {
+  /// The value for the resource of this companion.
+  late final String? resourceValue;
+
+  /// The API needed to execute this ad, or nil if unavailable.
+  late final String? apiFramework;
+
+  /// The width of the companion in pixels.
+  ///
+  /// 0 if unavailable.
+  late final int width;
+
+  /// The height of the companion in pixels.
+  ///
+  /// 0 if unavailable.
+  late final int height;
+}
diff --git a/packages/interactive_media_ads/pubspec.yaml b/packages/interactive_media_ads/pubspec.yaml
index 133f949..c67417b 100644
--- a/packages/interactive_media_ads/pubspec.yaml
+++ b/packages/interactive_media_ads/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin for using the Interactive Media Ads SDKs on Android and iOS.
 repository: https://github.com/flutter/packages/tree/main/packages/interactive_media_ads
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+interactive_media_ads%22
-version: 0.2.2+11 # This must match the version in
+version: 0.2.2+12 # This must match the version in
   # `android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt` and
   # `ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift`
 
@@ -31,7 +31,7 @@
   flutter_test:
     sdk: flutter
   mockito: ^5.4.4
-  pigeon: ^22.4.2
+  pigeon: ^22.5.0
 
 topics:
   - ads