@capacitor-community/admob 8.2.0-beta.pr483.shac8cc94ca69ee → 8.2.0-beta.pr484.shaa6be63853bbd
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorCommunityAdmob.podspec +1 -1
- package/Package.swift +1 -1
- package/README.md +1 -1
- package/docs/migration.md +3 -1
- package/ios/Sources/AdMobPlugin/AdMobPlugin.swift +30 -0
- package/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +3 -0
- package/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +3 -0
- package/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +3 -0
- package/ios/Tests/AdMobPluginTests/AdMobPluginTests.swift +45 -10
- package/package.json +2 -1
|
@@ -15,6 +15,6 @@ Pod::Spec.new do |s|
|
|
|
15
15
|
s.swift_version = '5.1'
|
|
16
16
|
s.static_framework = true
|
|
17
17
|
s.dependency 'Capacitor'
|
|
18
|
-
s.dependency 'Google-Mobile-Ads-SDK', '13.
|
|
18
|
+
s.dependency 'Google-Mobile-Ads-SDK', '13.11.0'
|
|
19
19
|
s.dependency 'GoogleUserMessagingPlatform', '~> 3.1'
|
|
20
20
|
end
|
package/Package.swift
CHANGED
|
@@ -11,7 +11,7 @@ let package = Package(
|
|
|
11
11
|
],
|
|
12
12
|
dependencies: [
|
|
13
13
|
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
|
|
14
|
-
.package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", exact: "13.
|
|
14
|
+
.package(url: "https://github.com/googleads/swift-package-manager-google-mobile-ads.git", exact: "13.11.0"),
|
|
15
15
|
.package(url: "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git", .upToNextMinor(from: "3.1.0"))
|
|
16
16
|
],
|
|
17
17
|
targets: [
|
package/README.md
CHANGED
|
@@ -67,7 +67,7 @@ If you still use Capacitor 7, install `@capacitor-community/admob@7`.
|
|
|
67
67
|
|
|
68
68
|
### Google Mobile Ads SDK versions
|
|
69
69
|
|
|
70
|
-
This major version pins Google Mobile Ads SDK **25.4.x** on Android and **13.
|
|
70
|
+
This major version pins Google Mobile Ads SDK **25.4.x** on Android and **13.11.0** on iOS (Swift Package Manager and CocoaPods). Leave those versions unless you have a specific need. Google's [Next-Gen SDK for Android](https://developers.google.com/admob/android/next-gen) waits until the next plugin major. See [Migration](https://docs.rdlabo.dev/projects/capacitor-admob/docs/migration) for the policy behind the pins.
|
|
71
71
|
|
|
72
72
|
### Android configuration
|
|
73
73
|
|
package/docs/migration.md
CHANGED
|
@@ -46,7 +46,9 @@ This major version keeps Google Mobile Ads SDK APIs that are deprecated but stil
|
|
|
46
46
|
|
|
47
47
|
Google's [Next-Gen SDK for Android](https://developers.google.com/admob/android/next-gen) also waits for the next major: it changes SDK initialization, ad requests, and mediation.
|
|
48
48
|
|
|
49
|
-
Pinned versions: Android 25.4.x, iOS 13.
|
|
49
|
+
Pinned versions: Android 25.4.x, iOS 13.11.0 (Swift Package Manager and CocoaPods). CocoaPods support is planned to be removed in the next major.
|
|
50
|
+
|
|
51
|
+
Android remains on 25.4.x because [SDK 25.5.0 raises the minimum Android API level](https://developers.google.com/admob/android/rel-notes). The iOS update from 13.6.0 to 13.11.0 keeps the plugin's existing platform and toolchain requirements; no public plugin API changes are required.
|
|
50
52
|
|
|
51
53
|
## Breaking changes from earlier versions
|
|
52
54
|
|
|
@@ -69,6 +69,36 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
|
|
|
69
69
|
self.consentExecutor.plugin = self
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/// Full-screen ads that currently have web media suspended.
|
|
73
|
+
private var webMediaSuspenders = Set<ObjectIdentifier>()
|
|
74
|
+
|
|
75
|
+
/// Pauses all web media while a full-screen ad is up, so WebKit releases its audio before the ad plays
|
|
76
|
+
/// and sets it up again afterwards, instead of leaving web audio silent until the app restarts.
|
|
77
|
+
func suspendWebMedia(for owner: AnyObject) {
|
|
78
|
+
Task { @MainActor [weak self] in
|
|
79
|
+
guard let self, self.webMediaSuspenders.insert(ObjectIdentifier(owner)).inserted,
|
|
80
|
+
self.webMediaSuspenders.count == 1
|
|
81
|
+
else { return }
|
|
82
|
+
self.setWebMediaPlaybackSuspended(true)
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/// Only resumes once every ad that suspended has resumed, so a failed present (which can arrive
|
|
87
|
+
/// without a preceding adWillPresentFullScreenContent) can't release another ad's suspension.
|
|
88
|
+
func resumeWebMedia(for owner: AnyObject) {
|
|
89
|
+
Task { @MainActor [weak self] in
|
|
90
|
+
guard let self, self.webMediaSuspenders.remove(ObjectIdentifier(owner)) != nil,
|
|
91
|
+
self.webMediaSuspenders.isEmpty
|
|
92
|
+
else { return }
|
|
93
|
+
self.setWebMediaPlaybackSuspended(false)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@MainActor
|
|
98
|
+
func setWebMediaPlaybackSuspended(_ suspended: Bool) {
|
|
99
|
+
self.bridge?.webView?.setAllMediaPlaybackSuspended(suspended, completionHandler: nil)
|
|
100
|
+
}
|
|
101
|
+
|
|
72
102
|
/**
|
|
73
103
|
* Enable SKAdNetwork to track conversions
|
|
74
104
|
* https://developers.google.com/admob/ios/ios14
|
|
@@ -73,6 +73,7 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
|
76
|
+
self.plugin?.resumeWebMedia(for: ad)
|
|
76
77
|
removeCurrentlyShowingAd()
|
|
77
78
|
NSLog("InterstitialFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
|
|
78
79
|
self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToShow.rawValue, data: [
|
|
@@ -82,11 +83,13 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
86
|
+
self.plugin?.suspendWebMedia(for: ad)
|
|
85
87
|
NSLog("InterstitialFullScreenDelegate Ad did present full screen content.")
|
|
86
88
|
self.plugin?.notifyListeners(InterstitialAdPluginEvents.Showed.rawValue, data: [:])
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
92
|
+
self.plugin?.resumeWebMedia(for: ad)
|
|
90
93
|
removeCurrentlyShowingAd()
|
|
91
94
|
NSLog("InterstitialFullScreenDelegate Ad did dismiss full screen content.")
|
|
92
95
|
self.plugin?.notifyListeners(InterstitialAdPluginEvents.Dismissed.rawValue, data: [:])
|
|
@@ -97,6 +97,7 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
|
100
|
+
self.plugin?.resumeWebMedia(for: ad)
|
|
100
101
|
removeCurrentlyShowingAd()
|
|
101
102
|
NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
|
|
102
103
|
self.plugin?.notifyListeners(RewardAdPluginEvents.FailedToShow.rawValue, data: [
|
|
@@ -106,6 +107,7 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
110
|
+
self.plugin?.suspendWebMedia(for: ad)
|
|
109
111
|
NSLog("RewardFullScreenDelegate Ad did present full screen content.")
|
|
110
112
|
self.plugin?.notifyListeners(RewardAdPluginEvents.Showed.rawValue, data: [:])
|
|
111
113
|
}
|
|
@@ -115,6 +117,7 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
120
|
+
self.plugin?.resumeWebMedia(for: ad)
|
|
118
121
|
removeCurrentlyShowingAd()
|
|
119
122
|
NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.")
|
|
120
123
|
self.plugin?.notifyListeners(RewardAdPluginEvents.Dismissed.rawValue, data: [:])
|
|
@@ -97,6 +97,7 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
|
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
|
100
|
+
self.plugin?.resumeWebMedia(for: ad)
|
|
100
101
|
removeCurrentlyShowingAd()
|
|
101
102
|
NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
|
|
102
103
|
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.FailedToShow.rawValue, data: [
|
|
@@ -106,11 +107,13 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
110
|
+
self.plugin?.suspendWebMedia(for: ad)
|
|
109
111
|
NSLog("RewardFullScreenDelegate Ad did present full screen content.")
|
|
110
112
|
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Showed.rawValue, data: [:])
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
116
|
+
self.plugin?.resumeWebMedia(for: ad)
|
|
114
117
|
removeCurrentlyShowingAd()
|
|
115
118
|
NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.")
|
|
116
119
|
self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Dismissed.rawValue, data: [:])
|
|
@@ -1,15 +1,50 @@
|
|
|
1
1
|
import XCTest
|
|
2
2
|
@testable import AdMobPlugin
|
|
3
3
|
|
|
4
|
-
class
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
final class AdMobPluginTests: XCTestCase {
|
|
5
|
+
@MainActor
|
|
6
|
+
func testNormalSuspensionAndResume() async {
|
|
7
|
+
await checkSuspensions([(0, true, true), (0, false, false)])
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@MainActor
|
|
11
|
+
func testFailedAdCannotReleaseAnotherAdsSuspension() async {
|
|
12
|
+
await checkSuspensions([(0, true, true), (1, false, nil), (0, false, false)])
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@MainActor
|
|
16
|
+
func testOnlyLastAdResumesMedia() async {
|
|
17
|
+
await checkSuspensions([(0, true, true), (1, true, nil), (0, false, nil), (1, false, false)])
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@MainActor
|
|
21
|
+
private func checkSuspensions(_ steps: [(Int, Bool, Bool?)]) async {
|
|
22
|
+
let plugin = MediaTestPlugin()
|
|
23
|
+
let owners = [NSObject(), NSObject()]
|
|
24
|
+
|
|
25
|
+
for (owner, suspend, expected) in steps {
|
|
26
|
+
let called = expectation(description: "WebKit suspension: \(String(describing: expected))")
|
|
27
|
+
called.isInverted = expected == nil
|
|
28
|
+
plugin.onSuspension = { actual in
|
|
29
|
+
XCTAssertEqual(actual, expected)
|
|
30
|
+
called.fulfill()
|
|
31
|
+
}
|
|
32
|
+
if suspend {
|
|
33
|
+
plugin.suspendWebMedia(for: owners[owner])
|
|
34
|
+
} else {
|
|
35
|
+
plugin.resumeWebMedia(for: owners[owner])
|
|
36
|
+
}
|
|
37
|
+
await fulfillment(of: [called], timeout: expected == nil ? 0.1 : 2)
|
|
38
|
+
}
|
|
39
|
+
plugin.onSuspension = nil
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private final class MediaTestPlugin: AdMobPlugin {
|
|
44
|
+
var onSuspension: ((Bool) -> Void)?
|
|
45
|
+
|
|
46
|
+
@MainActor
|
|
47
|
+
override func setWebMediaPlaybackSuspended(_ suspended: Bool) {
|
|
48
|
+
onSuspension?(suspended)
|
|
14
49
|
}
|
|
15
50
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor-community/admob",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "8.2.0-beta.
|
|
4
|
+
"version": "8.2.0-beta.pr484.shaa6be63853bbd",
|
|
5
5
|
"description": "A native plugin for AdMob",
|
|
6
6
|
"main": "dist/plugin.cjs.js",
|
|
7
7
|
"module": "dist/esm/index.js",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"scripts": {
|
|
34
34
|
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
35
35
|
"verify:ios": "xcodebuild -scheme CapacitorCommunityAdmob -destination generic/platform=iOS",
|
|
36
|
+
"test:ios": "xcodebuild test -scheme CapacitorCommunityAdmob",
|
|
36
37
|
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
37
38
|
"verify:web": "npm run build",
|
|
38
39
|
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|