cloudx-react-native 3.4.6 → 3.4.7
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/android/build.gradle +1 -1
- package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +10 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdView.kt +244 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +28 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewManagerImpl.kt +54 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXExtraParameters.kt +101 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +5 -57
- package/android/src/main/java/com/cloudxreactnative/CloudXPackage.kt +1 -1
- package/android/src/newarch/com/cloudxreactnative/CloudXAdViewManager.kt +52 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXAdViewManager.kt +46 -0
- package/ios/CloudX.mm +13 -57
- package/ios/CloudXAdView.h +35 -0
- package/ios/CloudXAdView.mm +505 -0
- package/ios/CloudXAdViewManager.h +12 -0
- package/ios/CloudXAdViewManager.mm +38 -0
- package/ios/CloudXExtraParameters.h +27 -0
- package/ios/CloudXExtraParameters.mm +117 -0
- package/lib/commonjs/CloudXAdViewBase.js +248 -0
- package/lib/commonjs/CloudXAdViewBase.js.map +1 -0
- package/lib/commonjs/CloudXBannerView.js +27 -0
- package/lib/commonjs/CloudXBannerView.js.map +1 -0
- package/lib/commonjs/CloudXMRECView.js +27 -0
- package/lib/commonjs/CloudXMRECView.js.map +1 -0
- package/lib/commonjs/index.js +16 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +30 -0
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +1 -0
- package/lib/commonjs/version.js +1 -1
- package/lib/module/CloudXAdViewBase.js +240 -0
- package/lib/module/CloudXAdViewBase.js.map +1 -0
- package/lib/module/CloudXBannerView.js +19 -0
- package/lib/module/CloudXBannerView.js.map +1 -0
- package/lib/module/CloudXMRECView.js +19 -0
- package/lib/module/CloudXMRECView.js.map +1 -0
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/specs/CloudXAdViewNativeComponent.js +27 -0
- package/lib/module/specs/CloudXAdViewNativeComponent.js.map +1 -0
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/CloudXAdViewBase.d.ts +28 -0
- package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -0
- package/lib/typescript/src/CloudXBannerView.d.ts +16 -0
- package/lib/typescript/src/CloudXBannerView.d.ts.map +1 -0
- package/lib/typescript/src/CloudXMRECView.d.ts +16 -0
- package/lib/typescript/src/CloudXMRECView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +62 -0
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/types/AdProps.d.ts +3 -0
- package/lib/typescript/src/types/AdProps.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/CloudXAdViewBase.tsx +293 -0
- package/src/CloudXBannerView.tsx +20 -0
- package/src/CloudXMRECView.tsx +20 -0
- package/src/index.ts +5 -0
- package/src/specs/CloudXAdViewNativeComponent.ts +84 -0
- package/src/types/AdProps.ts +4 -0
- package/src/version.ts +1 -1
package/android/build.gradle
CHANGED
|
@@ -17,6 +17,16 @@ object CloudXAdEvents {
|
|
|
17
17
|
const val ON_MREC_AD_COLLAPSED_EVENT = "OnMRecAdCollapsedEvent"
|
|
18
18
|
const val ON_MREC_AD_REVENUE_PAID = "OnMRecAdRevenuePaid"
|
|
19
19
|
|
|
20
|
+
/*
|
|
21
|
+
* In-tree Ad View component (CloudXBannerView / CloudXMRECView) per-view
|
|
22
|
+
* direct events. These strings are both the event key and the JS prop
|
|
23
|
+
* registrationName.
|
|
24
|
+
*/
|
|
25
|
+
const val ON_AD_VIEW_LOADED_EVENT = "onAdLoadedEvent"
|
|
26
|
+
const val ON_AD_VIEW_LOAD_FAILED_EVENT = "onAdLoadFailedEvent"
|
|
27
|
+
const val ON_AD_VIEW_CLICKED_EVENT = "onAdClickedEvent"
|
|
28
|
+
const val ON_AD_VIEW_REVENUE_PAID_EVENT = "onAdRevenuePaidEvent"
|
|
29
|
+
|
|
20
30
|
// Interstitial Events
|
|
21
31
|
const val ON_INTERSTITIAL_LOADED_EVENT = "OnInterstitialLoadedEvent"
|
|
22
32
|
const val ON_INTERSTITIAL_LOAD_FAILED_EVENT = "OnInterstitialLoadFailedEvent"
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import android.widget.FrameLayout
|
|
5
|
+
import com.facebook.react.bridge.Arguments
|
|
6
|
+
import com.facebook.react.bridge.WritableMap
|
|
7
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
8
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
9
|
+
import io.cloudx.sdk.CloudX
|
|
10
|
+
import io.cloudx.sdk.CloudXAd
|
|
11
|
+
import io.cloudx.sdk.CloudXAdRevenueListener
|
|
12
|
+
import io.cloudx.sdk.CloudXAdView as SdkAdView
|
|
13
|
+
import io.cloudx.sdk.CloudXAdViewListener
|
|
14
|
+
import io.cloudx.sdk.CloudXError
|
|
15
|
+
import org.json.JSONObject
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* In-tree banner/MREC view component.
|
|
19
|
+
*
|
|
20
|
+
* Extends [FrameLayout] (not ReactViewGroup, whose requestLayout is a no-op that
|
|
21
|
+
* would leave the hosted ad view at 0x0) and hosts the CloudX SDK ad view as a
|
|
22
|
+
* real child. Because it lives in the React view tree, app overlays such as
|
|
23
|
+
* toasts layer above it via normal RN z-ordering.
|
|
24
|
+
*/
|
|
25
|
+
class CloudXAdView(private val reactContext: ThemedReactContext) : FrameLayout(reactContext) {
|
|
26
|
+
|
|
27
|
+
private companion object {
|
|
28
|
+
const val TAG = "CloudXAdView"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
* adUnitId / adFormat are immutable once the ad view is created. Changing
|
|
33
|
+
* them on a mounted view is ignored (with a warning) - remount via a React
|
|
34
|
+
* key instead. The value check keeps benign same-value re-renders quiet.
|
|
35
|
+
*/
|
|
36
|
+
var adUnitId: String? = null
|
|
37
|
+
set(value) {
|
|
38
|
+
if (adView != null && value != field) {
|
|
39
|
+
Log.w(TAG, "adUnitId cannot change after the ad view is created; remount the component (e.g. via a React key).")
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
field = value
|
|
43
|
+
}
|
|
44
|
+
var adFormat: String? = null
|
|
45
|
+
set(value) {
|
|
46
|
+
if (adView != null && value != field) {
|
|
47
|
+
Log.w(TAG, "adFormat cannot change after the ad view is created; remount the component (e.g. via a React key).")
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
field = value
|
|
51
|
+
}
|
|
52
|
+
var placement: String? = null
|
|
53
|
+
set(value) {
|
|
54
|
+
field = value
|
|
55
|
+
adView?.setPlacement(value)
|
|
56
|
+
}
|
|
57
|
+
var customData: String? = null
|
|
58
|
+
set(value) {
|
|
59
|
+
field = value
|
|
60
|
+
adView?.setCustomData(value)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Latest declarative extra parameters from the RN component. */
|
|
64
|
+
var extraParameters: Map<String, Any?> = emptyMap()
|
|
65
|
+
set(value) {
|
|
66
|
+
field = value
|
|
67
|
+
applyExtraParametersIfReady()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private var adView: SdkAdView? = null
|
|
71
|
+
private var appliedExtraParameterKeys: Set<String> = emptySet()
|
|
72
|
+
|
|
73
|
+
private val measureAndLayoutRunnable = Runnable {
|
|
74
|
+
measure(
|
|
75
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
76
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY),
|
|
77
|
+
)
|
|
78
|
+
layout(left, top, right, bottom)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/*
|
|
82
|
+
* ReactViewGroup no-ops requestLayout, and getWidth()/getHeight() are 0 on
|
|
83
|
+
* attach - re-run measure/layout on the next frame so the hosted ad renders.
|
|
84
|
+
*/
|
|
85
|
+
override fun requestLayout() {
|
|
86
|
+
super.requestLayout()
|
|
87
|
+
removeCallbacks(measureAndLayoutRunnable)
|
|
88
|
+
post(measureAndLayoutRunnable)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** Invoked from the ViewManager's onAfterUpdateTransaction, after all props are set. */
|
|
92
|
+
fun onSetProps() {
|
|
93
|
+
maybeAttachAdView()
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
private fun maybeAttachAdView() {
|
|
97
|
+
if (adView != null) return
|
|
98
|
+
val unitId = adUnitId ?: return
|
|
99
|
+
val format = adFormat ?: return
|
|
100
|
+
|
|
101
|
+
val created = if (format.equals("MREC", ignoreCase = true)) {
|
|
102
|
+
CloudX.createMREC(reactContext, unitId)
|
|
103
|
+
} else {
|
|
104
|
+
CloudX.createBanner(reactContext, unitId)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
created.listener = createListener()
|
|
108
|
+
created.revenueListener = createRevenueListener()
|
|
109
|
+
placement?.let { created.setPlacement(it) }
|
|
110
|
+
customData?.let { created.setCustomData(it) }
|
|
111
|
+
|
|
112
|
+
adView = created
|
|
113
|
+
applyExtraParametersIfReady()
|
|
114
|
+
addView(created)
|
|
115
|
+
created.load()
|
|
116
|
+
updateAutoRefresh()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private fun updateAutoRefresh() {
|
|
120
|
+
val view = adView ?: return
|
|
121
|
+
if (isAttachedToWindow) view.startAutoRefresh() else view.stopAutoRefresh()
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
override fun onAttachedToWindow() {
|
|
125
|
+
super.onAttachedToWindow()
|
|
126
|
+
adView?.startAutoRefresh()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override fun onDetachedFromWindow() {
|
|
130
|
+
super.onDetachedFromWindow()
|
|
131
|
+
adView?.stopAutoRefresh()
|
|
132
|
+
|
|
133
|
+
/*
|
|
134
|
+
* Defer one frame: a tab switch detaches but keeps the parent, a real
|
|
135
|
+
* unmount removes it. Destroy only on a genuine unmount.
|
|
136
|
+
*/
|
|
137
|
+
post {
|
|
138
|
+
if (parent == null) {
|
|
139
|
+
destroyAdView()
|
|
140
|
+
} else {
|
|
141
|
+
/*
|
|
142
|
+
* Still parented on the deferred frame = a tab switch, not an
|
|
143
|
+
* unmount, so re-arm refresh. If the view is instead being
|
|
144
|
+
* dropped, CloudXAdViewManagerImpl.onDropViewInstance calls
|
|
145
|
+
* destroyAdView() first (nulling adView), so this stays a
|
|
146
|
+
* null-safe no-op - refresh is never armed on a dead view.
|
|
147
|
+
*/
|
|
148
|
+
adView?.startAutoRefresh()
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
fun destroyAdView() {
|
|
154
|
+
val view = adView ?: return
|
|
155
|
+
view.stopAutoRefresh()
|
|
156
|
+
view.listener = null
|
|
157
|
+
view.revenueListener = null
|
|
158
|
+
view.destroy()
|
|
159
|
+
removeView(view)
|
|
160
|
+
adView = null
|
|
161
|
+
appliedExtraParameterKeys = emptySet()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private fun applyExtraParametersIfReady() {
|
|
165
|
+
val view = adView ?: return
|
|
166
|
+
CloudXExtraParameters.applyToAdView(view, extraParameters)
|
|
167
|
+
|
|
168
|
+
val currentKeys = extraParameters.keys.toSet()
|
|
169
|
+
for (key in appliedExtraParameterKeys - currentKeys) {
|
|
170
|
+
view.setExtraParameter(key, null)
|
|
171
|
+
}
|
|
172
|
+
appliedExtraParameterKeys = currentKeys
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private fun dispatchAdEvent(eventName: String, payload: WritableMap) {
|
|
176
|
+
val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) ?: return
|
|
177
|
+
val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
|
|
178
|
+
dispatcher.dispatchEvent(CloudXAdViewEvent(surfaceId, id, eventName, payload))
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
private fun createListener(): CloudXAdViewListener = object : CloudXAdViewListener {
|
|
182
|
+
override fun onAdLoaded(cloudXAd: CloudXAd) {
|
|
183
|
+
dispatchAdEvent(CloudXAdEvents.ON_AD_VIEW_LOADED_EVENT, adInfoPayload(cloudXAd))
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
override fun onAdLoadFailed(failedAdUnitId: String, cloudXError: CloudXError) {
|
|
187
|
+
dispatchAdEvent(CloudXAdEvents.ON_AD_VIEW_LOAD_FAILED_EVENT, loadFailedPayload(failedAdUnitId, cloudXError))
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
override fun onAdClicked(cloudXAd: CloudXAd) {
|
|
191
|
+
dispatchAdEvent(CloudXAdEvents.ON_AD_VIEW_CLICKED_EVENT, adInfoPayload(cloudXAd))
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
override fun onAdExpanded(cloudXAd: CloudXAd) = Unit
|
|
195
|
+
|
|
196
|
+
override fun onAdCollapsed(cloudXAd: CloudXAd) = Unit
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private fun createRevenueListener(): CloudXAdRevenueListener = object : CloudXAdRevenueListener {
|
|
200
|
+
override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
|
|
201
|
+
dispatchAdEvent(CloudXAdEvents.ON_AD_VIEW_REVENUE_PAID_EVENT, adInfoPayload(cloudXAd))
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/*
|
|
206
|
+
* Codegen cannot express Record<string,string>, so ad values are serialized
|
|
207
|
+
* to a JSON string here and re-parsed by the JS wrapper.
|
|
208
|
+
*/
|
|
209
|
+
private fun adInfoPayload(ad: CloudXAd): WritableMap {
|
|
210
|
+
val map = Arguments.createMap()
|
|
211
|
+
map.putString("adUnitId", ad.adUnitId)
|
|
212
|
+
map.putString("adFormat", ad.adFormat.name)
|
|
213
|
+
map.putString("networkName", ad.networkName)
|
|
214
|
+
map.putString("networkPlacement", ad.networkPlacement ?: "")
|
|
215
|
+
map.putString("placement", ad.placement ?: "")
|
|
216
|
+
map.putDouble("revenue", ad.revenue)
|
|
217
|
+
/*
|
|
218
|
+
* The SDK types adValues as Map<String, String>, so the cast is safe
|
|
219
|
+
* today. Guard defensively anyway: an unexpected type or serialization
|
|
220
|
+
* failure here would otherwise crash the ad listener. Log rather than
|
|
221
|
+
* swallow silently so a genuine SDK contract change stays visible.
|
|
222
|
+
*/
|
|
223
|
+
val adValuesJson = try {
|
|
224
|
+
JSONObject(ad.adValues as Map<*, *>).toString()
|
|
225
|
+
} catch (e: Exception) {
|
|
226
|
+
Log.w(TAG, "Failed to serialize adValues; delivering empty object", e)
|
|
227
|
+
"{}"
|
|
228
|
+
}
|
|
229
|
+
map.putString("adValuesJson", adValuesJson)
|
|
230
|
+
return map
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private fun loadFailedPayload(failedAdUnitId: String, error: CloudXError): WritableMap {
|
|
234
|
+
val map = Arguments.createMap()
|
|
235
|
+
map.putString("adUnitId", failedAdUnitId)
|
|
236
|
+
/*
|
|
237
|
+
* Codegen spec declares `code` as Double; emit a double to match (and
|
|
238
|
+
* to stay consistent with `revenue` and the iOS side).
|
|
239
|
+
*/
|
|
240
|
+
map.putDouble("code", error.code.code.toDouble())
|
|
241
|
+
map.putString("message", error.message)
|
|
242
|
+
return map
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.WritableMap
|
|
4
|
+
import com.facebook.react.uimanager.events.Event
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A per-view direct event for the in-tree CloudXAdView. The event name doubles
|
|
8
|
+
* as the JS prop registrationName (see CloudXAdViewManagerImpl).
|
|
9
|
+
*/
|
|
10
|
+
class CloudXAdViewEvent(
|
|
11
|
+
surfaceId: Int,
|
|
12
|
+
viewId: Int,
|
|
13
|
+
private val eventName: String,
|
|
14
|
+
private val payload: WritableMap,
|
|
15
|
+
) : Event<CloudXAdViewEvent>(surfaceId, viewId) {
|
|
16
|
+
|
|
17
|
+
override fun getEventName(): String = eventName
|
|
18
|
+
|
|
19
|
+
override fun getEventData(): WritableMap = payload
|
|
20
|
+
|
|
21
|
+
/*
|
|
22
|
+
* Ad-lifecycle events are discrete and must never be dropped. The default
|
|
23
|
+
* (true) lets the dispatcher coalesce events sharing the same
|
|
24
|
+
* (eventName, viewId) within a batch, keeping only the latest - which would
|
|
25
|
+
* silently drop, e.g., back-to-back revenue events on the same view.
|
|
26
|
+
*/
|
|
27
|
+
override fun canCoalesce(): Boolean = false
|
|
28
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.common.MapBuilder
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shared logic for the CloudXAdView view manager, used by both the Old (Paper)
|
|
9
|
+
* and New (Fabric) architecture manager variants under src/oldarch and src/newarch.
|
|
10
|
+
*/
|
|
11
|
+
object CloudXAdViewManagerImpl {
|
|
12
|
+
|
|
13
|
+
const val NAME = "CloudXAdView"
|
|
14
|
+
|
|
15
|
+
fun createViewInstance(reactContext: ThemedReactContext): CloudXAdView = CloudXAdView(reactContext)
|
|
16
|
+
|
|
17
|
+
fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =
|
|
18
|
+
MapBuilder.builder<String, Any>()
|
|
19
|
+
.put(CloudXAdEvents.ON_AD_VIEW_LOADED_EVENT, eventRegistration(CloudXAdEvents.ON_AD_VIEW_LOADED_EVENT))
|
|
20
|
+
.put(CloudXAdEvents.ON_AD_VIEW_LOAD_FAILED_EVENT, eventRegistration(CloudXAdEvents.ON_AD_VIEW_LOAD_FAILED_EVENT))
|
|
21
|
+
.put(CloudXAdEvents.ON_AD_VIEW_CLICKED_EVENT, eventRegistration(CloudXAdEvents.ON_AD_VIEW_CLICKED_EVENT))
|
|
22
|
+
.put(CloudXAdEvents.ON_AD_VIEW_REVENUE_PAID_EVENT, eventRegistration(CloudXAdEvents.ON_AD_VIEW_REVENUE_PAID_EVENT))
|
|
23
|
+
.build()
|
|
24
|
+
|
|
25
|
+
private fun eventRegistration(name: String): Map<String, String> = MapBuilder.of("registrationName", name)
|
|
26
|
+
|
|
27
|
+
fun setAdUnitId(view: CloudXAdView, adUnitId: String?) {
|
|
28
|
+
view.adUnitId = adUnitId
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
fun setAdFormat(view: CloudXAdView, adFormat: String?) {
|
|
32
|
+
view.adFormat = adFormat
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fun setPlacement(view: CloudXAdView, placement: String?) {
|
|
36
|
+
view.placement = placement
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun setCustomData(view: CloudXAdView, customData: String?) {
|
|
40
|
+
view.customData = customData
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fun setExtraParameters(view: CloudXAdView, extraParameters: ReadableArray?) {
|
|
44
|
+
view.extraParameters = CloudXExtraParameters.entryArrayToMap(extraParameters)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fun onAfterUpdateTransaction(view: CloudXAdView) {
|
|
48
|
+
view.onSetProps()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
fun onDropViewInstance(view: CloudXAdView) {
|
|
52
|
+
view.destroyAdView()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import com.facebook.react.bridge.ReadableMap
|
|
5
|
+
import com.facebook.react.bridge.ReadableType
|
|
6
|
+
import io.cloudx.sdk.CloudXAdView as SdkAdView
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Shared conversion and application helpers for CloudX extra parameters.
|
|
10
|
+
*
|
|
11
|
+
* Programmatic APIs receive a [ReadableMap], while component props receive a
|
|
12
|
+
* [ReadableArray] of key/value entries from codegen. Both paths normalize into
|
|
13
|
+
* Kotlin values before calling the same SDK setter behavior.
|
|
14
|
+
*/
|
|
15
|
+
object CloudXExtraParameters {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Iterates a programmatic [ReadableMap], ignoring blank keys and preserving
|
|
19
|
+
* nested arrays/maps as Kotlin collections.
|
|
20
|
+
*/
|
|
21
|
+
fun forEach(extraParameters: ReadableMap, apply: (String, Any?) -> Unit) {
|
|
22
|
+
val iterator = extraParameters.keySetIterator()
|
|
23
|
+
while (iterator.hasNextKey()) {
|
|
24
|
+
val key = iterator.nextKey()
|
|
25
|
+
if (key.isBlank()) continue
|
|
26
|
+
apply(key, readableMapValue(extraParameters, key))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Converts component prop entries into a key/value map that can be diffed
|
|
32
|
+
* by the owning component view before being applied.
|
|
33
|
+
*/
|
|
34
|
+
fun entryArrayToMap(extraParameters: ReadableArray?): Map<String, Any?> {
|
|
35
|
+
if (extraParameters == null) {
|
|
36
|
+
return emptyMap()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
val result = linkedMapOf<String, Any?>()
|
|
40
|
+
for (index in 0 until extraParameters.size()) {
|
|
41
|
+
if (extraParameters.getType(index) != ReadableType.Map) continue
|
|
42
|
+
|
|
43
|
+
val entry = extraParameters.getMap(index) ?: continue
|
|
44
|
+
if (!entry.hasKey("key") || entry.getType("key") != ReadableType.String) continue
|
|
45
|
+
|
|
46
|
+
val key = entry.getString("key") ?: continue
|
|
47
|
+
if (key.isBlank()) continue
|
|
48
|
+
result[key] = if (entry.hasKey("value")) readableMapValue(entry, "value") else null
|
|
49
|
+
}
|
|
50
|
+
return result
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Applies already-normalized extra parameters to [adView].
|
|
55
|
+
*/
|
|
56
|
+
fun applyToAdView(adView: SdkAdView, extraParameters: Map<String, Any?>) {
|
|
57
|
+
for ((key, value) in extraParameters) {
|
|
58
|
+
adView.setExtraParameter(key, value)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private fun readableMapValue(map: ReadableMap, key: String): Any? {
|
|
63
|
+
return when (map.getType(key)) {
|
|
64
|
+
ReadableType.Null -> null
|
|
65
|
+
ReadableType.Boolean -> map.getBoolean(key)
|
|
66
|
+
ReadableType.Number -> map.getDouble(key)
|
|
67
|
+
ReadableType.String -> map.getString(key)
|
|
68
|
+
ReadableType.Map -> map.getMap(key)?.let(::readableMapToMap)
|
|
69
|
+
ReadableType.Array -> map.getArray(key)?.let(::readableArrayToList)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private fun readableMapToMap(readableMap: ReadableMap): Map<String, Any?> {
|
|
74
|
+
val result = mutableMapOf<String, Any?>()
|
|
75
|
+
val iterator = readableMap.keySetIterator()
|
|
76
|
+
while (iterator.hasNextKey()) {
|
|
77
|
+
val key = iterator.nextKey()
|
|
78
|
+
result[key] = readableMapValue(readableMap, key)
|
|
79
|
+
}
|
|
80
|
+
return result
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private fun readableArrayToList(readableArray: ReadableArray): List<Any?> {
|
|
84
|
+
val result = mutableListOf<Any?>()
|
|
85
|
+
for (index in 0 until readableArray.size()) {
|
|
86
|
+
result.add(readableArrayValue(readableArray, index))
|
|
87
|
+
}
|
|
88
|
+
return result
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private fun readableArrayValue(array: ReadableArray, index: Int): Any? {
|
|
92
|
+
return when (array.getType(index)) {
|
|
93
|
+
ReadableType.Null -> null
|
|
94
|
+
ReadableType.Boolean -> array.getBoolean(index)
|
|
95
|
+
ReadableType.Number -> array.getDouble(index)
|
|
96
|
+
ReadableType.String -> array.getString(index)
|
|
97
|
+
ReadableType.Map -> array.getMap(index)?.let(::readableMapToMap)
|
|
98
|
+
ReadableType.Array -> array.getArray(index)?.let(::readableArrayToList)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -13,7 +13,6 @@ import com.facebook.react.bridge.Arguments
|
|
|
13
13
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
14
14
|
import com.facebook.react.bridge.Promise
|
|
15
15
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
16
|
-
import com.facebook.react.bridge.ReadableArray
|
|
17
16
|
import com.facebook.react.bridge.ReadableMap
|
|
18
17
|
import com.facebook.react.bridge.ReadableType
|
|
19
18
|
import com.facebook.react.bridge.WritableMap
|
|
@@ -229,7 +228,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
fun setInterstitialExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
232
|
-
|
|
231
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
233
232
|
retrieveInterstitial(adUnitId).setExtraParameter(key, value)
|
|
234
233
|
}
|
|
235
234
|
}
|
|
@@ -269,7 +268,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
269
268
|
}
|
|
270
269
|
|
|
271
270
|
fun setRewardedExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
272
|
-
|
|
271
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
273
272
|
retrieveRewarded(adUnitId).setExtraParameter(key, value)
|
|
274
273
|
}
|
|
275
274
|
}
|
|
@@ -458,14 +457,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
458
457
|
reactApplicationContext.runOnUiQueueThread {
|
|
459
458
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
460
459
|
if (adView != null) {
|
|
461
|
-
|
|
460
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
462
461
|
adView.setExtraParameter(key, value)
|
|
463
462
|
}
|
|
464
463
|
return@runOnUiQueueThread
|
|
465
464
|
}
|
|
466
465
|
|
|
467
466
|
val pending = adViewExtraParameters.getOrPut(adUnitId) { ConcurrentHashMap() }
|
|
468
|
-
|
|
467
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
469
468
|
if (value == null) {
|
|
470
469
|
pending.remove(key)
|
|
471
470
|
} else {
|
|
@@ -477,58 +476,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
477
476
|
|
|
478
477
|
private fun applyPendingExtraParameters(adUnitId: String, adView: SdkAdView) {
|
|
479
478
|
val pending = adViewExtraParameters[adUnitId] ?: return
|
|
480
|
-
|
|
481
|
-
adView.setExtraParameter(key, value)
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
private fun applyExtraParameters(extraParameters: ReadableMap, apply: (String, Any?) -> Unit) {
|
|
486
|
-
val iterator = extraParameters.keySetIterator()
|
|
487
|
-
while (iterator.hasNextKey()) {
|
|
488
|
-
val key = iterator.nextKey()
|
|
489
|
-
if (key.isBlank()) continue
|
|
490
|
-
apply(key, readableMapValue(extraParameters, key))
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
private fun readableMapValue(map: ReadableMap, key: String): Any? {
|
|
495
|
-
return when (map.getType(key)) {
|
|
496
|
-
ReadableType.Null -> null
|
|
497
|
-
ReadableType.Boolean -> map.getBoolean(key)
|
|
498
|
-
ReadableType.Number -> map.getDouble(key)
|
|
499
|
-
ReadableType.String -> map.getString(key)
|
|
500
|
-
ReadableType.Map -> map.getMap(key)?.let(::readableMapToMap)
|
|
501
|
-
ReadableType.Array -> map.getArray(key)?.let(::readableArrayToList)
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
private fun readableMapToMap(readableMap: ReadableMap): Map<String, Any?> {
|
|
506
|
-
val result = mutableMapOf<String, Any?>()
|
|
507
|
-
val iterator = readableMap.keySetIterator()
|
|
508
|
-
while (iterator.hasNextKey()) {
|
|
509
|
-
val key = iterator.nextKey()
|
|
510
|
-
result[key] = readableMapValue(readableMap, key)
|
|
511
|
-
}
|
|
512
|
-
return result
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
private fun readableArrayToList(readableArray: ReadableArray): List<Any?> {
|
|
516
|
-
val result = mutableListOf<Any?>()
|
|
517
|
-
for (index in 0 until readableArray.size()) {
|
|
518
|
-
result.add(readableArrayValue(readableArray, index))
|
|
519
|
-
}
|
|
520
|
-
return result
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
private fun readableArrayValue(array: ReadableArray, index: Int): Any? {
|
|
524
|
-
return when (array.getType(index)) {
|
|
525
|
-
ReadableType.Null -> null
|
|
526
|
-
ReadableType.Boolean -> array.getBoolean(index)
|
|
527
|
-
ReadableType.Number -> array.getDouble(index)
|
|
528
|
-
ReadableType.String -> array.getString(index)
|
|
529
|
-
ReadableType.Map -> array.getMap(index)?.let(::readableMapToMap)
|
|
530
|
-
ReadableType.Array -> array.getArray(index)?.let(::readableArrayToList)
|
|
531
|
-
}
|
|
479
|
+
CloudXExtraParameters.applyToAdView(adView, pending)
|
|
532
480
|
}
|
|
533
481
|
|
|
534
482
|
private fun arbiterBids(configuration: ReadableMap): List<CloudXArbiterBid> {
|
|
@@ -9,7 +9,7 @@ import com.facebook.react.uimanager.ViewManager
|
|
|
9
9
|
|
|
10
10
|
class CloudXPackage : TurboReactPackage() {
|
|
11
11
|
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
12
|
-
return
|
|
12
|
+
return listOf(CloudXAdViewManager())
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
4
|
+
import com.facebook.react.bridge.ReadableArray
|
|
5
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
6
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
7
|
+
import com.facebook.react.uimanager.ViewManagerDelegate
|
|
8
|
+
import com.facebook.react.viewmanagers.CloudXAdViewManagerDelegate
|
|
9
|
+
import com.facebook.react.viewmanagers.CloudXAdViewManagerInterface
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* New-Architecture (Fabric) view manager for CloudXAdView. Props are routed
|
|
13
|
+
* through the codegen-generated delegate/interface; all logic delegates to the
|
|
14
|
+
* shared CloudXAdViewManagerImpl.
|
|
15
|
+
*/
|
|
16
|
+
@ReactModule(name = CloudXAdViewManagerImpl.NAME)
|
|
17
|
+
class CloudXAdViewManager :
|
|
18
|
+
SimpleViewManager<CloudXAdView>(),
|
|
19
|
+
CloudXAdViewManagerInterface<CloudXAdView> {
|
|
20
|
+
|
|
21
|
+
private val delegate = CloudXAdViewManagerDelegate(this)
|
|
22
|
+
|
|
23
|
+
override fun getDelegate(): ViewManagerDelegate<CloudXAdView> = delegate
|
|
24
|
+
|
|
25
|
+
override fun getName(): String = CloudXAdViewManagerImpl.NAME
|
|
26
|
+
|
|
27
|
+
override fun createViewInstance(reactContext: ThemedReactContext): CloudXAdView =
|
|
28
|
+
CloudXAdViewManagerImpl.createViewInstance(reactContext)
|
|
29
|
+
|
|
30
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =
|
|
31
|
+
CloudXAdViewManagerImpl.getExportedCustomDirectEventTypeConstants()
|
|
32
|
+
|
|
33
|
+
override fun setAdUnitId(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setAdUnitId(view, value)
|
|
34
|
+
|
|
35
|
+
override fun setAdFormat(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setAdFormat(view, value)
|
|
36
|
+
|
|
37
|
+
override fun setPlacement(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setPlacement(view, value)
|
|
38
|
+
|
|
39
|
+
override fun setCustomData(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setCustomData(view, value)
|
|
40
|
+
|
|
41
|
+
override fun setExtraParameters(view: CloudXAdView, value: ReadableArray?) = CloudXAdViewManagerImpl.setExtraParameters(view, value)
|
|
42
|
+
|
|
43
|
+
override fun onAfterUpdateTransaction(view: CloudXAdView) {
|
|
44
|
+
super.onAfterUpdateTransaction(view)
|
|
45
|
+
CloudXAdViewManagerImpl.onAfterUpdateTransaction(view)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
override fun onDropViewInstance(view: CloudXAdView) {
|
|
49
|
+
CloudXAdViewManagerImpl.onDropViewInstance(view)
|
|
50
|
+
super.onDropViewInstance(view)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
package com.cloudxreactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReadableArray
|
|
4
|
+
import com.facebook.react.uimanager.SimpleViewManager
|
|
5
|
+
import com.facebook.react.uimanager.ThemedReactContext
|
|
6
|
+
import com.facebook.react.uimanager.annotations.ReactProp
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Old-Architecture (Paper) view manager for CloudXAdView. Props are wired via
|
|
10
|
+
* [ReactProp]; all logic delegates to the shared CloudXAdViewManagerImpl.
|
|
11
|
+
*/
|
|
12
|
+
class CloudXAdViewManager : SimpleViewManager<CloudXAdView>() {
|
|
13
|
+
|
|
14
|
+
override fun getName(): String = CloudXAdViewManagerImpl.NAME
|
|
15
|
+
|
|
16
|
+
override fun createViewInstance(reactContext: ThemedReactContext): CloudXAdView =
|
|
17
|
+
CloudXAdViewManagerImpl.createViewInstance(reactContext)
|
|
18
|
+
|
|
19
|
+
override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> =
|
|
20
|
+
CloudXAdViewManagerImpl.getExportedCustomDirectEventTypeConstants()
|
|
21
|
+
|
|
22
|
+
@ReactProp(name = "adUnitId")
|
|
23
|
+
fun setAdUnitId(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setAdUnitId(view, value)
|
|
24
|
+
|
|
25
|
+
@ReactProp(name = "adFormat")
|
|
26
|
+
fun setAdFormat(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setAdFormat(view, value)
|
|
27
|
+
|
|
28
|
+
@ReactProp(name = "placement")
|
|
29
|
+
fun setPlacement(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setPlacement(view, value)
|
|
30
|
+
|
|
31
|
+
@ReactProp(name = "customData")
|
|
32
|
+
fun setCustomData(view: CloudXAdView, value: String?) = CloudXAdViewManagerImpl.setCustomData(view, value)
|
|
33
|
+
|
|
34
|
+
@ReactProp(name = "extraParameters")
|
|
35
|
+
fun setExtraParameters(view: CloudXAdView, value: ReadableArray?) = CloudXAdViewManagerImpl.setExtraParameters(view, value)
|
|
36
|
+
|
|
37
|
+
override fun onAfterUpdateTransaction(view: CloudXAdView) {
|
|
38
|
+
super.onAfterUpdateTransaction(view)
|
|
39
|
+
CloudXAdViewManagerImpl.onAfterUpdateTransaction(view)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun onDropViewInstance(view: CloudXAdView) {
|
|
43
|
+
CloudXAdViewManagerImpl.onDropViewInstance(view)
|
|
44
|
+
super.onDropViewInstance(view)
|
|
45
|
+
}
|
|
46
|
+
}
|