@capacitor-community/admob 8.0.0 → 8.1.0

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.
Files changed (100) hide show
  1. package/CapacitorCommunityAdmob.podspec +1 -1
  2. package/Package.swift +1 -1
  3. package/README.md +635 -169
  4. package/android/build.gradle +1 -1
  5. package/android/src/main/java/com/getcapacitor/community/admob/AdMob.java +73 -23
  6. package/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdManager.kt +92 -0
  7. package/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPlugin.kt +122 -0
  8. package/android/src/main/java/com/getcapacitor/community/admob/appopen/AppOpenAdPluginEvents.kt +10 -0
  9. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdPluginEvents.kt +2 -1
  10. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java +79 -29
  11. package/android/src/main/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallback.kt +7 -2
  12. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/AdInterstitialExecutor.java +21 -3
  13. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt +12 -2
  14. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt +1 -0
  15. package/android/src/main/java/com/getcapacitor/community/admob/models/AdMobRevenueData.kt +15 -0
  16. package/android/src/main/java/com/getcapacitor/community/admob/models/AdOptions.java +10 -0
  17. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/AdRewardExecutor.java +20 -3
  18. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt +1 -0
  19. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt +14 -4
  20. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/AdRewardInterstitialExecutor.java +20 -3
  21. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardInterstitialAdPluginEvents.kt +1 -0
  22. package/android/src/main/java/com/getcapacitor/community/admob/rewardedinterstitial/RewardedInterstitialAdCallbackAndListeners.kt +14 -3
  23. package/dist/docs.json +740 -193
  24. package/dist/esm/app-open/app-open-ad-options.interface.d.ts +9 -0
  25. package/dist/esm/app-open/app-open-ad-options.interface.js +2 -0
  26. package/dist/esm/app-open/app-open-ad-options.interface.js.map +1 -0
  27. package/dist/esm/app-open/app-open-ad-plugin-events.enum.d.ts +26 -0
  28. package/dist/esm/app-open/app-open-ad-plugin-events.enum.js +28 -0
  29. package/dist/esm/app-open/app-open-ad-plugin-events.enum.js.map +1 -0
  30. package/dist/esm/app-open/app-open-definitions.interface.d.ts +50 -0
  31. package/dist/esm/app-open/app-open-definitions.interface.js +2 -0
  32. package/dist/esm/app-open/app-open-definitions.interface.js.map +1 -0
  33. package/dist/esm/app-open/index.d.ts +3 -0
  34. package/dist/esm/app-open/index.js +4 -0
  35. package/dist/esm/app-open/index.js.map +1 -0
  36. package/dist/esm/banner/banner-ad-options.interface.d.ts +5 -6
  37. package/dist/esm/banner/banner-ad-plugin-events.enum.d.ts +17 -4
  38. package/dist/esm/banner/banner-ad-plugin-events.enum.js +16 -3
  39. package/dist/esm/banner/banner-ad-plugin-events.enum.js.map +1 -1
  40. package/dist/esm/banner/banner-ad-position.enum.d.ts +3 -3
  41. package/dist/esm/banner/banner-ad-position.enum.js +3 -3
  42. package/dist/esm/banner/banner-ad-size.enum.d.ts +4 -3
  43. package/dist/esm/banner/banner-ad-size.enum.js +4 -3
  44. package/dist/esm/banner/banner-ad-size.enum.js.map +1 -1
  45. package/dist/esm/banner/banner-definitions.interface.d.ts +17 -10
  46. package/dist/esm/banner/banner-size.interface.d.ts +8 -1
  47. package/dist/esm/definitions.d.ts +19 -17
  48. package/dist/esm/definitions.js.map +1 -1
  49. package/dist/esm/index.d.ts +1 -0
  50. package/dist/esm/index.js +1 -0
  51. package/dist/esm/index.js.map +1 -1
  52. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.d.ts +10 -6
  53. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.js +9 -5
  54. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.js.map +1 -1
  55. package/dist/esm/interstitial/interstitial-definitions.interface.d.ts +24 -4
  56. package/dist/esm/reward/reward-ad-options.interface.d.ts +7 -6
  57. package/dist/esm/reward/reward-ad-plugin-events.enum.d.ts +13 -12
  58. package/dist/esm/reward/reward-ad-plugin-events.enum.js +12 -11
  59. package/dist/esm/reward/reward-ad-plugin-events.enum.js.map +1 -1
  60. package/dist/esm/reward/reward-definitions.interface.d.ts +27 -4
  61. package/dist/esm/reward/reward-item.interface.d.ts +3 -4
  62. package/dist/esm/reward-interstitial/reward-interstitial-ad-options.interface.d.ts +7 -6
  63. package/dist/esm/reward-interstitial/reward-interstitial-ad-plugin-events.enum.d.ts +13 -12
  64. package/dist/esm/reward-interstitial/reward-interstitial-ad-plugin-events.enum.js +12 -11
  65. package/dist/esm/reward-interstitial/reward-interstitial-ad-plugin-events.enum.js.map +1 -1
  66. package/dist/esm/reward-interstitial/reward-interstitial-definitions.interface.d.ts +30 -7
  67. package/dist/esm/reward-interstitial/reward-interstitial-item.interface.d.ts +3 -4
  68. package/dist/esm/shared/ad-load-info.interface.d.ts +6 -0
  69. package/dist/esm/shared/ad-mob-revenue-data.interface.d.ts +50 -0
  70. package/dist/esm/shared/ad-mob-revenue-data.interface.js +23 -0
  71. package/dist/esm/shared/ad-mob-revenue-data.interface.js.map +1 -0
  72. package/dist/esm/shared/ad-options.interface.d.ts +9 -11
  73. package/dist/esm/shared/ad-show-options.interface.d.ts +12 -0
  74. package/dist/esm/shared/ad-show-options.interface.js +2 -0
  75. package/dist/esm/shared/ad-show-options.interface.js.map +1 -0
  76. package/dist/esm/shared/admob-error.interface.d.ts +3 -2
  77. package/dist/esm/shared/index.d.ts +2 -0
  78. package/dist/esm/shared/index.js +2 -0
  79. package/dist/esm/shared/index.js.map +1 -1
  80. package/dist/esm/shared/tracking-authorization-status.interface.d.ts +6 -1
  81. package/dist/esm/web.d.ts +13 -4
  82. package/dist/esm/web.js +25 -9
  83. package/dist/esm/web.js.map +1 -1
  84. package/dist/plugin.cjs.js +131 -45
  85. package/dist/plugin.cjs.js.map +1 -1
  86. package/dist/plugin.js +131 -45
  87. package/dist/plugin.js.map +1 -1
  88. package/ios/Sources/AdMobPlugin/AdMobPlugin.swift +30 -4
  89. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdManager.swift +112 -0
  90. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPlugin.swift +101 -0
  91. package/ios/Sources/AdMobPlugin/AppOpen/AppOpenAdPluginEvents.swift +8 -0
  92. package/ios/Sources/AdMobPlugin/Banner/BannerAdPluginEvents.swift +1 -0
  93. package/ios/Sources/AdMobPlugin/Banner/BannerExecutor.swift +20 -6
  94. package/ios/Sources/AdMobPlugin/Interstitial/AdInterstitialExecutor.swift +41 -5
  95. package/ios/Sources/AdMobPlugin/Interstitial/InterstitialAdPluginEvents.swift +1 -0
  96. package/ios/Sources/AdMobPlugin/Rewarded/AdRewardExecutor.swift +44 -5
  97. package/ios/Sources/AdMobPlugin/Rewarded/RewardAdPluginEvents.swift +1 -0
  98. package/ios/Sources/AdMobPlugin/RewardedInterstitial/AdRewardInterstitialExecutor.swift +45 -6
  99. package/ios/Sources/AdMobPlugin/RewardedInterstitial/RewardInterstitialAdPluginEvents.swift +1 -0
  100. package/package.json +2 -1
@@ -28,8 +28,34 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
28
28
  CAPPluginMethod(name: "prepareRewardVideoAd", returnType: CAPPluginReturnPromise),
29
29
  CAPPluginMethod(name: "showRewardVideoAd", returnType: CAPPluginReturnPromise),
30
30
  CAPPluginMethod(name: "prepareRewardInterstitialAd", returnType: CAPPluginReturnPromise),
31
- CAPPluginMethod(name: "showRewardInterstitialAd", returnType: CAPPluginReturnPromise)
31
+ CAPPluginMethod(name: "showRewardInterstitialAd", returnType: CAPPluginReturnPromise),
32
+ CAPPluginMethod(name: "loadAppOpen", returnType: CAPPluginReturnPromise),
33
+ CAPPluginMethod(name: "showAppOpen", returnType: CAPPluginReturnPromise),
34
+ CAPPluginMethod(name: "isAppOpenLoaded", returnType: CAPPluginReturnPromise)
32
35
  ]
36
+ private let appOpenAdPlugin = AppOpenAdPlugin()
37
+ @objc func loadAppOpen(_ call: CAPPluginCall) {
38
+ appOpenAdPlugin.loadAppOpen(
39
+ call,
40
+ notify: { [weak self] eventName, data in
41
+ self?.notifyListeners(eventName, data: data)
42
+ }
43
+ )
44
+ }
45
+
46
+ @objc func showAppOpen(_ call: CAPPluginCall) {
47
+ appOpenAdPlugin.showAppOpen(
48
+ call,
49
+ getRootViewController: self.getRootVC,
50
+ notify: { [weak self] eventName, data in
51
+ self?.notifyListeners(eventName, data: data)
52
+ }
53
+ )
54
+ }
55
+
56
+ @objc func isAppOpenLoaded(_ call: CAPPluginCall) {
57
+ appOpenAdPlugin.isAppOpenLoaded(call)
58
+ }
33
59
 
34
60
  var testingDevices: [String] = []
35
61
 
@@ -191,11 +217,11 @@ public class AdMobPlugin: CAPPlugin, CAPBridgedPlugin {
191
217
  switch ATTrackingManager.trackingAuthorizationStatus {
192
218
  case .authorized:
193
219
  call.resolve(["status": AuthorizationStatusEnum.Authorized.rawValue])
194
- case .denied:
220
+ case .denied:
195
221
  call.resolve(["status": AuthorizationStatusEnum.Denied.rawValue])
196
- case .restricted:
222
+ case .restricted:
197
223
  call.resolve(["status": AuthorizationStatusEnum.Restricted.rawValue])
198
- case .notDetermined:
224
+ case .notDetermined:
199
225
  call.resolve(["status": AuthorizationStatusEnum.NotDetermined.rawValue])
200
226
  @unknown default:
201
227
  call.reject("trackingAuthorizationStatus can't get status")
@@ -0,0 +1,112 @@
1
+ import Foundation
2
+ import GoogleMobileAds
3
+ import UIKit
4
+
5
+ @objc public class AppOpenAdManager: NSObject {
6
+ private var appOpenAd: AppOpenAd?
7
+ private var isLoadingAd = false
8
+ private var isShowingAd = false
9
+ private var adUnitId: String
10
+ private var onOpened: (() -> Void)?
11
+
12
+ public init(adUnitId: String) {
13
+ self.adUnitId = adUnitId
14
+ }
15
+
16
+ public func loadAd(onLoaded: @escaping () -> Void, onFailed: @escaping (Error?) -> Void, onPaidEvent: @escaping (_ valueMicros: Int64, _ currencyCode: String, _ precision: Int, _ networkName: String, _ impressionId: String) -> Void) {
17
+ if appOpenAd != nil {
18
+ onLoaded()
19
+ return
20
+ }
21
+
22
+ if isLoadingAd {
23
+ onFailed(nil)
24
+ return
25
+ }
26
+
27
+ isLoadingAd = true
28
+ Task { [weak self] in
29
+ guard let self = self else {
30
+ return
31
+ }
32
+ do {
33
+ let ad = try await AppOpenAd.load(with: self.adUnitId, request: Request())
34
+ await MainActor.run {
35
+ self.isLoadingAd = false
36
+ self.appOpenAd = ad
37
+ ad.paidEventHandler = { adValue in
38
+ let networkName = ad.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? ""
39
+ let impressionId = ad.responseInfo.responseIdentifier ?? ""
40
+ onPaidEvent(
41
+ adValue.value.int64Value,
42
+ adValue.currencyCode,
43
+ adValue.precision.rawValue,
44
+ networkName,
45
+ impressionId
46
+ )
47
+ }
48
+ onLoaded()
49
+ }
50
+ } catch {
51
+ await MainActor.run {
52
+ self.isLoadingAd = false
53
+ onFailed(error)
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ public func showAdIfAvailable(
60
+ rootViewController: UIViewController,
61
+ onOpened: @escaping () -> Void,
62
+ onClosed: @escaping () -> Void,
63
+ onFailedToShow: @escaping (Error?) -> Void
64
+ ) {
65
+ guard let ad = appOpenAd, !isShowingAd else {
66
+ onFailedToShow(nil)
67
+ return
68
+ }
69
+
70
+ self.onOpened = onOpened
71
+ self.onClosed = onClosed
72
+ self.onFailedToShow = onFailedToShow
73
+ isShowingAd = true
74
+ ad.fullScreenContentDelegate = self
75
+ ad.present(from: rootViewController)
76
+ }
77
+
78
+ public func isAdLoaded() -> Bool {
79
+ return appOpenAd != nil
80
+ }
81
+
82
+ private var onClosed: (() -> Void)?
83
+ private var onFailedToShow: ((Error?) -> Void)?
84
+ }
85
+
86
+ extension AppOpenAdManager: FullScreenContentDelegate {
87
+ public func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
88
+ let onOpened = self.onOpened
89
+ self.onOpened = nil
90
+ onOpened?()
91
+ }
92
+
93
+ public func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
94
+ appOpenAd = nil
95
+ isShowingAd = false
96
+ let onClosed = self.onClosed
97
+ self.onOpened = nil
98
+ self.onClosed = nil
99
+ self.onFailedToShow = nil
100
+ onClosed?()
101
+ }
102
+
103
+ public func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
104
+ appOpenAd = nil
105
+ isShowingAd = false
106
+ let onFailedToShow = self.onFailedToShow
107
+ self.onOpened = nil
108
+ self.onClosed = nil
109
+ self.onFailedToShow = nil
110
+ onFailedToShow?(error)
111
+ }
112
+ }
@@ -0,0 +1,101 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import UIKit
4
+
5
+ @objc public class AppOpenAdPlugin: NSObject {
6
+ private var preparedManagers: [String: AppOpenAdManager] = [:]
7
+ private var lastPreparedAdId: String?
8
+
9
+ @objc func loadAppOpen(
10
+ _ call: CAPPluginCall,
11
+ notify: @escaping (String, [String: Any]) -> Void
12
+ ) {
13
+ guard let adUnitId = call.getString("adId") else {
14
+ call.reject("adId is required")
15
+ return
16
+ }
17
+
18
+ DispatchQueue.main.async {
19
+ if self.preparedManagers[adUnitId] == nil {
20
+ self.preparedManagers[adUnitId] = AppOpenAdManager(adUnitId: adUnitId)
21
+ }
22
+
23
+ self.preparedManagers[adUnitId]?.loadAd(onLoaded: {
24
+ self.lastPreparedAdId = adUnitId
25
+ notify(AppOpenAdPluginEvents.Loaded.rawValue, ["adUnitId": adUnitId])
26
+ call.resolve(["adUnitId": adUnitId])
27
+ }, onFailed: { error in
28
+ let message = error?.localizedDescription ?? "Failed to load App Open Ad"
29
+ notify(AppOpenAdPluginEvents.FailedToLoad.rawValue, [
30
+ "code": 0,
31
+ "message": message
32
+ ])
33
+ call.reject(message)
34
+ }, onPaidEvent: { valueMicros, currencyCode, precision, networkName, impressionId in
35
+ notify(AppOpenAdPluginEvents.AdImpression.rawValue, [
36
+ "adUnitId": adUnitId,
37
+ "valueMicros": valueMicros,
38
+ "currencyCode": currencyCode,
39
+ "precision": precision,
40
+ "networkName": networkName,
41
+ "impressionId": impressionId
42
+ ])
43
+ })
44
+ }
45
+ }
46
+
47
+ @objc func showAppOpen(
48
+ _ call: CAPPluginCall,
49
+ getRootViewController: @escaping () -> UIViewController?,
50
+ notify: @escaping (String, [String: Any]) -> Void
51
+ ) {
52
+ guard let adId = call.getString("adId") ?? lastPreparedAdId else {
53
+ call.reject("No ad prepared")
54
+ return
55
+ }
56
+
57
+ DispatchQueue.main.async {
58
+ guard let manager = self.preparedManagers[adId], manager.isAdLoaded() else {
59
+ call.reject("App Open Ad is not loaded")
60
+ return
61
+ }
62
+
63
+ if let rootVC = getRootViewController() {
64
+ manager.showAdIfAvailable(rootViewController: rootVC, onOpened: {
65
+ notify(AppOpenAdPluginEvents.Opened.rawValue, [:])
66
+ }, onClosed: {
67
+ self.preparedManagers.removeValue(forKey: adId)
68
+ if self.lastPreparedAdId == adId {
69
+ self.lastPreparedAdId = self.preparedManagers.first(where: { $0.value.isAdLoaded() })?.key
70
+ }
71
+ notify(AppOpenAdPluginEvents.Closed.rawValue, [:])
72
+ call.resolve()
73
+ }, onFailedToShow: { error in
74
+ // A second show request while this ad is already presented fails
75
+ // without consuming the ad. Keep the manager alive so its weak
76
+ // full-screen delegate can still deliver the original close event.
77
+ if !manager.isAdLoaded() {
78
+ self.preparedManagers.removeValue(forKey: adId)
79
+ if self.lastPreparedAdId == adId {
80
+ self.lastPreparedAdId = self.preparedManagers.first(where: { $0.value.isAdLoaded() })?.key
81
+ }
82
+ }
83
+ let message = error?.localizedDescription ?? "Failed to show App Open Ad"
84
+ notify(AppOpenAdPluginEvents.FailedToShow.rawValue, [
85
+ "code": 0,
86
+ "message": message
87
+ ])
88
+ call.reject(message)
89
+ })
90
+ } else {
91
+ call.reject("No rootViewController")
92
+ }
93
+ }
94
+ }
95
+
96
+ @objc func isAppOpenLoaded(_ call: CAPPluginCall) {
97
+ let adId = call.getString("adId") ?? lastPreparedAdId
98
+ let loaded = adId.flatMap { preparedManagers[$0]?.isAdLoaded() } ?? false
99
+ call.resolve(["value": loaded])
100
+ }
101
+ }
@@ -0,0 +1,8 @@
1
+ public enum AppOpenAdPluginEvents: String {
2
+ case Loaded = "appOpenAdLoaded"
3
+ case FailedToLoad = "appOpenAdFailedToLoad"
4
+ case Opened = "appOpenAdOpened"
5
+ case Closed = "appOpenAdClosed"
6
+ case FailedToShow = "appOpenAdFailedToShow"
7
+ case AdImpression = "appOpenAdImpression"
8
+ }
@@ -5,4 +5,5 @@ public enum BannerAdPluginEvents: String {
5
5
  case Opened = "bannerAdOpened"
6
6
  case Loaded = "bannerAdLoaded"
7
7
  case AdImpression = "bannerAdImpression"
8
+ case AdPaid = "bannerAdPaid"
8
9
  }
@@ -20,17 +20,17 @@ class BannerExecutor: NSObject, BannerViewDelegate {
20
20
  switch adSize {
21
21
  case "BANNER":
22
22
  bannerSize = AdSizeBanner
23
- case "LARGE_BANNER":
23
+ case "LARGE_BANNER":
24
24
  bannerSize = AdSizeLargeBanner
25
- case "FULL_BANNER":
25
+ case "FULL_BANNER":
26
26
  bannerSize = AdSizeFullBanner
27
- case "LEADERBOARD":
27
+ case "LEADERBOARD":
28
28
  bannerSize = AdSizeLeaderboard
29
- case "MEDIUM_RECTANGLE":
29
+ case "MEDIUM_RECTANGLE":
30
30
  bannerSize = AdSizeMediumRectangle
31
- case "SMART_BANNER":
31
+ case "SMART_BANNER":
32
32
  bannerSize = kGADAdSizeSmartBannerPortrait
33
- default: // ADAPTIVE_BANNER
33
+ default: // ADAPTIVE_BANNER
34
34
  let frame = { () -> CGRect in
35
35
  // Here safe area is taken into account, hence the view frame is used
36
36
  // after the view has been laid out.
@@ -49,6 +49,20 @@ class BannerExecutor: NSObject, BannerViewDelegate {
49
49
  self.bannerView.load(request)
50
50
  self.bannerView.delegate = self
51
51
 
52
+ self.bannerView.paidEventHandler = { [weak self] adValue in
53
+ guard let self = self else { return }
54
+ let networkName = self.bannerView.responseInfo?.loadedAdNetworkResponseInfo?.adNetworkClassName ?? ""
55
+ let impressionId = self.bannerView.responseInfo?.responseIdentifier ?? ""
56
+ self.plugin?.notifyListeners(BannerAdPluginEvents.AdPaid.rawValue, data: [
57
+ "adUnitId": self.bannerView.adUnitID ?? "",
58
+ "valueMicros": adValue.value.int64Value,
59
+ "currencyCode": adValue.currencyCode,
60
+ "precision": adValue.precision.rawValue,
61
+ "networkName": networkName,
62
+ "impressionId": impressionId
63
+ ])
64
+ }
65
+
52
66
  call.resolve([:])
53
67
  }
54
68
  }
@@ -4,7 +4,9 @@ import GoogleMobileAds
4
4
 
5
5
  class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
6
6
  weak var plugin: AdMobPlugin?
7
- var interstitial: InterstitialAd!
7
+ private var preparedAds: [String: InterstitialAd] = [:]
8
+ private var lastPreparedAdId: String?
9
+ private var currentlyShowingAdId: String?
8
10
 
9
11
  func prepareInterstitial(_ call: CAPPluginCall, _ request: Request, _ adUnitID: String) {
10
12
  InterstitialAd.load(
@@ -12,7 +14,7 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
12
14
  request: request,
13
15
  completionHandler: { (ad, error) in
14
16
  if let error = error {
15
- NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)")
17
+ NSLog("Interstitial ad failed to load with error: \(error.localizedDescription)")
16
18
  self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToLoad.rawValue, data: [
17
19
  "code": 0,
18
20
  "message": error.localizedDescription
@@ -21,8 +23,23 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
21
23
  return
22
24
  }
23
25
 
24
- self.interstitial = ad
25
- self.interstitial.fullScreenContentDelegate = self
26
+ if let ad = ad {
27
+ ad.fullScreenContentDelegate = self
28
+ ad.paidEventHandler = { adValue in
29
+ let networkName = ad.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? ""
30
+ let impressionId = ad.responseInfo.responseIdentifier ?? ""
31
+ self.plugin?.notifyListeners(InterstitialAdPluginEvents.AdImpression.rawValue, data: [
32
+ "adUnitId": adUnitID,
33
+ "valueMicros": adValue.value.int64Value,
34
+ "currencyCode": adValue.currencyCode,
35
+ "precision": adValue.precision.rawValue,
36
+ "networkName": networkName,
37
+ "impressionId": impressionId
38
+ ])
39
+ }
40
+ self.preparedAds[adUnitID] = ad
41
+ self.lastPreparedAdId = adUnitID
42
+ }
26
43
  self.plugin?.notifyListeners(InterstitialAdPluginEvents.Loaded.rawValue, data: [
27
44
  "adUnitId": adUnitID
28
45
  ])
@@ -34,8 +51,18 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
34
51
  }
35
52
 
36
53
  func showInterstitial(_ call: CAPPluginCall) {
54
+ guard let adId = call.getString("adId") ?? lastPreparedAdId else {
55
+ call.reject("No ad prepared")
56
+ return
57
+ }
58
+ guard currentlyShowingAdId == nil else {
59
+ call.reject("An ad is already showing")
60
+ return
61
+ }
62
+
37
63
  if let rootViewController = plugin?.getRootVC() {
38
- if let ad = self.interstitial {
64
+ if let ad = preparedAds[adId] {
65
+ currentlyShowingAdId = adId
39
66
  ad.present(from: rootViewController)
40
67
  call.resolve([:])
41
68
  } else {
@@ -46,6 +73,7 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
46
73
  }
47
74
 
48
75
  func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
76
+ removeCurrentlyShowingAd()
49
77
  NSLog("InterstitialFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
50
78
  self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToShow.rawValue, data: [
51
79
  "code": 0,
@@ -59,7 +87,15 @@ class AdInterstitialExecutor: NSObject, FullScreenContentDelegate {
59
87
  }
60
88
 
61
89
  func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
90
+ removeCurrentlyShowingAd()
62
91
  NSLog("InterstitialFullScreenDelegate Ad did dismiss full screen content.")
63
92
  self.plugin?.notifyListeners(InterstitialAdPluginEvents.Dismissed.rawValue, data: [:])
64
93
  }
94
+
95
+ private func removeCurrentlyShowingAd() {
96
+ guard let adId = currentlyShowingAdId else { return }
97
+ preparedAds.removeValue(forKey: adId)
98
+ if lastPreparedAdId == adId { lastPreparedAdId = Array(preparedAds.keys).last }
99
+ currentlyShowingAdId = nil
100
+ }
65
101
  }
@@ -4,4 +4,5 @@ public enum InterstitialAdPluginEvents: String {
4
4
  case Showed = "interstitialAdShowed"
5
5
  case FailedToShow = "interstitialAdFailedToShow"
6
6
  case Dismissed = "interstitialAdDismissed"
7
+ case AdImpression = "interstitialAdImpression"
7
8
  }
@@ -4,7 +4,9 @@ import GoogleMobileAds
4
4
 
5
5
  class AdRewardExecutor: NSObject, FullScreenContentDelegate {
6
6
  weak var plugin: AdMobPlugin?
7
- var rewardedAd: RewardedAd!
7
+ private var preparedAds: [String: RewardedAd] = [:]
8
+ private var lastPreparedAdId: String?
9
+ private var currentlyShowingAdId: String?
8
10
 
9
11
  func prepareRewardVideoAd(_ call: CAPPluginCall, _ request: Request, _ adUnitID: String) {
10
12
  RewardedAd.load(
@@ -21,7 +23,10 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
21
23
  return
22
24
  }
23
25
 
24
- self.rewardedAd = ad
26
+ guard let ad = ad else {
27
+ call.reject("Loading failed")
28
+ return
29
+ }
25
30
 
26
31
  if let providedOptions = call.getObject("ssv") {
27
32
  let ssvOptions = ServerSideVerificationOptions()
@@ -36,10 +41,25 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
36
41
  ssvOptions.userIdentifier = userId
37
42
  }
38
43
 
39
- self.rewardedAd?.serverSideVerificationOptions = ssvOptions
44
+ ad.serverSideVerificationOptions = ssvOptions
45
+ }
46
+
47
+ ad.fullScreenContentDelegate = self
48
+ ad.paidEventHandler = { adValue in
49
+ let networkName = ad.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? ""
50
+ let impressionId = ad.responseInfo.responseIdentifier ?? ""
51
+ self.plugin?.notifyListeners(RewardAdPluginEvents.AdImpression.rawValue, data: [
52
+ "adUnitId": adUnitID,
53
+ "valueMicros": adValue.value.int64Value,
54
+ "currencyCode": adValue.currencyCode,
55
+ "precision": adValue.precision.rawValue,
56
+ "networkName": networkName,
57
+ "impressionId": impressionId
58
+ ])
40
59
  }
60
+ self.preparedAds[adUnitID] = ad
61
+ self.lastPreparedAdId = adUnitID
41
62
 
42
- self.rewardedAd?.fullScreenContentDelegate = self
43
63
  self.plugin?.notifyListeners(RewardAdPluginEvents.Loaded.rawValue, data: [
44
64
  "adUnitId": adUnitID
45
65
  ])
@@ -51,8 +71,18 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
51
71
  }
52
72
 
53
73
  func showRewardVideoAd(_ call: CAPPluginCall) {
74
+ guard let adId = call.getString("adId") ?? lastPreparedAdId else {
75
+ call.reject("No ad prepared")
76
+ return
77
+ }
78
+ guard currentlyShowingAdId == nil else {
79
+ call.reject("An ad is already showing")
80
+ return
81
+ }
82
+
54
83
  if let rootViewController = plugin?.getRootVC() {
55
- if let ad = self.rewardedAd {
84
+ if let ad = preparedAds[adId] {
85
+ currentlyShowingAdId = adId
56
86
  ad.present(from: rootViewController,
57
87
  userDidEarnRewardHandler: {
58
88
  let reward = ad.adReward
@@ -67,6 +97,7 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
67
97
  }
68
98
 
69
99
  func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
100
+ removeCurrentlyShowingAd()
70
101
  NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
71
102
  self.plugin?.notifyListeners(RewardAdPluginEvents.FailedToShow.rawValue, data: [
72
103
  "code": 0,
@@ -80,7 +111,15 @@ class AdRewardExecutor: NSObject, FullScreenContentDelegate {
80
111
  }
81
112
 
82
113
  func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
114
+ removeCurrentlyShowingAd()
83
115
  NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.")
84
116
  self.plugin?.notifyListeners(RewardAdPluginEvents.Dismissed.rawValue, data: [:])
85
117
  }
118
+
119
+ private func removeCurrentlyShowingAd() {
120
+ guard let adId = currentlyShowingAdId else { return }
121
+ preparedAds.removeValue(forKey: adId)
122
+ if lastPreparedAdId == adId { lastPreparedAdId = Array(preparedAds.keys).last }
123
+ currentlyShowingAdId = nil
124
+ }
86
125
  }
@@ -5,4 +5,5 @@ public enum RewardAdPluginEvents: String {
5
5
  case FailedToShow = "onRewardedVideoAdFailedToShow"
6
6
  case Dismissed = "onRewardedVideoAdDismissed"
7
7
  case Rewarded = "onRewardedVideoAdReward"
8
+ case AdImpression = "onRewardedVideoAdImpression"
8
9
  }
@@ -4,7 +4,9 @@ import GoogleMobileAds
4
4
 
5
5
  class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
6
6
  weak var plugin: AdMobPlugin?
7
- var rewardedInterstitialAd: RewardedInterstitialAd!
7
+ private var preparedAds: [String: RewardedInterstitialAd] = [:]
8
+ private var lastPreparedAdId: String?
9
+ private var currentlyShowingAdId: String?
8
10
 
9
11
  func prepareRewardInterstitialAd(_ call: CAPPluginCall, _ request: Request, _ adUnitID: String) {
10
12
  RewardedInterstitialAd.load(
@@ -12,7 +14,7 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
12
14
  request: request,
13
15
  completionHandler: { (ad, error) in
14
16
  if let error = error {
15
- NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)")
17
+ NSLog("Rewarded interstitial ad failed to load with error: \(error.localizedDescription)")
16
18
  self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.FailedToLoad.rawValue, data: [
17
19
  "code": 0,
18
20
  "message": error.localizedDescription
@@ -21,7 +23,10 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
21
23
  return
22
24
  }
23
25
 
24
- self.rewardedInterstitialAd = ad
26
+ guard let ad = ad else {
27
+ call.reject("Loading failed")
28
+ return
29
+ }
25
30
 
26
31
  if let providedOptions = call.getObject("ssv") {
27
32
  let ssvOptions = ServerSideVerificationOptions()
@@ -36,10 +41,25 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
36
41
  ssvOptions.userIdentifier = userId
37
42
  }
38
43
 
39
- self.rewardedInterstitialAd?.serverSideVerificationOptions = ssvOptions
44
+ ad.serverSideVerificationOptions = ssvOptions
45
+ }
46
+
47
+ ad.fullScreenContentDelegate = self
48
+ ad.paidEventHandler = { adValue in
49
+ let networkName = ad.responseInfo.loadedAdNetworkResponseInfo?.adNetworkClassName ?? ""
50
+ let impressionId = ad.responseInfo.responseIdentifier ?? ""
51
+ self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.AdImpression.rawValue, data: [
52
+ "adUnitId": adUnitID,
53
+ "valueMicros": adValue.value.int64Value,
54
+ "currencyCode": adValue.currencyCode,
55
+ "precision": adValue.precision.rawValue,
56
+ "networkName": networkName,
57
+ "impressionId": impressionId
58
+ ])
40
59
  }
60
+ self.preparedAds[adUnitID] = ad
61
+ self.lastPreparedAdId = adUnitID
41
62
 
42
- self.rewardedInterstitialAd?.fullScreenContentDelegate = self
43
63
  self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Loaded.rawValue, data: [
44
64
  "adUnitId": adUnitID
45
65
  ])
@@ -51,8 +71,18 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
51
71
  }
52
72
 
53
73
  func showRewardInterstitialAd(_ call: CAPPluginCall) {
74
+ guard let adId = call.getString("adId") ?? lastPreparedAdId else {
75
+ call.reject("No ad prepared")
76
+ return
77
+ }
78
+ guard currentlyShowingAdId == nil else {
79
+ call.reject("An ad is already showing")
80
+ return
81
+ }
82
+
54
83
  if let rootViewController = plugin?.getRootVC() {
55
- if let ad = self.rewardedInterstitialAd {
84
+ if let ad = preparedAds[adId] {
85
+ currentlyShowingAdId = adId
56
86
  ad.present(from: rootViewController,
57
87
  userDidEarnRewardHandler: {
58
88
  let reward = ad.adReward
@@ -67,6 +97,7 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
67
97
  }
68
98
 
69
99
  func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
100
+ removeCurrentlyShowingAd()
70
101
  NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
71
102
  self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.FailedToShow.rawValue, data: [
72
103
  "code": 0,
@@ -80,7 +111,15 @@ class AdRewardInterstitialExecutor: NSObject, FullScreenContentDelegate {
80
111
  }
81
112
 
82
113
  func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
114
+ removeCurrentlyShowingAd()
83
115
  NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.")
84
116
  self.plugin?.notifyListeners(RewardInterstitialAdPluginEvents.Dismissed.rawValue, data: [:])
85
117
  }
118
+
119
+ private func removeCurrentlyShowingAd() {
120
+ guard let adId = currentlyShowingAdId else { return }
121
+ preparedAds.removeValue(forKey: adId)
122
+ if lastPreparedAdId == adId { lastPreparedAdId = Array(preparedAds.keys).last }
123
+ currentlyShowingAdId = nil
124
+ }
86
125
  }
@@ -5,4 +5,5 @@ public enum RewardInterstitialAdPluginEvents: String {
5
5
  case FailedToShow = "onRewardedInterstitialAdFailedToShow"
6
6
  case Dismissed = "onRewardedInterstitialAdDismissed"
7
7
  case Rewarded = "onRewardedInterstitialAdReward"
8
+ case AdImpression = "onRewardedInterstitialAdImpression"
8
9
  }
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@capacitor-community/admob",
3
- "version": "8.0.0",
3
+ "private": false,
4
+ "version": "8.1.0",
4
5
  "description": "A native plugin for AdMob",
5
6
  "main": "dist/plugin.cjs.js",
6
7
  "module": "dist/esm/index.js",