Skip to content

Commit a99f9e6

Browse files
[interactive_media_ads] Adds internal wrapper for iOS native IMACompanionAd (#7873)
1 parent 5582669 commit a99f9e6

File tree

12 files changed

+392
-51
lines changed

12 files changed

+392
-51
lines changed

packages/interactive_media_ads/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.2+12
2+
3+
* Adds internal wrapper for iOS native `IMACompanionAd`.
4+
15
## 0.2.2+11
26

37
* Adds internal wrapper for Android native `UniversalAdId`.

packages/interactive_media_ads/CONTRIBUTING.md

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -135,40 +135,21 @@ To update a wrapper for a platform, follow the steps:
135135
* Android: Run `flutter build apk --debug` in `example/`.
136136
* iOS: Run `flutter build ios --simulator` in `example/`
137137

138-
##### 2. Ensure the correct `pigeon` package is added to `dev_dependencies` in the `pubspec.yaml` and run `pub upgrade`
138+
##### 2. Make changes to the respective pigeon file that matches the native SDK
139139

140-
Android:
141-
142-
```yaml
143-
pigeon: ^22.2.0
144-
```
145-
146-
iOS:
147-
148-
```yaml
149-
pigeon:
150-
git:
151-
url: [email protected]:bparrishMines/packages.git
152-
ref: pigeon_wrapper_swift
153-
path: packages/pigeon
154-
```
155-
156-
##### 3. Uncomment the multiline comments in the pigeon file
157-
158-
* Android: `pigeons/interactive_media_ads_android.dart`
159-
* iOS: `pigeons/interactive_media_ads_ios.dart`
160-
161-
##### 4. Make changes that match the native SDK
162-
163-
* [Android SDK]
164-
* [iOS SDK]
140+
* Android:
141+
- [Android SDK]
142+
- Pigeon file to update: `pigeons/interactive_media_ads_android.dart`
143+
* iOS:
144+
- [iOS SDK]
145+
- Pigeon file to update: `pigeons/interactive_media_ads_ios.dart`
165146

166-
##### 5. Run the code generator from the terminal
147+
##### 3. Run the code generator from the terminal
167148

168149
* Android: `dart run pigeon --input pigeons/interactive_media_ads_android.dart`
169150
* iOS: `dart run pigeon --input pigeons/interactive_media_ads_ios.dart`
170151

171-
##### 6. Update the generated APIs in native code
152+
##### 4. Update the generated APIs in native code
172153

173154
Running the `flutter build` step from step 1 again should provide build errors and indicate what
174155
needs to be done. Alternatively, it can be easier to update native code with the platform's specific
@@ -177,7 +158,7 @@ IDE:
177158
* Android: Open `example/android/` in a separate Android Studio project.
178159
* iOS: Open `example/ios/` in Xcode.
179160

180-
##### 7. Write API tests
161+
##### 5. Write API tests
181162

182163
Assuming a non-static method or constructor was added to the native wrapper, a native test will need
183164
to be added.

packages/interactive_media_ads/android/src/main/kotlin/dev/flutter/packages/interactive_media_ads/AdsRequestProxyApi.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class AdsRequestProxyApi(override val pigeonRegistrar: ProxyApiRegistrar) :
2121
*
2222
* This must match the version in pubspec.yaml.
2323
*/
24-
const val pluginVersion = "0.2.2+11"
24+
const val pluginVersion = "0.2.2+12"
2525
}
2626

2727
override fun setAdTagUrl(pigeon_instance: AdsRequest, adTagUrl: String) {

packages/interactive_media_ads/example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
8F599BBB2C332C010090A0DF /* AdsRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F599BBA2C332C010090A0DF /* AdsRequestTests.swift */; };
2121
8F599BBD2C332CFE0090A0DF /* ContentPlayheadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */; };
2222
8F599BBF2C3335B40090A0DF /* ViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */; };
23+
8F8382A32CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */; };
2324
8F977DCF2C2B99C600A90D4B /* AdDisplayContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DCE2C2B99C600A90D4B /* AdDisplayContainerTests.swift */; };
2425
8F977DD32C2BA15100A90D4B /* TestProxyApiRegistrar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DD22C2BA15100A90D4B /* TestProxyApiRegistrar.swift */; };
2526
8F977DD52C2C777600A90D4B /* AdErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8F977DD42C2C777600A90D4B /* AdErrorTests.swift */; };
@@ -78,6 +79,7 @@
7879
8F599BBA2C332C010090A0DF /* AdsRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdsRequestTests.swift; sourceTree = "<group>"; };
7980
8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentPlayheadTests.swift; sourceTree = "<group>"; };
8081
8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerTests.swift; sourceTree = "<group>"; };
82+
8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanionAdProxyApiTests.swift; sourceTree = "<group>"; };
8183
8F977DCE2C2B99C600A90D4B /* AdDisplayContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdDisplayContainerTests.swift; sourceTree = "<group>"; };
8284
8F977DD22C2BA15100A90D4B /* TestProxyApiRegistrar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProxyApiRegistrar.swift; sourceTree = "<group>"; };
8385
8F977DD42C2C777600A90D4B /* AdErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdErrorTests.swift; sourceTree = "<group>"; };
@@ -133,6 +135,7 @@
133135
8F599BBA2C332C010090A0DF /* AdsRequestTests.swift */,
134136
8F599BBC2C332CFE0090A0DF /* ContentPlayheadTests.swift */,
135137
8F599BBE2C3335B40090A0DF /* ViewControllerTests.swift */,
138+
8F8382A22CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift */,
136139
);
137140
path = RunnerTests;
138141
sourceTree = "<group>";
@@ -411,6 +414,7 @@
411414
buildActionMask = 2147483647;
412415
files = (
413416
8F599BBF2C3335B40090A0DF /* ViewControllerTests.swift in Sources */,
417+
8F8382A32CBDB4A4007F28E0 /* CompanionAdProxyApiTests.swift in Sources */,
414418
8FC919922CA5D86F00188068 /* FriendlyObstructionTests.swift in Sources */,
415419
8F977DD92C2C8C6A00A90D4B /* AdLoadingErrorDataTests.swift in Sources */,
416420
8F599BB32C2DD87D0090A0DF /* AdsLoaderTests.swift in Sources */,
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import Flutter
6+
import GoogleInteractiveMediaAds
7+
import XCTest
8+
9+
@testable import interactive_media_ads
10+
11+
class CompanionAdProxyApiTests: XCTestCase {
12+
func testResourceValue() {
13+
let registrar = TestProxyApiRegistrar()
14+
let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
15+
16+
let instance = TestCompanionAd.customInit()
17+
let value = try? api.pigeonDelegate.resourceValue(pigeonApi: api, pigeonInstance: instance)
18+
19+
XCTAssertEqual(value, instance.resourceValue)
20+
}
21+
22+
func testApiFramework() {
23+
let registrar = TestProxyApiRegistrar()
24+
let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
25+
26+
let instance = TestCompanionAd.customInit()
27+
let value = try? api.pigeonDelegate.apiFramework(pigeonApi: api, pigeonInstance: instance)
28+
29+
XCTAssertEqual(value, instance.apiFramework)
30+
}
31+
32+
func testWidth() {
33+
let registrar = TestProxyApiRegistrar()
34+
let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
35+
36+
let instance = TestCompanionAd.customInit()
37+
let value = try? api.pigeonDelegate.width(pigeonApi: api, pigeonInstance: instance)
38+
39+
XCTAssertEqual(value, Int64(instance.width))
40+
}
41+
42+
func testHeight() {
43+
let registrar = TestProxyApiRegistrar()
44+
let api = registrar.apiDelegate.pigeonApiIMACompanionAd(registrar)
45+
46+
let instance = TestCompanionAd.customInit()
47+
let value = try? api.pigeonDelegate.height(pigeonApi: api, pigeonInstance: instance)
48+
49+
XCTAssertEqual(value, Int64(instance.height))
50+
}
51+
52+
}
53+
54+
class TestCompanionAd: IMACompanionAd {
55+
// Workaround to subclass an Objective-C class that has an `init` constructor with NS_UNAVAILABLE
56+
static func customInit() -> TestCompanionAd {
57+
let instance =
58+
TestCompanionAd.perform(NSSelectorFromString("new")).takeRetainedValue() as! TestCompanionAd
59+
return instance
60+
}
61+
62+
override var resourceValue: String? {
63+
return "resourceValue"
64+
}
65+
66+
override var apiFramework: String? {
67+
return "apiFramework"
68+
}
69+
70+
override var width: Int {
71+
return 0
72+
}
73+
74+
override var height: Int {
75+
return 1
76+
}
77+
}

packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/AdsRequestProxyAPIDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class AdsRequestProxyAPIDelegate: PigeonApiDelegateIMAAdsRequest {
1313
/// The current version of the `interactive_media_ads` plugin.
1414
///
1515
/// This must match the version in pubspec.yaml.
16-
static let pluginVersion = "0.2.2+11"
16+
static let pluginVersion = "0.2.2+12"
1717

1818
func pigeonDefaultConstructor(
1919
pigeonApi: PigeonApiIMAAdsRequest, adTagUrl: String, adDisplayContainer: IMAAdDisplayContainer,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import Foundation
6+
import GoogleInteractiveMediaAds
7+
8+
/// ProxyApi implementation for [IMACompanionAd].
9+
///
10+
/// This class may handle instantiating native object instances that are attached to a Dart instance
11+
/// or handle method calls on the associated native class or an instance of that class.
12+
class CompanionAdProxyAPIDelegate: PigeonApiDelegateIMACompanionAd {
13+
func resourceValue(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
14+
-> String?
15+
{
16+
return pigeonInstance.resourceValue
17+
}
18+
19+
func apiFramework(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
20+
-> String?
21+
{
22+
return pigeonInstance.apiFramework
23+
}
24+
25+
func width(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64 {
26+
return Int64(pigeonInstance.width)
27+
}
28+
29+
func height(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64 {
30+
return Int64(pigeonInstance.height)
31+
}
32+
}

packages/interactive_media_ads/ios/interactive_media_ads/Sources/interactive_media_ads/InteractiveMediaAdsLibrary.g.swift

Lines changed: 110 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,10 @@ protocol InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
445445
func pigeonApiIMAFriendlyObstruction(
446446
_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
447447
) -> PigeonApiIMAFriendlyObstruction
448+
/// An implementation of [PigeonApiIMACompanionAd] used to add a new Dart instance of
449+
/// `IMACompanionAd` to the Dart `InstanceManager` and make calls to Dart.
450+
func pigeonApiIMACompanionAd(_ registrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar)
451+
-> PigeonApiIMACompanionAd
448452
}
449453

450454
extension InteractiveMediaAdsLibraryPigeonProxyApiDelegate {
@@ -769,8 +773,20 @@ private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter:
769773
return
770774
}
771775

772-
if let instance = value as? NSObject {
773-
pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar).pigeonNewInstance(
776+
if let instance = value as? IMAFriendlyObstruction {
777+
pigeonRegistrar.apiDelegate.pigeonApiIMAFriendlyObstruction(pigeonRegistrar)
778+
.pigeonNewInstance(
779+
pigeonInstance: instance
780+
) { _ in }
781+
super.writeByte(128)
782+
super.writeValue(
783+
pigeonRegistrar.instanceManager.identifierWithStrongReference(
784+
forInstance: instance as AnyObject)!)
785+
return
786+
}
787+
788+
if let instance = value as? IMACompanionAd {
789+
pigeonRegistrar.apiDelegate.pigeonApiIMACompanionAd(pigeonRegistrar).pigeonNewInstance(
774790
pigeonInstance: instance
775791
) { _ in }
776792
super.writeByte(128)
@@ -780,11 +796,10 @@ private class InteractiveMediaAdsLibraryPigeonInternalProxyApiCodecReaderWriter:
780796
return
781797
}
782798

783-
if let instance = value as? IMAFriendlyObstruction {
784-
pigeonRegistrar.apiDelegate.pigeonApiIMAFriendlyObstruction(pigeonRegistrar)
785-
.pigeonNewInstance(
786-
pigeonInstance: instance
787-
) { _ in }
799+
if let instance = value as? NSObject {
800+
pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar).pigeonNewInstance(
801+
pigeonInstance: instance
802+
) { _ in }
788803
super.writeByte(128)
789804
super.writeValue(
790805
pigeonRegistrar.instanceManager.identifierWithStrongReference(
@@ -3156,6 +3171,11 @@ protocol PigeonApiProtocolIMAFriendlyObstruction {
31563171
final class PigeonApiIMAFriendlyObstruction: PigeonApiProtocolIMAFriendlyObstruction {
31573172
unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
31583173
let pigeonDelegate: PigeonApiDelegateIMAFriendlyObstruction
3174+
///An implementation of [NSObject] used to access callback methods
3175+
var pigeonApiNSObject: PigeonApiNSObject {
3176+
return pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar)
3177+
}
3178+
31593179
init(
31603180
pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
31613181
delegate: PigeonApiDelegateIMAFriendlyObstruction
@@ -3244,3 +3264,86 @@ final class PigeonApiIMAFriendlyObstruction: PigeonApiProtocolIMAFriendlyObstruc
32443264
}
32453265
}
32463266
}
3267+
protocol PigeonApiDelegateIMACompanionAd {
3268+
/// The value for the resource of this companion.
3269+
func resourceValue(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
3270+
-> String?
3271+
/// The API needed to execute this ad, or nil if unavailable.
3272+
func apiFramework(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws
3273+
-> String?
3274+
/// The width of the companion in pixels.
3275+
///
3276+
/// 0 if unavailable.
3277+
func width(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64
3278+
/// The height of the companion in pixels.
3279+
///
3280+
/// 0 if unavailable.
3281+
func height(pigeonApi: PigeonApiIMACompanionAd, pigeonInstance: IMACompanionAd) throws -> Int64
3282+
}
3283+
3284+
protocol PigeonApiProtocolIMACompanionAd {
3285+
}
3286+
3287+
final class PigeonApiIMACompanionAd: PigeonApiProtocolIMACompanionAd {
3288+
unowned let pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar
3289+
let pigeonDelegate: PigeonApiDelegateIMACompanionAd
3290+
///An implementation of [NSObject] used to access callback methods
3291+
var pigeonApiNSObject: PigeonApiNSObject {
3292+
return pigeonRegistrar.apiDelegate.pigeonApiNSObject(pigeonRegistrar)
3293+
}
3294+
3295+
init(
3296+
pigeonRegistrar: InteractiveMediaAdsLibraryPigeonProxyApiRegistrar,
3297+
delegate: PigeonApiDelegateIMACompanionAd
3298+
) {
3299+
self.pigeonRegistrar = pigeonRegistrar
3300+
self.pigeonDelegate = delegate
3301+
}
3302+
///Creates a Dart instance of IMACompanionAd and attaches it to [pigeonInstance].
3303+
func pigeonNewInstance(
3304+
pigeonInstance: IMACompanionAd, completion: @escaping (Result<Void, PigeonError>) -> Void
3305+
) {
3306+
if pigeonRegistrar.ignoreCallsToDart {
3307+
completion(
3308+
.failure(
3309+
PigeonError(
3310+
code: "ignore-calls-error",
3311+
message: "Calls to Dart are being ignored.", details: "")))
3312+
return
3313+
}
3314+
if pigeonRegistrar.instanceManager.containsInstance(pigeonInstance as AnyObject) {
3315+
completion(.success(Void()))
3316+
return
3317+
}
3318+
let pigeonIdentifierArg = pigeonRegistrar.instanceManager.addHostCreatedInstance(
3319+
pigeonInstance as AnyObject)
3320+
let resourceValueArg = try! pigeonDelegate.resourceValue(
3321+
pigeonApi: self, pigeonInstance: pigeonInstance)
3322+
let apiFrameworkArg = try! pigeonDelegate.apiFramework(
3323+
pigeonApi: self, pigeonInstance: pigeonInstance)
3324+
let widthArg = try! pigeonDelegate.width(pigeonApi: self, pigeonInstance: pigeonInstance)
3325+
let heightArg = try! pigeonDelegate.height(pigeonApi: self, pigeonInstance: pigeonInstance)
3326+
let binaryMessenger = pigeonRegistrar.binaryMessenger
3327+
let codec = pigeonRegistrar.codec
3328+
let channelName: String =
3329+
"dev.flutter.pigeon.interactive_media_ads.IMACompanionAd.pigeon_newInstance"
3330+
let channel = FlutterBasicMessageChannel(
3331+
name: channelName, binaryMessenger: binaryMessenger, codec: codec)
3332+
channel.sendMessage(
3333+
[pigeonIdentifierArg, resourceValueArg, apiFrameworkArg, widthArg, heightArg] as [Any?]
3334+
) { response in
3335+
guard let listResponse = response as? [Any?] else {
3336+
completion(.failure(createConnectionError(withChannelName: channelName)))
3337+
return
3338+
}
3339+
if listResponse.count > 1 {
3340+
let code: String = listResponse[0] as! String
3341+
let message: String? = nilOrValue(listResponse[1])
3342+
let details: String? = nilOrValue(listResponse[2])
3343+
completion(.failure(PigeonError(code: code, message: message, details: details)))
3344+
} else {
3345+
completion(.success(Void()))
3346+
}
3347+
}
3348+
}
3349+
}

0 commit comments

Comments
 (0)