@ququplay/admob 5.3.1

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 (140) hide show
  1. package/CapacitorCommunityAdmob.podspec +19 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1091 -0
  4. package/android/build.gradle +92 -0
  5. package/android/src/main/AndroidManifest.xml +5 -0
  6. package/android/src/main/java/com/getcapacitor/community/admob/AdMob.java +240 -0
  7. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdPluginEvents.kt +11 -0
  8. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdSizeEnum.kt +20 -0
  9. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerAdSizeInfo.kt +17 -0
  10. package/android/src/main/java/com/getcapacitor/community/admob/banner/BannerExecutor.java +294 -0
  11. package/android/src/main/java/com/getcapacitor/community/admob/consent/AdConsentExecutor.java +232 -0
  12. package/android/src/main/java/com/getcapacitor/community/admob/helpers/AdViewIdHelper.java +31 -0
  13. package/android/src/main/java/com/getcapacitor/community/admob/helpers/AuthorizationStatusEnum.kt +5 -0
  14. package/android/src/main/java/com/getcapacitor/community/admob/helpers/FullscreenPluginCallback.kt +27 -0
  15. package/android/src/main/java/com/getcapacitor/community/admob/helpers/RequestHelper.java +49 -0
  16. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/AdInterstitialExecutor.java +80 -0
  17. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdCallbackAndListeners.kt +38 -0
  18. package/android/src/main/java/com/getcapacitor/community/admob/interstitial/InterstitialAdPluginPluginEvent.kt +11 -0
  19. package/android/src/main/java/com/getcapacitor/community/admob/models/AdMobPluginError.kt +15 -0
  20. package/android/src/main/java/com/getcapacitor/community/admob/models/AdOptions.java +225 -0
  21. package/android/src/main/java/com/getcapacitor/community/admob/models/Executor.java +34 -0
  22. package/android/src/main/java/com/getcapacitor/community/admob/models/LoadPluginEventNames.kt +7 -0
  23. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/AdRewardExecutor.java +80 -0
  24. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardAdPluginEvents.kt +12 -0
  25. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/RewardedAdCallbackAndListeners.kt +63 -0
  26. package/android/src/main/java/com/getcapacitor/community/admob/rewarded/models/SsvInfo.kt +20 -0
  27. package/android/src/main/res/layout/bridge_layout_main.xml +15 -0
  28. package/android/src/main/res/values/colors.xml +3 -0
  29. package/android/src/main/res/values/strings.xml +2 -0
  30. package/android/src/main/res/values/styles.xml +3 -0
  31. package/dist/docs.json +2467 -0
  32. package/dist/esm/banner/banner-ad-options.interface.d.ts +25 -0
  33. package/dist/esm/banner/banner-ad-options.interface.js +2 -0
  34. package/dist/esm/banner/banner-ad-options.interface.js.map +1 -0
  35. package/dist/esm/banner/banner-ad-plugin-events.enum.d.ts +17 -0
  36. package/dist/esm/banner/banner-ad-plugin-events.enum.js +20 -0
  37. package/dist/esm/banner/banner-ad-plugin-events.enum.js.map +1 -0
  38. package/dist/esm/banner/banner-ad-position.enum.d.ts +17 -0
  39. package/dist/esm/banner/banner-ad-position.enum.js +19 -0
  40. package/dist/esm/banner/banner-ad-position.enum.js.map +1 -0
  41. package/dist/esm/banner/banner-ad-size.enum.d.ts +42 -0
  42. package/dist/esm/banner/banner-ad-size.enum.js +44 -0
  43. package/dist/esm/banner/banner-ad-size.enum.js.map +1 -0
  44. package/dist/esm/banner/banner-definitions.interface.d.ts +91 -0
  45. package/dist/esm/banner/banner-definitions.interface.js +2 -0
  46. package/dist/esm/banner/banner-definitions.interface.js.map +1 -0
  47. package/dist/esm/banner/banner-size.interface.d.ts +7 -0
  48. package/dist/esm/banner/banner-size.interface.js +2 -0
  49. package/dist/esm/banner/banner-size.interface.js.map +1 -0
  50. package/dist/esm/banner/index.d.ts +6 -0
  51. package/dist/esm/banner/index.js +7 -0
  52. package/dist/esm/banner/index.js.map +1 -0
  53. package/dist/esm/consent/consent-debug-geography.enum.d.ts +19 -0
  54. package/dist/esm/consent/consent-debug-geography.enum.js +21 -0
  55. package/dist/esm/consent/consent-debug-geography.enum.js.map +1 -0
  56. package/dist/esm/consent/consent-definition.interface.d.ts +26 -0
  57. package/dist/esm/consent/consent-definition.interface.js +2 -0
  58. package/dist/esm/consent/consent-definition.interface.js.map +1 -0
  59. package/dist/esm/consent/consent-info.interface.d.ts +13 -0
  60. package/dist/esm/consent/consent-info.interface.js +2 -0
  61. package/dist/esm/consent/consent-info.interface.js.map +1 -0
  62. package/dist/esm/consent/consent-request-options.interface.d.ts +20 -0
  63. package/dist/esm/consent/consent-request-options.interface.js +2 -0
  64. package/dist/esm/consent/consent-request-options.interface.js.map +1 -0
  65. package/dist/esm/consent/consent-status.enum.d.ts +23 -0
  66. package/dist/esm/consent/consent-status.enum.js +25 -0
  67. package/dist/esm/consent/consent-status.enum.js.map +1 -0
  68. package/dist/esm/consent/index.d.ts +5 -0
  69. package/dist/esm/consent/index.js +6 -0
  70. package/dist/esm/consent/index.js.map +1 -0
  71. package/dist/esm/definitions.d.ts +129 -0
  72. package/dist/esm/definitions.js +20 -0
  73. package/dist/esm/definitions.js.map +1 -0
  74. package/dist/esm/index.d.ts +9 -0
  75. package/dist/esm/index.js +12 -0
  76. package/dist/esm/index.js.map +1 -0
  77. package/dist/esm/interstitial/index.d.ts +2 -0
  78. package/dist/esm/interstitial/index.js +3 -0
  79. package/dist/esm/interstitial/index.js.map +1 -0
  80. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.d.ts +22 -0
  81. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.js +25 -0
  82. package/dist/esm/interstitial/interstitial-ad-plugin-events.enum.js.map +1 -0
  83. package/dist/esm/interstitial/interstitial-definitions.interface.d.ts +27 -0
  84. package/dist/esm/interstitial/interstitial-definitions.interface.js +2 -0
  85. package/dist/esm/interstitial/interstitial-definitions.interface.js.map +1 -0
  86. package/dist/esm/private/validate-all-events-implemented.type.d.ts +12 -0
  87. package/dist/esm/private/validate-all-events-implemented.type.js +2 -0
  88. package/dist/esm/private/validate-all-events-implemented.type.js.map +1 -0
  89. package/dist/esm/reward/index.d.ts +4 -0
  90. package/dist/esm/reward/index.js +5 -0
  91. package/dist/esm/reward/index.js.map +1 -0
  92. package/dist/esm/reward/reward-ad-options.interface.d.ts +25 -0
  93. package/dist/esm/reward/reward-ad-options.interface.js +2 -0
  94. package/dist/esm/reward/reward-ad-options.interface.js.map +1 -0
  95. package/dist/esm/reward/reward-ad-plugin-events.enum.d.ts +32 -0
  96. package/dist/esm/reward/reward-ad-plugin-events.enum.js +35 -0
  97. package/dist/esm/reward/reward-ad-plugin-events.enum.js.map +1 -0
  98. package/dist/esm/reward/reward-definitions.interface.d.ts +30 -0
  99. package/dist/esm/reward/reward-definitions.interface.js +2 -0
  100. package/dist/esm/reward/reward-definitions.interface.js.map +1 -0
  101. package/dist/esm/reward/reward-item.interface.d.ts +14 -0
  102. package/dist/esm/reward/reward-item.interface.js +2 -0
  103. package/dist/esm/reward/reward-item.interface.js.map +1 -0
  104. package/dist/esm/shared/ad-load-info.interface.d.ts +3 -0
  105. package/dist/esm/shared/ad-load-info.interface.js +2 -0
  106. package/dist/esm/shared/ad-load-info.interface.js.map +1 -0
  107. package/dist/esm/shared/ad-options.interface.d.ts +35 -0
  108. package/dist/esm/shared/ad-options.interface.js +2 -0
  109. package/dist/esm/shared/ad-options.interface.js.map +1 -0
  110. package/dist/esm/shared/admob-error.interface.d.ts +14 -0
  111. package/dist/esm/shared/admob-error.interface.js +2 -0
  112. package/dist/esm/shared/admob-error.interface.js.map +1 -0
  113. package/dist/esm/shared/index.d.ts +3 -0
  114. package/dist/esm/shared/index.js +4 -0
  115. package/dist/esm/shared/index.js.map +1 -0
  116. package/dist/esm/shared/tracking-authorization-status.interface.d.ts +6 -0
  117. package/dist/esm/shared/tracking-authorization-status.interface.js +2 -0
  118. package/dist/esm/shared/tracking-authorization-status.interface.js.map +1 -0
  119. package/dist/esm/web.d.ts +25 -0
  120. package/dist/esm/web.js +83 -0
  121. package/dist/esm/web.js.map +1 -0
  122. package/dist/plugin.cjs.js +307 -0
  123. package/dist/plugin.cjs.js.map +1 -0
  124. package/dist/plugin.js +310 -0
  125. package/dist/plugin.js.map +1 -0
  126. package/ios/Plugin/Banner/BannerAdPluginEvents.swift +8 -0
  127. package/ios/Plugin/Banner/BannerAdSizeEnum.swift +10 -0
  128. package/ios/Plugin/Banner/BannerExecutor.swift +198 -0
  129. package/ios/Plugin/Consent/ConsentExecutor.swift +158 -0
  130. package/ios/Plugin/Helper/AuthorizationStatusEnum.swift +6 -0
  131. package/ios/Plugin/Info.plist +24 -0
  132. package/ios/Plugin/Interstitial/AdInterstitialExecutor.swift +65 -0
  133. package/ios/Plugin/Interstitial/InterstitialAdPluginEvents.swift +7 -0
  134. package/ios/Plugin/Models/FullScreenAdEventName.swift +12 -0
  135. package/ios/Plugin/Plugin.h +10 -0
  136. package/ios/Plugin/Plugin.m +23 -0
  137. package/ios/Plugin/Plugin.swift +275 -0
  138. package/ios/Plugin/Rewarded/AdRewardExecutor.swift +86 -0
  139. package/ios/Plugin/Rewarded/RewardAdPluginEvents.swift +8 -0
  140. package/package.json +108 -0
@@ -0,0 +1,158 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import GoogleMobileAds
4
+ import UserMessagingPlatform
5
+
6
+ class ConsentExecutor: NSObject {
7
+ public weak var plugin: AdMob?
8
+
9
+ func requestConsentInfo(_ call: CAPPluginCall, _ debugGeography: Int, _ testDeviceIdentifiers: [String], _ tagForUnderAgeOfConsent: Bool) {
10
+ let parameters = UMPRequestParameters()
11
+ let debugSettings = UMPDebugSettings()
12
+
13
+ debugSettings.geography = UMPDebugGeography(rawValue: debugGeography) ?? UMPDebugGeography.disabled
14
+ debugSettings.testDeviceIdentifiers = testDeviceIdentifiers
15
+
16
+ parameters.debugSettings = debugSettings
17
+ parameters.tagForUnderAgeOfConsent = tagForUnderAgeOfConsent
18
+
19
+ // Request an update to the consent information.
20
+ UMPConsentInformation.sharedInstance.requestConsentInfoUpdate(
21
+ with: parameters,
22
+ completionHandler: { error in
23
+ if error != nil {
24
+ call.reject("Request consent info failed")
25
+ } else {
26
+ call.resolve([
27
+ "status": self.getConsentStatusString(UMPConsentInformation.sharedInstance.consentStatus),
28
+ "isConsentFormAvailable": UMPConsentInformation.sharedInstance.formStatus == UMPFormStatus.available,
29
+ "canShowAds": self.canShowAds(),
30
+ "canShowPersonalizedAds": self.canShowPersonalizedAds()
31
+ ])
32
+ }
33
+ })
34
+ }
35
+
36
+ func showConsentForm(_ call: CAPPluginCall) {
37
+ if let rootViewController = plugin?.getRootVC() {
38
+ let formStatus = UMPConsentInformation.sharedInstance.formStatus
39
+
40
+ if formStatus == UMPFormStatus.available {
41
+ UMPConsentForm.load(completionHandler: {form, loadError in
42
+ if loadError != nil {
43
+ call.reject(loadError?.localizedDescription ?? "Load consent form error")
44
+ return
45
+ }
46
+
47
+ if UMPConsentInformation.sharedInstance.consentStatus == UMPConsentStatus.required {
48
+ form?.present(from: rootViewController, completionHandler: { dismissError in
49
+ if dismissError != nil {
50
+ call.reject(dismissError?.localizedDescription ?? "Consent dismiss error")
51
+ return
52
+ }
53
+
54
+ call.resolve([
55
+ "status": self.getConsentStatusString(UMPConsentInformation.sharedInstance.consentStatus),
56
+ "canShowAds": self.canShowAds(),
57
+ "canShowPersonalizedAds": self.canShowPersonalizedAds()
58
+ ])
59
+ })
60
+ } else {
61
+ call.resolve([
62
+ "status": self.getConsentStatusString(UMPConsentInformation.sharedInstance.consentStatus),
63
+ "canShowAds": self.canShowAds(),
64
+ "canShowPersonalizedAds": self.canShowPersonalizedAds()
65
+ ])
66
+ }
67
+ })
68
+ } else {
69
+ call.reject("Consent Form not available")
70
+ }
71
+ } else {
72
+ call.reject("No ViewController")
73
+ }
74
+ }
75
+
76
+ func resetConsentInfo(_ call: CAPPluginCall) {
77
+ UMPConsentInformation.sharedInstance.reset()
78
+ call.resolve()
79
+ }
80
+
81
+ func getConsentStatusString(_ consentStatus: UMPConsentStatus) -> String {
82
+ switch consentStatus {
83
+ case UMPConsentStatus.required:
84
+ return "REQUIRED"
85
+ case UMPConsentStatus.notRequired:
86
+ return "NOT_REQUIRED"
87
+ case UMPConsentStatus.obtained:
88
+ return "OBTAINED"
89
+ default:
90
+ return "UNKNOWN"
91
+ }
92
+ }
93
+
94
+ func isGDPR() -> Bool {
95
+ let settings = UserDefaults.standard
96
+ let gdpr = settings.integer(forKey: "IABTCF_gdprApplies")
97
+ return gdpr == 1
98
+ }
99
+
100
+ // Check if a binary string has a "1" at position "index" (1-based)
101
+ private func hasAttribute(input: String, index: Int) -> Bool {
102
+ return input.count >= index && String(Array(input)[index-1]) == "1"
103
+ }
104
+
105
+ // Check if consent is given for a list of purposes
106
+ private func hasConsentFor(_ purposes: [Int], _ purposeConsent: String, _ hasVendorConsent: Bool) -> Bool {
107
+ return purposes.allSatisfy { i in hasAttribute(input: purposeConsent, index: i) } && hasVendorConsent
108
+ }
109
+
110
+ // Check if a vendor either has consent or legitimate interest for a list of purposes
111
+ private func hasConsentOrLegitimateInterestFor(_ purposes: [Int], _ purposeConsent: String, _ purposeLI: String, _ hasVendorConsent: Bool, _ hasVendorLI: Bool) -> Bool {
112
+ return purposes.allSatisfy { i in
113
+ (hasAttribute(input: purposeLI, index: i) && hasVendorLI) ||
114
+ (hasAttribute(input: purposeConsent, index: i) && hasVendorConsent)
115
+ }
116
+ }
117
+
118
+ private func canShowAds() -> Bool {
119
+ let settings = UserDefaults.standard
120
+
121
+ //https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
122
+ //https://support.google.com/admob/answer/9760862?hl=en&ref_topic=9756841
123
+
124
+ let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
125
+ let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
126
+ let vendorLI = settings.string(forKey: "IABTCF_VendorLegitimateInterests") ?? ""
127
+ let purposeLI = settings.string(forKey: "IABTCF_PurposeLegitimateInterests") ?? ""
128
+
129
+ let googleId = 755
130
+ let hasGoogleVendorConsent = hasAttribute(input: vendorConsent, index: googleId)
131
+ let hasGoogleVendorLI = hasAttribute(input: vendorLI, index: googleId)
132
+
133
+ // Minimum required for at least non-personalized ads
134
+ return hasConsentFor([1], purposeConsent, hasGoogleVendorConsent)
135
+ && hasConsentOrLegitimateInterestFor([2,7,9,10], purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
136
+
137
+ }
138
+
139
+ private func canShowPersonalizedAds() -> Bool {
140
+ let settings = UserDefaults.standard
141
+
142
+ //https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#in-app-details
143
+ //https://support.google.com/admob/answer/9760862?hl=en&ref_topic=9756841
144
+
145
+ // required for personalized ads
146
+ let purposeConsent = settings.string(forKey: "IABTCF_PurposeConsents") ?? ""
147
+ let vendorConsent = settings.string(forKey: "IABTCF_VendorConsents") ?? ""
148
+ let vendorLI = settings.string(forKey: "IABTCF_VendorLegitimateInterests") ?? ""
149
+ let purposeLI = settings.string(forKey: "IABTCF_PurposeLegitimateInterests") ?? ""
150
+
151
+ let googleId = 755
152
+ let hasGoogleVendorConsent = hasAttribute(input: vendorConsent, index: googleId)
153
+ let hasGoogleVendorLI = hasAttribute(input: vendorLI, index: googleId)
154
+
155
+ return hasConsentFor([1,3,4], purposeConsent, hasGoogleVendorConsent)
156
+ && hasConsentOrLegitimateInterestFor([2,7,9,10], purposeConsent, purposeLI, hasGoogleVendorConsent, hasGoogleVendorLI)
157
+ }
158
+ }
@@ -0,0 +1,6 @@
1
+ public enum AuthorizationStatusEnum: String {
2
+ case Authorized = "authorized"
3
+ case Denied = "denied"
4
+ case NotDetermined = "notDetermined"
5
+ case Restricted = "restricted"
6
+ }
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>$(CURRENT_PROJECT_VERSION)</string>
21
+ <key>NSPrincipalClass</key>
22
+ <string></string>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,65 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import GoogleMobileAds
4
+
5
+ class AdInterstitialExecutor: NSObject, GADFullScreenContentDelegate {
6
+ public weak var plugin: AdMob?
7
+ var interstitial: GADInterstitialAd!
8
+
9
+ func prepareInterstitial(_ call: CAPPluginCall, _ request: GADRequest, _ adUnitID: String) {
10
+ GADInterstitialAd.load(
11
+ withAdUnitID: adUnitID,
12
+ request: request,
13
+ completionHandler: { (ad, error) in
14
+ if let error = error {
15
+ NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)")
16
+ self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToLoad.rawValue, data: [
17
+ "code": 0,
18
+ "message": error.localizedDescription
19
+ ])
20
+ call.reject("Loading failed")
21
+ return
22
+ }
23
+
24
+ self.interstitial = ad
25
+ self.interstitial.fullScreenContentDelegate = self
26
+ self.plugin?.notifyListeners(InterstitialAdPluginEvents.Loaded.rawValue, data: [
27
+ "adUnitId": adUnitID
28
+ ])
29
+ call.resolve([
30
+ "adUnitId": adUnitID
31
+ ])
32
+ }
33
+ )
34
+ }
35
+
36
+ func showInterstitial(_ call: CAPPluginCall) {
37
+ if let rootViewController = plugin?.getRootVC() {
38
+ if let ad = self.interstitial {
39
+ ad.present(fromRootViewController: rootViewController)
40
+ call.resolve([:])
41
+ } else {
42
+ NSLog("Ad wasn't ready")
43
+ call.reject("Ad wasn't ready")
44
+ }
45
+ }
46
+ }
47
+
48
+ public func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
49
+ NSLog("InterstitialFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
50
+ self.plugin?.notifyListeners(InterstitialAdPluginEvents.FailedToShow.rawValue, data: [
51
+ "code": 0,
52
+ "message": error.localizedDescription
53
+ ])
54
+ }
55
+
56
+ public func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
57
+ NSLog("InterstitialFullScreenDelegate Ad did present full screen content.")
58
+ self.plugin?.notifyListeners(InterstitialAdPluginEvents.Showed.rawValue, data: [:])
59
+ }
60
+
61
+ public func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
62
+ NSLog("InterstitialFullScreenDelegate Ad did dismiss full screen content.")
63
+ self.plugin?.notifyListeners(InterstitialAdPluginEvents.Dismissed.rawValue, data: [:])
64
+ }
65
+ }
@@ -0,0 +1,7 @@
1
+ public enum InterstitialAdPluginEvents: String {
2
+ case Loaded = "interstitialAdLoaded"
3
+ case FailedToLoad = "interstitialAdFailedToLoad"
4
+ case Showed = "interstitialAdShowed"
5
+ case FailedToShow = "interstitialAdFailedToShow"
6
+ case Dismissed = "interstitialAdDismissed"
7
+ }
@@ -0,0 +1,12 @@
1
+ public enum FullScreenAdEventName: String {
2
+ case onAdLoaded = "onAdLoaded"
3
+ case onAdFailedToLoad = "onAdFailedToLoad"
4
+ case adDidPresentFullScreenContent = "adDidPresentFullScreenContent"
5
+ case didFailToPresentFullScreenContentWithError = "didFailToPresentFullScreenContentWithError"
6
+
7
+ /**
8
+ * Follow iOS Event Name
9
+ * https://developers.google.com/admob/ios/api/reference/Protocols/GADFullScreenContentDelegate#-addidpresentfullscreencontent:
10
+ */
11
+ case adDidDismissFullScreenContent = "adDidDismissFullScreenContent"
12
+ }
@@ -0,0 +1,10 @@
1
+ #import <UIKit/UIKit.h>
2
+
3
+ //! Project version number for Plugin.
4
+ FOUNDATION_EXPORT double PluginVersionNumber;
5
+
6
+ //! Project version string for Plugin.
7
+ FOUNDATION_EXPORT const unsigned char PluginVersionString[];
8
+
9
+ // In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
10
+
@@ -0,0 +1,23 @@
1
+ #import <Foundation/Foundation.h>
2
+ #import <Capacitor/Capacitor.h>
3
+
4
+ // Define the plugin using the CAP_PLUGIN Macro, and
5
+ // each method the plugin supports using the CAP_PLUGIN_METHOD macro.
6
+ CAP_PLUGIN(AdMob, "AdMob",
7
+ CAP_PLUGIN_METHOD(initialize, CAPPluginReturnPromise);
8
+ CAP_PLUGIN_METHOD(trackingAuthorizationStatus, CAPPluginReturnPromise);
9
+ CAP_PLUGIN_METHOD(requestConsentInfo, CAPPluginReturnPromise);
10
+ CAP_PLUGIN_METHOD(requestTrackingAuthorization, CAPPluginReturnPromise);
11
+ CAP_PLUGIN_METHOD(showConsentForm, CAPPluginReturnPromise);
12
+ CAP_PLUGIN_METHOD(resetConsentInfo, CAPPluginReturnPromise);
13
+ CAP_PLUGIN_METHOD(setApplicationMuted, CAPPluginReturnPromise);
14
+ CAP_PLUGIN_METHOD(setApplicationVolume, CAPPluginReturnPromise);
15
+ CAP_PLUGIN_METHOD(showBanner, CAPPluginReturnPromise);
16
+ CAP_PLUGIN_METHOD(resumeBanner, CAPPluginReturnPromise);
17
+ CAP_PLUGIN_METHOD(hideBanner, CAPPluginReturnPromise);
18
+ CAP_PLUGIN_METHOD(removeBanner, CAPPluginReturnPromise);
19
+ CAP_PLUGIN_METHOD(prepareInterstitial, CAPPluginReturnPromise);
20
+ CAP_PLUGIN_METHOD(showInterstitial, CAPPluginReturnPromise);
21
+ CAP_PLUGIN_METHOD(prepareRewardVideoAd, CAPPluginReturnPromise);
22
+ CAP_PLUGIN_METHOD(showRewardVideoAd, CAPPluginReturnPromise);
23
+ )
@@ -0,0 +1,275 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import GoogleMobileAds
4
+ #if canImport(AppTrackingTransparency)
5
+ import AppTrackingTransparency
6
+ #endif
7
+
8
+ @objc(AdMob)
9
+ public class AdMob: CAPPlugin {
10
+
11
+ var testingDevices: [String] = []
12
+
13
+ private let bannerExecutor = BannerExecutor()
14
+ private let adInterstitialExecutor = AdInterstitialExecutor()
15
+ private let adRewardExecutor = AdRewardExecutor()
16
+ private let consentExecutor = ConsentExecutor()
17
+
18
+ /**
19
+ * Enable SKAdNetwork to track conversions
20
+ * https://developers.google.com/admob/ios/ios14
21
+ */
22
+ @objc func initialize(_ call: CAPPluginCall) {
23
+ self.bannerExecutor.plugin = self
24
+ self.adInterstitialExecutor.plugin = self
25
+ self.adRewardExecutor.plugin = self
26
+ self.consentExecutor.plugin = self
27
+ self.setRequestConfiguration(call)
28
+
29
+ GADMobileAds.sharedInstance().start(completionHandler: nil)
30
+ call.resolve([:])
31
+ }
32
+
33
+ /**
34
+ * DEPRECATED: It's now ship with Admob UMP Consent
35
+ */
36
+ @objc func requestTrackingAuthorization(_ call: CAPPluginCall) {
37
+ if #available(iOS 14, *) {
38
+ #if canImport(AppTrackingTransparency)
39
+ ATTrackingManager.requestTrackingAuthorization(completionHandler: { _ in
40
+ call.resolve([:])
41
+ })
42
+ #else
43
+ call.resolve([:])
44
+ #endif
45
+ } else {
46
+ call.resolve([:])
47
+ }
48
+ }
49
+
50
+ @objc func setApplicationMuted(_ call: CAPPluginCall) {
51
+ if let shouldMute = call.getBool("muted") {
52
+ GADMobileAds.sharedInstance().applicationMuted = shouldMute
53
+ call.resolve([:])
54
+ } else {
55
+ call.reject("muted property cannot be null")
56
+ return
57
+ }
58
+ }
59
+
60
+ @objc func setApplicationVolume(_ call: CAPPluginCall) {
61
+ if var volume = call.getFloat("volume") {
62
+ //Clamp volumes.
63
+ if volume < 0.0 {volume = 0.0} else if volume > 1.0 {volume = 1.0}
64
+
65
+ GADMobileAds.sharedInstance().applicationVolume = volume
66
+
67
+ call.resolve([:])
68
+ } else {
69
+ call.reject("volume property cannot be null")
70
+ return
71
+ }
72
+ }
73
+
74
+ /**
75
+ * AdMob: Banner
76
+ * https://developers.google.com/ad-manager/mobile-ads-sdk/ios/banner?hl=ja
77
+ */
78
+ @objc func showBanner(_ call: CAPPluginCall) {
79
+ let adUnitID = getAdId(call, "ca-app-pub-3940256099942544/6300978111")
80
+ let request = self.GADRequestWithOption(call.getBool("npa") ?? false)
81
+
82
+ DispatchQueue.main.async {
83
+ self.bannerExecutor.showBanner(call, request, adUnitID)
84
+ }
85
+ }
86
+
87
+ @objc func hideBanner(_ call: CAPPluginCall) {
88
+ DispatchQueue.main.async {
89
+ self.bannerExecutor.hideBanner(call)
90
+ }
91
+ }
92
+
93
+ @objc func resumeBanner(_ call: CAPPluginCall) {
94
+ DispatchQueue.main.async {
95
+ self.bannerExecutor.resumeBanner(call)
96
+ }
97
+ }
98
+
99
+ @objc func removeBanner(_ call: CAPPluginCall) {
100
+ DispatchQueue.main.async {
101
+ self.bannerExecutor.removeBanner(call)
102
+ }
103
+ }
104
+
105
+ /**
106
+ * AdMob: Intertitial
107
+ * https://developers.google.com/admob/ios/interstitial?hl=ja
108
+ */
109
+ @objc func prepareInterstitial(_ call: CAPPluginCall) {
110
+ let adUnitID = getAdId(call, "ca-app-pub-3940256099942544/1033173712")
111
+ let request = self.GADRequestWithOption(call.getBool("npa") ?? false)
112
+
113
+ DispatchQueue.main.async {
114
+ self.adInterstitialExecutor.prepareInterstitial(call, request, adUnitID)
115
+ }
116
+ }
117
+
118
+ @objc func showInterstitial(_ call: CAPPluginCall) {
119
+ DispatchQueue.main.async {
120
+ self.adInterstitialExecutor.showInterstitial(call)
121
+ }
122
+ }
123
+
124
+ /**
125
+ * AdMob: Rewarded Ads
126
+ * https://developers.google.com/ad-manager/mobile-ads-sdk/ios/rewarded-ads?hl=ja
127
+ */
128
+ @objc func prepareRewardVideoAd(_ call: CAPPluginCall) {
129
+ let adUnitID = getAdId(call, "ca-app-pub-3940256099942544/1712485313")
130
+ let request = self.GADRequestWithOption(call.getBool("npa") ?? false)
131
+
132
+ DispatchQueue.main.async {
133
+ self.adRewardExecutor.prepareRewardVideoAd(call, request, adUnitID)
134
+ }
135
+ }
136
+
137
+ @objc func showRewardVideoAd(_ call: CAPPluginCall) {
138
+ DispatchQueue.main.async {
139
+ self.adRewardExecutor.showRewardVideoAd(call)
140
+ }
141
+ }
142
+
143
+ @objc func trackingAuthorizationStatus(_ call: CAPPluginCall) {
144
+ DispatchQueue.main.async {
145
+ if #available(iOS 14, *) {
146
+ switch ATTrackingManager.trackingAuthorizationStatus {
147
+ case .authorized:
148
+ call.resolve(["status": AuthorizationStatusEnum.Authorized.rawValue])
149
+ break
150
+ case .denied:
151
+ call.resolve(["status": AuthorizationStatusEnum.Denied.rawValue])
152
+ break
153
+ case .restricted:
154
+ call.resolve(["status": AuthorizationStatusEnum.Restricted.rawValue])
155
+ break
156
+ case .notDetermined:
157
+ call.resolve(["status": AuthorizationStatusEnum.NotDetermined.rawValue])
158
+ break
159
+ @unknown default:
160
+ call.reject("trackingAuthorizationStatus can't get status")
161
+ }
162
+ } else {
163
+ call.resolve(["status": AuthorizationStatusEnum.Authorized])
164
+ }
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Admob: User Message Platform
170
+ * https://support.google.com/admob/answer/10113005?hl=en
171
+ */
172
+ @objc func requestConsentInfo(_ call: CAPPluginCall) {
173
+ let debugGeography = call.getInt("debugGeography", 0)
174
+
175
+ let testDeviceJSArray = call.getArray("testDeviceIdentifiers") ?? []
176
+ var testDeviceIdentifiers: [String] = []
177
+ if testDeviceJSArray.count > 0 {
178
+ for deviceId in testDeviceJSArray {
179
+ if let name = deviceId as? String {
180
+ testDeviceIdentifiers.append(name)
181
+ }
182
+ }
183
+ }
184
+
185
+ let tagForUnderAgeOfConsent = call.getBool("tagForUnderAgeOfConsent", false)
186
+
187
+ DispatchQueue.main.async {
188
+ self.consentExecutor.requestConsentInfo(call, debugGeography, testDeviceIdentifiers, tagForUnderAgeOfConsent)
189
+ }
190
+ }
191
+
192
+ @objc func showConsentForm(_ call: CAPPluginCall) {
193
+ DispatchQueue.main.async {
194
+ self.consentExecutor.showConsentForm(call)
195
+ }
196
+ }
197
+
198
+ @objc func resetConsentInfo(_ call: CAPPluginCall) {
199
+ DispatchQueue.main.async {
200
+ self.consentExecutor.resetConsentInfo(call)
201
+ }
202
+ }
203
+
204
+ private func getAdId(_ call: CAPPluginCall, _ testingID: String) -> String {
205
+ let adUnitID = call.getString("adId") ?? testingID
206
+ let isTest = call.getBool("isTesting") ?? false
207
+ if isTest {
208
+ return testingID
209
+ }
210
+ return adUnitID
211
+ }
212
+
213
+ private func GADRequestWithOption(_ npa: Bool) -> GADRequest {
214
+ let request = GADRequest()
215
+
216
+ if npa {
217
+ let extras = GADExtras()
218
+ extras.additionalParameters = ["npa": "1"]
219
+ request.register(extras)
220
+ }
221
+
222
+ return request
223
+ }
224
+
225
+ /**
226
+ * https://developers.google.com/admob/ios/targeting?hl=ja
227
+ */
228
+ private func setRequestConfiguration(_ call: CAPPluginCall) {
229
+
230
+ if call.getBool("initializeForTesting") ?? false {
231
+ GADMobileAds.sharedInstance().requestConfiguration.testDeviceIdentifiers = call.getArray("testingDevices", String.self) ?? []
232
+ }
233
+
234
+ if call.getBool("tagForChildDirectedTreatment") != nil {
235
+ GADMobileAds.sharedInstance().requestConfiguration.tag(forChildDirectedTreatment: call.getBool("tagForChildDirectedTreatment")!)
236
+ }
237
+
238
+ if call.getBool("tagForUnderAgeOfConsent") != nil {
239
+ GADMobileAds.sharedInstance().requestConfiguration.tagForUnderAge(ofConsent: call.getBool("tagForUnderAgeOfConsent")!)
240
+ }
241
+
242
+ if call.getString("maxAdContentRating") != nil {
243
+ switch call.getString("maxAdContentRating") {
244
+ case "General":
245
+ GADMobileAds.sharedInstance().requestConfiguration.maxAdContentRating =
246
+ GADMaxAdContentRating.general
247
+ case "ParentalGuidance":
248
+ GADMobileAds.sharedInstance().requestConfiguration.maxAdContentRating =
249
+ GADMaxAdContentRating.parentalGuidance
250
+ case "Teen":
251
+ GADMobileAds.sharedInstance().requestConfiguration.maxAdContentRating =
252
+ GADMaxAdContentRating.teen
253
+ case "MatureAudience":
254
+ GADMobileAds.sharedInstance().requestConfiguration.maxAdContentRating =
255
+ GADMaxAdContentRating.matureAudience
256
+ default:
257
+ print("maxAdContentRating can't find value")
258
+ }
259
+ }
260
+
261
+ }
262
+
263
+ func getRootVC() -> UIViewController? {
264
+ var window: UIWindow? = UIApplication.shared.delegate?.window ?? nil
265
+
266
+ if window == nil {
267
+ let scene: UIWindowScene? = UIApplication.shared.connectedScenes.first as? UIWindowScene
268
+ window = scene?.windows.filter({$0.isKeyWindow}).first
269
+ if window == nil {
270
+ window = scene?.windows.first
271
+ }
272
+ }
273
+ return window?.rootViewController
274
+ }
275
+ }
@@ -0,0 +1,86 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import GoogleMobileAds
4
+
5
+ class AdRewardExecutor: NSObject, GADFullScreenContentDelegate {
6
+ public weak var plugin: AdMob?
7
+ var rewardedAd: GADRewardedAd!
8
+
9
+ func prepareRewardVideoAd(_ call: CAPPluginCall, _ request: GADRequest, _ adUnitID: String) {
10
+ GADRewardedAd.load(
11
+ withAdUnitID: adUnitID,
12
+ request: request,
13
+ completionHandler: { (ad, error) in
14
+ if let error = error {
15
+ NSLog("Rewarded ad failed to load with error: \(error.localizedDescription)")
16
+ self.plugin?.notifyListeners(RewardAdPluginEvents.FailedToLoad.rawValue, data: [
17
+ "code": 0,
18
+ "message": error.localizedDescription
19
+ ])
20
+ call.reject("Loading failed")
21
+ return
22
+ }
23
+
24
+ self.rewardedAd = ad
25
+
26
+ if let providedOptions = call.getObject("ssv") {
27
+ let ssvOptions = GADServerSideVerificationOptions()
28
+
29
+ if let customData = providedOptions["customData"] as? String {
30
+ NSLog("Sending Custom Data: \(customData) to SSV callback")
31
+ ssvOptions.customRewardString = customData
32
+ }
33
+
34
+ if let userId = providedOptions["userId"] as? String {
35
+ NSLog("Sending UserId: \(userId) to SSV callback")
36
+ ssvOptions.userIdentifier = userId
37
+ }
38
+
39
+ self.rewardedAd?.serverSideVerificationOptions = ssvOptions
40
+ }
41
+
42
+ self.rewardedAd?.fullScreenContentDelegate = self
43
+ self.plugin?.notifyListeners(RewardAdPluginEvents.Loaded.rawValue, data: [
44
+ "adUnitId": adUnitID
45
+ ])
46
+ call.resolve([
47
+ "adUnitId": adUnitID
48
+ ])
49
+ }
50
+ )
51
+ }
52
+
53
+ func showRewardVideoAd(_ call: CAPPluginCall) {
54
+ if let rootViewController = plugin?.getRootVC() {
55
+ if let ad = self.rewardedAd {
56
+ ad.present(fromRootViewController: rootViewController,
57
+ userDidEarnRewardHandler: {
58
+ let reward = ad.adReward
59
+ self.plugin?.notifyListeners(RewardAdPluginEvents.Rewarded.rawValue, data: ["type": reward.type, "amount": reward.amount])
60
+ call.resolve(["type": reward.type, "amount": reward.amount])
61
+ }
62
+ )
63
+ } else {
64
+ call.reject("Reward Video is Not Ready Yet")
65
+ }
66
+ }
67
+ }
68
+
69
+ public func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
70
+ NSLog("RewardFullScreenDelegate Ad failed to present full screen content with error \(error.localizedDescription).")
71
+ self.plugin?.notifyListeners(RewardAdPluginEvents.FailedToShow.rawValue, data: [
72
+ "code": 0,
73
+ "message": error.localizedDescription
74
+ ])
75
+ }
76
+
77
+ public func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
78
+ NSLog("RewardFullScreenDelegate Ad did present full screen content.")
79
+ self.plugin?.notifyListeners(RewardAdPluginEvents.Showed.rawValue, data: [:])
80
+ }
81
+
82
+ public func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
83
+ NSLog("RewardFullScreenDelegate Ad did dismiss full screen content.")
84
+ self.plugin?.notifyListeners(RewardAdPluginEvents.Dismissed.rawValue, data: [:])
85
+ }
86
+ }