@ezoic/react-native-sdk 1.2.0 → 1.3.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 +4 -1
- package/README.md +26 -2
- package/android/build.gradle +7 -1
- package/android/src/main/java/com/ezoic/reactnative/EzoicNativeAdViewManager.kt +314 -0
- package/android/src/main/java/com/ezoic/reactnative/EzoicReactNativeSdkPackage.kt +4 -1
- package/ios/EzoicNativeAdHostView.swift +181 -0
- package/ios/EzoicNativeAdViewComponentView.mm +99 -0
- package/lib/module/EzoicNativeAdViewNativeComponent.ts +22 -0
- package/lib/module/helpers.js.map +1 -1
- package/lib/module/index.js +28 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/EzoicNativeAdViewNativeComponent.d.ts +18 -0
- package/lib/typescript/src/EzoicNativeAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/helpers.d.ts +1 -1
- package/lib/typescript/src/helpers.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +20 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/EzoicNativeAdViewNativeComponent.ts +22 -0
- package/src/helpers.ts +1 -1
- package/src/index.tsx +47 -0
|
@@ -20,6 +20,9 @@ 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.3"
|
|
24
|
+
# The native-ad host imports GoogleMobileAds directly (NativeAdView,
|
|
25
|
+
# MediaView, NativeAd). Pin GMA 12 so the module is on the compile path.
|
|
26
|
+
s.dependency "Google-Mobile-Ads-SDK", "~> 12.0"
|
|
24
27
|
s.swift_version = "5.9"
|
|
25
28
|
end
|
package/README.md
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# @ezoic/react-native-sdk
|
|
2
2
|
|
|
3
|
-
Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner ads).
|
|
3
|
+
Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner, native, interstitial and rewarded ads).
|
|
4
4
|
|
|
5
5
|
A thin React Native (New Architecture) wrapper over the native Ezoic Ads SDKs
|
|
6
6
|
for iOS (`EzoicAdsSDK`, via CocoaPods) and Android
|
|
7
7
|
(`com.ezoic.sdk:ezoic-ads-sdk`, via Maven Central). It exposes an imperative
|
|
8
|
-
`EzoicAds` TurboModule
|
|
8
|
+
`EzoicAds` TurboModule plus `EzoicBannerView` and `EzoicNativeAdView` Fabric
|
|
9
|
+
components.
|
|
9
10
|
|
|
10
11
|
## Requirements
|
|
11
12
|
|
|
@@ -68,6 +69,28 @@ const tracked = await EzoicAds.trackPageview();
|
|
|
68
69
|
`adUnitIdentifier` is a string coerced to a native integer. `size` is a `"WxH"`
|
|
69
70
|
string or comma-separated list (e.g. `"300x250"`, `"300x250,320x50"`).
|
|
70
71
|
|
|
72
|
+
### Native ads
|
|
73
|
+
|
|
74
|
+
`EzoicNativeAdView` loads a native ad and renders it in an SDK-built template
|
|
75
|
+
`NativeAdView` (headline, icon, media, body and a call-to-action). Unlike the
|
|
76
|
+
banner it has no `size` prop — size it with `style` and the template lays its
|
|
77
|
+
assets out inside those bounds.
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
import { EzoicAds, EzoicNativeAdView } from '@ezoic/react-native-sdk';
|
|
81
|
+
|
|
82
|
+
<EzoicNativeAdView
|
|
83
|
+
adUnitIdentifier="123456"
|
|
84
|
+
style={{ width: '100%', height: 300 }}
|
|
85
|
+
onLoad={() => console.log('loaded')}
|
|
86
|
+
onError={(e) => console.log('error', e.message, e.code)}
|
|
87
|
+
onImpression={() => console.log('impression')}
|
|
88
|
+
onClick={() => console.log('click')}
|
|
89
|
+
onOpen={() => console.log('open')}
|
|
90
|
+
onClose={() => console.log('close')}
|
|
91
|
+
/>;
|
|
92
|
+
```
|
|
93
|
+
|
|
71
94
|
## API
|
|
72
95
|
|
|
73
96
|
- `EzoicAds.initialize(config)` → `Promise<void>`
|
|
@@ -76,6 +99,7 @@ string or comma-separated list (e.g. `"300x250"`, `"300x250,320x50"`).
|
|
|
76
99
|
- `EzoicAds.setSubjectToCOPPA(value)` → `void`
|
|
77
100
|
- `EzoicAds.trackPageview()` → `Promise<boolean>`
|
|
78
101
|
- `<EzoicBannerView adUnitIdentifier size onLoad onError onImpression onClick onOpen onClose />`
|
|
102
|
+
- `<EzoicNativeAdView adUnitIdentifier onLoad onError onImpression onClick onOpen onClose />`
|
|
79
103
|
|
|
80
104
|
## License
|
|
81
105
|
|
package/android/build.gradle
CHANGED
|
@@ -68,5 +68,11 @@ 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.3.0"
|
|
72
|
+
|
|
73
|
+
// The native-ad wrapper references GMA's NativeAdView/MediaView/NativeAd
|
|
74
|
+
// types at compile time. The Ezoic SDK POM scopes Google Mobile Ads at
|
|
75
|
+
// runtime only, so pin the compile-time classpath here (runtime resolution
|
|
76
|
+
// still comes transitively from the Ezoic SDK).
|
|
77
|
+
compileOnly "com.google.android.gms:play-services-ads:22.6.0"
|
|
72
78
|
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
package com.ezoic.reactnative
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.graphics.Typeface
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.view.ViewGroup
|
|
7
|
+
import android.widget.Button
|
|
8
|
+
import android.widget.FrameLayout
|
|
9
|
+
import android.widget.ImageView
|
|
10
|
+
import android.widget.LinearLayout
|
|
11
|
+
import android.widget.TextView
|
|
12
|
+
import com.facebook.react.bridge.Arguments
|
|
13
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
14
|
+
import com.facebook.react.bridge.WritableMap
|
|
15
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
16
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
17
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
18
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
19
|
+
import com.facebook.react.uimanager.events.RCTEventEmitter
|
|
20
|
+
import com.ezoic.ads.sdk.adunits.EzoicNativeAd
|
|
21
|
+
import com.ezoic.ads.sdk.adunits.EzoicNativeAdListener
|
|
22
|
+
import com.ezoic.ads.sdk.adunits.EzoicNativeAdLoadListener
|
|
23
|
+
import com.ezoic.ads.sdk.core.EzoicError
|
|
24
|
+
import com.google.android.gms.ads.nativead.MediaView
|
|
25
|
+
import com.google.android.gms.ads.nativead.NativeAd
|
|
26
|
+
import com.google.android.gms.ads.nativead.NativeAdView
|
|
27
|
+
|
|
28
|
+
@ReactModule(name = EzoicNativeAdViewManager.NAME)
|
|
29
|
+
class EzoicNativeAdViewManager(private val ctx: ReactApplicationContext) :
|
|
30
|
+
SimpleViewManager<EzoicNativeAdViewManager.NativeAdContainer>() {
|
|
31
|
+
|
|
32
|
+
override fun getName() = NAME
|
|
33
|
+
|
|
34
|
+
override fun createViewInstance(reactContext: ThemedReactContext): NativeAdContainer {
|
|
35
|
+
val container = NativeAdContainer(reactContext)
|
|
36
|
+
container.layoutParams = ViewGroup.LayoutParams(
|
|
37
|
+
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
|
|
38
|
+
)
|
|
39
|
+
return container
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@ReactProp(name = "adUnitIdentifier")
|
|
43
|
+
fun setAdUnitIdentifier(view: NativeAdContainer, value: String?) {
|
|
44
|
+
val newAdUnitId = value?.toIntOrNull() ?: 0
|
|
45
|
+
// Ad unit changed after a load already started: tear down the loaded/loading
|
|
46
|
+
// ad and clear the started flag so onAfterUpdateTransaction's maybeLoad
|
|
47
|
+
// starts a fresh load for the new id.
|
|
48
|
+
if (newAdUnitId != view.adUnitId && view.loadStarted) {
|
|
49
|
+
view.ezoicNativeAd?.destroy()
|
|
50
|
+
view.ezoicNativeAd = null
|
|
51
|
+
view.removeAllViews()
|
|
52
|
+
view.loadStarted = false
|
|
53
|
+
view.loadGeneration++
|
|
54
|
+
}
|
|
55
|
+
view.adUnitId = newAdUnitId
|
|
56
|
+
view.rawAdUnitId = value ?: ""
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Fabric sets every prop for the mount transaction before this runs, so the
|
|
60
|
+
// ad unit id is final here. `view.post` escapes the mount transaction so the
|
|
61
|
+
// synchronous native-SDK failure path (uninitialized) can't reenter the
|
|
62
|
+
// mounting layer; the started flag survives repeated transactions.
|
|
63
|
+
override fun onAfterUpdateTransaction(view: NativeAdContainer) {
|
|
64
|
+
super.onAfterUpdateTransaction(view)
|
|
65
|
+
view.post { maybeLoad(view) }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private fun maybeLoad(view: NativeAdContainer) {
|
|
69
|
+
if (view.loadStarted || view.disposed) return
|
|
70
|
+
if (view.adUnitId <= 0) {
|
|
71
|
+
// Non-numeric or missing id coerces to 0 in setAdUnitIdentifier. Only
|
|
72
|
+
// emit an error when a prop was actually supplied (non-empty raw
|
|
73
|
+
// string); an unset prop should stay silent.
|
|
74
|
+
if (view.rawAdUnitId.isNotEmpty()) {
|
|
75
|
+
view.loadStarted = true
|
|
76
|
+
emit(view, "topError", errorMap("Invalid ad unit identifier", 0))
|
|
77
|
+
}
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
view.loadStarted = true
|
|
81
|
+
val generation = view.loadGeneration
|
|
82
|
+
EzoicNativeAd.load(view.context, view.adUnitId, object : EzoicNativeAdLoadListener {
|
|
83
|
+
override fun onNativeAdLoaded(nativeAd: EzoicNativeAd) {
|
|
84
|
+
// dispose() and this callback both arrive on the main thread, so the
|
|
85
|
+
// check is race-free. A late-arriving ad is destroyed, not rendered.
|
|
86
|
+
// A generation mismatch means the ad unit changed mid-load (mirrors
|
|
87
|
+
// the SDK's isCurrentLoad token pattern): destroy and emit nothing.
|
|
88
|
+
if (view.disposed || view.loadGeneration != generation) {
|
|
89
|
+
nativeAd.destroy()
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
val gmaAd = nativeAd.nativeAd ?: run {
|
|
93
|
+
// Empty-content ad: destroy it instead of keeping an unrenderable,
|
|
94
|
+
// errored ad alive on the view.
|
|
95
|
+
nativeAd.destroy()
|
|
96
|
+
emit(view, "topError", errorMap("Native ad loaded without content", 0))
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
view.ezoicNativeAd = nativeAd
|
|
100
|
+
// Attach the lifecycle listener before the rendered NativeAdView
|
|
101
|
+
// registers — the impression fires as soon as the view is displayed.
|
|
102
|
+
nativeAd.listener = object : EzoicNativeAdListener {
|
|
103
|
+
override fun onNativeAdImpression(nativeAd: EzoicNativeAd) =
|
|
104
|
+
emit(view, "topImpression", Arguments.createMap())
|
|
105
|
+
override fun onNativeAdClicked(nativeAd: EzoicNativeAd) =
|
|
106
|
+
emit(view, "topAdClick", Arguments.createMap())
|
|
107
|
+
override fun onNativeAdOpened(nativeAd: EzoicNativeAd) =
|
|
108
|
+
emit(view, "topOpen", Arguments.createMap())
|
|
109
|
+
override fun onNativeAdClosed(nativeAd: EzoicNativeAd) =
|
|
110
|
+
emit(view, "topClose", Arguments.createMap())
|
|
111
|
+
}
|
|
112
|
+
val adView = buildTemplate(view.context, gmaAd)
|
|
113
|
+
view.removeAllViews()
|
|
114
|
+
view.addView(adView)
|
|
115
|
+
emit(view, "topLoad", Arguments.createMap())
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
override fun onNativeAdFailedToLoad(error: EzoicError) {
|
|
119
|
+
if (view.disposed || view.loadGeneration != generation) return
|
|
120
|
+
emit(view, "topError", errorMap(error.message, error.code))
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Builds a template [NativeAdView] entirely in code (the module ships no
|
|
127
|
+
* `res/` layouts). Layout: a vertical column of a header row (icon +
|
|
128
|
+
* headline/advertiser), a [MediaView], the body text and a call-to-action
|
|
129
|
+
* button. Only the asset views actually present on [gmaAd] are created and
|
|
130
|
+
* registered; [NativeAdView.setNativeAd] is called last, as GMA requires.
|
|
131
|
+
*/
|
|
132
|
+
private fun buildTemplate(context: Context, gmaAd: NativeAd): NativeAdView {
|
|
133
|
+
val adView = NativeAdView(context)
|
|
134
|
+
|
|
135
|
+
val root = LinearLayout(context).apply {
|
|
136
|
+
orientation = LinearLayout.VERTICAL
|
|
137
|
+
layoutParams = FrameLayout.LayoutParams(
|
|
138
|
+
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
139
|
+
FrameLayout.LayoutParams.WRAP_CONTENT,
|
|
140
|
+
)
|
|
141
|
+
val pad = dp(context, 8)
|
|
142
|
+
setPadding(pad, pad, pad, pad)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
val headerRow = LinearLayout(context).apply {
|
|
146
|
+
orientation = LinearLayout.HORIZONTAL
|
|
147
|
+
layoutParams = LinearLayout.LayoutParams(
|
|
148
|
+
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
149
|
+
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var iconView: ImageView? = null
|
|
154
|
+
gmaAd.icon?.drawable?.let { drawable ->
|
|
155
|
+
val iv = ImageView(context).apply {
|
|
156
|
+
layoutParams = LinearLayout.LayoutParams(dp(context, 40), dp(context, 40))
|
|
157
|
+
setImageDrawable(drawable)
|
|
158
|
+
}
|
|
159
|
+
headerRow.addView(iv)
|
|
160
|
+
iconView = iv
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
val textColumn = LinearLayout(context).apply {
|
|
164
|
+
orientation = LinearLayout.VERTICAL
|
|
165
|
+
layoutParams = LinearLayout.LayoutParams(
|
|
166
|
+
0,
|
|
167
|
+
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
168
|
+
1f,
|
|
169
|
+
).apply { leftMargin = dp(context, 8) }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
var headlineView: TextView? = null
|
|
173
|
+
gmaAd.headline?.let { text ->
|
|
174
|
+
val tv = TextView(context).apply {
|
|
175
|
+
this.text = text
|
|
176
|
+
setTypeface(typeface, Typeface.BOLD)
|
|
177
|
+
textSize = 16f
|
|
178
|
+
}
|
|
179
|
+
textColumn.addView(tv)
|
|
180
|
+
headlineView = tv
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
var advertiserView: TextView? = null
|
|
184
|
+
gmaAd.advertiser?.let { text ->
|
|
185
|
+
val tv = TextView(context).apply {
|
|
186
|
+
this.text = text
|
|
187
|
+
textSize = 12f
|
|
188
|
+
}
|
|
189
|
+
textColumn.addView(tv)
|
|
190
|
+
advertiserView = tv
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
headerRow.addView(textColumn)
|
|
194
|
+
root.addView(headerRow)
|
|
195
|
+
|
|
196
|
+
var mediaView: MediaView? = null
|
|
197
|
+
gmaAd.mediaContent?.let { content ->
|
|
198
|
+
val mv = MediaView(context).apply {
|
|
199
|
+
layoutParams = LinearLayout.LayoutParams(
|
|
200
|
+
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
201
|
+
dp(context, 175),
|
|
202
|
+
).apply { topMargin = dp(context, 8) }
|
|
203
|
+
mediaContent = content
|
|
204
|
+
}
|
|
205
|
+
root.addView(mv)
|
|
206
|
+
mediaView = mv
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
var bodyView: TextView? = null
|
|
210
|
+
gmaAd.body?.let { text ->
|
|
211
|
+
val tv = TextView(context).apply {
|
|
212
|
+
this.text = text
|
|
213
|
+
textSize = 14f
|
|
214
|
+
setPadding(0, dp(context, 8), 0, 0)
|
|
215
|
+
}
|
|
216
|
+
root.addView(tv)
|
|
217
|
+
bodyView = tv
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
var callToActionView: Button? = null
|
|
221
|
+
gmaAd.callToAction?.let { text ->
|
|
222
|
+
val btn = Button(context).apply {
|
|
223
|
+
this.text = text
|
|
224
|
+
layoutParams = LinearLayout.LayoutParams(
|
|
225
|
+
LinearLayout.LayoutParams.MATCH_PARENT,
|
|
226
|
+
LinearLayout.LayoutParams.WRAP_CONTENT,
|
|
227
|
+
).apply { topMargin = dp(context, 8) }
|
|
228
|
+
}
|
|
229
|
+
root.addView(btn)
|
|
230
|
+
callToActionView = btn
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
adView.addView(root)
|
|
234
|
+
// Register only the asset views that were populated; a null assignment
|
|
235
|
+
// leaves that asset unregistered.
|
|
236
|
+
adView.headlineView = headlineView
|
|
237
|
+
adView.bodyView = bodyView
|
|
238
|
+
adView.iconView = iconView
|
|
239
|
+
adView.advertiserView = advertiserView
|
|
240
|
+
adView.callToActionView = callToActionView
|
|
241
|
+
adView.mediaView = mediaView
|
|
242
|
+
adView.setNativeAd(gmaAd)
|
|
243
|
+
return adView
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
override fun onDropViewInstance(view: NativeAdContainer) {
|
|
247
|
+
super.onDropViewInstance(view)
|
|
248
|
+
view.disposed = true
|
|
249
|
+
view.loadGeneration++
|
|
250
|
+
view.ezoicNativeAd?.destroy()
|
|
251
|
+
view.ezoicNativeAd = null
|
|
252
|
+
view.removeAllViews()
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private fun emit(view: NativeAdContainer, event: String, payload: WritableMap) {
|
|
256
|
+
if (view.disposed) return
|
|
257
|
+
ctx.getJSModule(RCTEventEmitter::class.java).receiveEvent(view.id, event, payload)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
private fun errorMap(message: String?, code: Int): WritableMap {
|
|
261
|
+
val map = Arguments.createMap()
|
|
262
|
+
map.putString("message", message ?: "")
|
|
263
|
+
map.putInt("code", code)
|
|
264
|
+
return map
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private fun dp(context: Context, value: Int): Int =
|
|
268
|
+
(value * context.resources.displayMetrics.density).toInt()
|
|
269
|
+
|
|
270
|
+
override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any> {
|
|
271
|
+
fun reg(on: String) = mapOf("phasedRegistrationNames" to mapOf("bubbled" to on))
|
|
272
|
+
return mapOf(
|
|
273
|
+
"topLoad" to reg("onLoad"),
|
|
274
|
+
"topError" to reg("onError"),
|
|
275
|
+
"topImpression" to reg("onImpression"),
|
|
276
|
+
"topAdClick" to reg("onAdClick"),
|
|
277
|
+
"topOpen" to reg("onOpen"),
|
|
278
|
+
"topClose" to reg("onClose")
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Container for the template ad view. RN lays out only Yoga-managed views;
|
|
284
|
+
* the template [NativeAdView] is added from native code and stays unmeasured
|
|
285
|
+
* (blank) unless we force a measure/layout pass. Overriding [requestLayout]
|
|
286
|
+
* to post a manual measure(EXACTLY)+layout of the current bounds is the
|
|
287
|
+
* proven fix (react-native-google-mobile-ads uses the same approach).
|
|
288
|
+
*/
|
|
289
|
+
class NativeAdContainer(context: Context) : FrameLayout(context) {
|
|
290
|
+
var adUnitId: Int = 0
|
|
291
|
+
var rawAdUnitId: String = ""
|
|
292
|
+
var loadStarted: Boolean = false
|
|
293
|
+
var disposed: Boolean = false
|
|
294
|
+
var loadGeneration: Int = 0
|
|
295
|
+
var ezoicNativeAd: EzoicNativeAd? = null
|
|
296
|
+
|
|
297
|
+
private val measureAndLayout = Runnable {
|
|
298
|
+
measure(
|
|
299
|
+
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
|
|
300
|
+
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
|
|
301
|
+
)
|
|
302
|
+
layout(left, top, right, bottom)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
override fun requestLayout() {
|
|
306
|
+
super.requestLayout()
|
|
307
|
+
post(measureAndLayout)
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
companion object {
|
|
312
|
+
const val NAME = "EzoicNativeAdView"
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -19,7 +19,10 @@ class EzoicReactNativeSdkPackage : BaseReactPackage() {
|
|
|
19
19
|
override fun createViewManagers(
|
|
20
20
|
reactContext: ReactApplicationContext
|
|
21
21
|
): List<ViewManager<*, *>> {
|
|
22
|
-
return listOf(
|
|
22
|
+
return listOf(
|
|
23
|
+
EzoicBannerViewManager(reactContext),
|
|
24
|
+
EzoicNativeAdViewManager(reactContext)
|
|
25
|
+
)
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
override fun getReactModuleInfoProvider() = ReactModuleInfoProvider {
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import EzoicAdsSDKBinary
|
|
3
|
+
import GoogleMobileAds
|
|
4
|
+
|
|
5
|
+
@objc public protocol EzoicNativeAdHostViewDelegate: AnyObject {
|
|
6
|
+
func nativeAdDidLoad()
|
|
7
|
+
func nativeAdDidFail(_ message: String, code: Int)
|
|
8
|
+
func nativeAdDidRecordImpression()
|
|
9
|
+
func nativeAdDidRecordClick()
|
|
10
|
+
func nativeAdWillPresentScreen()
|
|
11
|
+
func nativeAdDidDismissScreen()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@objc public class EzoicNativeAdHostView: UIView, EzoicNativeAdDelegate {
|
|
15
|
+
|
|
16
|
+
@objc public weak var hostDelegate: EzoicNativeAdHostViewDelegate?
|
|
17
|
+
|
|
18
|
+
private var adUnitId: Int = 0
|
|
19
|
+
private var ezoicNativeAd: EzoicNativeAd?
|
|
20
|
+
private var adView: NativeAdView?
|
|
21
|
+
private var loadStarted = false
|
|
22
|
+
|
|
23
|
+
/// Stores the ad unit id. The load is NOT started here — the Fabric
|
|
24
|
+
/// component view calls `startLoad()` from `finalizeUpdates`, after the
|
|
25
|
+
/// event emitter is attached, so a synchronous SDK failure (uninitialized)
|
|
26
|
+
/// can deliver `onError` instead of being dropped.
|
|
27
|
+
@objc public func configure(adUnitIdentifier: String) {
|
|
28
|
+
self.adUnitId = Int(adUnitIdentifier) ?? 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/// Starts the native-ad load once. A second call is a no-op; the guard
|
|
32
|
+
/// survives repeated `finalizeUpdates` calls.
|
|
33
|
+
@objc public func startLoad() {
|
|
34
|
+
if loadStarted { return }
|
|
35
|
+
loadStarted = true
|
|
36
|
+
EzoicNativeAd.load(adUnitIdentifier: adUnitId) { [weak self] result in
|
|
37
|
+
guard let self = self else { return }
|
|
38
|
+
switch result {
|
|
39
|
+
case .success(let ad):
|
|
40
|
+
guard let gmaAd = ad.nativeAd else {
|
|
41
|
+
// Empty-content ad: destroy it and do not retain it instead of
|
|
42
|
+
// keeping an unrenderable, errored ad alive.
|
|
43
|
+
ad.destroy()
|
|
44
|
+
self.hostDelegate?.nativeAdDidFail("Native ad loaded without content", code: 0)
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
self.ezoicNativeAd = ad
|
|
48
|
+
// Attach the delegate before rendering so the impression, which fires
|
|
49
|
+
// as soon as the NativeAdView is displayed, is delivered.
|
|
50
|
+
ad.delegate = self
|
|
51
|
+
self.render(gmaAd)
|
|
52
|
+
self.hostDelegate?.nativeAdDidLoad()
|
|
53
|
+
case .failure(let error):
|
|
54
|
+
self.hostDelegate?.nativeAdDidFail(error.localizedDescription, code: error.code)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/// Builds a template `NativeAdView` in code (mirrors the Android template):
|
|
60
|
+
/// a header row (icon + headline/advertiser), a `MediaView`, the body text
|
|
61
|
+
/// and a call-to-action button. Optional text/image assets are created and
|
|
62
|
+
/// registered only when present, but the `MediaView` is always built: on
|
|
63
|
+
/// GMA 12 `NativeAd.mediaContent` is non-optional and the media view is a
|
|
64
|
+
/// required asset. `adView.nativeAd` is assigned last.
|
|
65
|
+
private func render(_ gmaAd: GoogleMobileAds.NativeAd) {
|
|
66
|
+
let adView = NativeAdView()
|
|
67
|
+
adView.translatesAutoresizingMaskIntoConstraints = false
|
|
68
|
+
|
|
69
|
+
let mainStack = UIStackView()
|
|
70
|
+
mainStack.axis = .vertical
|
|
71
|
+
mainStack.spacing = 8
|
|
72
|
+
mainStack.translatesAutoresizingMaskIntoConstraints = false
|
|
73
|
+
|
|
74
|
+
let headerRow = UIStackView()
|
|
75
|
+
headerRow.axis = .horizontal
|
|
76
|
+
headerRow.spacing = 8
|
|
77
|
+
headerRow.alignment = .center
|
|
78
|
+
|
|
79
|
+
if let image = gmaAd.icon?.image {
|
|
80
|
+
let iconView = UIImageView(image: image)
|
|
81
|
+
iconView.translatesAutoresizingMaskIntoConstraints = false
|
|
82
|
+
NSLayoutConstraint.activate([
|
|
83
|
+
iconView.widthAnchor.constraint(equalToConstant: 40),
|
|
84
|
+
iconView.heightAnchor.constraint(equalToConstant: 40),
|
|
85
|
+
])
|
|
86
|
+
headerRow.addArrangedSubview(iconView)
|
|
87
|
+
adView.iconView = iconView
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let textColumn = UIStackView()
|
|
91
|
+
textColumn.axis = .vertical
|
|
92
|
+
|
|
93
|
+
if let headline = gmaAd.headline {
|
|
94
|
+
let label = UILabel()
|
|
95
|
+
label.text = headline
|
|
96
|
+
label.font = .boldSystemFont(ofSize: 16)
|
|
97
|
+
label.numberOfLines = 0
|
|
98
|
+
textColumn.addArrangedSubview(label)
|
|
99
|
+
adView.headlineView = label
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if let advertiser = gmaAd.advertiser {
|
|
103
|
+
let label = UILabel()
|
|
104
|
+
label.text = advertiser
|
|
105
|
+
label.font = .systemFont(ofSize: 12)
|
|
106
|
+
textColumn.addArrangedSubview(label)
|
|
107
|
+
adView.advertiserView = label
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
headerRow.addArrangedSubview(textColumn)
|
|
111
|
+
mainStack.addArrangedSubview(headerRow)
|
|
112
|
+
|
|
113
|
+
let mediaView = MediaView()
|
|
114
|
+
mediaView.mediaContent = gmaAd.mediaContent
|
|
115
|
+
mediaView.translatesAutoresizingMaskIntoConstraints = false
|
|
116
|
+
// Priority 999 so a caller-supplied style shorter than the template's
|
|
117
|
+
// natural height breaks this constraint instead of spamming
|
|
118
|
+
// unsatisfiable-constraint logs.
|
|
119
|
+
let mediaHeight = mediaView.heightAnchor.constraint(equalToConstant: 175)
|
|
120
|
+
mediaHeight.priority = UILayoutPriority(999)
|
|
121
|
+
mediaHeight.isActive = true
|
|
122
|
+
mainStack.addArrangedSubview(mediaView)
|
|
123
|
+
adView.mediaView = mediaView
|
|
124
|
+
|
|
125
|
+
if let body = gmaAd.body {
|
|
126
|
+
let label = UILabel()
|
|
127
|
+
label.text = body
|
|
128
|
+
label.font = .systemFont(ofSize: 14)
|
|
129
|
+
label.numberOfLines = 0
|
|
130
|
+
mainStack.addArrangedSubview(label)
|
|
131
|
+
adView.bodyView = label
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if let cta = gmaAd.callToAction {
|
|
135
|
+
let button = UIButton(type: .system)
|
|
136
|
+
button.setTitle(cta, for: .normal)
|
|
137
|
+
// The NativeAdView handles the tap; the button must not intercept it.
|
|
138
|
+
button.isUserInteractionEnabled = false
|
|
139
|
+
mainStack.addArrangedSubview(button)
|
|
140
|
+
adView.callToActionView = button
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
adView.addSubview(mainStack)
|
|
144
|
+
NSLayoutConstraint.activate([
|
|
145
|
+
mainStack.topAnchor.constraint(equalTo: adView.topAnchor, constant: 8),
|
|
146
|
+
mainStack.leadingAnchor.constraint(equalTo: adView.leadingAnchor, constant: 8),
|
|
147
|
+
mainStack.trailingAnchor.constraint(equalTo: adView.trailingAnchor, constant: -8),
|
|
148
|
+
mainStack.bottomAnchor.constraint(equalTo: adView.bottomAnchor, constant: -8),
|
|
149
|
+
])
|
|
150
|
+
|
|
151
|
+
self.adView?.removeFromSuperview()
|
|
152
|
+
addSubview(adView)
|
|
153
|
+
NSLayoutConstraint.activate([
|
|
154
|
+
adView.topAnchor.constraint(equalTo: topAnchor),
|
|
155
|
+
adView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
156
|
+
adView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
|
157
|
+
adView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
|
158
|
+
])
|
|
159
|
+
|
|
160
|
+
adView.nativeAd = gmaAd
|
|
161
|
+
self.adView = adView
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// MARK: - EzoicNativeAdDelegate
|
|
165
|
+
public func nativeAdDidRecordImpression(_ nativeAd: EzoicNativeAd) {
|
|
166
|
+
hostDelegate?.nativeAdDidRecordImpression()
|
|
167
|
+
}
|
|
168
|
+
public func nativeAdDidRecordClick(_ nativeAd: EzoicNativeAd) {
|
|
169
|
+
hostDelegate?.nativeAdDidRecordClick()
|
|
170
|
+
}
|
|
171
|
+
public func nativeAdWillPresentScreen(_ nativeAd: EzoicNativeAd) {
|
|
172
|
+
hostDelegate?.nativeAdWillPresentScreen()
|
|
173
|
+
}
|
|
174
|
+
public func nativeAdDidDismissScreen(_ nativeAd: EzoicNativeAd) {
|
|
175
|
+
hostDelegate?.nativeAdDidDismissScreen()
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
deinit {
|
|
179
|
+
ezoicNativeAd?.destroy()
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#import <React/RCTViewComponentView.h>
|
|
2
|
+
#import <react/renderer/components/EzoicReactNativeSdkSpec/ComponentDescriptors.h>
|
|
3
|
+
#import <react/renderer/components/EzoicReactNativeSdkSpec/EventEmitters.h>
|
|
4
|
+
#import <react/renderer/components/EzoicReactNativeSdkSpec/Props.h>
|
|
5
|
+
#import <react/renderer/components/EzoicReactNativeSdkSpec/RCTComponentViewHelpers.h>
|
|
6
|
+
#import <EzoicReactNativeSdk/EzoicReactNativeSdk-Swift.h>
|
|
7
|
+
|
|
8
|
+
using namespace facebook::react;
|
|
9
|
+
|
|
10
|
+
@interface EzoicNativeAdView : RCTViewComponentView <EzoicNativeAdHostViewDelegate>
|
|
11
|
+
@end
|
|
12
|
+
|
|
13
|
+
@implementation EzoicNativeAdView {
|
|
14
|
+
EzoicNativeAdHostView *_host;
|
|
15
|
+
NSString *_lastAdUnit;
|
|
16
|
+
BOOL _loadStarted;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
+ (ComponentDescriptorProvider)componentDescriptorProvider {
|
|
20
|
+
return concreteComponentDescriptorProvider<EzoicNativeAdViewComponentDescriptor>();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
- (instancetype)initWithFrame:(CGRect)frame {
|
|
24
|
+
if (self = [super initWithFrame:frame]) {
|
|
25
|
+
_host = [EzoicNativeAdHostView new];
|
|
26
|
+
_host.hostDelegate = self;
|
|
27
|
+
self.contentView = _host;
|
|
28
|
+
}
|
|
29
|
+
return self;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps {
|
|
33
|
+
const auto &newProps = *std::static_pointer_cast<EzoicNativeAdViewProps const>(props);
|
|
34
|
+
NSString *adUnit = [NSString stringWithUTF8String:newProps.adUnitIdentifier.c_str()];
|
|
35
|
+
if (![adUnit isEqualToString:_lastAdUnit]) {
|
|
36
|
+
// Ad unit changed after a load already started: swap in a fresh host
|
|
37
|
+
// (mirrors prepareForRecycle) and reset the load guard so
|
|
38
|
+
// finalizeUpdates starts a new load for the new id.
|
|
39
|
+
if (_loadStarted) {
|
|
40
|
+
[_host removeFromSuperview];
|
|
41
|
+
_host = [EzoicNativeAdHostView new];
|
|
42
|
+
_host.hostDelegate = self;
|
|
43
|
+
self.contentView = _host;
|
|
44
|
+
_loadStarted = NO;
|
|
45
|
+
}
|
|
46
|
+
_lastAdUnit = adUnit;
|
|
47
|
+
[_host configureWithAdUnitIdentifier:adUnit];
|
|
48
|
+
}
|
|
49
|
+
[super updateProps:props oldProps:oldProps];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// RCTMountingManager mounts on Insert as updateProps → updateEventEmitter →
|
|
53
|
+
// finalizeUpdates. Starting the load here (not in updateProps) guarantees the
|
|
54
|
+
// event emitter is attached before the native SDK can fail synchronously and
|
|
55
|
+
// emit onError, which would otherwise be dropped while _eventEmitter is nil.
|
|
56
|
+
- (void)finalizeUpdates:(RNComponentViewUpdateMask)updateMask {
|
|
57
|
+
[super finalizeUpdates:updateMask];
|
|
58
|
+
if (!_loadStarted && _lastAdUnit.length > 0) {
|
|
59
|
+
_loadStarted = YES;
|
|
60
|
+
[_host startLoad];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
- (void)nativeAdDidLoad {
|
|
65
|
+
if (_eventEmitter) std::static_pointer_cast<EzoicNativeAdViewEventEmitter const>(_eventEmitter)->onLoad({});
|
|
66
|
+
}
|
|
67
|
+
- (void)nativeAdDidFail:(NSString *)message code:(NSInteger)code {
|
|
68
|
+
if (_eventEmitter)
|
|
69
|
+
std::static_pointer_cast<EzoicNativeAdViewEventEmitter const>(_eventEmitter)
|
|
70
|
+
->onError({.message = std::string([message UTF8String]), .code = (int)code});
|
|
71
|
+
}
|
|
72
|
+
- (void)nativeAdDidRecordImpression {
|
|
73
|
+
if (_eventEmitter) std::static_pointer_cast<EzoicNativeAdViewEventEmitter const>(_eventEmitter)->onImpression({});
|
|
74
|
+
}
|
|
75
|
+
- (void)nativeAdDidRecordClick {
|
|
76
|
+
if (_eventEmitter) std::static_pointer_cast<EzoicNativeAdViewEventEmitter const>(_eventEmitter)->onAdClick({});
|
|
77
|
+
}
|
|
78
|
+
- (void)nativeAdWillPresentScreen {
|
|
79
|
+
if (_eventEmitter) std::static_pointer_cast<EzoicNativeAdViewEventEmitter const>(_eventEmitter)->onOpen({});
|
|
80
|
+
}
|
|
81
|
+
- (void)nativeAdDidDismissScreen {
|
|
82
|
+
if (_eventEmitter) std::static_pointer_cast<EzoicNativeAdViewEventEmitter const>(_eventEmitter)->onClose({});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
- (void)prepareForRecycle {
|
|
86
|
+
// Recycled views are reused for a new ad unit; rebuild the host (which owns
|
|
87
|
+
// the loaded EzoicNativeAd, destroyed on deinit) and reset the load guards.
|
|
88
|
+
[_host removeFromSuperview];
|
|
89
|
+
_host = [EzoicNativeAdHostView new];
|
|
90
|
+
_host.hostDelegate = self;
|
|
91
|
+
self.contentView = _host;
|
|
92
|
+
_lastAdUnit = nil;
|
|
93
|
+
_loadStarted = NO;
|
|
94
|
+
[super prepareForRecycle];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Class<RCTComponentViewProtocol> EzoicNativeAdViewCls(void) { return EzoicNativeAdView.class; }
|
|
98
|
+
|
|
99
|
+
@end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { codegenNativeComponent } from 'react-native';
|
|
2
|
+
import type { CodegenTypes, HostComponent, ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type LoadEvent = Readonly<{}>;
|
|
5
|
+
type ErrorEvent = Readonly<{ message: string; code: CodegenTypes.Int32 }>;
|
|
6
|
+
|
|
7
|
+
export interface NativeProps extends ViewProps {
|
|
8
|
+
adUnitIdentifier: string;
|
|
9
|
+
onLoad?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
10
|
+
onError?: CodegenTypes.BubblingEventHandler<ErrorEvent> | null;
|
|
11
|
+
onImpression?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
12
|
+
// `onClick` is reserved by core ViewProps (a gesture handler), so the native
|
|
13
|
+
// native-ad-click event is exposed as `onAdClick`. The public
|
|
14
|
+
// `EzoicNativeAdView` component maps the user-facing `onClick` prop onto this.
|
|
15
|
+
onAdClick?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
16
|
+
onOpen?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
17
|
+
onClose?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default codegenNativeComponent<NativeProps>(
|
|
21
|
+
'EzoicNativeAdView'
|
|
22
|
+
) as HostComponent<NativeProps>;
|
|
@@ -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","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,
|
|
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,gBAAiC,EAAU;EACxE,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
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import NativeEzoicAds from "./NativeEzoicAds.js";
|
|
4
4
|
import EzoicBannerNative from './EzoicBannerViewNativeComponent';
|
|
5
|
+
import EzoicNativeAdNative from './EzoicNativeAdViewNativeComponent';
|
|
5
6
|
import { coerceAdUnitId, normalizeConfig, normalizeSize } from "./helpers.js";
|
|
6
7
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
8
|
export { EzoicRewardedAd } from "./EzoicRewardedAd.js";
|
|
@@ -47,4 +48,31 @@ export function EzoicBannerView(props) {
|
|
|
47
48
|
onClose: onClose ? () => onClose() : undefined
|
|
48
49
|
});
|
|
49
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Renders a native ad in an SDK-built template `NativeAdView`. The component
|
|
53
|
+
* fills the bounds it is given by its RN style, so size it with `style` (e.g.
|
|
54
|
+
* `{ width: '100%', height: 300 }`); the template lays out its assets inside.
|
|
55
|
+
*/
|
|
56
|
+
export function EzoicNativeAdView(props) {
|
|
57
|
+
const {
|
|
58
|
+
adUnitIdentifier,
|
|
59
|
+
onLoad,
|
|
60
|
+
onError,
|
|
61
|
+
onImpression,
|
|
62
|
+
onClick,
|
|
63
|
+
onOpen,
|
|
64
|
+
onClose,
|
|
65
|
+
...rest
|
|
66
|
+
} = props;
|
|
67
|
+
return /*#__PURE__*/_jsx(EzoicNativeAdNative, {
|
|
68
|
+
...rest,
|
|
69
|
+
adUnitIdentifier: coerceAdUnitId(adUnitIdentifier),
|
|
70
|
+
onLoad: onLoad ? () => onLoad() : undefined,
|
|
71
|
+
onError: onError ? e => onError(e.nativeEvent) : undefined,
|
|
72
|
+
onImpression: onImpression ? () => onImpression() : undefined,
|
|
73
|
+
onAdClick: onClick ? () => onClick() : undefined,
|
|
74
|
+
onOpen: onOpen ? () => onOpen() : undefined,
|
|
75
|
+
onClose: onClose ? () => onClose() : undefined
|
|
76
|
+
});
|
|
77
|
+
}
|
|
50
78
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
1
|
+
{"version":3,"names":["NativeEzoicAds","EzoicBannerNative","EzoicNativeAdNative","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","EzoicNativeAdView"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AACA,OAAOA,cAAc,MAA4B,qBAAkB;AACnE,OAAOC,iBAAiB,MAAM,kCAAkC;AAChE,OAAOC,mBAAmB,MAAM,oCAAoC;AACpE,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,OAAOZ,cAAc,CAACW,UAAU,CAACP,eAAe,CAACQ,MAAM,CAAC,CAAC;EAC3D,CAAC;EACDC,cAAcA,CAACC,OAAgB,EAAEC,aAAsB,EAAQ;IAC7Df,cAAc,CAACa,cAAc,CAACC,OAAO,EAAEC,aAAa,CAAC;EACvD,CAAC;EACDC,aAAaA,CAACC,SAAkB,EAAEC,UAAmB,EAAQ;IAC3DlB,cAAc,CAACgB,aAAa,CAACC,SAAS,EAAEC,UAAU,CAAC;EACrD,CAAC;EACDC,iBAAiBA,CAACC,KAAc,EAAQ;IACtCpB,cAAc,CAACmB,iBAAiB,CAACC,KAAK,CAAC;EACzC,CAAC;EACDC,aAAaA,CAAA,EAAqB;IAChC,OAAOrB,cAAc,CAACqB,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,CAACN,iBAAiB;IAAA,GACZ+B,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;AAkBA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASI,iBAAiBA,CAACd,KAA6B,EAAE;EAC/D,MAAM;IACJC,gBAAgB;IAChBE,MAAM;IACNC,OAAO;IACPC,YAAY;IACZC,OAAO;IACPC,MAAM;IACNC,OAAO;IACP,GAAGC;EACL,CAAC,GAAGT,KAAK;EACT,oBACEhB,IAAA,CAACL,mBAAmB;IAAA,GACd8B,IAAI;IACRR,gBAAgB,EAAErB,cAAc,CAACqB,gBAAgB,CAAE;IACnDE,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,18 @@
|
|
|
1
|
+
import type { CodegenTypes, HostComponent, ViewProps } from 'react-native';
|
|
2
|
+
type LoadEvent = Readonly<{}>;
|
|
3
|
+
type ErrorEvent = Readonly<{
|
|
4
|
+
message: string;
|
|
5
|
+
code: CodegenTypes.Int32;
|
|
6
|
+
}>;
|
|
7
|
+
export interface NativeProps extends ViewProps {
|
|
8
|
+
adUnitIdentifier: string;
|
|
9
|
+
onLoad?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
10
|
+
onError?: CodegenTypes.BubblingEventHandler<ErrorEvent> | null;
|
|
11
|
+
onImpression?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
12
|
+
onAdClick?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
13
|
+
onOpen?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
14
|
+
onClose?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
15
|
+
}
|
|
16
|
+
declare const _default: HostComponent<NativeProps>;
|
|
17
|
+
export default _default;
|
|
18
|
+
//# sourceMappingURL=EzoicNativeAdViewNativeComponent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EzoicNativeAdViewNativeComponent.d.ts","sourceRoot":"","sources":["../../../src/EzoicNativeAdViewNativeComponent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3E,KAAK,SAAS,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC9B,KAAK,UAAU,GAAG,QAAQ,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC,KAAK,CAAA;CAAE,CAAC,CAAC;AAE1E,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAC7D,OAAO,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IAC/D,YAAY,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAInE,SAAS,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAChE,MAAM,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAC7D,OAAO,CAAC,EAAE,YAAY,CAAC,oBAAoB,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;CAC/D;wBAII,aAAa,CAAC,WAAW,CAAC;AAF/B,wBAEgC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
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
|
-
export declare function coerceAdUnitId(adUnitIdentifier: string): string;
|
|
4
|
+
export declare function coerceAdUnitId(adUnitIdentifier: string | number): string;
|
|
5
5
|
export interface RewardResultLike {
|
|
6
6
|
earned: boolean;
|
|
7
7
|
type: string;
|
|
@@ -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,
|
|
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,GAAG,MAAM,CAExE;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"}
|
|
@@ -26,4 +26,24 @@ export interface EzoicBannerViewProps {
|
|
|
26
26
|
onClose?: () => void;
|
|
27
27
|
}
|
|
28
28
|
export declare function EzoicBannerView(props: EzoicBannerViewProps): import("react").JSX.Element;
|
|
29
|
+
export interface EzoicNativeAdError {
|
|
30
|
+
message: string;
|
|
31
|
+
code: number;
|
|
32
|
+
}
|
|
33
|
+
export interface EzoicNativeAdViewProps {
|
|
34
|
+
adUnitIdentifier: string | number;
|
|
35
|
+
style?: StyleProp<ViewStyle>;
|
|
36
|
+
onLoad?: () => void;
|
|
37
|
+
onError?: (error: EzoicNativeAdError) => void;
|
|
38
|
+
onImpression?: () => void;
|
|
39
|
+
onClick?: () => void;
|
|
40
|
+
onOpen?: () => void;
|
|
41
|
+
onClose?: () => void;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Renders a native ad in an SDK-built template `NativeAdView`. The component
|
|
45
|
+
* fills the bounds it is given by its RN style, so size it with `style` (e.g.
|
|
46
|
+
* `{ width: '100%', height: 300 }`); the template lays out its assets inside.
|
|
47
|
+
*/
|
|
48
|
+
export declare function EzoicNativeAdView(props: EzoicNativeAdViewProps): import("react").JSX.Element;
|
|
29
49
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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;
|
|
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;AAKpE,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;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC9C,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;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,+BAuB9D"}
|
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, interstitial and rewarded ads).",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Ezoic Ads SDK for React Native (Prebid + Google Ad Manager banner, native, 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,22 @@
|
|
|
1
|
+
import { codegenNativeComponent } from 'react-native';
|
|
2
|
+
import type { CodegenTypes, HostComponent, ViewProps } from 'react-native';
|
|
3
|
+
|
|
4
|
+
type LoadEvent = Readonly<{}>;
|
|
5
|
+
type ErrorEvent = Readonly<{ message: string; code: CodegenTypes.Int32 }>;
|
|
6
|
+
|
|
7
|
+
export interface NativeProps extends ViewProps {
|
|
8
|
+
adUnitIdentifier: string;
|
|
9
|
+
onLoad?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
10
|
+
onError?: CodegenTypes.BubblingEventHandler<ErrorEvent> | null;
|
|
11
|
+
onImpression?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
12
|
+
// `onClick` is reserved by core ViewProps (a gesture handler), so the native
|
|
13
|
+
// native-ad-click event is exposed as `onAdClick`. The public
|
|
14
|
+
// `EzoicNativeAdView` component maps the user-facing `onClick` prop onto this.
|
|
15
|
+
onAdClick?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
16
|
+
onOpen?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
17
|
+
onClose?: CodegenTypes.BubblingEventHandler<LoadEvent> | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default codegenNativeComponent<NativeProps>(
|
|
21
|
+
'EzoicNativeAdView'
|
|
22
|
+
) as HostComponent<NativeProps>;
|
package/src/helpers.ts
CHANGED
|
@@ -25,7 +25,7 @@ export function normalizeSize(size: string | undefined): string {
|
|
|
25
25
|
.join(',');
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
export function coerceAdUnitId(adUnitIdentifier: string): string {
|
|
28
|
+
export function coerceAdUnitId(adUnitIdentifier: string | number): string {
|
|
29
29
|
return String(adUnitIdentifier);
|
|
30
30
|
}
|
|
31
31
|
|
package/src/index.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
2
2
|
import NativeEzoicAds, { type EzoicConfig } from './NativeEzoicAds';
|
|
3
3
|
import EzoicBannerNative from './EzoicBannerViewNativeComponent';
|
|
4
|
+
import EzoicNativeAdNative from './EzoicNativeAdViewNativeComponent';
|
|
4
5
|
import { coerceAdUnitId, normalizeConfig, normalizeSize } from './helpers';
|
|
5
6
|
|
|
6
7
|
export type { EzoicConfig };
|
|
@@ -75,3 +76,49 @@ export function EzoicBannerView(props: EzoicBannerViewProps) {
|
|
|
75
76
|
/>
|
|
76
77
|
);
|
|
77
78
|
}
|
|
79
|
+
|
|
80
|
+
export interface EzoicNativeAdError {
|
|
81
|
+
message: string;
|
|
82
|
+
code: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface EzoicNativeAdViewProps {
|
|
86
|
+
adUnitIdentifier: string | number;
|
|
87
|
+
style?: StyleProp<ViewStyle>;
|
|
88
|
+
onLoad?: () => void;
|
|
89
|
+
onError?: (error: EzoicNativeAdError) => void;
|
|
90
|
+
onImpression?: () => void;
|
|
91
|
+
onClick?: () => void;
|
|
92
|
+
onOpen?: () => void;
|
|
93
|
+
onClose?: () => void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Renders a native ad in an SDK-built template `NativeAdView`. The component
|
|
98
|
+
* fills the bounds it is given by its RN style, so size it with `style` (e.g.
|
|
99
|
+
* `{ width: '100%', height: 300 }`); the template lays out its assets inside.
|
|
100
|
+
*/
|
|
101
|
+
export function EzoicNativeAdView(props: EzoicNativeAdViewProps) {
|
|
102
|
+
const {
|
|
103
|
+
adUnitIdentifier,
|
|
104
|
+
onLoad,
|
|
105
|
+
onError,
|
|
106
|
+
onImpression,
|
|
107
|
+
onClick,
|
|
108
|
+
onOpen,
|
|
109
|
+
onClose,
|
|
110
|
+
...rest
|
|
111
|
+
} = props;
|
|
112
|
+
return (
|
|
113
|
+
<EzoicNativeAdNative
|
|
114
|
+
{...rest}
|
|
115
|
+
adUnitIdentifier={coerceAdUnitId(adUnitIdentifier)}
|
|
116
|
+
onLoad={onLoad ? () => onLoad() : undefined}
|
|
117
|
+
onError={onError ? (e) => onError(e.nativeEvent) : undefined}
|
|
118
|
+
onImpression={onImpression ? () => onImpression() : undefined}
|
|
119
|
+
onAdClick={onClick ? () => onClick() : undefined}
|
|
120
|
+
onOpen={onOpen ? () => onOpen() : undefined}
|
|
121
|
+
onClose={onClose ? () => onClose() : undefined}
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
}
|