@ezoic/react-native-sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EzoicReactNativeSdk.podspec +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/ezoic/reactnative/EzoicAdsModule.kt +145 -0
- package/ios/EzoicAdsImpl.swift +108 -0
- package/ios/EzoicReactNativeSdk.h +4 -1
- package/ios/EzoicReactNativeSdk.mm +45 -0
- package/lib/module/EzoicRewardedAd.js +112 -0
- package/lib/module/EzoicRewardedAd.js.map +1 -0
- package/lib/module/NativeEzoicAds.js +8 -0
- package/lib/module/NativeEzoicAds.js.map +1 -1
- package/lib/module/helpers.js +13 -0
- package/lib/module/helpers.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/EzoicRewardedAd.d.ts +54 -0
- package/lib/typescript/src/EzoicRewardedAd.d.ts.map +1 -0
- package/lib/typescript/src/NativeEzoicAds.d.ts +15 -0
- package/lib/typescript/src/NativeEzoicAds.d.ts.map +1 -1
- package/lib/typescript/src/helpers.d.ts +13 -0
- package/lib/typescript/src/helpers.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/EzoicRewardedAd.ts +137 -0
- package/src/NativeEzoicAds.ts +17 -0
- package/src/helpers.ts +19 -0
- package/src/index.tsx +5 -0
|
@@ -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.
|
|
23
|
+
s.dependency "EzoicAdsSDK", "~> 1.1"
|
|
24
24
|
s.swift_version = "5.9"
|
|
25
25
|
end
|
package/android/build.gradle
CHANGED
|
@@ -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.
|
|
71
|
+
implementation "com.ezoic.sdk:ezoic-ads-sdk:1.1.0"
|
|
72
72
|
}
|
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
package com.ezoic.reactnative
|
|
2
2
|
|
|
3
3
|
import android.app.Application
|
|
4
|
+
import com.facebook.react.bridge.Arguments
|
|
4
5
|
import com.facebook.react.bridge.Promise
|
|
5
6
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
7
|
import com.facebook.react.bridge.ReadableMap
|
|
8
|
+
import com.facebook.react.bridge.WritableMap
|
|
9
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
10
|
+
import com.ezoic.ads.sdk.adunits.EzoicReward
|
|
11
|
+
import com.ezoic.ads.sdk.adunits.EzoicRewardedAd
|
|
12
|
+
import com.ezoic.ads.sdk.adunits.EzoicRewardedAdListener
|
|
13
|
+
import com.ezoic.ads.sdk.adunits.EzoicRewardedAdListenerAdapter
|
|
7
14
|
import com.ezoic.ads.sdk.core.EzoicAds
|
|
8
15
|
import com.ezoic.ads.sdk.core.EzoicConfiguration
|
|
16
|
+
import com.ezoic.ads.sdk.core.EzoicError
|
|
17
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
9
18
|
|
|
10
19
|
class EzoicAdsModule(reactContext: ReactApplicationContext) :
|
|
11
20
|
NativeEzoicAdsSpec(reactContext) {
|
|
12
21
|
|
|
13
22
|
override fun getName() = NAME
|
|
14
23
|
|
|
24
|
+
/** Loaded rewarded ads awaiting `show`, keyed by ad unit id. */
|
|
25
|
+
private val rewardedAds = ConcurrentHashMap<Int, EzoicRewardedAd>()
|
|
26
|
+
|
|
27
|
+
/** In-flight `show` calls, keyed by ad unit id. */
|
|
28
|
+
private val pendingShows = ConcurrentHashMap<Int, RewardShow>()
|
|
29
|
+
|
|
30
|
+
private class RewardShow(val promise: Promise) {
|
|
31
|
+
@Volatile var settled = false
|
|
32
|
+
@Volatile var reward: EzoicReward? = null
|
|
33
|
+
}
|
|
34
|
+
|
|
15
35
|
override fun initialize(config: ReadableMap, promise: Promise) {
|
|
16
36
|
val domain = if (config.hasKey("domain")) config.getString("domain") else null
|
|
17
37
|
if (domain.isNullOrEmpty()) {
|
|
@@ -53,10 +73,135 @@ class EzoicAdsModule(reactContext: ReactApplicationContext) :
|
|
|
53
73
|
EzoicAds.instance.trackPageview { success -> promise.resolve(success) }
|
|
54
74
|
}
|
|
55
75
|
|
|
76
|
+
override fun loadRewardedAd(adUnitIdentifier: String, promise: Promise) {
|
|
77
|
+
val id = adUnitIdentifier.toIntOrNull()
|
|
78
|
+
if (id == null) {
|
|
79
|
+
promise.reject("EzoicAds", "Invalid adUnitIdentifier: $adUnitIdentifier")
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
EzoicRewardedAd.load(reactApplicationContext, id) { result ->
|
|
83
|
+
result.onSuccess { ad ->
|
|
84
|
+
ad.listener = makeListener(adUnitIdentifier)
|
|
85
|
+
rewardedAds[id] = ad
|
|
86
|
+
promise.resolve(null)
|
|
87
|
+
}.onFailure { e ->
|
|
88
|
+
promise.reject("EzoicAds", e.message ?: "Rewarded ad failed to load", e)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
override fun showRewardedAd(adUnitIdentifier: String, promise: Promise) {
|
|
94
|
+
val id = adUnitIdentifier.toIntOrNull()
|
|
95
|
+
val ad = if (id != null) rewardedAds[id] else null
|
|
96
|
+
if (id == null || ad == null) {
|
|
97
|
+
promise.reject("EzoicAds", "Rewarded ad not loaded for $adUnitIdentifier")
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
val activity = currentActivity
|
|
101
|
+
if (activity == null) {
|
|
102
|
+
promise.reject("EzoicAds", "No current Activity to present the rewarded ad")
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
val show = RewardShow(promise)
|
|
107
|
+
pendingShows[id] = show
|
|
108
|
+
|
|
109
|
+
// Replace the load-time listener with one that also settles the promise on
|
|
110
|
+
// terminal events (dismiss = resolve, failed-to-show = reject).
|
|
111
|
+
ad.listener = makeListener(
|
|
112
|
+
adUnitIdentifier,
|
|
113
|
+
onDismiss = {
|
|
114
|
+
rewardedAds.remove(id)
|
|
115
|
+
val pending = pendingShows.remove(id)
|
|
116
|
+
if (pending != null && !pending.settled) {
|
|
117
|
+
pending.settled = true
|
|
118
|
+
val reward = pending.reward
|
|
119
|
+
val map = Arguments.createMap()
|
|
120
|
+
map.putBoolean("earned", reward != null)
|
|
121
|
+
map.putString("type", reward?.type ?: "")
|
|
122
|
+
map.putDouble("amount", (reward?.amount ?: 0).toDouble())
|
|
123
|
+
pending.promise.resolve(map)
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
onFailedToShow = { message ->
|
|
127
|
+
rewardedAds.remove(id)
|
|
128
|
+
val pending = pendingShows.remove(id)
|
|
129
|
+
if (pending != null && !pending.settled) {
|
|
130
|
+
pending.settled = true
|
|
131
|
+
pending.promise.reject("EzoicAds", message)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
activity.runOnUiThread {
|
|
137
|
+
ad.show(activity) { reward -> show.reward = reward }
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
override fun addListener(eventName: String) {
|
|
142
|
+
// No-op: required by the React Native NativeEventEmitter contract.
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override fun removeListeners(count: Double) {
|
|
146
|
+
// No-op: required by the React Native NativeEventEmitter contract.
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private fun makeListener(
|
|
150
|
+
adUnitIdentifier: String,
|
|
151
|
+
onDismiss: (() -> Unit)? = null,
|
|
152
|
+
onFailedToShow: ((String) -> Unit)? = null
|
|
153
|
+
): EzoicRewardedAdListener = object : EzoicRewardedAdListenerAdapter() {
|
|
154
|
+
override fun onRewardedAdShown(rewardedAd: EzoicRewardedAd) {
|
|
155
|
+
emitRewardedEvent(adUnitIdentifier, "shown")
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
override fun onRewardedAdFailedToShow(rewardedAd: EzoicRewardedAd, error: EzoicError) {
|
|
159
|
+
emitRewardedEvent(adUnitIdentifier, "failedToShow") {
|
|
160
|
+
putString("message", error.message)
|
|
161
|
+
}
|
|
162
|
+
onFailedToShow?.invoke(error.message)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
override fun onRewardedAdImpression(rewardedAd: EzoicRewardedAd) {
|
|
166
|
+
emitRewardedEvent(adUnitIdentifier, "impression")
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
override fun onRewardedAdClicked(rewardedAd: EzoicRewardedAd) {
|
|
170
|
+
emitRewardedEvent(adUnitIdentifier, "clicked")
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
override fun onUserEarnedReward(rewardedAd: EzoicRewardedAd, reward: EzoicReward) {
|
|
174
|
+
emitRewardedEvent(adUnitIdentifier, "reward") {
|
|
175
|
+
putString("rewardType", reward.type)
|
|
176
|
+
putDouble("rewardAmount", reward.amount.toDouble())
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
override fun onRewardedAdDismissed(rewardedAd: EzoicRewardedAd) {
|
|
181
|
+
emitRewardedEvent(adUnitIdentifier, "dismissed")
|
|
182
|
+
onDismiss?.invoke()
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private fun emitRewardedEvent(
|
|
187
|
+
adUnitIdentifier: String,
|
|
188
|
+
type: String,
|
|
189
|
+
extra: (WritableMap.() -> Unit)? = null
|
|
190
|
+
) {
|
|
191
|
+
val map = Arguments.createMap()
|
|
192
|
+
map.putString("adUnitIdentifier", adUnitIdentifier)
|
|
193
|
+
map.putString("type", type)
|
|
194
|
+
extra?.invoke(map)
|
|
195
|
+
reactApplicationContext
|
|
196
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
197
|
+
.emit(REWARDED_EVENT, map)
|
|
198
|
+
}
|
|
199
|
+
|
|
56
200
|
private fun ReadableMap.optBool(key: String, default: Boolean): Boolean =
|
|
57
201
|
if (hasKey(key) && !isNull(key)) getBoolean(key) else default
|
|
58
202
|
|
|
59
203
|
companion object {
|
|
60
204
|
const val NAME = NativeEzoicAdsSpec.NAME
|
|
205
|
+
private const val REWARDED_EVENT = "EzoicRewardedAdEvent"
|
|
61
206
|
}
|
|
62
207
|
}
|
package/ios/EzoicAdsImpl.swift
CHANGED
|
@@ -3,6 +3,25 @@ import EzoicAdsSDKBinary
|
|
|
3
3
|
|
|
4
4
|
@objc public class EzoicAdsImpl: NSObject {
|
|
5
5
|
|
|
6
|
+
/// Set by the Obj-C module to forward rewarded lifecycle events to JS.
|
|
7
|
+
@objc public var eventEmitter: ((String, [String: Any]) -> Void)?
|
|
8
|
+
|
|
9
|
+
/// Loaded rewarded ads awaiting `show`, keyed by ad unit id.
|
|
10
|
+
private var rewardedAds: [Int: EzoicRewardedAd] = [:]
|
|
11
|
+
|
|
12
|
+
/// In-flight `show` calls, keyed by ad unit id.
|
|
13
|
+
private var pendingShows: [Int: PendingRewardShow] = [:]
|
|
14
|
+
|
|
15
|
+
private final class PendingRewardShow {
|
|
16
|
+
let resolve: (Any?) -> Void
|
|
17
|
+
let reject: (String, String, NSError?) -> Void
|
|
18
|
+
var reward: EzoicReward?
|
|
19
|
+
init(resolve: @escaping (Any?) -> Void, reject: @escaping (String, String, NSError?) -> Void) {
|
|
20
|
+
self.resolve = resolve
|
|
21
|
+
self.reject = reject
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
6
25
|
@objc public func initialize(_ config: NSDictionary,
|
|
7
26
|
resolve: @escaping (Any?) -> Void,
|
|
8
27
|
reject: @escaping (String, String, NSError?) -> Void) {
|
|
@@ -45,4 +64,93 @@ import EzoicAdsSDKBinary
|
|
|
45
64
|
resolve(NSNumber(value: success))
|
|
46
65
|
}
|
|
47
66
|
}
|
|
67
|
+
|
|
68
|
+
@objc public func loadRewardedAd(_ adUnitIdentifier: String,
|
|
69
|
+
resolve: @escaping (Any?) -> Void,
|
|
70
|
+
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
|
|
76
|
+
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)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@objc public func showRewardedAd(_ adUnitIdentifier: String,
|
|
89
|
+
resolve: @escaping (Any?) -> Void,
|
|
90
|
+
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
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
private func emit(_ ad: EzoicRewardedAd, _ type: String, _ extra: [String: Any] = [:]) {
|
|
103
|
+
var body: [String: Any] = [
|
|
104
|
+
"adUnitIdentifier": String(ad.adUnitIdentifier),
|
|
105
|
+
"type": type
|
|
106
|
+
]
|
|
107
|
+
for (key, value) in extra { body[key] = value }
|
|
108
|
+
eventEmitter?("EzoicRewardedAdEvent", body)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// MARK: - EzoicRewardedAdDelegate
|
|
113
|
+
|
|
114
|
+
extension EzoicAdsImpl: EzoicRewardedAdDelegate {
|
|
115
|
+
|
|
116
|
+
public func rewardedAdDidPresent(_ rewardedAd: EzoicRewardedAd) {
|
|
117
|
+
emit(rewardedAd, "shown")
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public func rewardedAd(_ rewardedAd: EzoicRewardedAd, didFailToPresentWithError error: EzoicError) {
|
|
121
|
+
emit(rewardedAd, "failedToShow", ["message": error.localizedDescription])
|
|
122
|
+
let id = rewardedAd.adUnitIdentifier
|
|
123
|
+
rewardedAds.removeValue(forKey: id)
|
|
124
|
+
if let pending = pendingShows.removeValue(forKey: id) {
|
|
125
|
+
pending.reject("EzoicAds", error.localizedDescription, error as NSError)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
public func rewardedAdDidRecordImpression(_ rewardedAd: EzoicRewardedAd) {
|
|
130
|
+
emit(rewardedAd, "impression")
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public func rewardedAdDidRecordClick(_ rewardedAd: EzoicRewardedAd) {
|
|
134
|
+
emit(rewardedAd, "clicked")
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public func rewardedAd(_ rewardedAd: EzoicRewardedAd, userDidEarn reward: EzoicReward) {
|
|
138
|
+
emit(rewardedAd, "reward", ["rewardType": reward.type, "rewardAmount": reward.amount])
|
|
139
|
+
pendingShows[rewardedAd.adUnitIdentifier]?.reward = reward
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public func rewardedAdDidDismiss(_ rewardedAd: EzoicRewardedAd) {
|
|
143
|
+
emit(rewardedAd, "dismissed")
|
|
144
|
+
let id = rewardedAd.adUnitIdentifier
|
|
145
|
+
rewardedAds.removeValue(forKey: id)
|
|
146
|
+
if let pending = pendingShows.removeValue(forKey: id) {
|
|
147
|
+
let reward = pending.reward
|
|
148
|
+
let result: [String: Any] = [
|
|
149
|
+
"earned": reward != nil,
|
|
150
|
+
"type": reward?.type ?? "",
|
|
151
|
+
"amount": reward?.amount ?? 0
|
|
152
|
+
]
|
|
153
|
+
pending.resolve(result)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
48
156
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#import <EzoicReactNativeSdkSpec/EzoicReactNativeSdkSpec.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// Subclasses RCTEventEmitter so the rewarded ad lifecycle can be surfaced to
|
|
5
|
+
// JS via NativeEventEmitter, while still vending the codegen'd TurboModule.
|
|
6
|
+
@interface EzoicReactNativeSdk : RCTEventEmitter <NativeEzoicAdsSpec>
|
|
4
7
|
|
|
5
8
|
@end
|
|
@@ -1,17 +1,46 @@
|
|
|
1
1
|
#import "EzoicReactNativeSdk.h"
|
|
2
2
|
#import <EzoicReactNativeSdk/EzoicReactNativeSdk-Swift.h>
|
|
3
3
|
|
|
4
|
+
static NSString *const kEzoicRewardedEvent = @"EzoicRewardedAdEvent";
|
|
5
|
+
|
|
4
6
|
@implementation EzoicReactNativeSdk {
|
|
5
7
|
EzoicAdsImpl *_impl;
|
|
8
|
+
BOOL _hasListeners;
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
- (instancetype)init {
|
|
9
12
|
if (self = [super init]) {
|
|
10
13
|
_impl = [EzoicAdsImpl new];
|
|
14
|
+
__weak __typeof(self) weakSelf = self;
|
|
15
|
+
// The Swift impl invokes this for every rewarded lifecycle signal; forward
|
|
16
|
+
// to JS through RCTEventEmitter (guarded by an active-listener check so we
|
|
17
|
+
// don't log the "no listeners" warning when nothing is subscribed).
|
|
18
|
+
_impl.eventEmitter = ^(NSString *name, NSDictionary *body) {
|
|
19
|
+
__typeof(self) strongSelf = weakSelf;
|
|
20
|
+
if (strongSelf != nil && strongSelf->_hasListeners) {
|
|
21
|
+
[strongSelf sendEventWithName:name body:body];
|
|
22
|
+
}
|
|
23
|
+
};
|
|
11
24
|
}
|
|
12
25
|
return self;
|
|
13
26
|
}
|
|
14
27
|
|
|
28
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
29
|
+
return NO;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (NSArray<NSString *> *)supportedEvents {
|
|
33
|
+
return @[ kEzoicRewardedEvent ];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
- (void)startObserving {
|
|
37
|
+
_hasListeners = YES;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
- (void)stopObserving {
|
|
41
|
+
_hasListeners = NO;
|
|
42
|
+
}
|
|
43
|
+
|
|
15
44
|
- (void)initialize:(JS::NativeEzoicAds::EzoicConfig &)config
|
|
16
45
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
17
46
|
reject:(RCTPromiseRejectBlock)reject {
|
|
@@ -43,6 +72,22 @@
|
|
|
43
72
|
[_impl trackPageview:^(id _Nullable v) { resolve(v); }];
|
|
44
73
|
}
|
|
45
74
|
|
|
75
|
+
- (void)loadRewardedAd:(NSString *)adUnitIdentifier
|
|
76
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
77
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
78
|
+
[_impl loadRewardedAd:adUnitIdentifier
|
|
79
|
+
resolve:^(id _Nullable v) { resolve(v); }
|
|
80
|
+
reject:^(NSString *code, NSString *msg, NSError *_Nullable e) { reject(code, msg, e); }];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
- (void)showRewardedAd:(NSString *)adUnitIdentifier
|
|
84
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
85
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
86
|
+
[_impl showRewardedAd:adUnitIdentifier
|
|
87
|
+
resolve:^(id _Nullable v) { resolve(v); }
|
|
88
|
+
reject:^(NSString *code, NSString *msg, NSError *_Nullable e) { reject(code, msg, e); }];
|
|
89
|
+
}
|
|
90
|
+
|
|
46
91
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
47
92
|
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
48
93
|
return std::make_shared<facebook::react::NativeEzoicAdsSpecJSI>(params);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { NativeEventEmitter } from 'react-native';
|
|
4
|
+
import NativeEzoicAds from "./NativeEzoicAds.js";
|
|
5
|
+
import { coerceAdUnitId, mapRewardResult } from "./helpers.js";
|
|
6
|
+
|
|
7
|
+
/** A reward earned by the user for completing a rewarded ad. */
|
|
8
|
+
|
|
9
|
+
/** Lifecycle callbacks for a rewarded ad. All are optional. */
|
|
10
|
+
|
|
11
|
+
/** The single native event name carrying every rewarded lifecycle signal. */
|
|
12
|
+
const REWARDED_EVENT = 'EzoicRewardedAdEvent';
|
|
13
|
+
// A single shared emitter is sufficient — events are routed to the right
|
|
14
|
+
// instance by adUnitIdentifier below.
|
|
15
|
+
const emitter = new NativeEventEmitter(NativeEzoicAds);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A rewarded ad. Use the static `load` to fetch an ad ahead of time, then call
|
|
19
|
+
* `show()` to present it and grant the reward when the user finishes watching.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* const ad = await EzoicRewardedAd.load('12345');
|
|
23
|
+
* ad.setListeners({ onDismissed: () => console.log('closed') });
|
|
24
|
+
* const reward = await ad.show();
|
|
25
|
+
* if (reward) grantReward(reward.amount);
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Mirrors the native `EzoicRewardedAd` load/show lifecycle on both platforms.
|
|
29
|
+
* Rewarded ads are single-use — load a new one for the next opportunity.
|
|
30
|
+
*/
|
|
31
|
+
export class EzoicRewardedAd {
|
|
32
|
+
/** The Ezoic ad unit identifier this ad was loaded for. */
|
|
33
|
+
|
|
34
|
+
listeners = {};
|
|
35
|
+
subscription = null;
|
|
36
|
+
constructor(adUnitIdentifier) {
|
|
37
|
+
this.adUnitIdentifier = adUnitIdentifier;
|
|
38
|
+
this.subscription = emitter.addListener(REWARDED_EVENT, raw => {
|
|
39
|
+
const event = raw;
|
|
40
|
+
if (event.adUnitIdentifier !== this.adUnitIdentifier) return;
|
|
41
|
+
this.handleEvent(event);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Loads a rewarded ad for the given Ezoic ad unit identifier. Resolves with
|
|
47
|
+
* a ready-to-show `EzoicRewardedAd`, or rejects if no ad could be loaded.
|
|
48
|
+
*/
|
|
49
|
+
static async load(adUnitIdentifier) {
|
|
50
|
+
const id = coerceAdUnitId(adUnitIdentifier);
|
|
51
|
+
const ad = new EzoicRewardedAd(id);
|
|
52
|
+
try {
|
|
53
|
+
await NativeEzoicAds.loadRewardedAd(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 rewarded ad full-screen. Resolves with the earned reward, or
|
|
68
|
+
* `null` if the ad was dismissed before the reward was earned. Rejects if the
|
|
69
|
+
* ad was not ready (load first) or failed to present.
|
|
70
|
+
*/
|
|
71
|
+
async show() {
|
|
72
|
+
const result = await NativeEzoicAds.showRewardedAd(this.adUnitIdentifier);
|
|
73
|
+
return mapRewardResult(result);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Releases the event subscription. Safe to call multiple times. */
|
|
77
|
+
destroy() {
|
|
78
|
+
this.subscription?.remove();
|
|
79
|
+
this.subscription = null;
|
|
80
|
+
this.listeners = {};
|
|
81
|
+
}
|
|
82
|
+
handleEvent(event) {
|
|
83
|
+
switch (event.type) {
|
|
84
|
+
case 'shown':
|
|
85
|
+
this.listeners.onShown?.();
|
|
86
|
+
break;
|
|
87
|
+
case 'failedToShow':
|
|
88
|
+
this.listeners.onFailedToShow?.({
|
|
89
|
+
message: event.message ?? ''
|
|
90
|
+
});
|
|
91
|
+
break;
|
|
92
|
+
case 'impression':
|
|
93
|
+
this.listeners.onImpression?.();
|
|
94
|
+
break;
|
|
95
|
+
case 'clicked':
|
|
96
|
+
this.listeners.onClicked?.();
|
|
97
|
+
break;
|
|
98
|
+
case 'reward':
|
|
99
|
+
this.listeners.onUserEarnedReward?.({
|
|
100
|
+
type: event.rewardType ?? '',
|
|
101
|
+
amount: event.rewardAmount ?? 0
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
case 'dismissed':
|
|
105
|
+
this.listeners.onDismissed?.();
|
|
106
|
+
// Dismissal is terminal — the native ad is single-use.
|
|
107
|
+
this.destroy();
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=EzoicRewardedAd.js.map
|
|
@@ -0,0 +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,5 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { TurboModuleRegistry } from 'react-native';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Result of `showRewardedAd`. `earned` is true when the user completed the ad
|
|
7
|
+
* and earned the reward; `type`/`amount` describe the granted reward (empty/0
|
|
8
|
+
* when the ad was dismissed without earning). The public `EzoicRewardedAd.show`
|
|
9
|
+
* maps this to `EzoicReward | null`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
4
12
|
export default TurboModuleRegistry.getEnforcing('EzoicReactNativeSdk');
|
|
5
13
|
//# sourceMappingURL=NativeEzoicAds.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","getEnforcing"],"sourceRoot":"../../src","sources":["NativeEzoicAds.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;
|
|
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":[]}
|
package/lib/module/helpers.js
CHANGED
|
@@ -21,4 +21,17 @@ export function normalizeSize(size) {
|
|
|
21
21
|
export function coerceAdUnitId(adUnitIdentifier) {
|
|
22
22
|
return String(adUnitIdentifier);
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Maps the native `showRewardedAd` result to the public reward shape: the
|
|
26
|
+
* `{ type, amount }` reward when earned, otherwise `null` (dismissed unearned).
|
|
27
|
+
*/
|
|
28
|
+
export function mapRewardResult(result) {
|
|
29
|
+
if (result && result.earned) {
|
|
30
|
+
return {
|
|
31
|
+
type: result.type,
|
|
32
|
+
amount: result.amount
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
24
37
|
//# sourceMappingURL=helpers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["normalizeConfig","config","domain","Error","out","autoReadConsent","undefined","subjectToCOPPA","requestATTBeforeAds","debugEnabled","testMode","normalizeSize","size","split","map","s","trim","filter","length","join","coerceAdUnitId","adUnitIdentifier","String"],"sourceRoot":"../../src","sources":["helpers.ts"],"mappings":";;AAEA,OAAO,SAASA,eAAeA,CAACC,MAAmB,EAAe;EAChE,IAAI,CAACA,MAAM,IAAI,CAACA,MAAM,CAACC,MAAM,EAAE;IAC7B,MAAM,IAAIC,KAAK,CAAC,oDAAoD,CAAC;EACvE;EACA,MAAMC,GAAgB,GAAG;IAAEF,MAAM,EAAED,MAAM,CAACC;EAAO,CAAC;EAClD,IAAID,MAAM,CAACI,eAAe,KAAKC,SAAS,EACtCF,GAAG,CAACC,eAAe,GAAGJ,MAAM,CAACI,eAAe;EAC9C,IAAIJ,MAAM,CAACM,cAAc,KAAKD,SAAS,EACrCF,GAAG,CAACG,cAAc,GAAGN,MAAM,CAACM,cAAc;EAC5C,IAAIN,MAAM,CAACO,mBAAmB,KAAKF,SAAS,EAC1CF,GAAG,CAACI,mBAAmB,GAAGP,MAAM,CAACO,mBAAmB;EACtD,IAAIP,MAAM,CAACQ,YAAY,KAAKH,SAAS,EAAEF,GAAG,CAACK,YAAY,GAAGR,MAAM,CAACQ,YAAY;EAC7E,IAAIR,MAAM,CAACS,QAAQ,KAAKJ,SAAS,EAAEF,GAAG,CAACM,QAAQ,GAAGT,MAAM,CAACS,QAAQ;EACjE,OAAON,GAAG;AACZ;AAEA,OAAO,SAASO,aAAaA,CAACC,IAAwB,EAAU;EAC9D,IAAI,CAACA,IAAI,EAAE,OAAO,EAAE;EACpB,OAAOA,IAAI,CACRC,KAAK,CAAC,GAAG,CAAC,CACVC,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,CAAC,CAAC,CAAC,CACpBC,MAAM,CAAEF,CAAC,IAAKA,CAAC,CAACG,MAAM,GAAG,CAAC,CAAC,CAC3BC,IAAI,CAAC,GAAG,CAAC;AACd;AAEA,OAAO,SAASC,cAAcA,CAACC,gBAAwB,EAAU;EAC/D,OAAOC,MAAM,CAACD,gBAAgB,CAAC;AACjC","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["normalizeConfig","config","domain","Error","out","autoReadConsent","undefined","subjectToCOPPA","requestATTBeforeAds","debugEnabled","testMode","normalizeSize","size","split","map","s","trim","filter","length","join","coerceAdUnitId","adUnitIdentifier","String","mapRewardResult","result","earned","type","amount"],"sourceRoot":"../../src","sources":["helpers.ts"],"mappings":";;AAEA,OAAO,SAASA,eAAeA,CAACC,MAAmB,EAAe;EAChE,IAAI,CAACA,MAAM,IAAI,CAACA,MAAM,CAACC,MAAM,EAAE;IAC7B,MAAM,IAAIC,KAAK,CAAC,oDAAoD,CAAC;EACvE;EACA,MAAMC,GAAgB,GAAG;IAAEF,MAAM,EAAED,MAAM,CAACC;EAAO,CAAC;EAClD,IAAID,MAAM,CAACI,eAAe,KAAKC,SAAS,EACtCF,GAAG,CAACC,eAAe,GAAGJ,MAAM,CAACI,eAAe;EAC9C,IAAIJ,MAAM,CAACM,cAAc,KAAKD,SAAS,EACrCF,GAAG,CAACG,cAAc,GAAGN,MAAM,CAACM,cAAc;EAC5C,IAAIN,MAAM,CAACO,mBAAmB,KAAKF,SAAS,EAC1CF,GAAG,CAACI,mBAAmB,GAAGP,MAAM,CAACO,mBAAmB;EACtD,IAAIP,MAAM,CAACQ,YAAY,KAAKH,SAAS,EAAEF,GAAG,CAACK,YAAY,GAAGR,MAAM,CAACQ,YAAY;EAC7E,IAAIR,MAAM,CAACS,QAAQ,KAAKJ,SAAS,EAAEF,GAAG,CAACM,QAAQ,GAAGT,MAAM,CAACS,QAAQ;EACjE,OAAON,GAAG;AACZ;AAEA,OAAO,SAASO,aAAaA,CAACC,IAAwB,EAAU;EAC9D,IAAI,CAACA,IAAI,EAAE,OAAO,EAAE;EACpB,OAAOA,IAAI,CACRC,KAAK,CAAC,GAAG,CAAC,CACVC,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,IAAI,CAAC,CAAC,CAAC,CACpBC,MAAM,CAAEF,CAAC,IAAKA,CAAC,CAACG,MAAM,GAAG,CAAC,CAAC,CAC3BC,IAAI,CAAC,GAAG,CAAC;AACd;AAEA,OAAO,SAASC,cAAcA,CAACC,gBAAwB,EAAU;EAC/D,OAAOC,MAAM,CAACD,gBAAgB,CAAC;AACjC;AAQA;AACA;AACA;AACA;AACA,OAAO,SAASE,eAAeA,CAC7BC,MAA2C,EACF;EACzC,IAAIA,MAAM,IAAIA,MAAM,CAACC,MAAM,EAAE;IAC3B,OAAO;MAAEC,IAAI,EAAEF,MAAM,CAACE,IAAI;MAAEC,MAAM,EAAEH,MAAM,CAACG;IAAO,CAAC;EACrD;EACA,OAAO,IAAI;AACb","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import NativeEzoicAds from "./NativeEzoicAds.js";
|
|
|
4
4
|
import EzoicBannerNative from './EzoicBannerViewNativeComponent';
|
|
5
5
|
import { coerceAdUnitId, normalizeConfig, normalizeSize } from "./helpers.js";
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
|
+
export { EzoicRewardedAd } from "./EzoicRewardedAd.js";
|
|
7
8
|
export const EzoicAds = {
|
|
8
9
|
initialize(config) {
|
|
9
10
|
return NativeEzoicAds.initialize(normalizeConfig(config));
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEzoicAds","EzoicBannerNative","coerceAdUnitId","normalizeConfig","normalizeSize","jsx","_jsx","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;
|
|
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":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** A reward earned by the user for completing a rewarded ad. */
|
|
2
|
+
export interface EzoicReward {
|
|
3
|
+
type: string;
|
|
4
|
+
amount: number;
|
|
5
|
+
}
|
|
6
|
+
/** Lifecycle callbacks for a rewarded ad. All are optional. */
|
|
7
|
+
export interface EzoicRewardedAdListeners {
|
|
8
|
+
onShown?: () => void;
|
|
9
|
+
onFailedToShow?: (error: {
|
|
10
|
+
message: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
onImpression?: () => void;
|
|
13
|
+
onClicked?: () => void;
|
|
14
|
+
onDismissed?: () => void;
|
|
15
|
+
onUserEarnedReward?: (reward: EzoicReward) => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A rewarded ad. Use the static `load` to fetch an ad ahead of time, then call
|
|
19
|
+
* `show()` to present it and grant the reward when the user finishes watching.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* const ad = await EzoicRewardedAd.load('12345');
|
|
23
|
+
* ad.setListeners({ onDismissed: () => console.log('closed') });
|
|
24
|
+
* const reward = await ad.show();
|
|
25
|
+
* if (reward) grantReward(reward.amount);
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Mirrors the native `EzoicRewardedAd` load/show lifecycle on both platforms.
|
|
29
|
+
* Rewarded ads are single-use — load a new one for the next opportunity.
|
|
30
|
+
*/
|
|
31
|
+
export declare class EzoicRewardedAd {
|
|
32
|
+
/** The Ezoic ad unit identifier this ad was loaded for. */
|
|
33
|
+
readonly adUnitIdentifier: string;
|
|
34
|
+
private listeners;
|
|
35
|
+
private subscription;
|
|
36
|
+
private constructor();
|
|
37
|
+
/**
|
|
38
|
+
* Loads a rewarded ad for the given Ezoic ad unit identifier. Resolves with
|
|
39
|
+
* a ready-to-show `EzoicRewardedAd`, or rejects if no ad could be loaded.
|
|
40
|
+
*/
|
|
41
|
+
static load(adUnitIdentifier: string): Promise<EzoicRewardedAd>;
|
|
42
|
+
/** Registers lifecycle callbacks. Replaces any previously set listeners. */
|
|
43
|
+
setListeners(listeners: EzoicRewardedAdListeners): void;
|
|
44
|
+
/**
|
|
45
|
+
* Presents the rewarded ad full-screen. Resolves with the earned reward, or
|
|
46
|
+
* `null` if the ad was dismissed before the reward was earned. Rejects if the
|
|
47
|
+
* ad was not ready (load first) or failed to present.
|
|
48
|
+
*/
|
|
49
|
+
show(): Promise<EzoicReward | null>;
|
|
50
|
+
/** Releases the event subscription. Safe to call multiple times. */
|
|
51
|
+
destroy(): void;
|
|
52
|
+
private handleEvent;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=EzoicRewardedAd.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -7,12 +7,27 @@ export interface EzoicConfig {
|
|
|
7
7
|
debugEnabled?: boolean;
|
|
8
8
|
testMode?: boolean;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Result of `showRewardedAd`. `earned` is true when the user completed the ad
|
|
12
|
+
* and earned the reward; `type`/`amount` describe the granted reward (empty/0
|
|
13
|
+
* when the ad was dismissed without earning). The public `EzoicRewardedAd.show`
|
|
14
|
+
* maps this to `EzoicReward | null`.
|
|
15
|
+
*/
|
|
16
|
+
export interface EzoicRewardResult {
|
|
17
|
+
earned: boolean;
|
|
18
|
+
type: string;
|
|
19
|
+
amount: number;
|
|
20
|
+
}
|
|
10
21
|
export interface Spec extends TurboModule {
|
|
11
22
|
initialize(config: EzoicConfig): Promise<void>;
|
|
12
23
|
setGDPRConsent(applies: boolean, consentString?: string): void;
|
|
13
24
|
setGPPConsent(gppString?: string, sectionIds?: string): void;
|
|
14
25
|
setSubjectToCOPPA(value: boolean): void;
|
|
15
26
|
trackPageview(): Promise<boolean>;
|
|
27
|
+
loadRewardedAd(adUnitIdentifier: string): Promise<void>;
|
|
28
|
+
showRewardedAd(adUnitIdentifier: string): Promise<EzoicRewardResult>;
|
|
29
|
+
addListener(eventName: string): void;
|
|
30
|
+
removeListeners(count: number): void;
|
|
16
31
|
}
|
|
17
32
|
declare const _default: Spec;
|
|
18
33
|
export default _default;
|
|
@@ -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,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;
|
|
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"}
|
|
@@ -2,4 +2,17 @@ import type { EzoicConfig } from './NativeEzoicAds.js';
|
|
|
2
2
|
export declare function normalizeConfig(config: EzoicConfig): EzoicConfig;
|
|
3
3
|
export declare function normalizeSize(size: string | undefined): string;
|
|
4
4
|
export declare function coerceAdUnitId(adUnitIdentifier: string): string;
|
|
5
|
+
export interface RewardResultLike {
|
|
6
|
+
earned: boolean;
|
|
7
|
+
type: string;
|
|
8
|
+
amount: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Maps the native `showRewardedAd` result to the public reward shape: the
|
|
12
|
+
* `{ type, amount }` reward when earned, otherwise `null` (dismissed unearned).
|
|
13
|
+
*/
|
|
14
|
+
export declare function mapRewardResult(result: RewardResultLike | null | undefined): {
|
|
15
|
+
type: string;
|
|
16
|
+
amount: number;
|
|
17
|
+
} | null;
|
|
5
18
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAkB,CAAC;AAEpD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAchE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAO9D;AAED,wBAAgB,cAAc,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAE/D"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAkB,CAAC;AAEpD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAchE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAO9D;AAED,wBAAgB,cAAc,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,SAAS,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKzC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
2
|
import { type EzoicConfig } from './NativeEzoicAds.js';
|
|
3
3
|
export type { EzoicConfig };
|
|
4
|
+
export { EzoicRewardedAd, type EzoicReward, type EzoicRewardedAdListeners, } from './EzoicRewardedAd.js';
|
|
4
5
|
export declare const EzoicAds: {
|
|
5
6
|
initialize(config: EzoicConfig): Promise<void>;
|
|
6
7
|
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;
|
|
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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ezoic/react-native-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner ads).",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner 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,137 @@
|
|
|
1
|
+
import { NativeEventEmitter, type EmitterSubscription } from 'react-native';
|
|
2
|
+
import NativeEzoicAds from './NativeEzoicAds';
|
|
3
|
+
import { coerceAdUnitId, mapRewardResult } from './helpers';
|
|
4
|
+
|
|
5
|
+
/** A reward earned by the user for completing a rewarded ad. */
|
|
6
|
+
export interface EzoicReward {
|
|
7
|
+
type: string;
|
|
8
|
+
amount: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Lifecycle callbacks for a rewarded ad. All are optional. */
|
|
12
|
+
export interface EzoicRewardedAdListeners {
|
|
13
|
+
onShown?: () => void;
|
|
14
|
+
onFailedToShow?: (error: { message: string }) => void;
|
|
15
|
+
onImpression?: () => void;
|
|
16
|
+
onClicked?: () => void;
|
|
17
|
+
onDismissed?: () => void;
|
|
18
|
+
onUserEarnedReward?: (reward: EzoicReward) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** The single native event name carrying every rewarded lifecycle signal. */
|
|
22
|
+
const REWARDED_EVENT = 'EzoicRewardedAdEvent';
|
|
23
|
+
|
|
24
|
+
interface RewardedNativeEvent {
|
|
25
|
+
adUnitIdentifier: string;
|
|
26
|
+
type:
|
|
27
|
+
| 'shown'
|
|
28
|
+
| 'failedToShow'
|
|
29
|
+
| 'impression'
|
|
30
|
+
| 'clicked'
|
|
31
|
+
| 'dismissed'
|
|
32
|
+
| 'reward';
|
|
33
|
+
message?: string;
|
|
34
|
+
rewardType?: string;
|
|
35
|
+
rewardAmount?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// A single shared emitter is sufficient — events are routed to the right
|
|
39
|
+
// instance by adUnitIdentifier below.
|
|
40
|
+
const emitter = new NativeEventEmitter(NativeEzoicAds as never);
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A rewarded ad. Use the static `load` to fetch an ad ahead of time, then call
|
|
44
|
+
* `show()` to present it and grant the reward when the user finishes watching.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* const ad = await EzoicRewardedAd.load('12345');
|
|
48
|
+
* ad.setListeners({ onDismissed: () => console.log('closed') });
|
|
49
|
+
* const reward = await ad.show();
|
|
50
|
+
* if (reward) grantReward(reward.amount);
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* Mirrors the native `EzoicRewardedAd` load/show lifecycle on both platforms.
|
|
54
|
+
* Rewarded ads are single-use — load a new one for the next opportunity.
|
|
55
|
+
*/
|
|
56
|
+
export class EzoicRewardedAd {
|
|
57
|
+
/** The Ezoic ad unit identifier this ad was loaded for. */
|
|
58
|
+
readonly adUnitIdentifier: string;
|
|
59
|
+
|
|
60
|
+
private listeners: EzoicRewardedAdListeners = {};
|
|
61
|
+
private subscription: EmitterSubscription | null = null;
|
|
62
|
+
|
|
63
|
+
private constructor(adUnitIdentifier: string) {
|
|
64
|
+
this.adUnitIdentifier = adUnitIdentifier;
|
|
65
|
+
this.subscription = emitter.addListener(REWARDED_EVENT, (raw: unknown) => {
|
|
66
|
+
const event = raw as RewardedNativeEvent;
|
|
67
|
+
if (event.adUnitIdentifier !== this.adUnitIdentifier) return;
|
|
68
|
+
this.handleEvent(event);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Loads a rewarded ad for the given Ezoic ad unit identifier. Resolves with
|
|
74
|
+
* a ready-to-show `EzoicRewardedAd`, or rejects if no ad could be loaded.
|
|
75
|
+
*/
|
|
76
|
+
static async load(adUnitIdentifier: string): Promise<EzoicRewardedAd> {
|
|
77
|
+
const id = coerceAdUnitId(adUnitIdentifier);
|
|
78
|
+
const ad = new EzoicRewardedAd(id);
|
|
79
|
+
try {
|
|
80
|
+
await NativeEzoicAds.loadRewardedAd(id);
|
|
81
|
+
return ad;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
ad.destroy();
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Registers lifecycle callbacks. Replaces any previously set listeners. */
|
|
89
|
+
setListeners(listeners: EzoicRewardedAdListeners): void {
|
|
90
|
+
this.listeners = listeners;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Presents the rewarded ad full-screen. Resolves with the earned reward, or
|
|
95
|
+
* `null` if the ad was dismissed before the reward was earned. Rejects if the
|
|
96
|
+
* ad was not ready (load first) or failed to present.
|
|
97
|
+
*/
|
|
98
|
+
async show(): Promise<EzoicReward | null> {
|
|
99
|
+
const result = await NativeEzoicAds.showRewardedAd(this.adUnitIdentifier);
|
|
100
|
+
return mapRewardResult(result);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Releases the event subscription. Safe to call multiple times. */
|
|
104
|
+
destroy(): void {
|
|
105
|
+
this.subscription?.remove();
|
|
106
|
+
this.subscription = null;
|
|
107
|
+
this.listeners = {};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private handleEvent(event: RewardedNativeEvent): void {
|
|
111
|
+
switch (event.type) {
|
|
112
|
+
case 'shown':
|
|
113
|
+
this.listeners.onShown?.();
|
|
114
|
+
break;
|
|
115
|
+
case 'failedToShow':
|
|
116
|
+
this.listeners.onFailedToShow?.({ message: event.message ?? '' });
|
|
117
|
+
break;
|
|
118
|
+
case 'impression':
|
|
119
|
+
this.listeners.onImpression?.();
|
|
120
|
+
break;
|
|
121
|
+
case 'clicked':
|
|
122
|
+
this.listeners.onClicked?.();
|
|
123
|
+
break;
|
|
124
|
+
case 'reward':
|
|
125
|
+
this.listeners.onUserEarnedReward?.({
|
|
126
|
+
type: event.rewardType ?? '',
|
|
127
|
+
amount: event.rewardAmount ?? 0,
|
|
128
|
+
});
|
|
129
|
+
break;
|
|
130
|
+
case 'dismissed':
|
|
131
|
+
this.listeners.onDismissed?.();
|
|
132
|
+
// Dismissal is terminal — the native ad is single-use.
|
|
133
|
+
this.destroy();
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/NativeEzoicAds.ts
CHANGED
|
@@ -10,12 +10,29 @@ export interface EzoicConfig {
|
|
|
10
10
|
testMode?: boolean;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Result of `showRewardedAd`. `earned` is true when the user completed the ad
|
|
15
|
+
* and earned the reward; `type`/`amount` describe the granted reward (empty/0
|
|
16
|
+
* when the ad was dismissed without earning). The public `EzoicRewardedAd.show`
|
|
17
|
+
* maps this to `EzoicReward | null`.
|
|
18
|
+
*/
|
|
19
|
+
export interface EzoicRewardResult {
|
|
20
|
+
earned: boolean;
|
|
21
|
+
type: string;
|
|
22
|
+
amount: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
13
25
|
export interface Spec extends TurboModule {
|
|
14
26
|
initialize(config: EzoicConfig): Promise<void>;
|
|
15
27
|
setGDPRConsent(applies: boolean, consentString?: string): void;
|
|
16
28
|
setGPPConsent(gppString?: string, sectionIds?: string): void;
|
|
17
29
|
setSubjectToCOPPA(value: boolean): void;
|
|
18
30
|
trackPageview(): Promise<boolean>;
|
|
31
|
+
loadRewardedAd(adUnitIdentifier: string): Promise<void>;
|
|
32
|
+
showRewardedAd(adUnitIdentifier: string): Promise<EzoicRewardResult>;
|
|
33
|
+
// Required by NativeEventEmitter for the rewarded ad lifecycle events.
|
|
34
|
+
addListener(eventName: string): void;
|
|
35
|
+
removeListeners(count: number): void;
|
|
19
36
|
}
|
|
20
37
|
|
|
21
38
|
export default TurboModuleRegistry.getEnforcing<Spec>('EzoicReactNativeSdk');
|
package/src/helpers.ts
CHANGED
|
@@ -28,3 +28,22 @@ export function normalizeSize(size: string | undefined): string {
|
|
|
28
28
|
export function coerceAdUnitId(adUnitIdentifier: string): string {
|
|
29
29
|
return String(adUnitIdentifier);
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
export interface RewardResultLike {
|
|
33
|
+
earned: boolean;
|
|
34
|
+
type: string;
|
|
35
|
+
amount: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Maps the native `showRewardedAd` result to the public reward shape: the
|
|
40
|
+
* `{ type, amount }` reward when earned, otherwise `null` (dismissed unearned).
|
|
41
|
+
*/
|
|
42
|
+
export function mapRewardResult(
|
|
43
|
+
result: RewardResultLike | null | undefined
|
|
44
|
+
): { type: string; amount: number } | null {
|
|
45
|
+
if (result && result.earned) {
|
|
46
|
+
return { type: result.type, amount: result.amount };
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
package/src/index.tsx
CHANGED
|
@@ -4,6 +4,11 @@ import EzoicBannerNative from './EzoicBannerViewNativeComponent';
|
|
|
4
4
|
import { coerceAdUnitId, normalizeConfig, normalizeSize } from './helpers';
|
|
5
5
|
|
|
6
6
|
export type { EzoicConfig };
|
|
7
|
+
export {
|
|
8
|
+
EzoicRewardedAd,
|
|
9
|
+
type EzoicReward,
|
|
10
|
+
type EzoicRewardedAdListeners,
|
|
11
|
+
} from './EzoicRewardedAd';
|
|
7
12
|
|
|
8
13
|
export const EzoicAds = {
|
|
9
14
|
initialize(config: EzoicConfig): Promise<void> {
|