@capgo/capacitor-admob 8.1.21 → 8.2.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.
- package/CapgoCapacitorAdmob.podspec +1 -0
- package/Package.swift +4 -2
- package/README.md +327 -8
- package/android/build.gradle +3 -2
- package/android/src/main/kotlin/admob/plus/capacitor/AdMobPlusPlugin.kt +121 -0
- package/android/src/main/kotlin/admob/plus/capacitor/ConsentHelper.kt +140 -0
- package/android/src/main/kotlin/admob/plus/capacitor/Generated.kt +7 -0
- package/android/src/main/kotlin/admob/plus/capacitor/feed/FeedAdManager.kt +512 -0
- package/android/src/main/kotlin/admob/plus/core/Ad.kt +2 -4
- package/android/src/main/kotlin/admob/plus/core/Helper.kt +18 -1
- package/dist/docs.json +543 -5
- package/dist/esm/definitions.d.ts +284 -1
- package/dist/esm/definitions.js +55 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/events.d.ts +127 -0
- package/dist/esm/events.js +50 -0
- package/dist/esm/events.js.map +1 -0
- package/dist/esm/feed-ad.d.ts +32 -0
- package/dist/esm/feed-ad.js +133 -0
- package/dist/esm/feed-ad.js.map +1 -0
- package/dist/esm/index.d.ts +4 -2
- package/dist/esm/index.js +4 -32
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/plugin-instance.d.ts +3 -0
- package/dist/esm/plugin-instance.js +35 -0
- package/dist/esm/plugin-instance.js.map +1 -0
- package/dist/esm/web.d.ts +11 -1
- package/dist/esm/web.js +40 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +313 -31
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +313 -31
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/AdmobPlusPlugin/AdmobPlusPlugin.swift +131 -1
- package/ios/Sources/AdmobPlusPlugin/BannerAd.swift +6 -9
- package/ios/Sources/AdmobPlusPlugin/ConsentExecutor.swift +100 -0
- package/ios/Sources/AdmobPlusPlugin/FeedAdManager.swift +435 -0
- package/ios/Sources/AdmobPlusPlugin/Generated.swift +7 -0
- package/ios/Sources/AdmobPlusPlugin/Helper.swift +29 -0
- package/ios/Sources/AdmobPlusPlugin/InterstitialAd.swift +7 -13
- package/ios/Sources/AdmobPlusPlugin/RewardedAd.swift +13 -20
- package/ios/Sources/AdmobPlusPlugin/RewardedInterstitialAd.swift +13 -20
- package/ios/Tests/AdmobPlusPluginTests/AdmobPlusPluginTests.swift +3 -6
- package/package.json +2 -2
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
import GoogleMobileAds
|
|
4
|
+
import Capacitor
|
|
5
|
+
|
|
6
|
+
private let minAutoRefreshMs = 30_000
|
|
7
|
+
|
|
8
|
+
private final class PassthroughView: UIView {
|
|
9
|
+
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
10
|
+
let hit = super.hitTest(point, with: event)
|
|
11
|
+
return hit === self ? nil : hit
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
final class FeedAdManager {
|
|
16
|
+
static let shared = FeedAdManager()
|
|
17
|
+
private var entries: [Int: FeedAdEntry] = [:]
|
|
18
|
+
private var nextId = 1
|
|
19
|
+
|
|
20
|
+
private init() {}
|
|
21
|
+
|
|
22
|
+
func create(
|
|
23
|
+
format: String,
|
|
24
|
+
adUnitId: String,
|
|
25
|
+
positionKey: String?,
|
|
26
|
+
autoRefreshMs: Int?,
|
|
27
|
+
nativeStyle: [String: String]?,
|
|
28
|
+
plugin: AdmobPlusPlugin
|
|
29
|
+
) -> Int {
|
|
30
|
+
let id = nextId
|
|
31
|
+
nextId += 1
|
|
32
|
+
let entry = FeedAdEntry(
|
|
33
|
+
id: id,
|
|
34
|
+
format: format == "banner" ? .banner : .native,
|
|
35
|
+
adUnitId: adUnitId,
|
|
36
|
+
positionKey: positionKey,
|
|
37
|
+
nativeStyle: nativeStyle ?? [:],
|
|
38
|
+
plugin: plugin
|
|
39
|
+
)
|
|
40
|
+
if let ms = autoRefreshMs {
|
|
41
|
+
entry.setAutoRefresh(ms: ms)
|
|
42
|
+
}
|
|
43
|
+
entries[id] = entry
|
|
44
|
+
return id
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func destroy(id: Int) {
|
|
48
|
+
entries[id]?.destroy()
|
|
49
|
+
entries.removeValue(forKey: id)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func load(id: Int, completion: @escaping (Error?) -> Void) {
|
|
53
|
+
guard let entry = entries[id] else {
|
|
54
|
+
completion(AdMobError.adNotFound)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
entry.load(completion: completion)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
func isLoaded(id: Int) -> Bool {
|
|
61
|
+
entries[id]?.isLoaded ?? false
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
func updateBounds(id: Int, x: Double, y: Double, width: Double, height: Double, visible: Bool) {
|
|
65
|
+
entries[id]?.updateBounds(x: x, y: y, width: width, height: height, visible: visible)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
func setAutoRefresh(id: Int, autoRefreshMs: Int?) {
|
|
69
|
+
entries[id]?.setAutoRefresh(ms: autoRefreshMs)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private enum FeedAdFormat {
|
|
74
|
+
case native
|
|
75
|
+
case banner
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private final class FeedAdEntry: NSObject {
|
|
79
|
+
let id: Int
|
|
80
|
+
let format: FeedAdFormat
|
|
81
|
+
let adUnitId: String
|
|
82
|
+
let positionKey: String?
|
|
83
|
+
let nativeStyle: [String: String]
|
|
84
|
+
weak var plugin: AdmobPlusPlugin?
|
|
85
|
+
|
|
86
|
+
private var overlayContainer: UIView?
|
|
87
|
+
private var nativeAdView: NativeAdView?
|
|
88
|
+
private var nativeAd: NativeAd?
|
|
89
|
+
private var adLoader: AdLoader?
|
|
90
|
+
private var bannerView: BannerView?
|
|
91
|
+
private var loaded = false
|
|
92
|
+
private var refreshTimer: Timer?
|
|
93
|
+
private var autoRefreshMs: Int?
|
|
94
|
+
private var loadCompletion: ((Error?) -> Void)?
|
|
95
|
+
|
|
96
|
+
init(
|
|
97
|
+
id: Int,
|
|
98
|
+
format: FeedAdFormat,
|
|
99
|
+
adUnitId: String,
|
|
100
|
+
positionKey: String?,
|
|
101
|
+
nativeStyle: [String: String],
|
|
102
|
+
plugin: AdmobPlusPlugin
|
|
103
|
+
) {
|
|
104
|
+
self.id = id
|
|
105
|
+
self.format = format
|
|
106
|
+
self.adUnitId = adUnitId
|
|
107
|
+
self.positionKey = positionKey
|
|
108
|
+
self.nativeStyle = nativeStyle
|
|
109
|
+
self.plugin = plugin
|
|
110
|
+
super.init()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
var isLoaded: Bool { loaded }
|
|
114
|
+
|
|
115
|
+
func load(completion: @escaping (Error?) -> Void) {
|
|
116
|
+
DispatchQueue.main.async {
|
|
117
|
+
self.loadCompletion = completion
|
|
118
|
+
switch self.format {
|
|
119
|
+
case .native:
|
|
120
|
+
self.loadNative()
|
|
121
|
+
case .banner:
|
|
122
|
+
self.loadBanner()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private func finishLoad(error: Error?) {
|
|
128
|
+
let completion = loadCompletion
|
|
129
|
+
loadCompletion = nil
|
|
130
|
+
completion?(error)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func destroy() {
|
|
134
|
+
refreshTimer?.invalidate()
|
|
135
|
+
refreshTimer = nil
|
|
136
|
+
nativeAd = nil
|
|
137
|
+
nativeAdView?.removeFromSuperview()
|
|
138
|
+
nativeAdView = nil
|
|
139
|
+
bannerView?.removeFromSuperview()
|
|
140
|
+
bannerView = nil
|
|
141
|
+
overlayContainer?.removeFromSuperview()
|
|
142
|
+
overlayContainer = nil
|
|
143
|
+
loaded = false
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func setAutoRefresh(ms: Int?) {
|
|
147
|
+
refreshTimer?.invalidate()
|
|
148
|
+
refreshTimer = nil
|
|
149
|
+
autoRefreshMs = ms
|
|
150
|
+
guard let ms = ms, ms >= minAutoRefreshMs else { return }
|
|
151
|
+
refreshTimer = Timer.scheduledTimer(withTimeInterval: Double(ms) / 1000.0, repeats: true) { [weak self] _ in
|
|
152
|
+
self?.plugin?.notifyFeedListeners(Events.feedRefresh, feedAdId: self?.id ?? 0, positionKey: self?.positionKey, format: self?.formatString)
|
|
153
|
+
self?.load { _ in }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
func updateBounds(x: Double, y: Double, width: Double, height: Double, visible: Bool) {
|
|
158
|
+
DispatchQueue.main.async {
|
|
159
|
+
guard let webView = self.plugin?.bridge?.webView,
|
|
160
|
+
let rootView = self.plugin?.bridge?.viewController?.view else { return }
|
|
161
|
+
|
|
162
|
+
let container = self.ensureOverlayContainer(on: rootView, below: webView)
|
|
163
|
+
let originY = webView.frame.origin.y + CGFloat(y)
|
|
164
|
+
let frame = CGRect(x: CGFloat(x), y: originY, width: CGFloat(width), height: CGFloat(height))
|
|
165
|
+
let target = self.nativeAdView ?? self.bannerView
|
|
166
|
+
target?.frame = frame
|
|
167
|
+
container.isHidden = !visible || !self.loaded
|
|
168
|
+
container.frame = rootView.bounds
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private var formatString: String {
|
|
173
|
+
format == .banner ? "banner" : "native"
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private func ensureOverlayContainer(on rootView: UIView, below webView: UIView) -> UIView {
|
|
177
|
+
if let overlayContainer = overlayContainer {
|
|
178
|
+
return overlayContainer
|
|
179
|
+
}
|
|
180
|
+
let container = PassthroughView(frame: rootView.bounds)
|
|
181
|
+
container.backgroundColor = .clear
|
|
182
|
+
container.isUserInteractionEnabled = true
|
|
183
|
+
container.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
184
|
+
rootView.insertSubview(container, aboveSubview: webView)
|
|
185
|
+
overlayContainer = container
|
|
186
|
+
return container
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private func loadNative() {
|
|
190
|
+
guard let viewController = plugin?.bridge?.viewController else {
|
|
191
|
+
finishLoad(error: AdMobError.unknown("Unable to access view controller"))
|
|
192
|
+
return
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
adLoader = AdLoader(
|
|
196
|
+
adUnitID: adUnitId,
|
|
197
|
+
rootViewController: viewController,
|
|
198
|
+
adTypes: [.native],
|
|
199
|
+
options: nil
|
|
200
|
+
)
|
|
201
|
+
adLoader?.delegate = self
|
|
202
|
+
adLoader?.load(AdMobHelper.buildAdRequest())
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
private func loadBanner() {
|
|
206
|
+
if bannerView == nil {
|
|
207
|
+
let banner = BannerView(adSize: AdSizeBanner)
|
|
208
|
+
banner.adUnitID = adUnitId
|
|
209
|
+
banner.delegate = self
|
|
210
|
+
banner.rootViewController = plugin?.bridge?.viewController
|
|
211
|
+
bannerView = banner
|
|
212
|
+
if let root = plugin?.bridge?.viewController?.view,
|
|
213
|
+
let webView = plugin?.bridge?.webView {
|
|
214
|
+
let container = ensureOverlayContainer(on: root, below: webView)
|
|
215
|
+
container.addSubview(banner)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
loaded = false
|
|
219
|
+
bannerView?.load(AdMobHelper.buildAdRequest())
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private func displayNativeAd(_ nativeAd: NativeAd) {
|
|
223
|
+
self.nativeAd = nativeAd
|
|
224
|
+
nativeAd.delegate = self
|
|
225
|
+
|
|
226
|
+
guard let root = plugin?.bridge?.viewController?.view,
|
|
227
|
+
let webView = plugin?.bridge?.webView else { return }
|
|
228
|
+
|
|
229
|
+
nativeAdView?.removeFromSuperview()
|
|
230
|
+
nativeAdView = nil
|
|
231
|
+
let adView = buildNativeAdView(for: nativeAd)
|
|
232
|
+
let container = ensureOverlayContainer(on: root, below: webView)
|
|
233
|
+
container.addSubview(adView)
|
|
234
|
+
nativeAdView = adView
|
|
235
|
+
loaded = true
|
|
236
|
+
container.isHidden = false
|
|
237
|
+
|
|
238
|
+
let assets: [String: Any] = [
|
|
239
|
+
"headline": nativeAd.headline ?? "",
|
|
240
|
+
"body": nativeAd.body ?? "",
|
|
241
|
+
"callToAction": nativeAd.callToAction ?? "",
|
|
242
|
+
"advertiser": nativeAd.advertiser ?? "",
|
|
243
|
+
"price": nativeAd.price ?? "",
|
|
244
|
+
"store": nativeAd.store ?? "",
|
|
245
|
+
"starRating": nativeAd.starRating ?? 0,
|
|
246
|
+
"mediaAspectRatio": nativeAd.mediaContent.aspectRatio,
|
|
247
|
+
]
|
|
248
|
+
plugin?.notifyFeedLoad(feedAdId: id, positionKey: positionKey, format: formatString, assets: assets)
|
|
249
|
+
finishLoad(error: nil)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private func buildNativeAdView(for nativeAd: NativeAd) -> NativeAdView {
|
|
253
|
+
let adView = NativeAdView()
|
|
254
|
+
adView.backgroundColor = color(from: nativeStyle["backgroundColor"]) ?? UIColor.secondarySystemBackground
|
|
255
|
+
adView.layer.cornerRadius = 12
|
|
256
|
+
adView.clipsToBounds = true
|
|
257
|
+
|
|
258
|
+
let stack = UIStackView()
|
|
259
|
+
stack.axis = .vertical
|
|
260
|
+
stack.spacing = 8
|
|
261
|
+
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
262
|
+
adView.addSubview(stack)
|
|
263
|
+
|
|
264
|
+
let attribution = UILabel()
|
|
265
|
+
attribution.text = "Ad"
|
|
266
|
+
attribution.font = .systemFont(ofSize: 10, weight: .semibold)
|
|
267
|
+
attribution.textColor = .secondaryLabel
|
|
268
|
+
attribution.textAlignment = .right
|
|
269
|
+
stack.addArrangedSubview(attribution)
|
|
270
|
+
|
|
271
|
+
let mediaView = MediaView()
|
|
272
|
+
mediaView.mediaContent = nativeAd.mediaContent
|
|
273
|
+
mediaView.translatesAutoresizingMaskIntoConstraints = false
|
|
274
|
+
mediaView.heightAnchor.constraint(equalToConstant: 180).isActive = true
|
|
275
|
+
adView.mediaView = mediaView
|
|
276
|
+
stack.addArrangedSubview(mediaView)
|
|
277
|
+
|
|
278
|
+
let headline = UILabel()
|
|
279
|
+
headline.font = .boldSystemFont(ofSize: 16)
|
|
280
|
+
headline.textColor = color(from: nativeStyle["headlineTextColor"]) ?? .label
|
|
281
|
+
headline.text = nativeAd.headline
|
|
282
|
+
headline.numberOfLines = 2
|
|
283
|
+
adView.headlineView = headline
|
|
284
|
+
stack.addArrangedSubview(headline)
|
|
285
|
+
|
|
286
|
+
if let bodyText = nativeAd.body {
|
|
287
|
+
let body = UILabel()
|
|
288
|
+
body.font = .systemFont(ofSize: 14)
|
|
289
|
+
body.textColor = color(from: nativeStyle["bodyTextColor"]) ?? .secondaryLabel
|
|
290
|
+
body.text = bodyText
|
|
291
|
+
body.numberOfLines = 3
|
|
292
|
+
adView.bodyView = body
|
|
293
|
+
stack.addArrangedSubview(body)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
let cta = UIButton(type: .system)
|
|
297
|
+
cta.setTitle(nativeAd.callToAction, for: .normal)
|
|
298
|
+
cta.backgroundColor = color(from: nativeStyle["ctaBackgroundColor"]) ?? .systemBlue
|
|
299
|
+
cta.setTitleColor(color(from: nativeStyle["ctaTextColor"]) ?? .white, for: .normal)
|
|
300
|
+
cta.layer.cornerRadius = 8
|
|
301
|
+
cta.isUserInteractionEnabled = false
|
|
302
|
+
cta.contentEdgeInsets = UIEdgeInsets(top: 10, left: 12, bottom: 10, right: 12)
|
|
303
|
+
adView.callToActionView = cta
|
|
304
|
+
stack.addArrangedSubview(cta)
|
|
305
|
+
|
|
306
|
+
NSLayoutConstraint.activate([
|
|
307
|
+
stack.leadingAnchor.constraint(equalTo: adView.leadingAnchor, constant: 12),
|
|
308
|
+
stack.trailingAnchor.constraint(equalTo: adView.trailingAnchor, constant: -12),
|
|
309
|
+
stack.topAnchor.constraint(equalTo: adView.topAnchor, constant: 12),
|
|
310
|
+
stack.bottomAnchor.constraint(equalTo: adView.bottomAnchor, constant: -12),
|
|
311
|
+
])
|
|
312
|
+
|
|
313
|
+
adView.nativeAd = nativeAd
|
|
314
|
+
return adView
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private func color(from hex: String?) -> UIColor? {
|
|
318
|
+
guard let hex = hex?.trimmingCharacters(in: .whitespacesAndNewlines), hex.hasPrefix("#"), hex.count == 7 else {
|
|
319
|
+
return nil
|
|
320
|
+
}
|
|
321
|
+
var rgb: UInt64 = 0
|
|
322
|
+
Scanner(string: String(hex.dropFirst())).scanHexInt64(&rgb)
|
|
323
|
+
return UIColor(
|
|
324
|
+
red: CGFloat((rgb & 0xFF0000) >> 16) / 255,
|
|
325
|
+
green: CGFloat((rgb & 0x00FF00) >> 8) / 255,
|
|
326
|
+
blue: CGFloat(rgb & 0x0000FF) / 255,
|
|
327
|
+
alpha: 1
|
|
328
|
+
)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
extension FeedAdEntry: AdLoaderDelegate {
|
|
333
|
+
func adLoader(_ adLoader: AdLoader, didFailToReceiveAdWithError error: Error) {
|
|
334
|
+
plugin?.notifyFeedFailure(Events.feedLoadFail, feedAdId: id, positionKey: positionKey, format: formatString, error: error)
|
|
335
|
+
loaded = false
|
|
336
|
+
finishLoad(error: error)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
extension FeedAdEntry: NativeAdLoaderDelegate {
|
|
341
|
+
func adLoader(_ adLoader: AdLoader, didReceive nativeAd: NativeAd) {
|
|
342
|
+
displayNativeAd(nativeAd)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
extension FeedAdEntry: NativeAdDelegate {
|
|
347
|
+
func nativeAdDidRecordClick(_ nativeAd: NativeAd) {
|
|
348
|
+
plugin?.notifyFeedListeners(Events.feedClick, feedAdId: id, positionKey: positionKey, format: formatString)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
func nativeAdDidRecordImpression(_ nativeAd: NativeAd) {
|
|
352
|
+
plugin?.notifyFeedListeners(Events.feedImpression, feedAdId: id, positionKey: positionKey, format: formatString)
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
extension FeedAdEntry: BannerViewDelegate {
|
|
357
|
+
func bannerViewDidReceiveAd(_ bannerView: BannerView) {
|
|
358
|
+
loaded = true
|
|
359
|
+
overlayContainer?.isHidden = false
|
|
360
|
+
let assets: [String: Any] = [
|
|
361
|
+
"width": bannerView.adSize.size.width,
|
|
362
|
+
"height": bannerView.adSize.size.height,
|
|
363
|
+
]
|
|
364
|
+
plugin?.notifyFeedLoad(feedAdId: id, positionKey: positionKey, format: formatString, assets: assets)
|
|
365
|
+
finishLoad(error: nil)
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) {
|
|
369
|
+
plugin?.notifyFeedFailure(Events.feedLoadFail, feedAdId: id, positionKey: positionKey, format: formatString, error: error)
|
|
370
|
+
loaded = false
|
|
371
|
+
finishLoad(error: error)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
func bannerViewDidRecordImpression(_ bannerView: BannerView) {
|
|
375
|
+
plugin?.notifyFeedListeners(Events.feedImpression, feedAdId: id, positionKey: positionKey, format: formatString)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
func bannerViewDidRecordClick(_ bannerView: BannerView) {
|
|
379
|
+
plugin?.notifyFeedListeners(Events.feedClick, feedAdId: id, positionKey: positionKey, format: formatString)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
func bannerViewWillPresentScreen(_ bannerView: BannerView) {
|
|
383
|
+
plugin?.notifyFeedListeners(Events.feedOpen, feedAdId: id, positionKey: positionKey, format: formatString)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
func bannerViewWillDismissScreen(_ bannerView: BannerView) {
|
|
387
|
+
plugin?.notifyFeedListeners(Events.feedClose, feedAdId: id, positionKey: positionKey, format: formatString)
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
extension AdmobPlusPlugin {
|
|
392
|
+
func notifyFeedListeners(_ eventName: String, feedAdId: Int, positionKey: String?, format: String?) {
|
|
393
|
+
var data: [String: Any] = ["feedAdId": feedAdId]
|
|
394
|
+
if let positionKey = positionKey {
|
|
395
|
+
data["positionKey"] = positionKey
|
|
396
|
+
}
|
|
397
|
+
if let format = format {
|
|
398
|
+
data["format"] = format
|
|
399
|
+
}
|
|
400
|
+
notifyListeners(eventName, data: data)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
func notifyFeedLoad(feedAdId: Int, positionKey: String?, format: String?, assets: [String: Any]) {
|
|
404
|
+
var data: [String: Any] = ["feedAdId": feedAdId, "assets": assets]
|
|
405
|
+
if let positionKey = positionKey {
|
|
406
|
+
data["positionKey"] = positionKey
|
|
407
|
+
}
|
|
408
|
+
if let format = format {
|
|
409
|
+
data["format"] = format
|
|
410
|
+
}
|
|
411
|
+
notifyListeners(Events.feedLoad, data: data)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
func notifyFeedFailure(
|
|
415
|
+
_ eventName: String,
|
|
416
|
+
feedAdId: Int,
|
|
417
|
+
positionKey: String?,
|
|
418
|
+
format: String?,
|
|
419
|
+
error: Error
|
|
420
|
+
) {
|
|
421
|
+
let nsError = error as NSError
|
|
422
|
+
var data: [String: Any] = [
|
|
423
|
+
"feedAdId": feedAdId,
|
|
424
|
+
"code": nsError.code,
|
|
425
|
+
"message": nsError.localizedDescription,
|
|
426
|
+
]
|
|
427
|
+
if let positionKey = positionKey {
|
|
428
|
+
data["positionKey"] = positionKey
|
|
429
|
+
}
|
|
430
|
+
if let format = format {
|
|
431
|
+
data["format"] = format
|
|
432
|
+
}
|
|
433
|
+
notifyListeners(eventName, data: data)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
@@ -37,4 +37,11 @@ struct Events {
|
|
|
37
37
|
static let rewardedReward = "rewarded.reward"
|
|
38
38
|
static let rewardedShow = "rewarded.show"
|
|
39
39
|
static let rewardedShowFail = "rewarded.showfail"
|
|
40
|
+
static let feedClick = "feed.click"
|
|
41
|
+
static let feedClose = "feed.close"
|
|
42
|
+
static let feedImpression = "feed.impression"
|
|
43
|
+
static let feedLoad = "feed.load"
|
|
44
|
+
static let feedLoadFail = "feed.loadfail"
|
|
45
|
+
static let feedOpen = "feed.open"
|
|
46
|
+
static let feedRefresh = "feed.refresh"
|
|
40
47
|
}
|
|
@@ -64,6 +64,35 @@ class AdMobHelper {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
extension AdmobPlusPlugin {
|
|
68
|
+
func notifyAdListeners(_ eventName: String, adId: Int) {
|
|
69
|
+
notifyListeners(eventName, data: ["adId": adId, "id": adId])
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
func notifyAdFailureListeners(_ eventName: String, adId: Int, error: Error) {
|
|
73
|
+
let nsError = error as NSError
|
|
74
|
+
let message = nsError.localizedDescription
|
|
75
|
+
notifyListeners(eventName, data: [
|
|
76
|
+
"adId": adId,
|
|
77
|
+
"id": adId,
|
|
78
|
+
"code": nsError.code,
|
|
79
|
+
"message": message,
|
|
80
|
+
"error": message,
|
|
81
|
+
])
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
func notifyAdRewardListeners(_ eventName: String, adId: Int, amount: Int, type: String) {
|
|
85
|
+
notifyListeners(eventName, data: [
|
|
86
|
+
"adId": adId,
|
|
87
|
+
"id": adId,
|
|
88
|
+
"reward": [
|
|
89
|
+
"amount": amount,
|
|
90
|
+
"type": type,
|
|
91
|
+
],
|
|
92
|
+
])
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
67
96
|
enum AdMobError: Error {
|
|
68
97
|
case adNotFound
|
|
69
98
|
case adNotLoaded
|
|
@@ -27,10 +27,7 @@ class InterstitialAd: NSObject, Ad {
|
|
|
27
27
|
guard let self = self else { return }
|
|
28
28
|
|
|
29
29
|
if let error = error {
|
|
30
|
-
self.plugin?.
|
|
31
|
-
"id": self.id,
|
|
32
|
-
"error": error.localizedDescription
|
|
33
|
-
])
|
|
30
|
+
self.plugin?.notifyAdFailureListeners(Events.interstitialLoadFail, adId: self.id, error: error)
|
|
34
31
|
completion(error)
|
|
35
32
|
return
|
|
36
33
|
}
|
|
@@ -38,7 +35,7 @@ class InterstitialAd: NSObject, Ad {
|
|
|
38
35
|
self.interstitial = ad
|
|
39
36
|
self.interstitial?.fullScreenContentDelegate = self
|
|
40
37
|
|
|
41
|
-
self.plugin?.
|
|
38
|
+
self.plugin?.notifyAdListeners(Events.interstitialLoad, adId: self.id)
|
|
42
39
|
completion(nil)
|
|
43
40
|
}
|
|
44
41
|
}
|
|
@@ -67,26 +64,23 @@ class InterstitialAd: NSObject, Ad {
|
|
|
67
64
|
|
|
68
65
|
extension InterstitialAd: FullScreenContentDelegate {
|
|
69
66
|
func adDidRecordImpression(_ ad: FullScreenPresentingAd) {
|
|
70
|
-
plugin?.
|
|
67
|
+
plugin?.notifyAdListeners(Events.interstitialImpression, adId: id)
|
|
71
68
|
}
|
|
72
69
|
|
|
73
70
|
func adDidRecordClick(_ ad: FullScreenPresentingAd) {
|
|
74
|
-
plugin?.
|
|
71
|
+
plugin?.notifyAdListeners(Events.adClick, adId: id)
|
|
75
72
|
}
|
|
76
73
|
|
|
77
74
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
|
78
|
-
plugin?.
|
|
79
|
-
"id": id,
|
|
80
|
-
"error": error.localizedDescription
|
|
81
|
-
])
|
|
75
|
+
plugin?.notifyAdFailureListeners(Events.interstitialShowFail, adId: id, error: error)
|
|
82
76
|
}
|
|
83
77
|
|
|
84
78
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
85
|
-
plugin?.
|
|
79
|
+
plugin?.notifyAdListeners(Events.interstitialShow, adId: id)
|
|
86
80
|
}
|
|
87
81
|
|
|
88
82
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
89
|
-
plugin?.
|
|
83
|
+
plugin?.notifyAdListeners(Events.interstitialDismiss, adId: id)
|
|
90
84
|
interstitial = nil
|
|
91
85
|
}
|
|
92
86
|
}
|
|
@@ -29,10 +29,7 @@ class RewardedAd: NSObject, Ad {
|
|
|
29
29
|
guard let self = self else { return }
|
|
30
30
|
|
|
31
31
|
if let error = error {
|
|
32
|
-
self.plugin?.
|
|
33
|
-
"id": self.id,
|
|
34
|
-
"error": error.localizedDescription
|
|
35
|
-
])
|
|
32
|
+
self.plugin?.notifyAdFailureListeners(Events.rewardedLoadFail, adId: self.id, error: error)
|
|
36
33
|
completion(error)
|
|
37
34
|
return
|
|
38
35
|
}
|
|
@@ -41,7 +38,7 @@ class RewardedAd: NSObject, Ad {
|
|
|
41
38
|
self.rewardedAd?.serverSideVerificationOptions = self.serverSideVerificationOptions
|
|
42
39
|
self.rewardedAd?.fullScreenContentDelegate = self
|
|
43
40
|
|
|
44
|
-
self.plugin?.
|
|
41
|
+
self.plugin?.notifyAdListeners(Events.rewardedLoad, adId: self.id)
|
|
45
42
|
completion(nil)
|
|
46
43
|
}
|
|
47
44
|
}
|
|
@@ -61,13 +58,12 @@ class RewardedAd: NSObject, Ad {
|
|
|
61
58
|
rewardedAd.present(from: viewController) { [weak self] in
|
|
62
59
|
guard let self = self else { return }
|
|
63
60
|
let reward = rewardedAd.adReward
|
|
64
|
-
self.plugin?.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
])
|
|
61
|
+
self.plugin?.notifyAdRewardListeners(
|
|
62
|
+
Events.rewardedReward,
|
|
63
|
+
adId: self.id,
|
|
64
|
+
amount: reward.amount.intValue,
|
|
65
|
+
type: reward.type
|
|
66
|
+
)
|
|
71
67
|
}
|
|
72
68
|
completion(nil)
|
|
73
69
|
}
|
|
@@ -80,26 +76,23 @@ class RewardedAd: NSObject, Ad {
|
|
|
80
76
|
|
|
81
77
|
extension RewardedAd: FullScreenContentDelegate {
|
|
82
78
|
func adDidRecordImpression(_ ad: FullScreenPresentingAd) {
|
|
83
|
-
plugin?.
|
|
79
|
+
plugin?.notifyAdListeners(Events.rewardedImpression, adId: id)
|
|
84
80
|
}
|
|
85
81
|
|
|
86
82
|
func adDidRecordClick(_ ad: FullScreenPresentingAd) {
|
|
87
|
-
plugin?.
|
|
83
|
+
plugin?.notifyAdListeners(Events.adClick, adId: id)
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
|
91
|
-
plugin?.
|
|
92
|
-
"id": id,
|
|
93
|
-
"error": error.localizedDescription
|
|
94
|
-
])
|
|
87
|
+
plugin?.notifyAdFailureListeners(Events.rewardedShowFail, adId: id, error: error)
|
|
95
88
|
}
|
|
96
89
|
|
|
97
90
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
98
|
-
plugin?.
|
|
91
|
+
plugin?.notifyAdListeners(Events.rewardedShow, adId: id)
|
|
99
92
|
}
|
|
100
93
|
|
|
101
94
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
102
|
-
plugin?.
|
|
95
|
+
plugin?.notifyAdListeners(Events.rewardedDismiss, adId: id)
|
|
103
96
|
rewardedAd = nil
|
|
104
97
|
}
|
|
105
98
|
}
|
|
@@ -29,10 +29,7 @@ class RewardedInterstitialAd: NSObject, Ad {
|
|
|
29
29
|
guard let self = self else { return }
|
|
30
30
|
|
|
31
31
|
if let error = error {
|
|
32
|
-
self.plugin?.
|
|
33
|
-
"id": self.id,
|
|
34
|
-
"error": error.localizedDescription
|
|
35
|
-
])
|
|
32
|
+
self.plugin?.notifyAdFailureListeners(Events.rewardedInterstitialLoadFail, adId: self.id, error: error)
|
|
36
33
|
completion(error)
|
|
37
34
|
return
|
|
38
35
|
}
|
|
@@ -41,7 +38,7 @@ class RewardedInterstitialAd: NSObject, Ad {
|
|
|
41
38
|
self.rewardedInterstitialAd?.serverSideVerificationOptions = self.serverSideVerificationOptions
|
|
42
39
|
self.rewardedInterstitialAd?.fullScreenContentDelegate = self
|
|
43
40
|
|
|
44
|
-
self.plugin?.
|
|
41
|
+
self.plugin?.notifyAdListeners(Events.rewardedInterstitialLoad, adId: self.id)
|
|
45
42
|
completion(nil)
|
|
46
43
|
}
|
|
47
44
|
}
|
|
@@ -61,13 +58,12 @@ class RewardedInterstitialAd: NSObject, Ad {
|
|
|
61
58
|
rewardedInterstitialAd.present(from: viewController) { [weak self] in
|
|
62
59
|
guard let self = self else { return }
|
|
63
60
|
let reward = rewardedInterstitialAd.adReward
|
|
64
|
-
self.plugin?.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
])
|
|
61
|
+
self.plugin?.notifyAdRewardListeners(
|
|
62
|
+
Events.rewardedInterstitialReward,
|
|
63
|
+
adId: self.id,
|
|
64
|
+
amount: reward.amount.intValue,
|
|
65
|
+
type: reward.type
|
|
66
|
+
)
|
|
71
67
|
}
|
|
72
68
|
completion(nil)
|
|
73
69
|
}
|
|
@@ -80,26 +76,23 @@ class RewardedInterstitialAd: NSObject, Ad {
|
|
|
80
76
|
|
|
81
77
|
extension RewardedInterstitialAd: FullScreenContentDelegate {
|
|
82
78
|
func adDidRecordImpression(_ ad: FullScreenPresentingAd) {
|
|
83
|
-
plugin?.
|
|
79
|
+
plugin?.notifyAdListeners(Events.rewardedInterstitialImpression, adId: id)
|
|
84
80
|
}
|
|
85
81
|
|
|
86
82
|
func adDidRecordClick(_ ad: FullScreenPresentingAd) {
|
|
87
|
-
plugin?.
|
|
83
|
+
plugin?.notifyAdListeners(Events.adClick, adId: id)
|
|
88
84
|
}
|
|
89
85
|
|
|
90
86
|
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
|
91
|
-
plugin?.
|
|
92
|
-
"id": id,
|
|
93
|
-
"error": error.localizedDescription
|
|
94
|
-
])
|
|
87
|
+
plugin?.notifyAdFailureListeners(Events.rewardedInterstitialShowFail, adId: id, error: error)
|
|
95
88
|
}
|
|
96
89
|
|
|
97
90
|
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
98
|
-
plugin?.
|
|
91
|
+
plugin?.notifyAdListeners(Events.rewardedInterstitialShow, adId: id)
|
|
99
92
|
}
|
|
100
93
|
|
|
101
94
|
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
|
102
|
-
plugin?.
|
|
95
|
+
plugin?.notifyAdListeners(Events.rewardedInterstitialDismiss, adId: id)
|
|
103
96
|
rewardedInterstitialAd = nil
|
|
104
97
|
}
|
|
105
98
|
}
|