diff --git a/packages/interactive_media_ads/CHANGELOG.md b/packages/interactive_media_ads/CHANGELOG.md index 7bfcc2e6e164..5ae570839df5 100644 --- a/packages/interactive_media_ads/CHANGELOG.md +++ b/packages/interactive_media_ads/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.2.2+14 + +* Adds internal wrapper for iOS native `IMACompanionAdSlot` and `IMACompanionDelegate`. + ## 0.2.2+13 * Adds internal wrapper for Android native `Ad`. 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 469848956ca2..a2c2dde0c086 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 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) : * * This must match the version in pubspec.yaml. */ - const val pluginVersion = "0.2.2+13" + const val pluginVersion = "0.2.2+14" } 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 545e2e91598f..b37fd7b5a413 100644 --- a/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ 8F977DD92C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DD82C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift */; }; 8F977DDB2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DDA2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift */; }; 8FC919922CA5D86F00188068 /* FriendlyObstructionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FC919912CA5D86F00188068 /* FriendlyObstructionTests.swift */; }; + 8FFF0C182CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */; }; + 8FFF0C1A2CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -87,6 +89,8 @@ 8F977DD82C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdLoadingErrorDataTests.swift; sourceTree = ""; }; 8F977DDA2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsLoadedDataTests.swift; sourceTree = ""; }; 8FC919912CA5D86F00188068 /* FriendlyObstructionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FriendlyObstructionTests.swift; sourceTree = ""; }; + 8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanionAdSlotProxyApiTests.swift; sourceTree = ""; }; + 8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanionDelegateProxyApiTests.swift; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -136,6 +140,8 @@ 8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */, 8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */, 8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */, + 8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */, + 8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */, ); path = RunnerTests; sourceTree = ""; @@ -423,6 +429,8 @@ 8F599BBB2C332C010090A0DF /* AdsRequestTests.swift in Sources */, 8F599BB72C3327F10090A0DF /* AdsManagerDelegateTests.swift in Sources */, 8F599BBD2C332CFE0090A0DF /* ContentPlayheadTests.swift in Sources */, + 8FFF0C182CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift in Sources */, + 8FFF0C1A2CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift in Sources */, 8F977DCF2C2B99C600A90D4B /* AdDisplayContainerTests.swift in Sources */, 8F599BB52C2DD8EC0090A0DF /* AdsLoaderDelegateTests.swift in Sources */, 8F599BB92C332A320090A0DF /* AdsRenderingSettingsTests.swift in Sources */, diff --git a/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdSlotProxyApiTests.swift b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdSlotProxyApiTests.swift new file mode 100644 index 000000000000..987389e58226 --- /dev/null +++ b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionAdSlotProxyApiTests.swift @@ -0,0 +1,58 @@ +// 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 UIKit +import XCTest + +@testable import interactive_media_ads + +class CompanionAdSlotProxyApiTests: XCTestCase { + func testPigeonDefaultConstructor() { + let registrar = TestProxyApiRegistrar() + let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar) + + let view = UIView() + let instance = try! api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api, view: view) + XCTAssertEqual(instance.view, view) + } + + func testSize() { + let registrar = TestProxyApiRegistrar() + let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar) + + let view = UIView() + let width = 0 + let height = 1 + let instance = try! api.pigeonDelegate.size( + pigeonApi: api, view: view, width: Int64(width), height: Int64(height)) + XCTAssertEqual(instance.view, view) + XCTAssertEqual(instance.width, width) + XCTAssertEqual(instance.height, height) + } + + func testView() { + let registrar = TestProxyApiRegistrar() + let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar) + + let instance = IMACompanionAdSlot(view: UIView()) + let value = try? api.pigeonDelegate.view(pigeonApi: api, pigeonInstance: instance) + + XCTAssertEqual(value, instance.view) + } + + func testSetDelegate() { + let registrar = TestProxyApiRegistrar() + let api = registrar.apiDelegate.pigeonApiIMACompanionAdSlot(registrar) + + let instance = IMACompanionAdSlot(view: UIView()) + let delegate = CompanionDelegateImpl( + api: registrar.apiDelegate.pigeonApiIMACompanionDelegate(registrar)) + try? api.pigeonDelegate.setDelegate( + pigeonApi: api, pigeonInstance: instance, delegate: delegate) + + XCTAssertIdentical(instance.delegate, delegate) + } +} diff --git a/packages/interactive_media_ads/example/ios/RunnerTests/CompanionDelegateProxyApiTests.swift b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionDelegateProxyApiTests.swift new file mode 100644 index 000000000000..e66f5e2a5f06 --- /dev/null +++ b/packages/interactive_media_ads/example/ios/RunnerTests/CompanionDelegateProxyApiTests.swift @@ -0,0 +1,59 @@ +// 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 UIKit +import XCTest + +@testable import interactive_media_ads + +class CompanionDelegateProxyApiTests: XCTestCase { + func testPigeonDefaultConstructor() { + let registrar = TestProxyApiRegistrar() + let api = registrar.apiDelegate.pigeonApiIMACompanionDelegate(registrar) + + let instance = try? api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api) + XCTAssertNotNil(instance) + } + + func testCompanionAdSlotFilled() { + let api = TestCompanionDelegateApi() + let instance = CompanionDelegateImpl(api: api) + let slot = IMACompanionAdSlot(view: UIView()) + let filled = true + instance.companionSlot(slot, filled: filled) + + XCTAssertEqual(api.companionAdSlotFilledArgs, [slot, filled]) + } + + func testCompanionSlotWasClicked() { + let api = TestCompanionDelegateApi() + let instance = CompanionDelegateImpl(api: api) + let slot = IMACompanionAdSlot(view: UIView()) + instance.companionSlotWasClicked(slot) + + XCTAssertEqual(api.companionSlotWasClickedArgs, [slot]) + } +} + +class TestCompanionDelegateApi: PigeonApiProtocolIMACompanionDelegate { + var companionAdSlotFilledArgs: [AnyHashable?]? = nil + var companionSlotWasClickedArgs: [AnyHashable?]? = nil + + func companionAdSlotFilled( + pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot, + filled filledArg: Bool, + completion: @escaping (Result) -> Void + ) { + companionAdSlotFilledArgs = [slotArg, filledArg] + } + + func companionSlotWasClicked( + pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot, + completion: @escaping (Result) -> Void + ) { + companionSlotWasClickedArgs = [slotArg] + } +} 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 c451d574ab23..f652b7506cd1 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 @@ class AdsRequestProxyAPIDelegate: PigeonApiDelegateIMAAdsRequest { /// The current version of the `interactive_media_ads` plugin. /// /// This must match the version in pubspec.yaml. - static let pluginVersion = "0.2.2+13" + static let pluginVersion = "0.2.2+14" func pigeonDefaultConstructor( pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer, diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdSlotProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdSlotProxyAPIDelegate.swift new file mode 100644 index 000000000000..263063221a5e --- /dev/null +++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionAdSlotProxyAPIDelegate.swift @@ -0,0 +1,38 @@ +// 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 +import UIKit + +/// ProxyApi implementation for [IMACompanionAdSlot]. +/// +/// 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 CompanionAdSlotProxyAPIDelegate: PigeonApiDelegateIMACompanionAdSlot { + func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView) throws + -> IMACompanionAdSlot + { + return IMACompanionAdSlot(view: view) + } + + func size(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView, width: Int64, height: Int64) + throws -> IMACompanionAdSlot + { + return IMACompanionAdSlot(view: view, width: Int(width), height: Int(height)) + } + + func view(pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot) throws + -> UIView + { + return pigeonInstance.view + } + + func setDelegate( + pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot, + delegate: IMACompanionDelegate? + ) throws { + pigeonInstance.delegate = delegate + } +} diff --git a/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionDelegateProxyAPIDelegate.swift b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionDelegateProxyAPIDelegate.swift new file mode 100644 index 000000000000..b7e1a5f6d08b --- /dev/null +++ b/packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/CompanionDelegateProxyAPIDelegate.swift @@ -0,0 +1,35 @@ +// 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 + +/// Implementation of `IMACompanionDelegate` that calls to Dart in callback methods. +class CompanionDelegateImpl: NSObject, IMACompanionDelegate { + let api: PigeonApiProtocolIMACompanionDelegate + + init(api: PigeonApiProtocolIMACompanionDelegate) { + self.api = api + } + + func companionSlot(_ slot: IMACompanionAdSlot, filled: Bool) { + api.companionAdSlotFilled(pigeonInstance: self, slot: slot, filled: filled) { _ in } + } + + func companionSlotWasClicked(_ slot: IMACompanionAdSlot) { + api.companionSlotWasClicked(pigeonInstance: self, slot: slot) { _ in } + } +} + +/// ProxyApi implementation for [IMACompanionDelegate]. +/// +/// 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 CompanionDelegateProxyAPIDelegate: PigeonApiDelegateIMACompanionDelegate { + func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionDelegate) throws + -> IMACompanionDelegate + { + return CompanionDelegateImpl(api: pigeonApi) + } +} 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 3100f774490d..501b6ac923ff 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 @@ -449,6 +449,14 @@ protocol InteractiveMediaAdsLibraryPigeonProxyApiDelegate { /// `IMACompanionAd` to the Dart `InstanceManager` and make calls to Dart. func pigeonApiIMACompanionAd(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar) -> PigeonApiIMACompanionAd + /// An implementation of [PigeonApiIMACompanionAdSlot] used to add a new Dart instance of + /// `IMACompanionAdSlot` to the Dart `InstanceManager` and make calls to Dart. + func pigeonApiIMACompanionAdSlot(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar) + -> PigeonApiIMACompanionAdSlot + /// An implementation of [PigeonApiIMACompanionDelegate] used to add a new Dart instance of + /// `IMACompanionDelegate` to the Dart `InstanceManager` and make calls to Dart. + func pigeonApiIMACompanionDelegate(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar) + -> PigeonApiIMACompanionDelegate } extension InteractiveMediaAdsLibraryPigeonProxyApiDelegate { @@ -536,6 +544,10 @@ open class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar { binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMAAdsRenderingSettings(self)) PigeonApiIMAFriendlyObstruction.setUpMessageHandlers( binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMAFriendlyObstruction(self)) + PigeonApiIMACompanionAdSlot.setUpMessageHandlers( + binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMACompanionAdSlot(self)) + PigeonApiIMACompanionDelegate.setUpMessageHandlers( + binaryMessenger: binaryMessenger, api: apiDelegate.pigeonApiIMACompanionDelegate(self)) } func tearDown() { InteractiveMediaAdsLibraryPigeonInstanceManagerApi.setUpMessageHandlers( @@ -551,6 +563,8 @@ open class InteractiveMediaAdsLibraryPigeonProxyApiRegistrar { PigeonApiIMAAdsRenderingSettings.setUpMessageHandlers( binaryMessenger: binaryMessenger, api: nil) PigeonApiIMAFriendlyObstruction.setUpMessageHandlers(binaryMessenger: binaryMessenger, api: nil) + PigeonApiIMACompanionAdSlot.setUpMessageHandlers(binaryMessenger: binaryMessenger, api: nil) + PigeonApiIMACompanionDelegate.setUpMessageHandlers(binaryMessenger: binaryMessenger, api: nil) } } private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter: @@ -796,6 +810,29 @@ private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter: return } + if let instance = value as? IMACompanionAdSlot { + pigeonRegistrar.apiDelegate.pigeonApiIMACompanionAdSlot(pigeonRegistrar).pigeonNewInstance( + pigeonInstance: instance + ) { _ in } + super.writeByte(128) + super.writeValue( + pigeonRegistrar.instanceManager.identifierWithStrongReference( + forInstance: instance as AnyObject)!) + return + } + + if let instance = value as? IMACompanionDelegate { + pigeonRegistrar.apiDelegate.pigeonApiIMACompanionDelegate(pigeonRegistrar) + .pigeonNewInstance( + pigeonInstance: instance + ) { _ in } + super.writeByte(128) + super.writeValue( + pigeonRegistrar.instanceManager.identifierWithStrongReference( + forInstance: instance as AnyObject)!) + return + } + if let instance = value as? NSObject { pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar).pigeonNewInstance( pigeonInstance: instance @@ -3347,3 +3384,328 @@ final class PigeonApiIMACompanionAd: PigeonApiProtocolIMACompanionAd { } } } +protocol PigeonApiDelegateIMACompanionAdSlot { + /// Initializes an instance of a IMACompanionAdSlot with fluid size. + func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView) throws + -> IMACompanionAdSlot + /// Initializes an instance of a IMACompanionAdSlot with design ad width and + /// height. + /// + /// `width` and `height` are in pixels. + func size(pigeonApi: PigeonApiIMACompanionAdSlot, view: UIView, width: Int64, height: Int64) + throws -> IMACompanionAdSlot + /// The view the companion will be rendered in. + /// + /// Display this view in your application before video ad starts. + func view(pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot) throws + -> UIView + /// The IMACompanionDelegate for receiving events from the companion ad slot. + /// + /// This instance only creates a weak reference to the delegate, so the Dart + /// instance should create an explicit reference to receive callbacks. + func setDelegate( + pigeonApi: PigeonApiIMACompanionAdSlot, pigeonInstance: IMACompanionAdSlot, + delegate: IMACompanionDelegate?) throws +} + +protocol PigeonApiProtocolIMACompanionAdSlot { +} + +final class PigeonApiIMACompanionAdSlot: PigeonApiProtocolIMACompanionAdSlot { + unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar + let pigeonDelegate: PigeonApiDelegateIMACompanionAdSlot + init( + pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar, + delegate: PigeonApiDelegateIMACompanionAdSlot + ) { + self.pigeonRegistrar = pigeonRegistrar + self.pigeonDelegate = delegate + } + static func setUpMessageHandlers( + binaryMessenger: FlutterBinaryMessenger, api: PigeonApiIMACompanionAdSlot? + ) { + let codec: FlutterStandardMessageCodec = + api != nil + ? FlutterStandardMessageCodec( + readerWriter: InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter( + pigeonRegistrar: api!.pigeonRegistrar)) + : FlutterStandardMessageCodec.sharedInstance() + let pigeonDefaultConstructorChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pigeonDefaultConstructorChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pigeonIdentifierArg = args[0] as! Int64 + let viewArg = args[1] as! UIView + do { + api.pigeonRegistrar.instanceManager.addDartCreatedInstance( + try api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api, view: viewArg), + withIdentifier: pigeonIdentifierArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + pigeonDefaultConstructorChannel.setMessageHandler(nil) + } + let sizeChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + sizeChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pigeonIdentifierArg = args[0] as! Int64 + let viewArg = args[1] as! UIView + let widthArg = args[2] as! Int64 + let heightArg = args[3] as! Int64 + do { + api.pigeonRegistrar.instanceManager.addDartCreatedInstance( + try api.pigeonDelegate.size( + pigeonApi: api, view: viewArg, width: widthArg, height: heightArg), + withIdentifier: pigeonIdentifierArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + sizeChannel.setMessageHandler(nil) + } + let setDelegateChannel = FlutterBasicMessageChannel( + name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.setDelegate", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + setDelegateChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pigeonInstanceArg = args[0] as! IMACompanionAdSlot + let delegateArg: IMACompanionDelegate? = nilOrValue(args[1]) + do { + try api.pigeonDelegate.setDelegate( + pigeonApi: api, pigeonInstance: pigeonInstanceArg, delegate: delegateArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + setDelegateChannel.setMessageHandler(nil) + } + } + + ///Creates a Dart instance of IMACompanionAdSlot and attaches it to [pigeonInstance]. + func pigeonNewInstance( + pigeonInstance: IMACompanionAdSlot, completion: @escaping (Result) -> 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 viewArg = try! pigeonDelegate.view(pigeonApi: self, pigeonInstance: pigeonInstance) + let binaryMessenger = pigeonRegistrar.binaryMessenger + let codec = pigeonRegistrar.codec + let channelName: String = + "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([pigeonIdentifierArg, viewArg] 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())) + } + } + } +} +protocol PigeonApiDelegateIMACompanionDelegate { + func pigeonDefaultConstructor(pigeonApi: PigeonApiIMACompanionDelegate) throws + -> IMACompanionDelegate +} + +protocol PigeonApiProtocolIMACompanionDelegate { + /// Called when the slot is either filled or not filled. + func companionAdSlotFilled( + pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot, + filled filledArg: Bool, completion: @escaping (Result) -> Void) + /// Called when the slot is clicked on by the user and will successfully + /// navigate away. + func companionSlotWasClicked( + pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot, + completion: @escaping (Result) -> Void) +} + +final class PigeonApiIMACompanionDelegate: PigeonApiProtocolIMACompanionDelegate { + unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar + let pigeonDelegate: PigeonApiDelegateIMACompanionDelegate + ///An implementation of [NSObject] used to access callback methods + var pigeonApiNSObject: PigeonApiNSObject { + return pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar) + } + + init( + pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar, + delegate: PigeonApiDelegateIMACompanionDelegate + ) { + self.pigeonRegistrar = pigeonRegistrar + self.pigeonDelegate = delegate + } + static func setUpMessageHandlers( + binaryMessenger: FlutterBinaryMessenger, api: PigeonApiIMACompanionDelegate? + ) { + let codec: FlutterStandardMessageCodec = + api != nil + ? FlutterStandardMessageCodec( + readerWriter: InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter( + pigeonRegistrar: api!.pigeonRegistrar)) + : FlutterStandardMessageCodec.sharedInstance() + let pigeonDefaultConstructorChannel = FlutterBasicMessageChannel( + name: + "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_defaultConstructor", + binaryMessenger: binaryMessenger, codec: codec) + if let api = api { + pigeonDefaultConstructorChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let pigeonIdentifierArg = args[0] as! Int64 + do { + api.pigeonRegistrar.instanceManager.addDartCreatedInstance( + try api.pigeonDelegate.pigeonDefaultConstructor(pigeonApi: api), + withIdentifier: pigeonIdentifierArg) + reply(wrapResult(nil)) + } catch { + reply(wrapError(error)) + } + } + } else { + pigeonDefaultConstructorChannel.setMessageHandler(nil) + } + } + + ///Creates a Dart instance of IMACompanionDelegate and attaches it to [pigeonInstance]. + func pigeonNewInstance( + pigeonInstance: IMACompanionDelegate, completion: @escaping (Result) -> 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 binaryMessenger = pigeonRegistrar.binaryMessenger + let codec = pigeonRegistrar.codec + let channelName: String = + "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_newInstance" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([pigeonIdentifierArg] 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())) + } + } + } + /// Called when the slot is either filled or not filled. + func companionAdSlotFilled( + pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot, + filled filledArg: Bool, completion: @escaping (Result) -> Void + ) { + if pigeonRegistrar.ignoreCallsToDart { + completion( + .failure( + PigeonError( + code: "ignore-calls-error", + message: "Calls to Dart are being ignored.", details: ""))) + return + } + let binaryMessenger = pigeonRegistrar.binaryMessenger + let codec = pigeonRegistrar.codec + let channelName: String = + "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([pigeonInstanceArg, slotArg, filledArg] 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())) + } + } + } + + /// Called when the slot is clicked on by the user and will successfully + /// navigate away. + func companionSlotWasClicked( + pigeonInstance pigeonInstanceArg: IMACompanionDelegate, slot slotArg: IMACompanionAdSlot, + completion: @escaping (Result) -> Void + ) { + if pigeonRegistrar.ignoreCallsToDart { + completion( + .failure( + PigeonError( + code: "ignore-calls-error", + message: "Calls to Dart are being ignored.", details: ""))) + return + } + let binaryMessenger = pigeonRegistrar.binaryMessenger + let codec = pigeonRegistrar.codec + let channelName: String = + "dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked" + let channel = FlutterBasicMessageChannel( + name: channelName, binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([pigeonInstanceArg, slotArg] 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 3c9a26c6a4fc..0475adf37efa 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 @@ -131,4 +131,18 @@ open class ProxyApiDelegate: InteractiveMediaAdsLibraryPigeonProxyApiDelegate { return PigeonApiIMACompanionAd( pigeonRegistrar: registrar, delegate: CompanionAdProxyAPIDelegate()) } + + func pigeonApiIMACompanionAdSlot(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar) + -> PigeonApiIMACompanionAdSlot + { + return PigeonApiIMACompanionAdSlot( + pigeonRegistrar: registrar, delegate: CompanionAdSlotProxyAPIDelegate()) + } + + func pigeonApiIMACompanionDelegate(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar) + -> PigeonApiIMACompanionDelegate + { + return PigeonApiIMACompanionDelegate( + pigeonRegistrar: registrar, delegate: CompanionDelegateProxyAPIDelegate()) + } } 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 b3ac07482862..a26cfa675acb 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 @@ -173,6 +173,10 @@ class PigeonInstanceManager { pigeon_instanceManager: instanceManager); IMACompanionAd.pigeon_setUpMessageHandlers( pigeon_instanceManager: instanceManager); + IMACompanionAdSlot.pigeon_setUpMessageHandlers( + pigeon_instanceManager: instanceManager); + IMACompanionDelegate.pigeon_setUpMessageHandlers( + pigeon_instanceManager: instanceManager); return instanceManager; } @@ -3608,3 +3612,450 @@ class IMACompanionAd extends NSObject { ); } } + +/// Ad slot for companion ads. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Classes/IMACompanionAdSlot. +class IMACompanionAdSlot extends PigeonInternalProxyApiBaseClass { + /// Initializes an instance of a IMACompanionAdSlot with fluid size. + IMACompanionAdSlot({ + super.pigeon_binaryMessenger, + super.pigeon_instanceManager, + required this.view, + }) { + final int pigeonVar_instanceIdentifier = + pigeon_instanceManager.addDartCreatedInstance(this); + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecIMACompanionAdSlot; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + () async { + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([pigeonVar_instanceIdentifier, view]) + as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + }(); + } + + /// Initializes an instance of a IMACompanionAdSlot with design ad width and + /// height. + /// + /// `width` and `height` are in pixels. + IMACompanionAdSlot.size({ + super.pigeon_binaryMessenger, + super.pigeon_instanceManager, + required this.view, + required int width, + required int height, + }) { + final int pigeonVar_instanceIdentifier = + pigeon_instanceManager.addDartCreatedInstance(this); + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecIMACompanionAdSlot; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + () async { + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.size'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel.send( + [pigeonVar_instanceIdentifier, view, width, height]) + as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + }(); + } + + /// Constructs [IMACompanionAdSlot] 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 + IMACompanionAdSlot.pigeon_detached({ + super.pigeon_binaryMessenger, + super.pigeon_instanceManager, + required this.view, + }); + + late final _PigeonInternalProxyApiBaseCodec + _pigeonVar_codecIMACompanionAdSlot = + _PigeonInternalProxyApiBaseCodec(pigeon_instanceManager); + + /// The view the companion will be rendered in. + /// + /// Display this view in your application before video ad starts. + final UIView view; + + static void pigeon_setUpMessageHandlers({ + bool pigeon_clearHandlers = false, + BinaryMessenger? pigeon_binaryMessenger, + PigeonInstanceManager? pigeon_instanceManager, + IMACompanionAdSlot Function(UIView view)? 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.IMACompanionAdSlot.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.IMACompanionAdSlot.pigeon_newInstance was null.'); + final List args = (message as List?)!; + final int? arg_pigeon_instanceIdentifier = (args[0] as int?); + assert(arg_pigeon_instanceIdentifier != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance was null, expected non-null int.'); + final UIView? arg_view = (args[1] as UIView?); + assert(arg_view != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_newInstance was null, expected non-null UIView.'); + try { + (pigeon_instanceManager ?? PigeonInstanceManager.instance) + .addHostCreatedInstance( + pigeon_newInstance?.call(arg_view!) ?? + IMACompanionAdSlot.pigeon_detached( + pigeon_binaryMessenger: pigeon_binaryMessenger, + pigeon_instanceManager: pigeon_instanceManager, + view: arg_view!, + ), + 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())); + } + }); + } + } + } + + /// The IMACompanionDelegate for receiving events from the companion ad slot. + /// + /// This instance only creates a weak reference to the delegate, so the Dart + /// instance should create an explicit reference to receive callbacks. + Future setDelegate(IMACompanionDelegate? delegate) async { + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecIMACompanionAdSlot; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.setDelegate'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([this, delegate]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + } + + @override + IMACompanionAdSlot pigeon_copy() { + return IMACompanionAdSlot.pigeon_detached( + pigeon_binaryMessenger: pigeon_binaryMessenger, + pigeon_instanceManager: pigeon_instanceManager, + view: view, + ); + } +} + +/// Delegate to receive events from the companion ad slot. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Protocols/IMACompanionDelegate.html. +class IMACompanionDelegate extends NSObject { + IMACompanionDelegate({ + super.pigeon_binaryMessenger, + super.pigeon_instanceManager, + this.companionAdSlotFilled, + this.companionSlotWasClicked, + }) : super.pigeon_detached() { + final int pigeonVar_instanceIdentifier = + pigeon_instanceManager.addDartCreatedInstance(this); + final _PigeonInternalProxyApiBaseCodec pigeonChannelCodec = + _pigeonVar_codecIMACompanionDelegate; + final BinaryMessenger? pigeonVar_binaryMessenger = pigeon_binaryMessenger; + () async { + const String pigeonVar_channelName = + 'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_defaultConstructor'; + final BasicMessageChannel pigeonVar_channel = + BasicMessageChannel( + pigeonVar_channelName, + pigeonChannelCodec, + binaryMessenger: pigeonVar_binaryMessenger, + ); + final List? pigeonVar_replyList = await pigeonVar_channel + .send([pigeonVar_instanceIdentifier]) as List?; + if (pigeonVar_replyList == null) { + throw _createConnectionError(pigeonVar_channelName); + } else if (pigeonVar_replyList.length > 1) { + throw PlatformException( + code: pigeonVar_replyList[0]! as String, + message: pigeonVar_replyList[1] as String?, + details: pigeonVar_replyList[2], + ); + } else { + return; + } + }(); + } + + /// Constructs [IMACompanionDelegate] 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 + IMACompanionDelegate.pigeon_detached({ + super.pigeon_binaryMessenger, + super.pigeon_instanceManager, + this.companionAdSlotFilled, + this.companionSlotWasClicked, + }) : super.pigeon_detached(); + + late final _PigeonInternalProxyApiBaseCodec + _pigeonVar_codecIMACompanionDelegate = + _PigeonInternalProxyApiBaseCodec(pigeon_instanceManager); + + /// Called when the slot is either filled or not filled. + /// + /// For the associated Native object to be automatically garbage collected, + /// it is required that the implementation of this `Function` doesn't have a + /// strong reference to the encapsulating class instance. When this `Function` + /// references a non-local variable, it is strongly recommended to access it + /// with a `WeakReference`: + /// + /// ```dart + /// final WeakReference weakMyVariable = WeakReference(myVariable); + /// final IMACompanionDelegate instance = IMACompanionDelegate( + /// companionAdSlotFilled: (IMACompanionDelegate pigeon_instance, ...) { + /// print(weakMyVariable?.target); + /// }, + /// ); + /// ``` + /// + /// Alternatively, [PigeonInstanceManager.removeWeakReference] can be used to + /// release the associated Native object manually. + final void Function( + IMACompanionDelegate pigeon_instance, + IMACompanionAdSlot slot, + bool filled, + )? companionAdSlotFilled; + + /// Called when the slot is clicked on by the user and will successfully + /// navigate away. + /// + /// For the associated Native object to be automatically garbage collected, + /// it is required that the implementation of this `Function` doesn't have a + /// strong reference to the encapsulating class instance. When this `Function` + /// references a non-local variable, it is strongly recommended to access it + /// with a `WeakReference`: + /// + /// ```dart + /// final WeakReference weakMyVariable = WeakReference(myVariable); + /// final IMACompanionDelegate instance = IMACompanionDelegate( + /// companionSlotWasClicked: (IMACompanionDelegate pigeon_instance, ...) { + /// print(weakMyVariable?.target); + /// }, + /// ); + /// ``` + /// + /// Alternatively, [PigeonInstanceManager.removeWeakReference] can be used to + /// release the associated Native object manually. + final void Function( + IMACompanionDelegate pigeon_instance, + IMACompanionAdSlot slot, + )? companionSlotWasClicked; + + static void pigeon_setUpMessageHandlers({ + bool pigeon_clearHandlers = false, + BinaryMessenger? pigeon_binaryMessenger, + PigeonInstanceManager? pigeon_instanceManager, + IMACompanionDelegate Function()? pigeon_newInstance, + void Function( + IMACompanionDelegate pigeon_instance, + IMACompanionAdSlot slot, + bool filled, + )? companionAdSlotFilled, + void Function( + IMACompanionDelegate pigeon_instance, + IMACompanionAdSlot slot, + )? companionSlotWasClicked, + }) { + 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.IMACompanionDelegate.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.IMACompanionDelegate.pigeon_newInstance was null.'); + final List args = (message as List?)!; + final int? arg_pigeon_instanceIdentifier = (args[0] as int?); + assert(arg_pigeon_instanceIdentifier != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.pigeon_newInstance was null, expected non-null int.'); + try { + (pigeon_instanceManager ?? PigeonInstanceManager.instance) + .addHostCreatedInstance( + pigeon_newInstance?.call() ?? + IMACompanionDelegate.pigeon_detached( + pigeon_binaryMessenger: pigeon_binaryMessenger, + pigeon_instanceManager: pigeon_instanceManager, + ), + 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())); + } + }); + } + } + + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled', + 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.IMACompanionDelegate.companionAdSlotFilled was null.'); + final List args = (message as List?)!; + final IMACompanionDelegate? arg_pigeon_instance = + (args[0] as IMACompanionDelegate?); + assert(arg_pigeon_instance != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null, expected non-null IMACompanionDelegate.'); + final IMACompanionAdSlot? arg_slot = (args[1] as IMACompanionAdSlot?); + assert(arg_slot != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null, expected non-null IMACompanionAdSlot.'); + final bool? arg_filled = (args[2] as bool?); + assert(arg_filled != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionAdSlotFilled was null, expected non-null bool.'); + try { + (companionAdSlotFilled ?? + arg_pigeon_instance!.companionAdSlotFilled) + ?.call(arg_pigeon_instance!, arg_slot!, arg_filled!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + + { + final BasicMessageChannel< + Object?> pigeonVar_channel = BasicMessageChannel< + Object?>( + 'dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked', + 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.IMACompanionDelegate.companionSlotWasClicked was null.'); + final List args = (message as List?)!; + final IMACompanionDelegate? arg_pigeon_instance = + (args[0] as IMACompanionDelegate?); + assert(arg_pigeon_instance != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked was null, expected non-null IMACompanionDelegate.'); + final IMACompanionAdSlot? arg_slot = (args[1] as IMACompanionAdSlot?); + assert(arg_slot != null, + 'Argument for dev.flutter.pigeon.interactive_media_ads.IMACompanionDelegate.companionSlotWasClicked was null, expected non-null IMACompanionAdSlot.'); + try { + (companionSlotWasClicked ?? + arg_pigeon_instance!.companionSlotWasClicked) + ?.call(arg_pigeon_instance!, arg_slot!); + return wrapResponse(empty: true); + } on PlatformException catch (e) { + return wrapResponse(error: e); + } catch (e) { + return wrapResponse( + error: PlatformException(code: 'error', message: e.toString())); + } + }); + } + } + } + + @override + IMACompanionDelegate pigeon_copy() { + return IMACompanionDelegate.pigeon_detached( + pigeon_binaryMessenger: pigeon_binaryMessenger, + pigeon_instanceManager: pigeon_instanceManager, + companionAdSlotFilled: companionAdSlotFilled, + companionSlotWasClicked: companionSlotWasClicked, + ); + } +} diff --git a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart index 664578c3f682..53b472f4fb62 100644 --- a/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart +++ b/packages/interactive_media_ads/lib/src/ios/interactive_media_ads_proxy.dart @@ -22,6 +22,9 @@ class InteractiveMediaAdsProxy { this.newIMAAdsManagerDelegate = IMAAdsManagerDelegate.new, this.newIMAAdsRenderingSettings = IMAAdsRenderingSettings.new, this.newIMAFriendlyObstruction = IMAFriendlyObstruction.new, + this.newIMACompanionAdSlot = IMACompanionAdSlot.new, + this.sizeIMACompanionAdSlot = IMACompanionAdSlot.size, + this.newIMACompanionDelegate = IMACompanionDelegate.new, }); /// Constructs [IMAAdDisplayContainer]. @@ -80,4 +83,18 @@ class InteractiveMediaAdsProxy { required FriendlyObstructionPurpose purpose, String? detailedReason, }) newIMAFriendlyObstruction; + + /// Constructs [IMACompanionAdSlot]. + final IMACompanionAdSlot Function({required UIView view}) + newIMACompanionAdSlot; + + /// Constructs [IMACompanionAdSlot]. + final IMACompanionAdSlot Function({ + required int width, + required int height, + required UIView view, + }) sizeIMACompanionAdSlot; + + /// Constructs [IMACompanionDelegate]. + final IMACompanionDelegate Function() newIMACompanionDelegate; } 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 ff34c8ed01b8..da64692f8456 100644 --- a/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart +++ b/packages/interactive_media_ads/pigeons/interactive_media_ads_ios.dart @@ -608,3 +608,47 @@ abstract class IMACompanionAd extends NSObject { /// 0 if unavailable. late final int height; } + +/// Ad slot for companion ads. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Classes/IMACompanionAdSlot. +@ProxyApi() +abstract class IMACompanionAdSlot { + /// Initializes an instance of a IMACompanionAdSlot with fluid size. + IMACompanionAdSlot(); + + /// Initializes an instance of a IMACompanionAdSlot with design ad width and + /// height. + /// + /// `width` and `height` are in pixels. + IMACompanionAdSlot.size(int width, int height); + + /// The view the companion will be rendered in. + /// + /// Display this view in your application before video ad starts. + late final UIView view; + + /// The IMACompanionDelegate for receiving events from the companion ad slot. + /// + /// This instance only creates a weak reference to the delegate, so the Dart + /// instance should create an explicit reference to receive callbacks. + void setDelegate(IMACompanionDelegate? delegate); +} + +/// Delegate to receive events from the companion ad slot. +/// +/// See https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Protocols/IMACompanionDelegate.html. +@ProxyApi() +abstract class IMACompanionDelegate extends NSObject { + IMACompanionDelegate(); + + /// Called when the slot is either filled or not filled. + late void Function( + IMACompanionAdSlot slot, + bool filled, + )? companionAdSlotFilled; + + /// Called when the slot is clicked on by the user and will successfully + /// navigate away. + late void Function(IMACompanionAdSlot slot)? companionSlotWasClicked; +} diff --git a/packages/interactive_media_ads/pubspec.yaml b/packages/interactive_media_ads/pubspec.yaml index d3101f0322d7..7f8c020004be 100644 --- a/packages/interactive_media_ads/pubspec.yaml +++ b/packages/interactive_media_ads/pubspec.yaml @@ -2,7 +2,7 @@ name: interactive_media_ads 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+13 # This must match the version in +version: 0.2.2+14 # 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`