Skip to content

[interactive_media_ads] Adds internal wrapper for iOS native IMAAdPodInfo #8429

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/interactive_media_ads/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.2.3+6

* Adds internal wrapper for iOS native `IMAAdPodInfo`.

## 0.2.3+5

* Bumps gradle-plugin to 2.1.0.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) :
*
* This must match the version in pubspec.yaml.
*/
const val pluginVersion = "0.2.3+5"
const val pluginVersion = "0.2.3+6"
}

override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
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 */; };
8F9035362D00D9A1004F6450 /* AdPodInfoProxyAPITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F9035352D00D9A1004F6450 /* AdPodInfoProxyAPITests.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 */; };
Expand Down Expand Up @@ -83,6 +84,7 @@
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>"; };
8F9035352D00D9A1004F6450 /* AdPodInfoProxyAPITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdPodInfoProxyAPITests.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>"; };
Expand Down Expand Up @@ -144,6 +146,7 @@
8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */,
8FFF0C172CC1A7F300A7CB98 /* CompanionAdSlotProxyApiTests.swift */,
8FFF0C192CC1A97B00A7CB98 /* CompanionDelegateProxyApiTests.swift */,
8F9035352D00D9A1004F6450 /* AdPodInfoProxyAPITests.swift */,
);
path = RunnerTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -426,6 +429,7 @@
8F599BB92C332A320090A0DF /* AdsRenderingSettingsTests.swift in Sources */,
8F977DD52C2C777600A90D4B /* AdErrorTests.swift in Sources */,
8F599BB12C2DD1FD0090A0DF /* AdsManagerTests.swift in Sources */,
8F9035362D00D9A1004F6450 /* AdPodInfoProxyAPITests.swift in Sources */,
8F977DDB2C2C8D2E00A90D4B /* AdsLoadedDataTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// 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 AdPodInfoProxyAPITests: XCTestCase {
func testAdPosition() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiIMAAdPodInfo(registrar)

let instance = TestAdPodInfo.customInit()
let value = try? api.pigeonDelegate.adPosition(pigeonApi: api, pigeonInstance: instance)

XCTAssertEqual(value, Int64(instance.adPosition))
}

func testMaxDuration() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiIMAAdPodInfo(registrar)

let instance = TestAdPodInfo.customInit()
let value = try? api.pigeonDelegate.maxDuration(pigeonApi: api, pigeonInstance: instance)

XCTAssertEqual(value, instance.maxDuration)
}

func testPodIndex() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiIMAAdPodInfo(registrar)

let instance = TestAdPodInfo.customInit()
let value = try? api.pigeonDelegate.podIndex(pigeonApi: api, pigeonInstance: instance)

XCTAssertEqual(value, Int64(instance.podIndex))
}

func testTimeOffset() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiIMAAdPodInfo(registrar)

let instance = TestAdPodInfo.customInit()
let value = try? api.pigeonDelegate.timeOffset(pigeonApi: api, pigeonInstance: instance)

XCTAssertEqual(value, instance.timeOffset)
}

func testTotalAds() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiIMAAdPodInfo(registrar)

let instance = TestAdPodInfo.customInit()
let value = try? api.pigeonDelegate.totalAds(pigeonApi: api, pigeonInstance: instance)

XCTAssertEqual(value, Int64(instance.totalAds))
}

func testIsBumper() {
let registrar = TestProxyApiRegistrar()
let api = registrar.apiDelegate.pigeonApiIMAAdPodInfo(registrar)

let instance = TestAdPodInfo.customInit()
let value = try? api.pigeonDelegate.isBumper(pigeonApi: api, pigeonInstance: instance)

XCTAssertEqual(value, instance.isBumper)
}
}

class TestAdPodInfo: IMAAdPodInfo {
// Workaround to subclass an Objective-C class that has an `init` constructor with NS_UNAVAILABLE
static func customInit() -> TestAdPodInfo {
let instance =
TestAdPodInfo.perform(NSSelectorFromString("new")).takeRetainedValue() as! TestAdPodInfo
return instance
}

override var adPosition: Int {
return 5
}

override var maxDuration: TimeInterval {
return 2.0
}

override var podIndex: Int {
return 3
}

override var timeOffset: TimeInterval {
return 6.0
}

override var totalAds: Int {
return 7
}

override var isBumper: Bool {
return false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// 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 `IMAAdPodInfo`.
///
/// 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 AdPodInfoProxyAPIDelegate: PigeonApiDelegateIMAAdPodInfo {
func adPosition(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Int64 {
return Int64(pigeonInstance.adPosition)
}

func maxDuration(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Double
{
return pigeonInstance.maxDuration
}

func podIndex(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Int64 {
return Int64(pigeonInstance.podIndex)
}

func timeOffset(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Double {
return pigeonInstance.timeOffset
}

func totalAds(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Int64 {
return Int64(pigeonInstance.totalAds)
}

func isBumper(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Bool {
return pigeonInstance.isBumper
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.3+5"
static let pluginVersion = "0.2.3+6"

func pigeonDefaultConstructor(
pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// 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.
// Autogenerated from Pigeon (v22.6.2), do not edit directly.
// Autogenerated from Pigeon (v22.7.2), do not edit directly.
// See also: https://pub.dev/packages/pigeon

import Foundation
Expand Down Expand Up @@ -457,6 +457,10 @@ protocol InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
/// `IMACompanionDelegate` to the Dart `InstanceManager` and make calls to Dart.
func pigeonApiIMACompanionDelegate(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
-> PigeonApiIMACompanionDelegate
/// An implementation of [PigeonApiIMAAdPodInfo] used to add a new Dart instance of
/// `IMAAdPodInfo` to the Dart `InstanceManager` and make calls to Dart.
func pigeonApiIMAAdPodInfo(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
-> PigeonApiIMAAdPodInfo
}

extension InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
Expand Down Expand Up @@ -844,6 +848,17 @@ private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter:
return
}

if let instance = value as? IMAAdPodInfo {
pigeonRegistrar.apiDelegate.pigeonApiIMAAdPodInfo(pigeonRegistrar).pigeonNewInstance(
pigeonInstance: instance
) { _ in }
super.writeByte(128)
super.writeValue(
pigeonRegistrar.instanceManager.identifierWithStrongReference(
forInstance: instance as AnyObject)!)
return
}

if let instance = value as AnyObject?,
pigeonRegistrar.instanceManager.containsInstance(instance)
{
Expand Down Expand Up @@ -3564,7 +3579,7 @@ final class PigeonApiIMACompanionAdSlot: PigeonApiProtocolIMACompanionAdSlot {
pigeonDefaultConstructorChannel.setMessageHandler(nil)
}
let sizeChannel = FlutterBasicMessageChannel(
name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.pigeon_defaultConstructor",
name: "dev.flutter.pigeon.interactive_media_ads.IMACompanionAdSlot.size",
binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
sizeChannel.setMessageHandler { message, reply in
Expand Down Expand Up @@ -3822,3 +3837,108 @@ final class PigeonApiIMACompanionDelegate: PigeonApiProtocolIMACompanionDelegate
}

}
protocol PigeonApiDelegateIMAAdPodInfo {
/// The position of this ad within an ad pod.
///
/// Will be 1 for standalone ads.
func adPosition(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Int64
/// The maximum duration of the pod in seconds.
///
/// For unknown duration, -1 is returned.
func maxDuration(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Double
/// Returns the index of the ad pod.
///
/// Client side: For a preroll pod, returns 0. For midrolls, returns 1, 2,…,
/// N. For a postroll pod, returns -1. Defaults to 0 if this ad is not part of
/// a pod, or this pod is not part of a playlist.
///
/// DAI VOD: Returns the index of the ad pod. For a preroll pod, returns 0.
/// For midrolls, returns 1, 2,…,N. For a postroll pod, returns N+1…N+X.
/// Defaults to 0 if this ad is not part of a pod, or this pod is not part of
/// a playlist.
///
/// DAI live stream: For a preroll pod, returns 0. For midrolls, returns the
/// break ID. Returns -2 if pod index cannot be determined (internal error).
func podIndex(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Int64
/// The position of the pod in the content in seconds.
///
/// Pre-roll returns 0, post-roll returns -1 and mid-rolls return the
/// scheduled time of the pod.
func timeOffset(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Double
/// Total number of ads in the pod this ad belongs to.
///
/// Will be 1 for standalone ads.
func totalAds(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Int64
/// Specifies whether the ad is a bumper.
///
/// Bumpers are short videos used to open and close ad breaks.
func isBumper(pigeonApi: PigeonApiIMAAdPodInfo, pigeonInstance: IMAAdPodInfo) throws -> Bool
}

protocol PigeonApiProtocolIMAAdPodInfo {
}

final class PigeonApiIMAAdPodInfo: PigeonApiProtocolIMAAdPodInfo {
unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
let pigeonDelegate: PigeonApiDelegateIMAAdPodInfo
init(
pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
delegate: PigeonApiDelegateIMAAdPodInfo
) {
self.pigeonRegistrar = pigeonRegistrar
self.pigeonDelegate = delegate
}
///Creates a Dart instance of IMAAdPodInfo and attaches it to [pigeonInstance].
func pigeonNewInstance(
pigeonInstance: IMAAdPodInfo, 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 adPositionArg = try! pigeonDelegate.adPosition(
pigeonApi: self, pigeonInstance: pigeonInstance)
let maxDurationArg = try! pigeonDelegate.maxDuration(
pigeonApi: self, pigeonInstance: pigeonInstance)
let podIndexArg = try! pigeonDelegate.podIndex(pigeonApi: self, pigeonInstance: pigeonInstance)
let timeOffsetArg = try! pigeonDelegate.timeOffset(
pigeonApi: self, pigeonInstance: pigeonInstance)
let totalAdsArg = try! pigeonDelegate.totalAds(pigeonApi: self, pigeonInstance: pigeonInstance)
let isBumperArg = try! pigeonDelegate.isBumper(pigeonApi: self, pigeonInstance: pigeonInstance)
let binaryMessenger = pigeonRegistrar.binaryMessenger
let codec = pigeonRegistrar.codec
let channelName: String =
"dev.flutter.pigeon.interactive_media_ads.IMAAdPodInfo.pigeon_newInstance"
let channel = FlutterBasicMessageChannel(
name: channelName, binaryMessenger: binaryMessenger, codec: codec)
channel.sendMessage(
[
pigeonIdentifierArg, adPositionArg, maxDurationArg, podIndexArg, timeOffsetArg, totalAdsArg,
isBumperArg,
] 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()))
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,10 @@ open class ProxyApiDelegate: InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
return PigeonApiIMACompanionDelegate(
pigeonRegistrar: registrar, delegate: CompanionDelegateProxyAPIDelegate())
}

func pigeonApiIMAAdPodInfo(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
-> PigeonApiIMAAdPodInfo
{
return PigeonApiIMAAdPodInfo(pigeonRegistrar: registrar, delegate: AdPodInfoProxyAPIDelegate())
}
}
Loading