@ezoic/react-native-sdk 1.1.0 → 1.2.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.
@@ -20,6 +20,6 @@ Pod::Spec.new do |s|
20
20
 
21
21
  # Native Ezoic Ads SDK (vends the `EzoicAdsSDKBinary` module). Brings in
22
22
  # PrebidMobile + Google-Mobile-Ads-SDK transitively.
23
- s.dependency "EzoicAdsSDK", "~> 1.1"
23
+ s.dependency "EzoicAdsSDK", "~> 1.2"
24
24
  s.swift_version = "5.9"
25
25
  end
@@ -68,5 +68,5 @@ dependencies {
68
68
  // Native Ezoic Ads SDK (resolved from Maven Central). Brings in Google Mobile
69
69
  // Ads + Prebid transitively. Requires mavenCentral() + google() in the
70
70
  // consuming app's repositories (the RN template provides both).
71
- implementation "com.ezoic.sdk:ezoic-ads-sdk:1.1.0"
71
+ implementation "com.ezoic.sdk:ezoic-ads-sdk:1.2.0"
72
72
  }
@@ -7,6 +7,9 @@ import com.facebook.react.bridge.ReactApplicationContext
7
7
  import com.facebook.react.bridge.ReadableMap
8
8
  import com.facebook.react.bridge.WritableMap
9
9
  import com.facebook.react.modules.core.DeviceEventManagerModule
10
+ import com.ezoic.ads.sdk.adunits.EzoicInterstitialAd
11
+ import com.ezoic.ads.sdk.adunits.EzoicInterstitialAdListener
12
+ import com.ezoic.ads.sdk.adunits.EzoicInterstitialAdListenerAdapter
10
13
  import com.ezoic.ads.sdk.adunits.EzoicReward
11
14
  import com.ezoic.ads.sdk.adunits.EzoicRewardedAd
12
15
  import com.ezoic.ads.sdk.adunits.EzoicRewardedAdListener
@@ -32,6 +35,22 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
32
35
  @Volatile var reward: EzoicReward? = null
33
36
  }
34
37
 
38
+ /** Loaded interstitial ads awaiting `show`, keyed by ad unit id. */
39
+ private val interstitialAds = ConcurrentHashMap<Int, EzoicInterstitialAd>()
40
+
41
+ /** In-flight interstitial `show` calls, keyed by ad unit id. */
42
+ private val pendingInterstitialShows = ConcurrentHashMap<Int, InterstitialShow>()
43
+
44
+ private class InterstitialShow(val promise: Promise) {
45
+ @Volatile var settled = false
46
+ }
47
+
48
+ /** Ad unit ids with an in-flight rewarded `load`. */
49
+ private val loadingRewarded = ConcurrentHashMap.newKeySet<Int>()
50
+
51
+ /** Ad unit ids with an in-flight interstitial `load`. */
52
+ private val loadingInterstitial = ConcurrentHashMap.newKeySet<Int>()
53
+
35
54
  override fun initialize(config: ReadableMap, promise: Promise) {
36
55
  val domain = if (config.hasKey("domain")) config.getString("domain") else null
37
56
  if (domain.isNullOrEmpty()) {
@@ -79,7 +98,12 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
79
98
  promise.reject("EzoicAds", "Invalid adUnitIdentifier: $adUnitIdentifier")
80
99
  return
81
100
  }
101
+ if (rewardedAds.containsKey(id) || !loadingRewarded.add(id)) {
102
+ promise.reject("EzoicAds", "An ad is already loaded/loading for ad unit $adUnitIdentifier")
103
+ return
104
+ }
82
105
  EzoicRewardedAd.load(reactApplicationContext, id) { result ->
106
+ loadingRewarded.remove(id)
83
107
  result.onSuccess { ad ->
84
108
  ad.listener = makeListener(adUnitIdentifier)
85
109
  rewardedAds[id] = ad
@@ -97,6 +121,10 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
97
121
  promise.reject("EzoicAds", "Rewarded ad not loaded for $adUnitIdentifier")
98
122
  return
99
123
  }
124
+ if (pendingShows.containsKey(id)) {
125
+ promise.reject("EzoicAds", "A show is already in progress for ad unit $adUnitIdentifier")
126
+ return
127
+ }
100
128
  val activity = currentActivity
101
129
  if (activity == null) {
102
130
  promise.reject("EzoicAds", "No current Activity to present the rewarded ad")
@@ -138,6 +166,75 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
138
166
  }
139
167
  }
140
168
 
169
+ override fun loadInterstitialAd(adUnitIdentifier: String, promise: Promise) {
170
+ val id = adUnitIdentifier.toIntOrNull()
171
+ if (id == null) {
172
+ promise.reject("EzoicAds", "Invalid adUnitIdentifier: $adUnitIdentifier")
173
+ return
174
+ }
175
+ if (interstitialAds.containsKey(id) || !loadingInterstitial.add(id)) {
176
+ promise.reject("EzoicAds", "An ad is already loaded/loading for ad unit $adUnitIdentifier")
177
+ return
178
+ }
179
+ EzoicInterstitialAd.load(reactApplicationContext, id) { result ->
180
+ loadingInterstitial.remove(id)
181
+ result.onSuccess { ad ->
182
+ ad.listener = makeInterstitialListener(adUnitIdentifier)
183
+ interstitialAds[id] = ad
184
+ promise.resolve(null)
185
+ }.onFailure { e ->
186
+ promise.reject("EzoicAds", e.message ?: "Interstitial ad failed to load", e)
187
+ }
188
+ }
189
+ }
190
+
191
+ override fun showInterstitialAd(adUnitIdentifier: String, promise: Promise) {
192
+ val id = adUnitIdentifier.toIntOrNull()
193
+ val ad = if (id != null) interstitialAds[id] else null
194
+ if (id == null || ad == null) {
195
+ promise.reject("EzoicAds", "Interstitial ad not loaded for $adUnitIdentifier")
196
+ return
197
+ }
198
+ if (pendingInterstitialShows.containsKey(id)) {
199
+ promise.reject("EzoicAds", "A show is already in progress for ad unit $adUnitIdentifier")
200
+ return
201
+ }
202
+ val activity = currentActivity
203
+ if (activity == null) {
204
+ promise.reject("EzoicAds", "No current Activity to present the interstitial ad")
205
+ return
206
+ }
207
+
208
+ pendingInterstitialShows[id] = InterstitialShow(promise)
209
+
210
+ // Native show(activity) has no completion lambda, so replace the load-time
211
+ // listener with one that settles the promise on terminal events
212
+ // (dismiss = resolve, failed-to-show = reject).
213
+ ad.listener = makeInterstitialListener(
214
+ adUnitIdentifier,
215
+ onDismiss = {
216
+ interstitialAds.remove(id)
217
+ val pending = pendingInterstitialShows.remove(id)
218
+ if (pending != null && !pending.settled) {
219
+ pending.settled = true
220
+ pending.promise.resolve(null)
221
+ }
222
+ },
223
+ onFailedToShow = { message ->
224
+ interstitialAds.remove(id)
225
+ val pending = pendingInterstitialShows.remove(id)
226
+ if (pending != null && !pending.settled) {
227
+ pending.settled = true
228
+ pending.promise.reject("EzoicAds", message)
229
+ }
230
+ }
231
+ )
232
+
233
+ activity.runOnUiThread {
234
+ ad.show(activity)
235
+ }
236
+ }
237
+
141
238
  override fun addListener(eventName: String) {
142
239
  // No-op: required by the React Native NativeEventEmitter contract.
143
240
  }
@@ -158,6 +255,7 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
158
255
  override fun onRewardedAdFailedToShow(rewardedAd: EzoicRewardedAd, error: EzoicError) {
159
256
  emitRewardedEvent(adUnitIdentifier, "failedToShow") {
160
257
  putString("message", error.message)
258
+ putInt("code", error.code)
161
259
  }
162
260
  onFailedToShow?.invoke(error.message)
163
261
  }
@@ -197,11 +295,57 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
197
295
  .emit(REWARDED_EVENT, map)
198
296
  }
199
297
 
298
+ private fun makeInterstitialListener(
299
+ adUnitIdentifier: String,
300
+ onDismiss: (() -> Unit)? = null,
301
+ onFailedToShow: ((String) -> Unit)? = null
302
+ ): EzoicInterstitialAdListener = object : EzoicInterstitialAdListenerAdapter() {
303
+ override fun onInterstitialAdShown(interstitialAd: EzoicInterstitialAd) {
304
+ emitInterstitialEvent(adUnitIdentifier, "shown")
305
+ }
306
+
307
+ override fun onInterstitialAdFailedToShow(interstitialAd: EzoicInterstitialAd, error: EzoicError) {
308
+ emitInterstitialEvent(adUnitIdentifier, "failedToShow") {
309
+ putString("message", error.message)
310
+ putInt("code", error.code)
311
+ }
312
+ onFailedToShow?.invoke(error.message)
313
+ }
314
+
315
+ override fun onInterstitialAdImpression(interstitialAd: EzoicInterstitialAd) {
316
+ emitInterstitialEvent(adUnitIdentifier, "impression")
317
+ }
318
+
319
+ override fun onInterstitialAdClicked(interstitialAd: EzoicInterstitialAd) {
320
+ emitInterstitialEvent(adUnitIdentifier, "clicked")
321
+ }
322
+
323
+ override fun onInterstitialAdDismissed(interstitialAd: EzoicInterstitialAd) {
324
+ emitInterstitialEvent(adUnitIdentifier, "dismissed")
325
+ onDismiss?.invoke()
326
+ }
327
+ }
328
+
329
+ private fun emitInterstitialEvent(
330
+ adUnitIdentifier: String,
331
+ type: String,
332
+ extra: (WritableMap.() -> Unit)? = null
333
+ ) {
334
+ val map = Arguments.createMap()
335
+ map.putString("adUnitIdentifier", adUnitIdentifier)
336
+ map.putString("type", type)
337
+ extra?.invoke(map)
338
+ reactApplicationContext
339
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
340
+ .emit(INTERSTITIAL_EVENT, map)
341
+ }
342
+
200
343
  private fun ReadableMap.optBool(key: String, default: Boolean): Boolean =
201
344
  if (hasKey(key) && !isNull(key)) getBoolean(key) else default
202
345
 
203
346
  companion object {
204
347
  const val NAME = NativeEzoicAdsSpec.NAME
205
348
  private const val REWARDED_EVENT = "EzoicRewardedAdEvent"
349
+ private const val INTERSTITIAL_EVENT = "EzoicInterstitialAdEvent"
206
350
  }
207
351
  }
@@ -22,65 +22,118 @@ import EzoicAdsSDKBinary
22
22
  }
23
23
  }
24
24
 
25
+ /// Loaded interstitial ads awaiting `show`, keyed by ad unit id.
26
+ private var interstitialAds: [Int: EzoicInterstitialAd] = [:]
27
+
28
+ /// In-flight interstitial `show` calls, keyed by ad unit id.
29
+ private var pendingInterstitialShows: [Int: PendingInterstitialShow] = [:]
30
+
31
+ private final class PendingInterstitialShow {
32
+ let resolve: (Any?) -> Void
33
+ let reject: (String, String, NSError?) -> Void
34
+ init(resolve: @escaping (Any?) -> Void, reject: @escaping (String, String, NSError?) -> Void) {
35
+ self.resolve = resolve
36
+ self.reject = reject
37
+ }
38
+ }
39
+
40
+ /// Ad unit ids with an in-flight rewarded `load`.
41
+ private var loadingRewarded: Set<Int> = []
42
+
43
+ /// Ad unit ids with an in-flight interstitial `load`.
44
+ private var loadingInterstitial: Set<Int> = []
45
+
46
+ /// Runs `work` on the main thread. The ad/pending/loading dictionaries and
47
+ /// every native load/show call touch UIKit and this shared state, so they must
48
+ /// only run on main. Delegate callbacks already arrive on main.
49
+ private func onMain(_ work: @escaping () -> Void) {
50
+ if Thread.isMainThread {
51
+ work()
52
+ } else {
53
+ DispatchQueue.main.async(execute: work)
54
+ }
55
+ }
56
+
25
57
  @objc public func initialize(_ config: NSDictionary,
26
58
  resolve: @escaping (Any?) -> Void,
27
59
  reject: @escaping (String, String, NSError?) -> Void) {
28
- guard let domain = config["domain"] as? String, !domain.isEmpty else {
29
- reject("EzoicAds", "initialize requires a non-empty `domain`.", nil)
30
- return
31
- }
32
- let configuration = EzoicConfiguration(
33
- domain: domain,
34
- autoReadConsent: (config["autoReadConsent"] as? Bool) ?? true,
35
- subjectToCOPPA: (config["subjectToCOPPA"] as? Bool) ?? false,
36
- requestATTBeforeAds: (config["requestATTBeforeAds"] as? Bool) ?? true,
37
- debugEnabled: (config["debugEnabled"] as? Bool) ?? false,
38
- testMode: (config["testMode"] as? Bool) ?? false
39
- )
40
- EzoicAds.shared.initialize(with: configuration) { result in
41
- switch result {
42
- case .success:
43
- resolve(nil)
44
- case .failure(let error):
45
- reject("EzoicAds", error.localizedDescription, error as NSError)
60
+ onMain {
61
+ guard let domain = config["domain"] as? String, !domain.isEmpty else {
62
+ reject("EzoicAds", "initialize requires a non-empty `domain`.", nil)
63
+ return
64
+ }
65
+ let configuration = EzoicConfiguration(
66
+ domain: domain,
67
+ autoReadConsent: (config["autoReadConsent"] as? Bool) ?? true,
68
+ subjectToCOPPA: (config["subjectToCOPPA"] as? Bool) ?? false,
69
+ requestATTBeforeAds: (config["requestATTBeforeAds"] as? Bool) ?? true,
70
+ debugEnabled: (config["debugEnabled"] as? Bool) ?? false,
71
+ testMode: (config["testMode"] as? Bool) ?? false
72
+ )
73
+ EzoicAds.shared.initialize(with: configuration) { result in
74
+ switch result {
75
+ case .success:
76
+ resolve(nil)
77
+ case .failure(let error):
78
+ reject("EzoicAds", error.localizedDescription, error as NSError)
79
+ }
46
80
  }
47
81
  }
48
82
  }
49
83
 
50
84
  @objc public func setGDPRConsent(_ applies: Bool, consentString: String?) {
51
- EzoicAds.shared.setGDPRConsent(applies: applies, consentString: consentString)
85
+ onMain {
86
+ EzoicAds.shared.setGDPRConsent(applies: applies, consentString: consentString)
87
+ }
52
88
  }
53
89
 
54
90
  @objc public func setGPPConsent(_ gppString: String?, sectionIds: String?) {
55
- EzoicAds.shared.setGPPConsent(gppString: gppString, sectionIds: sectionIds)
91
+ onMain {
92
+ EzoicAds.shared.setGPPConsent(gppString: gppString, sectionIds: sectionIds)
93
+ }
56
94
  }
57
95
 
58
96
  @objc public func setSubjectToCOPPA(_ value: Bool) {
59
- EzoicAds.shared.setSubjectToCOPPA(value)
97
+ onMain {
98
+ EzoicAds.shared.setSubjectToCOPPA(value)
99
+ }
60
100
  }
61
101
 
62
102
  @objc public func trackPageview(_ resolve: @escaping (Any?) -> Void) {
63
- EzoicAds.shared.trackPageview { success in
64
- resolve(NSNumber(value: success))
103
+ onMain {
104
+ EzoicAds.shared.trackPageview { success in
105
+ resolve(NSNumber(value: success))
106
+ }
65
107
  }
66
108
  }
67
109
 
68
110
  @objc public func loadRewardedAd(_ adUnitIdentifier: String,
69
111
  resolve: @escaping (Any?) -> Void,
70
112
  reject: @escaping (String, String, NSError?) -> Void) {
71
- guard let id = Int(adUnitIdentifier) else {
72
- reject("EzoicAds", "Invalid adUnitIdentifier: \(adUnitIdentifier)", nil)
73
- return
74
- }
75
- EzoicRewardedAd.load(adUnitIdentifier: id) { [weak self] result in
113
+ onMain { [weak self] in
76
114
  guard let self = self else { return }
77
- switch result {
78
- case .success(let ad):
79
- ad.delegate = self
80
- self.rewardedAds[id] = ad
81
- resolve(nil)
82
- case .failure(let error):
83
- reject("EzoicAds", error.localizedDescription, error as NSError)
115
+ guard let id = Int(adUnitIdentifier) else {
116
+ reject("EzoicAds", "Invalid adUnitIdentifier: \(adUnitIdentifier)", nil)
117
+ return
118
+ }
119
+ if self.rewardedAds[id] != nil || self.loadingRewarded.contains(id) {
120
+ reject("EzoicAds", "An ad is already loaded/loading for ad unit \(adUnitIdentifier)", nil)
121
+ return
122
+ }
123
+ self.loadingRewarded.insert(id)
124
+ EzoicRewardedAd.load(adUnitIdentifier: id) { [weak self] result in
125
+ guard let self = self else { return }
126
+ self.onMain {
127
+ self.loadingRewarded.remove(id)
128
+ switch result {
129
+ case .success(let ad):
130
+ ad.delegate = self
131
+ self.rewardedAds[id] = ad
132
+ resolve(nil)
133
+ case .failure(let error):
134
+ reject("EzoicAds", error.localizedDescription, error as NSError)
135
+ }
136
+ }
84
137
  }
85
138
  }
86
139
  }
@@ -88,14 +141,21 @@ import EzoicAdsSDKBinary
88
141
  @objc public func showRewardedAd(_ adUnitIdentifier: String,
89
142
  resolve: @escaping (Any?) -> Void,
90
143
  reject: @escaping (String, String, NSError?) -> Void) {
91
- guard let id = Int(adUnitIdentifier), let ad = rewardedAds[id] else {
92
- reject("EzoicAds", "Rewarded ad not loaded for \(adUnitIdentifier)", nil)
93
- return
94
- }
95
- pendingShows[id] = PendingRewardShow(resolve: resolve, reject: reject)
96
- // Presenting from nil lets GMA use the application's top view controller.
97
- ad.show(from: nil) { [weak self] reward in
98
- self?.pendingShows[id]?.reward = reward
144
+ onMain { [weak self] in
145
+ guard let self = self else { return }
146
+ guard let id = Int(adUnitIdentifier), let ad = self.rewardedAds[id] else {
147
+ reject("EzoicAds", "Rewarded ad not loaded for \(adUnitIdentifier)", nil)
148
+ return
149
+ }
150
+ if self.pendingShows[id] != nil {
151
+ reject("EzoicAds", "A show is already in progress for ad unit \(adUnitIdentifier)", nil)
152
+ return
153
+ }
154
+ self.pendingShows[id] = PendingRewardShow(resolve: resolve, reject: reject)
155
+ // Presenting from nil lets GMA use the application's top view controller.
156
+ ad.show(from: nil) { [weak self] reward in
157
+ self?.onMain { self?.pendingShows[id]?.reward = reward }
158
+ }
99
159
  }
100
160
  }
101
161
 
@@ -107,6 +167,67 @@ import EzoicAdsSDKBinary
107
167
  for (key, value) in extra { body[key] = value }
108
168
  eventEmitter?("EzoicRewardedAdEvent", body)
109
169
  }
170
+
171
+ @objc public func loadInterstitialAd(_ adUnitIdentifier: String,
172
+ resolve: @escaping (Any?) -> Void,
173
+ reject: @escaping (String, String, NSError?) -> Void) {
174
+ onMain { [weak self] in
175
+ guard let self = self else { return }
176
+ guard let id = Int(adUnitIdentifier) else {
177
+ reject("EzoicAds", "Invalid adUnitIdentifier: \(adUnitIdentifier)", nil)
178
+ return
179
+ }
180
+ if self.interstitialAds[id] != nil || self.loadingInterstitial.contains(id) {
181
+ reject("EzoicAds", "An ad is already loaded/loading for ad unit \(adUnitIdentifier)", nil)
182
+ return
183
+ }
184
+ self.loadingInterstitial.insert(id)
185
+ EzoicInterstitialAd.load(adUnitIdentifier: id) { [weak self] result in
186
+ guard let self = self else { return }
187
+ self.onMain {
188
+ self.loadingInterstitial.remove(id)
189
+ switch result {
190
+ case .success(let ad):
191
+ ad.delegate = self
192
+ self.interstitialAds[id] = ad
193
+ resolve(nil)
194
+ case .failure(let error):
195
+ reject("EzoicAds", error.localizedDescription, error as NSError)
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ @objc public func showInterstitialAd(_ adUnitIdentifier: String,
203
+ resolve: @escaping (Any?) -> Void,
204
+ reject: @escaping (String, String, NSError?) -> Void) {
205
+ onMain { [weak self] in
206
+ guard let self = self else { return }
207
+ guard let id = Int(adUnitIdentifier), let ad = self.interstitialAds[id] else {
208
+ reject("EzoicAds", "Interstitial ad not loaded for \(adUnitIdentifier)", nil)
209
+ return
210
+ }
211
+ if self.pendingInterstitialShows[id] != nil {
212
+ reject("EzoicAds", "A show is already in progress for ad unit \(adUnitIdentifier)", nil)
213
+ return
214
+ }
215
+ self.pendingInterstitialShows[id] = PendingInterstitialShow(resolve: resolve, reject: reject)
216
+ // Native show(from:) has no completion handler, so the show promise is
217
+ // settled from the delegate (dismiss = resolve, failed-to-present = reject).
218
+ // Presenting from nil lets GMA use the application's top view controller.
219
+ ad.show(from: nil)
220
+ }
221
+ }
222
+
223
+ private func emitInterstitial(_ ad: EzoicInterstitialAd, _ type: String, _ extra: [String: Any] = [:]) {
224
+ var body: [String: Any] = [
225
+ "adUnitIdentifier": String(ad.adUnitIdentifier),
226
+ "type": type
227
+ ]
228
+ for (key, value) in extra { body[key] = value }
229
+ eventEmitter?("EzoicInterstitialAdEvent", body)
230
+ }
110
231
  }
111
232
 
112
233
  // MARK: - EzoicRewardedAdDelegate
@@ -118,7 +239,7 @@ extension EzoicAdsImpl: EzoicRewardedAdDelegate {
118
239
  }
119
240
 
120
241
  public func rewardedAd(_ rewardedAd: EzoicRewardedAd, didFailToPresentWithError error: EzoicError) {
121
- emit(rewardedAd, "failedToShow", ["message": error.localizedDescription])
242
+ emit(rewardedAd, "failedToShow", ["message": error.localizedDescription, "code": error.code])
122
243
  let id = rewardedAd.adUnitIdentifier
123
244
  rewardedAds.removeValue(forKey: id)
124
245
  if let pending = pendingShows.removeValue(forKey: id) {
@@ -154,3 +275,38 @@ extension EzoicAdsImpl: EzoicRewardedAdDelegate {
154
275
  }
155
276
  }
156
277
  }
278
+
279
+ // MARK: - EzoicInterstitialAdDelegate
280
+
281
+ extension EzoicAdsImpl: EzoicInterstitialAdDelegate {
282
+
283
+ public func interstitialAdDidPresent(_ interstitialAd: EzoicInterstitialAd) {
284
+ emitInterstitial(interstitialAd, "shown")
285
+ }
286
+
287
+ public func interstitialAd(_ interstitialAd: EzoicInterstitialAd, didFailToPresentWithError error: EzoicError) {
288
+ emitInterstitial(interstitialAd, "failedToShow", ["message": error.localizedDescription, "code": error.code])
289
+ let id = interstitialAd.adUnitIdentifier
290
+ interstitialAds.removeValue(forKey: id)
291
+ if let pending = pendingInterstitialShows.removeValue(forKey: id) {
292
+ pending.reject("EzoicAds", error.localizedDescription, error as NSError)
293
+ }
294
+ }
295
+
296
+ public func interstitialAdDidRecordImpression(_ interstitialAd: EzoicInterstitialAd) {
297
+ emitInterstitial(interstitialAd, "impression")
298
+ }
299
+
300
+ public func interstitialAdDidRecordClick(_ interstitialAd: EzoicInterstitialAd) {
301
+ emitInterstitial(interstitialAd, "clicked")
302
+ }
303
+
304
+ public func interstitialAdDidDismiss(_ interstitialAd: EzoicInterstitialAd) {
305
+ emitInterstitial(interstitialAd, "dismissed")
306
+ let id = interstitialAd.adUnitIdentifier
307
+ interstitialAds.removeValue(forKey: id)
308
+ if let pending = pendingInterstitialShows.removeValue(forKey: id) {
309
+ pending.resolve(nil)
310
+ }
311
+ }
312
+ }
@@ -2,6 +2,7 @@
2
2
  #import <EzoicReactNativeSdk/EzoicReactNativeSdk-Swift.h>
3
3
 
4
4
  static NSString *const kEzoicRewardedEvent = @"EzoicRewardedAdEvent";
5
+ static NSString *const kEzoicInterstitialEvent = @"EzoicInterstitialAdEvent";
5
6
 
6
7
  @implementation EzoicReactNativeSdk {
7
8
  EzoicAdsImpl *_impl;
@@ -30,7 +31,7 @@ static NSString *const kEzoicRewardedEvent = @"EzoicRewardedAdEvent";
30
31
  }
31
32
 
32
33
  - (NSArray<NSString *> *)supportedEvents {
33
- return @[ kEzoicRewardedEvent ];
34
+ return @[ kEzoicRewardedEvent, kEzoicInterstitialEvent ];
34
35
  }
35
36
 
36
37
  - (void)startObserving {
@@ -88,6 +89,22 @@ static NSString *const kEzoicRewardedEvent = @"EzoicRewardedAdEvent";
88
89
  reject:^(NSString *code, NSString *msg, NSError *_Nullable e) { reject(code, msg, e); }];
89
90
  }
90
91
 
92
+ - (void)loadInterstitialAd:(NSString *)adUnitIdentifier
93
+ resolve:(RCTPromiseResolveBlock)resolve
94
+ reject:(RCTPromiseRejectBlock)reject {
95
+ [_impl loadInterstitialAd:adUnitIdentifier
96
+ resolve:^(id _Nullable v) { resolve(v); }
97
+ reject:^(NSString *code, NSString *msg, NSError *_Nullable e) { reject(code, msg, e); }];
98
+ }
99
+
100
+ - (void)showInterstitialAd:(NSString *)adUnitIdentifier
101
+ resolve:(RCTPromiseResolveBlock)resolve
102
+ reject:(RCTPromiseRejectBlock)reject {
103
+ [_impl showInterstitialAd:adUnitIdentifier
104
+ resolve:^(id _Nullable v) { resolve(v); }
105
+ reject:^(NSString *code, NSString *msg, NSError *_Nullable e) { reject(code, msg, e); }];
106
+ }
107
+
91
108
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
92
109
  (const facebook::react::ObjCTurboModule::InitParams &)params {
93
110
  return std::make_shared<facebook::react::NativeEzoicAdsSpecJSI>(params);
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+
3
+ import { NativeEventEmitter } from 'react-native';
4
+ import NativeEzoicAds from "./NativeEzoicAds.js";
5
+ import { coerceAdUnitId } from "./helpers.js";
6
+
7
+ /** Lifecycle callbacks for an interstitial ad. All are optional. */
8
+
9
+ /** The single native event name carrying every interstitial lifecycle signal. */
10
+ const INTERSTITIAL_EVENT = 'EzoicInterstitialAdEvent';
11
+ // A single shared emitter is sufficient — events are routed to the right
12
+ // instance by adUnitIdentifier below.
13
+ const emitter = new NativeEventEmitter(NativeEzoicAds);
14
+
15
+ /**
16
+ * An interstitial ad. Use the static `load` to fetch an ad ahead of time, then
17
+ * call `show()` to present it full-screen at a natural transition point.
18
+ * Interstitials carry no reward.
19
+ *
20
+ * ```ts
21
+ * const ad = await EzoicInterstitialAd.load('12345');
22
+ * ad.setListeners({ onDismissed: () => console.log('closed') });
23
+ * await ad.show();
24
+ * ```
25
+ *
26
+ * Mirrors the native `EzoicInterstitialAd` load/show lifecycle on both
27
+ * platforms. Interstitial ads are single-use — load a new one for the next
28
+ * opportunity.
29
+ */
30
+ export class EzoicInterstitialAd {
31
+ /** The Ezoic ad unit identifier this ad was loaded for. */
32
+
33
+ listeners = {};
34
+ subscription = null;
35
+ constructor(adUnitIdentifier) {
36
+ this.adUnitIdentifier = adUnitIdentifier;
37
+ this.subscription = emitter.addListener(INTERSTITIAL_EVENT, raw => {
38
+ const event = raw;
39
+ if (event.adUnitIdentifier !== this.adUnitIdentifier) return;
40
+ this.handleEvent(event);
41
+ });
42
+ }
43
+
44
+ /**
45
+ * Loads an interstitial ad for the given Ezoic ad unit identifier. Resolves
46
+ * with a ready-to-show `EzoicInterstitialAd`, or rejects if no ad could be
47
+ * loaded.
48
+ */
49
+ static async load(adUnitIdentifier) {
50
+ const id = coerceAdUnitId(adUnitIdentifier);
51
+ const ad = new EzoicInterstitialAd(id);
52
+ try {
53
+ await NativeEzoicAds.loadInterstitialAd(id);
54
+ return ad;
55
+ } catch (error) {
56
+ ad.destroy();
57
+ throw error;
58
+ }
59
+ }
60
+
61
+ /** Registers lifecycle callbacks. Replaces any previously set listeners. */
62
+ setListeners(listeners) {
63
+ this.listeners = listeners;
64
+ }
65
+
66
+ /**
67
+ * Presents the interstitial ad full-screen. Resolves when the ad is
68
+ * dismissed. Rejects if the ad was not ready (load first) or failed to
69
+ * present.
70
+ */
71
+ async show() {
72
+ await NativeEzoicAds.showInterstitialAd(this.adUnitIdentifier);
73
+ }
74
+
75
+ /** Releases the event subscription. Safe to call multiple times. */
76
+ destroy() {
77
+ this.subscription?.remove();
78
+ this.subscription = null;
79
+ this.listeners = {};
80
+ }
81
+ handleEvent(event) {
82
+ switch (event.type) {
83
+ case 'shown':
84
+ this.listeners.onShown?.();
85
+ break;
86
+ case 'failedToShow':
87
+ this.listeners.onFailedToShow?.({
88
+ message: event.message ?? '',
89
+ code: event.code
90
+ });
91
+ // Failure to show is terminal — the native ad is single-use.
92
+ this.destroy();
93
+ break;
94
+ case 'impression':
95
+ this.listeners.onImpression?.();
96
+ break;
97
+ case 'clicked':
98
+ this.listeners.onClicked?.();
99
+ break;
100
+ case 'dismissed':
101
+ this.listeners.onDismissed?.();
102
+ // Dismissal is terminal — the native ad is single-use.
103
+ this.destroy();
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=EzoicInterstitialAd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NativeEventEmitter","NativeEzoicAds","coerceAdUnitId","INTERSTITIAL_EVENT","emitter","EzoicInterstitialAd","listeners","subscription","constructor","adUnitIdentifier","addListener","raw","event","handleEvent","load","id","ad","loadInterstitialAd","error","destroy","setListeners","show","showInterstitialAd","remove","type","onShown","onFailedToShow","message","code","onImpression","onClicked","onDismissed"],"sourceRoot":"../../src","sources":["EzoicInterstitialAd.ts"],"mappings":";;AAAA,SAASA,kBAAkB,QAAkC,cAAc;AAC3E,OAAOC,cAAc,MAAM,qBAAkB;AAC7C,SAASC,cAAc,QAAQ,cAAW;;AAE1C;;AASA;AACA,MAAMC,kBAAkB,GAAG,0BAA0B;AASrD;AACA;AACA,MAAMC,OAAO,GAAG,IAAIJ,kBAAkB,CAACC,cAAuB,CAAC;;AAE/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMI,mBAAmB,CAAC;EAC/B;;EAGQC,SAAS,GAAiC,CAAC,CAAC;EAC5CC,YAAY,GAA+B,IAAI;EAE/CC,WAAWA,CAACC,gBAAwB,EAAE;IAC5C,IAAI,CAACA,gBAAgB,GAAGA,gBAAgB;IACxC,IAAI,CAACF,YAAY,GAAGH,OAAO,CAACM,WAAW,CACrCP,kBAAkB,EACjBQ,GAAY,IAAK;MAChB,MAAMC,KAAK,GAAGD,GAA8B;MAC5C,IAAIC,KAAK,CAACH,gBAAgB,KAAK,IAAI,CAACA,gBAAgB,EAAE;MACtD,IAAI,CAACI,WAAW,CAACD,KAAK,CAAC;IACzB,CACF,CAAC;EACH;;EAEA;AACF;AACA;AACA;AACA;EACE,aAAaE,IAAIA,CAACL,gBAAwB,EAAgC;IACxE,MAAMM,EAAE,GAAGb,cAAc,CAACO,gBAAgB,CAAC;IAC3C,MAAMO,EAAE,GAAG,IAAIX,mBAAmB,CAACU,EAAE,CAAC;IACtC,IAAI;MACF,MAAMd,cAAc,CAACgB,kBAAkB,CAACF,EAAE,CAAC;MAC3C,OAAOC,EAAE;IACX,CAAC,CAAC,OAAOE,KAAK,EAAE;MACdF,EAAE,CAACG,OAAO,CAAC,CAAC;MACZ,MAAMD,KAAK;IACb;EACF;;EAEA;EACAE,YAAYA,CAACd,SAAuC,EAAQ;IAC1D,IAAI,CAACA,SAAS,GAAGA,SAAS;EAC5B;;EAEA;AACF;AACA;AACA;AACA;EACE,MAAMe,IAAIA,CAAA,EAAkB;IAC1B,MAAMpB,cAAc,CAACqB,kBAAkB,CAAC,IAAI,CAACb,gBAAgB,CAAC;EAChE;;EAEA;EACAU,OAAOA,CAAA,EAAS;IACd,IAAI,CAACZ,YAAY,EAAEgB,MAAM,CAAC,CAAC;IAC3B,IAAI,CAAChB,YAAY,GAAG,IAAI;IACxB,IAAI,CAACD,SAAS,GAAG,CAAC,CAAC;EACrB;EAEQO,WAAWA,CAACD,KAA8B,EAAQ;IACxD,QAAQA,KAAK,CAACY,IAAI;MAChB,KAAK,OAAO;QACV,IAAI,CAAClB,SAAS,CAACmB,OAAO,GAAG,CAAC;QAC1B;MACF,KAAK,cAAc;QACjB,IAAI,CAACnB,SAAS,CAACoB,cAAc,GAAG;UAC9BC,OAAO,EAAEf,KAAK,CAACe,OAAO,IAAI,EAAE;UAC5BC,IAAI,EAAEhB,KAAK,CAACgB;QACd,CAAC,CAAC;QACF;QACA,IAAI,CAACT,OAAO,CAAC,CAAC;QACd;MACF,KAAK,YAAY;QACf,IAAI,CAACb,SAAS,CAACuB,YAAY,GAAG,CAAC;QAC/B;MACF,KAAK,SAAS;QACZ,IAAI,CAACvB,SAAS,CAACwB,SAAS,GAAG,CAAC;QAC5B;MACF,KAAK,WAAW;QACd,IAAI,CAACxB,SAAS,CAACyB,WAAW,GAAG,CAAC;QAC9B;QACA,IAAI,CAACZ,OAAO,CAAC,CAAC;QACd;IACJ;EACF;AACF","ignoreList":[]}
@@ -86,8 +86,11 @@ export class EzoicRewardedAd {
86
86
  break;
87
87
  case 'failedToShow':
88
88
  this.listeners.onFailedToShow?.({
89
- message: event.message ?? ''
89
+ message: event.message ?? '',
90
+ code: event.code
90
91
  });
92
+ // Failure to show is terminal — the native ad is single-use.
93
+ this.destroy();
91
94
  break;
92
95
  case 'impression':
93
96
  this.listeners.onImpression?.();
@@ -1 +1 @@
1
- {"version":3,"names":["NativeEventEmitter","NativeEzoicAds","coerceAdUnitId","mapRewardResult","REWARDED_EVENT","emitter","EzoicRewardedAd","listeners","subscription","constructor","adUnitIdentifier","addListener","raw","event","handleEvent","load","id","ad","loadRewardedAd","error","destroy","setListeners","show","result","showRewardedAd","remove","type","onShown","onFailedToShow","message","onImpression","onClicked","onUserEarnedReward","rewardType","amount","rewardAmount","onDismissed"],"sourceRoot":"../../src","sources":["EzoicRewardedAd.ts"],"mappings":";;AAAA,SAASA,kBAAkB,QAAkC,cAAc;AAC3E,OAAOC,cAAc,MAAM,qBAAkB;AAC7C,SAASC,cAAc,EAAEC,eAAe,QAAQ,cAAW;;AAE3D;;AAMA;;AAUA;AACA,MAAMC,cAAc,GAAG,sBAAsB;AAgB7C;AACA;AACA,MAAMC,OAAO,GAAG,IAAIL,kBAAkB,CAACC,cAAuB,CAAC;;AAE/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMK,eAAe,CAAC;EAC3B;;EAGQC,SAAS,GAA6B,CAAC,CAAC;EACxCC,YAAY,GAA+B,IAAI;EAE/CC,WAAWA,CAACC,gBAAwB,EAAE;IAC5C,IAAI,CAACA,gBAAgB,GAAGA,gBAAgB;IACxC,IAAI,CAACF,YAAY,GAAGH,OAAO,CAACM,WAAW,CAACP,cAAc,EAAGQ,GAAY,IAAK;MACxE,MAAMC,KAAK,GAAGD,GAA0B;MACxC,IAAIC,KAAK,CAACH,gBAAgB,KAAK,IAAI,CAACA,gBAAgB,EAAE;MACtD,IAAI,CAACI,WAAW,CAACD,KAAK,CAAC;IACzB,CAAC,CAAC;EACJ;;EAEA;AACF;AACA;AACA;EACE,aAAaE,IAAIA,CAACL,gBAAwB,EAA4B;IACpE,MAAMM,EAAE,GAAGd,cAAc,CAACQ,gBAAgB,CAAC;IAC3C,MAAMO,EAAE,GAAG,IAAIX,eAAe,CAACU,EAAE,CAAC;IAClC,IAAI;MACF,MAAMf,cAAc,CAACiB,cAAc,CAACF,EAAE,CAAC;MACvC,OAAOC,EAAE;IACX,CAAC,CAAC,OAAOE,KAAK,EAAE;MACdF,EAAE,CAACG,OAAO,CAAC,CAAC;MACZ,MAAMD,KAAK;IACb;EACF;;EAEA;EACAE,YAAYA,CAACd,SAAmC,EAAQ;IACtD,IAAI,CAACA,SAAS,GAAGA,SAAS;EAC5B;;EAEA;AACF;AACA;AACA;AACA;EACE,MAAMe,IAAIA,CAAA,EAAgC;IACxC,MAAMC,MAAM,GAAG,MAAMtB,cAAc,CAACuB,cAAc,CAAC,IAAI,CAACd,gBAAgB,CAAC;IACzE,OAAOP,eAAe,CAACoB,MAAM,CAAC;EAChC;;EAEA;EACAH,OAAOA,CAAA,EAAS;IACd,IAAI,CAACZ,YAAY,EAAEiB,MAAM,CAAC,CAAC;IAC3B,IAAI,CAACjB,YAAY,GAAG,IAAI;IACxB,IAAI,CAACD,SAAS,GAAG,CAAC,CAAC;EACrB;EAEQO,WAAWA,CAACD,KAA0B,EAAQ;IACpD,QAAQA,KAAK,CAACa,IAAI;MAChB,KAAK,OAAO;QACV,IAAI,CAACnB,SAAS,CAACoB,OAAO,GAAG,CAAC;QAC1B;MACF,KAAK,cAAc;QACjB,IAAI,CAACpB,SAAS,CAACqB,cAAc,GAAG;UAAEC,OAAO,EAAEhB,KAAK,CAACgB,OAAO,IAAI;QAAG,CAAC,CAAC;QACjE;MACF,KAAK,YAAY;QACf,IAAI,CAACtB,SAAS,CAACuB,YAAY,GAAG,CAAC;QAC/B;MACF,KAAK,SAAS;QACZ,IAAI,CAACvB,SAAS,CAACwB,SAAS,GAAG,CAAC;QAC5B;MACF,KAAK,QAAQ;QACX,IAAI,CAACxB,SAAS,CAACyB,kBAAkB,GAAG;UAClCN,IAAI,EAAEb,KAAK,CAACoB,UAAU,IAAI,EAAE;UAC5BC,MAAM,EAAErB,KAAK,CAACsB,YAAY,IAAI;QAChC,CAAC,CAAC;QACF;MACF,KAAK,WAAW;QACd,IAAI,CAAC5B,SAAS,CAAC6B,WAAW,GAAG,CAAC;QAC9B;QACA,IAAI,CAAChB,OAAO,CAAC,CAAC;QACd;IACJ;EACF;AACF","ignoreList":[]}
1
+ {"version":3,"names":["NativeEventEmitter","NativeEzoicAds","coerceAdUnitId","mapRewardResult","REWARDED_EVENT","emitter","EzoicRewardedAd","listeners","subscription","constructor","adUnitIdentifier","addListener","raw","event","handleEvent","load","id","ad","loadRewardedAd","error","destroy","setListeners","show","result","showRewardedAd","remove","type","onShown","onFailedToShow","message","code","onImpression","onClicked","onUserEarnedReward","rewardType","amount","rewardAmount","onDismissed"],"sourceRoot":"../../src","sources":["EzoicRewardedAd.ts"],"mappings":";;AAAA,SAASA,kBAAkB,QAAkC,cAAc;AAC3E,OAAOC,cAAc,MAAM,qBAAkB;AAC7C,SAASC,cAAc,EAAEC,eAAe,QAAQ,cAAW;;AAE3D;;AAMA;;AAUA;AACA,MAAMC,cAAc,GAAG,sBAAsB;AAiB7C;AACA;AACA,MAAMC,OAAO,GAAG,IAAIL,kBAAkB,CAACC,cAAuB,CAAC;;AAE/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMK,eAAe,CAAC;EAC3B;;EAGQC,SAAS,GAA6B,CAAC,CAAC;EACxCC,YAAY,GAA+B,IAAI;EAE/CC,WAAWA,CAACC,gBAAwB,EAAE;IAC5C,IAAI,CAACA,gBAAgB,GAAGA,gBAAgB;IACxC,IAAI,CAACF,YAAY,GAAGH,OAAO,CAACM,WAAW,CAACP,cAAc,EAAGQ,GAAY,IAAK;MACxE,MAAMC,KAAK,GAAGD,GAA0B;MACxC,IAAIC,KAAK,CAACH,gBAAgB,KAAK,IAAI,CAACA,gBAAgB,EAAE;MACtD,IAAI,CAACI,WAAW,CAACD,KAAK,CAAC;IACzB,CAAC,CAAC;EACJ;;EAEA;AACF;AACA;AACA;EACE,aAAaE,IAAIA,CAACL,gBAAwB,EAA4B;IACpE,MAAMM,EAAE,GAAGd,cAAc,CAACQ,gBAAgB,CAAC;IAC3C,MAAMO,EAAE,GAAG,IAAIX,eAAe,CAACU,EAAE,CAAC;IAClC,IAAI;MACF,MAAMf,cAAc,CAACiB,cAAc,CAACF,EAAE,CAAC;MACvC,OAAOC,EAAE;IACX,CAAC,CAAC,OAAOE,KAAK,EAAE;MACdF,EAAE,CAACG,OAAO,CAAC,CAAC;MACZ,MAAMD,KAAK;IACb;EACF;;EAEA;EACAE,YAAYA,CAACd,SAAmC,EAAQ;IACtD,IAAI,CAACA,SAAS,GAAGA,SAAS;EAC5B;;EAEA;AACF;AACA;AACA;AACA;EACE,MAAMe,IAAIA,CAAA,EAAgC;IACxC,MAAMC,MAAM,GAAG,MAAMtB,cAAc,CAACuB,cAAc,CAAC,IAAI,CAACd,gBAAgB,CAAC;IACzE,OAAOP,eAAe,CAACoB,MAAM,CAAC;EAChC;;EAEA;EACAH,OAAOA,CAAA,EAAS;IACd,IAAI,CAACZ,YAAY,EAAEiB,MAAM,CAAC,CAAC;IAC3B,IAAI,CAACjB,YAAY,GAAG,IAAI;IACxB,IAAI,CAACD,SAAS,GAAG,CAAC,CAAC;EACrB;EAEQO,WAAWA,CAACD,KAA0B,EAAQ;IACpD,QAAQA,KAAK,CAACa,IAAI;MAChB,KAAK,OAAO;QACV,IAAI,CAACnB,SAAS,CAACoB,OAAO,GAAG,CAAC;QAC1B;MACF,KAAK,cAAc;QACjB,IAAI,CAACpB,SAAS,CAACqB,cAAc,GAAG;UAC9BC,OAAO,EAAEhB,KAAK,CAACgB,OAAO,IAAI,EAAE;UAC5BC,IAAI,EAAEjB,KAAK,CAACiB;QACd,CAAC,CAAC;QACF;QACA,IAAI,CAACV,OAAO,CAAC,CAAC;QACd;MACF,KAAK,YAAY;QACf,IAAI,CAACb,SAAS,CAACwB,YAAY,GAAG,CAAC;QAC/B;MACF,KAAK,SAAS;QACZ,IAAI,CAACxB,SAAS,CAACyB,SAAS,GAAG,CAAC;QAC5B;MACF,KAAK,QAAQ;QACX,IAAI,CAACzB,SAAS,CAAC0B,kBAAkB,GAAG;UAClCP,IAAI,EAAEb,KAAK,CAACqB,UAAU,IAAI,EAAE;UAC5BC,MAAM,EAAEtB,KAAK,CAACuB,YAAY,IAAI;QAChC,CAAC,CAAC;QACF;MACF,KAAK,WAAW;QACd,IAAI,CAAC7B,SAAS,CAAC8B,WAAW,GAAG,CAAC;QAC9B;QACA,IAAI,CAACjB,OAAO,CAAC,CAAC;QACd;IACJ;EACF;AACF","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeEzoicAds.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAWlD;AACA;AACA;AACA;AACA;AACA;;AAoBA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,qBAAqB,CAAC","ignoreList":[]}
1
+ {"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeEzoicAds.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;;AAWlD;AACA;AACA;AACA;AACA;AACA;;AAsBA,eAAeA,mBAAmB,CAACC,YAAY,CAAO,qBAAqB,CAAC","ignoreList":[]}
@@ -5,6 +5,7 @@ import EzoicBannerNative from './EzoicBannerViewNativeComponent';
5
5
  import { coerceAdUnitId, normalizeConfig, normalizeSize } from "./helpers.js";
6
6
  import { jsx as _jsx } from "react/jsx-runtime";
7
7
  export { EzoicRewardedAd } from "./EzoicRewardedAd.js";
8
+ export { EzoicInterstitialAd } from "./EzoicInterstitialAd.js";
8
9
  export const EzoicAds = {
9
10
  initialize(config) {
10
11
  return NativeEzoicAds.initialize(normalizeConfig(config));
@@ -1 +1 @@
1
- {"version":3,"names":["NativeEzoicAds","EzoicBannerNative","coerceAdUnitId","normalizeConfig","normalizeSize","jsx","_jsx","EzoicRewardedAd","EzoicAds","initialize","config","setGDPRConsent","applies","consentString","setGPPConsent","gppString","sectionIds","setSubjectToCOPPA","value","trackPageview","EzoicBannerView","props","adUnitIdentifier","size","onLoad","onError","onImpression","onClick","onOpen","onClose","rest","undefined","e","nativeEvent","onAdClick"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AACA,OAAOA,cAAc,MAA4B,qBAAkB;AACnE,OAAOC,iBAAiB,MAAM,kCAAkC;AAChE,SAASC,cAAc,EAAEC,eAAe,EAAEC,aAAa,QAAQ,cAAW;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAG3E,SACEC,eAAe,QAGV,sBAAmB;AAE1B,OAAO,MAAMC,QAAQ,GAAG;EACtBC,UAAUA,CAACC,MAAmB,EAAiB;IAC7C,OAAOV,cAAc,CAACS,UAAU,CAACN,eAAe,CAACO,MAAM,CAAC,CAAC;EAC3D,CAAC;EACDC,cAAcA,CAACC,OAAgB,EAAEC,aAAsB,EAAQ;IAC7Db,cAAc,CAACW,cAAc,CAACC,OAAO,EAAEC,aAAa,CAAC;EACvD,CAAC;EACDC,aAAaA,CAACC,SAAkB,EAAEC,UAAmB,EAAQ;IAC3DhB,cAAc,CAACc,aAAa,CAACC,SAAS,EAAEC,UAAU,CAAC;EACrD,CAAC;EACDC,iBAAiBA,CAACC,KAAc,EAAQ;IACtClB,cAAc,CAACiB,iBAAiB,CAACC,KAAK,CAAC;EACzC,CAAC;EACDC,aAAaA,CAAA,EAAqB;IAChC,OAAOnB,cAAc,CAACmB,aAAa,CAAC,CAAC;EACvC;AACF,CAAC;AAmBD,OAAO,SAASC,eAAeA,CAACC,KAA2B,EAAE;EAC3D,MAAM;IACJC,gBAAgB;IAChBC,IAAI;IACJC,MAAM;IACNC,OAAO;IACPC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGT,KAAK;EACT,oBACEf,IAAA,CAACL,iBAAiB;IAAA,GACZ6B,IAAI;IACRR,gBAAgB,EAAEpB,cAAc,CAACoB,gBAAgB,CAAE;IACnDC,IAAI,EAAEnB,aAAa,CAACmB,IAAI,CAAE;IAC1BC,MAAM,EAAEA,MAAM,GAAG,MAAMA,MAAM,CAAC,CAAC,GAAGO,SAAU;IAC5CN,OAAO,EAAEA,OAAO,GAAIO,CAAC,IAAKP,OAAO,CAACO,CAAC,CAACC,WAAW,CAAC,GAAGF,SAAU;IAC7DL,YAAY,EAAEA,YAAY,GAAG,MAAMA,YAAY,CAAC,CAAC,GAAGK,SAAU;IAC9DG,SAAS,EAAEP,OAAO,GAAG,MAAMA,OAAO,CAAC,CAAC,GAAGI,SAAU;IACjDH,MAAM,EAAEA,MAAM,GAAG,MAAMA,MAAM,CAAC,CAAC,GAAGG,SAAU;IAC5CF,OAAO,EAAEA,OAAO,GAAG,MAAMA,OAAO,CAAC,CAAC,GAAGE;EAAU,CAChD,CAAC;AAEN","ignoreList":[]}
1
+ {"version":3,"names":["NativeEzoicAds","EzoicBannerNative","coerceAdUnitId","normalizeConfig","normalizeSize","jsx","_jsx","EzoicRewardedAd","EzoicInterstitialAd","EzoicAds","initialize","config","setGDPRConsent","applies","consentString","setGPPConsent","gppString","sectionIds","setSubjectToCOPPA","value","trackPageview","EzoicBannerView","props","adUnitIdentifier","size","onLoad","onError","onImpression","onClick","onOpen","onClose","rest","undefined","e","nativeEvent","onAdClick"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AACA,OAAOA,cAAc,MAA4B,qBAAkB;AACnE,OAAOC,iBAAiB,MAAM,kCAAkC;AAChE,SAASC,cAAc,EAAEC,eAAe,EAAEC,aAAa,QAAQ,cAAW;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAG3E,SACEC,eAAe,QAGV,sBAAmB;AAC1B,SACEC,mBAAmB,QAEd,0BAAuB;AAE9B,OAAO,MAAMC,QAAQ,GAAG;EACtBC,UAAUA,CAACC,MAAmB,EAAiB;IAC7C,OAAOX,cAAc,CAACU,UAAU,CAACP,eAAe,CAACQ,MAAM,CAAC,CAAC;EAC3D,CAAC;EACDC,cAAcA,CAACC,OAAgB,EAAEC,aAAsB,EAAQ;IAC7Dd,cAAc,CAACY,cAAc,CAACC,OAAO,EAAEC,aAAa,CAAC;EACvD,CAAC;EACDC,aAAaA,CAACC,SAAkB,EAAEC,UAAmB,EAAQ;IAC3DjB,cAAc,CAACe,aAAa,CAACC,SAAS,EAAEC,UAAU,CAAC;EACrD,CAAC;EACDC,iBAAiBA,CAACC,KAAc,EAAQ;IACtCnB,cAAc,CAACkB,iBAAiB,CAACC,KAAK,CAAC;EACzC,CAAC;EACDC,aAAaA,CAAA,EAAqB;IAChC,OAAOpB,cAAc,CAACoB,aAAa,CAAC,CAAC;EACvC;AACF,CAAC;AAmBD,OAAO,SAASC,eAAeA,CAACC,KAA2B,EAAE;EAC3D,MAAM;IACJC,gBAAgB;IAChBC,IAAI;IACJC,MAAM;IACNC,OAAO;IACPC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGT,KAAK;EACT,oBACEhB,IAAA,CAACL,iBAAiB;IAAA,GACZ8B,IAAI;IACRR,gBAAgB,EAAErB,cAAc,CAACqB,gBAAgB,CAAE;IACnDC,IAAI,EAAEpB,aAAa,CAACoB,IAAI,CAAE;IAC1BC,MAAM,EAAEA,MAAM,GAAG,MAAMA,MAAM,CAAC,CAAC,GAAGO,SAAU;IAC5CN,OAAO,EAAEA,OAAO,GAAIO,CAAC,IAAKP,OAAO,CAACO,CAAC,CAACC,WAAW,CAAC,GAAGF,SAAU;IAC7DL,YAAY,EAAEA,YAAY,GAAG,MAAMA,YAAY,CAAC,CAAC,GAAGK,SAAU;IAC9DG,SAAS,EAAEP,OAAO,GAAG,MAAMA,OAAO,CAAC,CAAC,GAAGI,SAAU;IACjDH,MAAM,EAAEA,MAAM,GAAG,MAAMA,MAAM,CAAC,CAAC,GAAGG,SAAU;IAC5CF,OAAO,EAAEA,OAAO,GAAG,MAAMA,OAAO,CAAC,CAAC,GAAGE;EAAU,CAChD,CAAC;AAEN","ignoreList":[]}
@@ -0,0 +1,51 @@
1
+ /** Lifecycle callbacks for an interstitial ad. All are optional. */
2
+ export interface EzoicInterstitialAdListeners {
3
+ onShown?: () => void;
4
+ onFailedToShow?: (error: {
5
+ message: string;
6
+ code?: number;
7
+ }) => void;
8
+ onImpression?: () => void;
9
+ onClicked?: () => void;
10
+ onDismissed?: () => void;
11
+ }
12
+ /**
13
+ * An interstitial ad. Use the static `load` to fetch an ad ahead of time, then
14
+ * call `show()` to present it full-screen at a natural transition point.
15
+ * Interstitials carry no reward.
16
+ *
17
+ * ```ts
18
+ * const ad = await EzoicInterstitialAd.load('12345');
19
+ * ad.setListeners({ onDismissed: () => console.log('closed') });
20
+ * await ad.show();
21
+ * ```
22
+ *
23
+ * Mirrors the native `EzoicInterstitialAd` load/show lifecycle on both
24
+ * platforms. Interstitial ads are single-use — load a new one for the next
25
+ * opportunity.
26
+ */
27
+ export declare class EzoicInterstitialAd {
28
+ /** The Ezoic ad unit identifier this ad was loaded for. */
29
+ readonly adUnitIdentifier: string;
30
+ private listeners;
31
+ private subscription;
32
+ private constructor();
33
+ /**
34
+ * Loads an interstitial ad for the given Ezoic ad unit identifier. Resolves
35
+ * with a ready-to-show `EzoicInterstitialAd`, or rejects if no ad could be
36
+ * loaded.
37
+ */
38
+ static load(adUnitIdentifier: string): Promise<EzoicInterstitialAd>;
39
+ /** Registers lifecycle callbacks. Replaces any previously set listeners. */
40
+ setListeners(listeners: EzoicInterstitialAdListeners): void;
41
+ /**
42
+ * Presents the interstitial ad full-screen. Resolves when the ad is
43
+ * dismissed. Rejects if the ad was not ready (load first) or failed to
44
+ * present.
45
+ */
46
+ show(): Promise<void>;
47
+ /** Releases the event subscription. Safe to call multiple times. */
48
+ destroy(): void;
49
+ private handleEvent;
50
+ }
51
+ //# sourceMappingURL=EzoicInterstitialAd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EzoicInterstitialAd.d.ts","sourceRoot":"","sources":["../../../src/EzoicInterstitialAd.ts"],"names":[],"mappings":"AAIA,oEAAoE;AACpE,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B;AAgBD;;;;;;;;;;;;;;GAcG;AACH,qBAAa,mBAAmB;IAC9B,2DAA2D;IAC3D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,SAAS,CAAoC;IACrD,OAAO,CAAC,YAAY,CAAoC;IAExD,OAAO;IAYP;;;;OAIG;WACU,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAYzE,4EAA4E;IAC5E,YAAY,CAAC,SAAS,EAAE,4BAA4B,GAAG,IAAI;IAI3D;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,oEAAoE;IACpE,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,WAAW;CA0BpB"}
@@ -8,6 +8,7 @@ export interface EzoicRewardedAdListeners {
8
8
  onShown?: () => void;
9
9
  onFailedToShow?: (error: {
10
10
  message: string;
11
+ code?: number;
11
12
  }) => void;
12
13
  onImpression?: () => void;
13
14
  onClicked?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"EzoicRewardedAd.d.ts","sourceRoot":"","sources":["../../../src/EzoicRewardedAd.ts"],"names":[],"mappings":"AAIA,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,+DAA+D;AAC/D,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACtD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACpD;AAuBD;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAoC;IAExD,OAAO;IASP;;;OAGG;WACU,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAYrE,4EAA4E;IAC5E,YAAY,CAAC,SAAS,EAAE,wBAAwB,GAAG,IAAI;IAIvD;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAKzC,oEAAoE;IACpE,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,WAAW;CA2BpB"}
1
+ {"version":3,"file":"EzoicRewardedAd.d.ts","sourceRoot":"","sources":["../../../src/EzoicRewardedAd.ts"],"names":[],"mappings":"AAIA,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,+DAA+D;AAC/D,MAAM,WAAW,wBAAwB;IACvC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACrE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACpD;AAwBD;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAElC,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,YAAY,CAAoC;IAExD,OAAO;IASP;;;OAGG;WACU,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAYrE,4EAA4E;IAC5E,YAAY,CAAC,SAAS,EAAE,wBAAwB,GAAG,IAAI;IAIvD;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAKzC,oEAAoE;IACpE,OAAO,IAAI,IAAI;IAMf,OAAO,CAAC,WAAW;CAgCpB"}
@@ -26,6 +26,8 @@ export interface Spec extends TurboModule {
26
26
  trackPageview(): Promise<boolean>;
27
27
  loadRewardedAd(adUnitIdentifier: string): Promise<void>;
28
28
  showRewardedAd(adUnitIdentifier: string): Promise<EzoicRewardResult>;
29
+ loadInterstitialAd(adUnitIdentifier: string): Promise<void>;
30
+ showInterstitialAd(adUnitIdentifier: string): Promise<void>;
29
31
  addListener(eventName: string): void;
30
32
  removeListeners(count: number): void;
31
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NativeEzoicAds.d.ts","sourceRoot":"","sources":["../../../src/NativeEzoicAds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7D,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,cAAc,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAErE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;;AAED,wBAA6E"}
1
+ {"version":3,"file":"NativeEzoicAds.d.ts","sourceRoot":"","sources":["../../../src/NativeEzoicAds.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/D,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7D,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IACxC,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,cAAc,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,cAAc,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACrE,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,kBAAkB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5D,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;;AAED,wBAA6E"}
@@ -2,6 +2,7 @@ import type { StyleProp, ViewStyle } from 'react-native';
2
2
  import { type EzoicConfig } from './NativeEzoicAds.js';
3
3
  export type { EzoicConfig };
4
4
  export { EzoicRewardedAd, type EzoicReward, type EzoicRewardedAdListeners, } from './EzoicRewardedAd.js';
5
+ export { EzoicInterstitialAd, type EzoicInterstitialAdListeners, } from './EzoicInterstitialAd.js';
5
6
  export declare const EzoicAds: {
6
7
  initialize(config: EzoicConfig): Promise<void>;
7
8
  setGDPRConsent(applies: boolean, consentString?: string): void;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAuB,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAkB,CAAC;AAIpE,YAAY,EAAE,WAAW,EAAE,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAC9B,MAAM,sBAAmB,CAAC;AAE3B,eAAO,MAAM,QAAQ;uBACA,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;4BAGtB,OAAO,kBAAkB,MAAM,GAAG,IAAI;8BAGpC,MAAM,eAAe,MAAM,GAAG,IAAI;6BAGnC,OAAO,GAAG,IAAI;qBAGtB,OAAO,CAAC,OAAO,CAAC;CAGlC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,+BAyB1D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzD,OAAuB,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAkB,CAAC;AAIpE,YAAY,EAAE,WAAW,EAAE,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAC9B,MAAM,sBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,KAAK,4BAA4B,GAClC,MAAM,0BAAuB,CAAC;AAE/B,eAAO,MAAM,QAAQ;uBACA,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;4BAGtB,OAAO,kBAAkB,MAAM,GAAG,IAAI;8BAGpC,MAAM,eAAe,MAAM,GAAG,IAAI;6BAGnC,OAAO,GAAG,IAAI;qBAGtB,OAAO,CAAC,OAAO,CAAC;CAGlC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC5C,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,+BAyB1D"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ezoic/react-native-sdk",
3
- "version": "1.1.0",
4
- "description": "Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner and rewarded ads).",
3
+ "version": "1.2.0",
4
+ "description": "Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner, interstitial and rewarded ads).",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
7
7
  "exports": {
@@ -0,0 +1,126 @@
1
+ import { NativeEventEmitter, type EmitterSubscription } from 'react-native';
2
+ import NativeEzoicAds from './NativeEzoicAds';
3
+ import { coerceAdUnitId } from './helpers';
4
+
5
+ /** Lifecycle callbacks for an interstitial ad. All are optional. */
6
+ export interface EzoicInterstitialAdListeners {
7
+ onShown?: () => void;
8
+ onFailedToShow?: (error: { message: string; code?: number }) => void;
9
+ onImpression?: () => void;
10
+ onClicked?: () => void;
11
+ onDismissed?: () => void;
12
+ }
13
+
14
+ /** The single native event name carrying every interstitial lifecycle signal. */
15
+ const INTERSTITIAL_EVENT = 'EzoicInterstitialAdEvent';
16
+
17
+ interface InterstitialNativeEvent {
18
+ adUnitIdentifier: string;
19
+ type: 'shown' | 'failedToShow' | 'impression' | 'clicked' | 'dismissed';
20
+ message?: string;
21
+ code?: number;
22
+ }
23
+
24
+ // A single shared emitter is sufficient — events are routed to the right
25
+ // instance by adUnitIdentifier below.
26
+ const emitter = new NativeEventEmitter(NativeEzoicAds as never);
27
+
28
+ /**
29
+ * An interstitial ad. Use the static `load` to fetch an ad ahead of time, then
30
+ * call `show()` to present it full-screen at a natural transition point.
31
+ * Interstitials carry no reward.
32
+ *
33
+ * ```ts
34
+ * const ad = await EzoicInterstitialAd.load('12345');
35
+ * ad.setListeners({ onDismissed: () => console.log('closed') });
36
+ * await ad.show();
37
+ * ```
38
+ *
39
+ * Mirrors the native `EzoicInterstitialAd` load/show lifecycle on both
40
+ * platforms. Interstitial ads are single-use — load a new one for the next
41
+ * opportunity.
42
+ */
43
+ export class EzoicInterstitialAd {
44
+ /** The Ezoic ad unit identifier this ad was loaded for. */
45
+ readonly adUnitIdentifier: string;
46
+
47
+ private listeners: EzoicInterstitialAdListeners = {};
48
+ private subscription: EmitterSubscription | null = null;
49
+
50
+ private constructor(adUnitIdentifier: string) {
51
+ this.adUnitIdentifier = adUnitIdentifier;
52
+ this.subscription = emitter.addListener(
53
+ INTERSTITIAL_EVENT,
54
+ (raw: unknown) => {
55
+ const event = raw as InterstitialNativeEvent;
56
+ if (event.adUnitIdentifier !== this.adUnitIdentifier) return;
57
+ this.handleEvent(event);
58
+ }
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Loads an interstitial ad for the given Ezoic ad unit identifier. Resolves
64
+ * with a ready-to-show `EzoicInterstitialAd`, or rejects if no ad could be
65
+ * loaded.
66
+ */
67
+ static async load(adUnitIdentifier: string): Promise<EzoicInterstitialAd> {
68
+ const id = coerceAdUnitId(adUnitIdentifier);
69
+ const ad = new EzoicInterstitialAd(id);
70
+ try {
71
+ await NativeEzoicAds.loadInterstitialAd(id);
72
+ return ad;
73
+ } catch (error) {
74
+ ad.destroy();
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ /** Registers lifecycle callbacks. Replaces any previously set listeners. */
80
+ setListeners(listeners: EzoicInterstitialAdListeners): void {
81
+ this.listeners = listeners;
82
+ }
83
+
84
+ /**
85
+ * Presents the interstitial ad full-screen. Resolves when the ad is
86
+ * dismissed. Rejects if the ad was not ready (load first) or failed to
87
+ * present.
88
+ */
89
+ async show(): Promise<void> {
90
+ await NativeEzoicAds.showInterstitialAd(this.adUnitIdentifier);
91
+ }
92
+
93
+ /** Releases the event subscription. Safe to call multiple times. */
94
+ destroy(): void {
95
+ this.subscription?.remove();
96
+ this.subscription = null;
97
+ this.listeners = {};
98
+ }
99
+
100
+ private handleEvent(event: InterstitialNativeEvent): void {
101
+ switch (event.type) {
102
+ case 'shown':
103
+ this.listeners.onShown?.();
104
+ break;
105
+ case 'failedToShow':
106
+ this.listeners.onFailedToShow?.({
107
+ message: event.message ?? '',
108
+ code: event.code,
109
+ });
110
+ // Failure to show is terminal — the native ad is single-use.
111
+ this.destroy();
112
+ break;
113
+ case 'impression':
114
+ this.listeners.onImpression?.();
115
+ break;
116
+ case 'clicked':
117
+ this.listeners.onClicked?.();
118
+ break;
119
+ case 'dismissed':
120
+ this.listeners.onDismissed?.();
121
+ // Dismissal is terminal — the native ad is single-use.
122
+ this.destroy();
123
+ break;
124
+ }
125
+ }
126
+ }
@@ -11,7 +11,7 @@ export interface EzoicReward {
11
11
  /** Lifecycle callbacks for a rewarded ad. All are optional. */
12
12
  export interface EzoicRewardedAdListeners {
13
13
  onShown?: () => void;
14
- onFailedToShow?: (error: { message: string }) => void;
14
+ onFailedToShow?: (error: { message: string; code?: number }) => void;
15
15
  onImpression?: () => void;
16
16
  onClicked?: () => void;
17
17
  onDismissed?: () => void;
@@ -31,6 +31,7 @@ interface RewardedNativeEvent {
31
31
  | 'dismissed'
32
32
  | 'reward';
33
33
  message?: string;
34
+ code?: number;
34
35
  rewardType?: string;
35
36
  rewardAmount?: number;
36
37
  }
@@ -113,7 +114,12 @@ export class EzoicRewardedAd {
113
114
  this.listeners.onShown?.();
114
115
  break;
115
116
  case 'failedToShow':
116
- this.listeners.onFailedToShow?.({ message: event.message ?? '' });
117
+ this.listeners.onFailedToShow?.({
118
+ message: event.message ?? '',
119
+ code: event.code,
120
+ });
121
+ // Failure to show is terminal — the native ad is single-use.
122
+ this.destroy();
117
123
  break;
118
124
  case 'impression':
119
125
  this.listeners.onImpression?.();
@@ -30,7 +30,9 @@ export interface Spec extends TurboModule {
30
30
  trackPageview(): Promise<boolean>;
31
31
  loadRewardedAd(adUnitIdentifier: string): Promise<void>;
32
32
  showRewardedAd(adUnitIdentifier: string): Promise<EzoicRewardResult>;
33
- // Required by NativeEventEmitter for the rewarded ad lifecycle events.
33
+ loadInterstitialAd(adUnitIdentifier: string): Promise<void>;
34
+ showInterstitialAd(adUnitIdentifier: string): Promise<void>;
35
+ // Required by NativeEventEmitter for the ad lifecycle events.
34
36
  addListener(eventName: string): void;
35
37
  removeListeners(count: number): void;
36
38
  }
package/src/index.tsx CHANGED
@@ -9,6 +9,10 @@ export {
9
9
  type EzoicReward,
10
10
  type EzoicRewardedAdListeners,
11
11
  } from './EzoicRewardedAd';
12
+ export {
13
+ EzoicInterstitialAd,
14
+ type EzoicInterstitialAdListeners,
15
+ } from './EzoicInterstitialAd';
12
16
 
13
17
  export const EzoicAds = {
14
18
  initialize(config: EzoicConfig): Promise<void> {