cloudx-react-native 3.7.0 → 3.10.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/android/build.gradle +2 -1
- package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +1 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXAdView.kt +1 -0
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +185 -101
- package/android/src/newarch/com/cloudxreactnative/CloudXModule.kt +1 -0
- package/android/src/oldarch/com/cloudxreactnative/CloudXModule.kt +1 -0
- package/android/src/test/java/com/cloudxreactnative/CloudXModuleImplArbiterBidsTest.kt +3 -3
- package/android/src/test/java/com/cloudxreactnative/CloudXModuleImplThreadingTest.kt +261 -0
- package/android/src/test/java/com/cloudxreactnative/FakeReadable.kt +2 -2
- package/cloudx-react-native.podspec +2 -1
- package/ios/CloudX.mm +6 -0
- package/ios/CloudXAdView.mm +2 -0
- package/ios/PrivacyInfo.xcprivacy +20 -0
- package/lib/commonjs/CloudX.js +4 -0
- package/lib/commonjs/CloudX.js.map +1 -1
- package/lib/commonjs/CloudXAdViewBase.js +1 -0
- package/lib/commonjs/CloudXAdViewBase.js.map +1 -1
- package/lib/commonjs/CloudXErrorCode.js +2 -0
- package/lib/commonjs/CloudXErrorCode.js.map +1 -1
- package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +1 -1
- package/lib/commonjs/specs/NativeCloudX.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/module/CloudX.js +4 -0
- package/lib/module/CloudX.js.map +1 -1
- package/lib/module/CloudXAdViewBase.js +1 -0
- package/lib/module/CloudXAdViewBase.js.map +1 -1
- package/lib/module/CloudXErrorCode.js +2 -0
- package/lib/module/CloudXErrorCode.js.map +1 -1
- package/lib/module/specs/CloudXAdViewNativeComponent.js.map +1 -1
- package/lib/module/specs/NativeCloudX.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/src/CloudX.d.ts.map +1 -1
- package/lib/typescript/src/CloudXAdViewBase.d.ts.map +1 -1
- package/lib/typescript/src/CloudXErrorCode.d.ts +2 -0
- package/lib/typescript/src/CloudXErrorCode.d.ts.map +1 -1
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +1 -0
- package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeCloudX.d.ts +1 -0
- package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -1
- package/lib/typescript/src/types/AdInfo.d.ts +2 -0
- package/lib/typescript/src/types/AdInfo.d.ts.map +1 -1
- package/lib/typescript/src/types/CloudX.d.ts +2 -0
- package/lib/typescript/src/types/CloudX.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/lib/typescript/src/version.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/CloudX.ts +5 -0
- package/src/CloudXAdViewBase.tsx +1 -0
- package/src/CloudXErrorCode.ts +3 -0
- package/src/specs/CloudXAdViewNativeComponent.ts +1 -0
- package/src/specs/NativeCloudX.ts +1 -0
- package/src/types/AdInfo.ts +3 -0
- package/src/types/CloudX.ts +3 -0
- package/src/version.ts +1 -1
package/android/build.gradle
CHANGED
|
@@ -158,8 +158,9 @@ repositories {
|
|
|
158
158
|
dependencies {
|
|
159
159
|
implementation "com.facebook.react:react-native:0.76.2"
|
|
160
160
|
|
|
161
|
-
implementation "io.cloudx:sdk:4.
|
|
161
|
+
implementation "io.cloudx:sdk:4.9.0"
|
|
162
162
|
|
|
163
163
|
testImplementation "junit:junit:4.13.2"
|
|
164
164
|
testImplementation "io.mockk:mockk:1.13.10"
|
|
165
|
+
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2"
|
|
165
166
|
}
|
|
@@ -12,6 +12,7 @@ fun getAdInfo(ad: CloudXAd): WritableMap {
|
|
|
12
12
|
map.putString("networkName", ad.networkName)
|
|
13
13
|
map.putString("networkPlacement", ad.networkPlacement ?: "")
|
|
14
14
|
map.putString("placement", ad.placement ?: "")
|
|
15
|
+
map.putString("creativeId", ad.creativeId ?: "")
|
|
15
16
|
map.putDouble("revenue", ad.revenue)
|
|
16
17
|
map.putMap("adValues", ad.adValues.toWritableMap())
|
|
17
18
|
return map
|
|
@@ -209,6 +209,7 @@ class CloudXAdView(private val reactContext: ThemedReactContext) : FrameLayout(r
|
|
|
209
209
|
map.putString("networkName", ad.networkName)
|
|
210
210
|
map.putString("networkPlacement", ad.networkPlacement ?: "")
|
|
211
211
|
map.putString("placement", ad.placement ?: "")
|
|
212
|
+
map.putString("creativeId", ad.creativeId ?: "")
|
|
212
213
|
map.putDouble("revenue", ad.revenue)
|
|
213
214
|
/*
|
|
214
215
|
* The SDK types adValues as Map<String, String>, so the cast is safe
|
|
@@ -9,6 +9,7 @@ import android.view.View
|
|
|
9
9
|
import android.view.ViewGroup
|
|
10
10
|
import android.widget.LinearLayout
|
|
11
11
|
import android.widget.RelativeLayout
|
|
12
|
+
import androidx.annotation.VisibleForTesting
|
|
12
13
|
import com.facebook.react.bridge.Arguments
|
|
13
14
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
14
15
|
import com.facebook.react.bridge.Promise
|
|
@@ -87,42 +88,79 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
87
88
|
return currentActivity
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
// =========================================================================
|
|
92
|
+
// Threading
|
|
93
|
+
// =========================================================================
|
|
94
|
+
|
|
95
|
+
/*
|
|
96
|
+
* Every public module method runs its whole body on the UI thread, including reads of the
|
|
97
|
+
* module's own state. React Native invokes Android native-module methods on a shared
|
|
98
|
+
* background thread, so a method that did work inline could execute before a previously
|
|
99
|
+
* posted one (e.g. loadInterstitial() running on an instance that a queued
|
|
100
|
+
* destroyInterstitial() then destroys). Posting everything here keeps JS call order intact,
|
|
101
|
+
* makes the lazy retrieveX() create paths single-threaded, and matches the iOS module, whose
|
|
102
|
+
* methodQueue is the main queue.
|
|
103
|
+
*/
|
|
104
|
+
private inline fun onUiThread(crossinline block: () -> Unit) {
|
|
105
|
+
reactApplicationContext.runOnUiQueueThread { block() }
|
|
106
|
+
}
|
|
107
|
+
|
|
90
108
|
// =========================================================================
|
|
91
109
|
// Initialization
|
|
92
110
|
// =========================================================================
|
|
93
111
|
|
|
94
112
|
fun isInitialized(promise: Promise) {
|
|
95
|
-
|
|
113
|
+
onUiThread {
|
|
114
|
+
promise.resolve(CloudX.isInitialized())
|
|
115
|
+
}
|
|
96
116
|
}
|
|
97
117
|
|
|
98
|
-
fun
|
|
99
|
-
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
CloudX.initialize(reactApplicationContext, config, object : CloudXInitializationListener {
|
|
104
|
-
override fun onInitialized(configuration: CloudXSdkConfiguration) {
|
|
105
|
-
setupOrientationListener()
|
|
106
|
-
val result = Arguments.createMap()
|
|
107
|
-
result.putBoolean("success", true)
|
|
108
|
-
result.putString("message", "SDK initialized successfully")
|
|
109
|
-
promise.resolve(result)
|
|
118
|
+
fun showMediationDebugger(promise: Promise) {
|
|
119
|
+
onUiThread {
|
|
120
|
+
if (!CloudX.isInitialized()) {
|
|
121
|
+
promise.resolve(false)
|
|
122
|
+
return@onUiThread
|
|
110
123
|
}
|
|
111
124
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
CloudX.showMediationDebugger(maybeGetCurrentActivity() ?: reactApplicationContext)
|
|
126
|
+
promise.resolve(true)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fun initialize(pluginVersion: String, appKey: String, promise: Promise) {
|
|
131
|
+
onUiThread {
|
|
132
|
+
val config = CloudXInitializationConfiguration.builder(appKey)
|
|
133
|
+
.setPluginVersion(pluginVersion)
|
|
134
|
+
.build()
|
|
135
|
+
|
|
136
|
+
CloudX.initialize(reactApplicationContext, config, object : CloudXInitializationListener {
|
|
137
|
+
override fun onInitialized(configuration: CloudXSdkConfiguration) {
|
|
138
|
+
setupOrientationListener()
|
|
139
|
+
val result = Arguments.createMap()
|
|
140
|
+
result.putBoolean("success", true)
|
|
141
|
+
result.putString("message", "SDK initialized successfully")
|
|
142
|
+
promise.resolve(result)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
override fun onInitializationFailed(cloudXError: CloudXError) {
|
|
146
|
+
Log.e(TAG, "CloudX SDK initialization failed: ${cloudXError.message}")
|
|
147
|
+
promise.reject(cloudXError.code.name, cloudXError.message, null)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
}
|
|
117
151
|
}
|
|
118
152
|
|
|
119
153
|
fun isTablet(promise: Promise) {
|
|
120
|
-
|
|
121
|
-
|
|
154
|
+
onUiThread {
|
|
155
|
+
val isTablet = reactApplicationContext.resources.configuration.smallestScreenWidthDp >= 600
|
|
156
|
+
promise.resolve(isTablet)
|
|
157
|
+
}
|
|
122
158
|
}
|
|
123
159
|
|
|
124
160
|
fun getVersion(promise: Promise) {
|
|
125
|
-
|
|
161
|
+
onUiThread {
|
|
162
|
+
promise.resolve(CloudX.getVersion())
|
|
163
|
+
}
|
|
126
164
|
}
|
|
127
165
|
|
|
128
166
|
// =========================================================================
|
|
@@ -130,16 +168,18 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
130
168
|
// =========================================================================
|
|
131
169
|
|
|
132
170
|
fun setMinLogLevel(level: String) {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
171
|
+
onUiThread {
|
|
172
|
+
val logLevel = when (level.lowercase()) {
|
|
173
|
+
"verbose" -> CloudXLogLevel.VERBOSE
|
|
174
|
+
"debug" -> CloudXLogLevel.DEBUG
|
|
175
|
+
"info" -> CloudXLogLevel.INFO
|
|
176
|
+
"warn" -> CloudXLogLevel.WARN
|
|
177
|
+
"error" -> CloudXLogLevel.ERROR
|
|
178
|
+
"none" -> CloudXLogLevel.NONE
|
|
179
|
+
else -> CloudXLogLevel.INFO
|
|
180
|
+
}
|
|
181
|
+
CloudX.setMinLogLevel(logLevel)
|
|
141
182
|
}
|
|
142
|
-
CloudX.setMinLogLevel(logLevel)
|
|
143
183
|
}
|
|
144
184
|
|
|
145
185
|
fun setVisualDebuggingEnabled(enabled: Boolean) {
|
|
@@ -151,19 +191,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
151
191
|
// =========================================================================
|
|
152
192
|
|
|
153
193
|
fun setHashedUserID(hashedUserID: String) {
|
|
154
|
-
|
|
194
|
+
onUiThread {
|
|
195
|
+
CloudX.setHashedUserId(hashedUserID)
|
|
196
|
+
}
|
|
155
197
|
}
|
|
156
198
|
|
|
157
199
|
fun setUserKeyValue(key: String, value: String) {
|
|
158
|
-
|
|
200
|
+
onUiThread {
|
|
201
|
+
CloudX.setUserKeyValue(key, value)
|
|
202
|
+
}
|
|
159
203
|
}
|
|
160
204
|
|
|
161
205
|
fun setAppKeyValue(key: String, value: String) {
|
|
162
|
-
|
|
206
|
+
onUiThread {
|
|
207
|
+
CloudX.setAppKeyValue(key, value)
|
|
208
|
+
}
|
|
163
209
|
}
|
|
164
210
|
|
|
165
211
|
fun clearAllKeyValues() {
|
|
166
|
-
|
|
212
|
+
onUiThread {
|
|
213
|
+
CloudX.clearAllKeyValues()
|
|
214
|
+
}
|
|
167
215
|
}
|
|
168
216
|
|
|
169
217
|
// =========================================================================
|
|
@@ -171,11 +219,15 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
171
219
|
// =========================================================================
|
|
172
220
|
|
|
173
221
|
fun setHasUserConsent(hasUserConsent: Boolean?) {
|
|
174
|
-
|
|
222
|
+
onUiThread {
|
|
223
|
+
CloudX.setHasUserConsent(hasUserConsent)
|
|
224
|
+
}
|
|
175
225
|
}
|
|
176
226
|
|
|
177
227
|
fun setDoNotSell(isDoNotSell: Boolean?) {
|
|
178
|
-
|
|
228
|
+
onUiThread {
|
|
229
|
+
CloudX.setDoNotSell(isDoNotSell)
|
|
230
|
+
}
|
|
179
231
|
}
|
|
180
232
|
|
|
181
233
|
// =========================================================================
|
|
@@ -183,27 +235,31 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
183
235
|
// =========================================================================
|
|
184
236
|
|
|
185
237
|
fun arbiter(configuration: ReadableMap, promise: Promise) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
val arbiterConfiguration = CloudXArbiterConfiguration.builder(bids).build()
|
|
193
|
-
CloudX.arbiter(arbiterConfiguration, object : CloudXArbiterListener {
|
|
194
|
-
override fun onCompleted(result: CloudXArbiterResult) {
|
|
195
|
-
promise.resolve(result.toWritableMap())
|
|
238
|
+
onUiThread {
|
|
239
|
+
val bids = arbiterBids(configuration)
|
|
240
|
+
if (bids.isEmpty()) {
|
|
241
|
+
promise.resolve(emptyArbiterResult())
|
|
242
|
+
return@onUiThread
|
|
196
243
|
}
|
|
197
|
-
|
|
244
|
+
|
|
245
|
+
val arbiterConfiguration = CloudXArbiterConfiguration.builder(bids).build()
|
|
246
|
+
CloudX.arbiter(arbiterConfiguration, object : CloudXArbiterListener {
|
|
247
|
+
override fun onCompleted(result: CloudXArbiterResult) {
|
|
248
|
+
promise.resolve(result.toWritableMap())
|
|
249
|
+
}
|
|
250
|
+
})
|
|
251
|
+
}
|
|
198
252
|
}
|
|
199
253
|
|
|
200
254
|
fun reportRevenueData(data: ReadableMap, promise: Promise) {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
255
|
+
onUiThread {
|
|
256
|
+
val revenueData = data.toRevenueData()
|
|
257
|
+
if (revenueData == null) {
|
|
258
|
+
promise.resolve(false)
|
|
259
|
+
return@onUiThread
|
|
260
|
+
}
|
|
261
|
+
promise.resolve(CloudX.reportRevenueData(revenueData))
|
|
205
262
|
}
|
|
206
|
-
promise.resolve(CloudX.reportRevenueData(revenueData))
|
|
207
263
|
}
|
|
208
264
|
|
|
209
265
|
// =========================================================================
|
|
@@ -216,8 +272,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
216
272
|
fun setBannerPlacement(adUnitId: String, placement: String?) = setAdViewPlacement(adUnitId, CloudXAdFormat.BANNER, placement)
|
|
217
273
|
fun setBannerCustomData(adUnitId: String, customData: String?) = setAdViewCustomData(adUnitId, CloudXAdFormat.BANNER, customData)
|
|
218
274
|
fun setBannerExtraParameters(adUnitId: String, extraParameters: ReadableMap) = setAdViewExtraParameters(adUnitId, CloudXAdFormat.BANNER, extraParameters)
|
|
219
|
-
fun updateBannerPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER, position,
|
|
220
|
-
fun updateBannerOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER,
|
|
275
|
+
fun updateBannerPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER, position, null)
|
|
276
|
+
fun updateBannerOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER, null, Pair(xOffset.toFloat(), yOffset.toFloat()))
|
|
221
277
|
fun startBannerAutoRefresh(adUnitId: String) = startAdViewAutoRefresh(adUnitId, CloudXAdFormat.BANNER)
|
|
222
278
|
fun stopBannerAutoRefresh(adUnitId: String) = stopAdViewAutoRefresh(adUnitId, CloudXAdFormat.BANNER)
|
|
223
279
|
fun showBanner(adUnitId: String) = showAdView(adUnitId, CloudXAdFormat.BANNER)
|
|
@@ -234,8 +290,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
234
290
|
fun setMRECPlacement(adUnitId: String, placement: String?) = setAdViewPlacement(adUnitId, CloudXAdFormat.MREC, placement)
|
|
235
291
|
fun setMRECCustomData(adUnitId: String, customData: String?) = setAdViewCustomData(adUnitId, CloudXAdFormat.MREC, customData)
|
|
236
292
|
fun setMRECExtraParameters(adUnitId: String, extraParameters: ReadableMap) = setAdViewExtraParameters(adUnitId, CloudXAdFormat.MREC, extraParameters)
|
|
237
|
-
fun updateMRECPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC, position,
|
|
238
|
-
fun updateMRECOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC,
|
|
293
|
+
fun updateMRECPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC, position, null)
|
|
294
|
+
fun updateMRECOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC, null, Pair(xOffset.toFloat(), yOffset.toFloat()))
|
|
239
295
|
fun startMRECAutoRefresh(adUnitId: String) = startAdViewAutoRefresh(adUnitId, CloudXAdFormat.MREC)
|
|
240
296
|
fun stopMRECAutoRefresh(adUnitId: String) = stopAdViewAutoRefresh(adUnitId, CloudXAdFormat.MREC)
|
|
241
297
|
fun showMREC(adUnitId: String) = showAdView(adUnitId, CloudXAdFormat.MREC)
|
|
@@ -247,21 +303,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
247
303
|
// =========================================================================
|
|
248
304
|
|
|
249
305
|
fun loadInterstitial(adUnitId: String) {
|
|
250
|
-
|
|
306
|
+
onUiThread {
|
|
307
|
+
retrieveInterstitial(adUnitId).load()
|
|
308
|
+
}
|
|
251
309
|
}
|
|
252
310
|
|
|
253
311
|
fun setInterstitialExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
254
|
-
|
|
255
|
-
|
|
312
|
+
onUiThread {
|
|
313
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
314
|
+
retrieveInterstitial(adUnitId).setExtraParameter(key, value)
|
|
315
|
+
}
|
|
256
316
|
}
|
|
257
317
|
}
|
|
258
318
|
|
|
259
319
|
fun isInterstitialReady(adUnitId: String, promise: Promise) {
|
|
260
|
-
|
|
320
|
+
onUiThread {
|
|
321
|
+
promise.resolve(retrieveInterstitial(adUnitId).isAdReady)
|
|
322
|
+
}
|
|
261
323
|
}
|
|
262
324
|
|
|
263
325
|
fun showInterstitial(adUnitId: String, placement: String?, customData: String?) {
|
|
264
|
-
|
|
326
|
+
onUiThread {
|
|
265
327
|
val interstitial = retrieveInterstitial(adUnitId)
|
|
266
328
|
val activity = maybeGetCurrentActivity()
|
|
267
329
|
if (activity == null) {
|
|
@@ -270,14 +332,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
270
332
|
CloudXAdEvents.ON_INTERSTITIAL_DISPLAY_FAILED_EVENT,
|
|
271
333
|
getNoActivityDisplayFailedInfo(adUnitId),
|
|
272
334
|
)
|
|
273
|
-
return@
|
|
335
|
+
return@onUiThread
|
|
274
336
|
}
|
|
275
337
|
interstitial.show(activity, placement, customData)
|
|
276
338
|
}
|
|
277
339
|
}
|
|
278
340
|
|
|
279
341
|
fun destroyInterstitial(adUnitId: String) {
|
|
280
|
-
|
|
342
|
+
onUiThread {
|
|
281
343
|
interstitials.remove(adUnitId)?.let {
|
|
282
344
|
it.listener = null
|
|
283
345
|
it.revenueListener = null
|
|
@@ -291,21 +353,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
291
353
|
// =========================================================================
|
|
292
354
|
|
|
293
355
|
fun loadAppOpen(adUnitId: String) {
|
|
294
|
-
|
|
356
|
+
onUiThread {
|
|
357
|
+
retrieveAppOpen(adUnitId).load()
|
|
358
|
+
}
|
|
295
359
|
}
|
|
296
360
|
|
|
297
361
|
fun setAppOpenExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
298
|
-
|
|
299
|
-
|
|
362
|
+
onUiThread {
|
|
363
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
364
|
+
retrieveAppOpen(adUnitId).setExtraParameter(key, value)
|
|
365
|
+
}
|
|
300
366
|
}
|
|
301
367
|
}
|
|
302
368
|
|
|
303
369
|
fun isAppOpenReady(adUnitId: String, promise: Promise) {
|
|
304
|
-
|
|
370
|
+
onUiThread {
|
|
371
|
+
promise.resolve(retrieveAppOpen(adUnitId).isAdReady)
|
|
372
|
+
}
|
|
305
373
|
}
|
|
306
374
|
|
|
307
375
|
fun showAppOpen(adUnitId: String, placement: String?, customData: String?) {
|
|
308
|
-
|
|
376
|
+
onUiThread {
|
|
309
377
|
val appOpen = retrieveAppOpen(adUnitId)
|
|
310
378
|
val activity = maybeGetCurrentActivity()
|
|
311
379
|
if (activity == null) {
|
|
@@ -314,14 +382,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
314
382
|
CloudXAdEvents.ON_APPOPEN_DISPLAY_FAILED_EVENT,
|
|
315
383
|
getNoActivityDisplayFailedInfo(adUnitId),
|
|
316
384
|
)
|
|
317
|
-
return@
|
|
385
|
+
return@onUiThread
|
|
318
386
|
}
|
|
319
387
|
appOpen.show(activity, placement, customData)
|
|
320
388
|
}
|
|
321
389
|
}
|
|
322
390
|
|
|
323
391
|
fun destroyAppOpen(adUnitId: String) {
|
|
324
|
-
|
|
392
|
+
onUiThread {
|
|
325
393
|
appOpenAds.remove(adUnitId)?.let {
|
|
326
394
|
it.listener = null
|
|
327
395
|
it.revenueListener = null
|
|
@@ -335,21 +403,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
335
403
|
// =========================================================================
|
|
336
404
|
|
|
337
405
|
fun loadRewarded(adUnitId: String) {
|
|
338
|
-
|
|
406
|
+
onUiThread {
|
|
407
|
+
retrieveRewarded(adUnitId).load()
|
|
408
|
+
}
|
|
339
409
|
}
|
|
340
410
|
|
|
341
411
|
fun setRewardedExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
342
|
-
|
|
343
|
-
|
|
412
|
+
onUiThread {
|
|
413
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
414
|
+
retrieveRewarded(adUnitId).setExtraParameter(key, value)
|
|
415
|
+
}
|
|
344
416
|
}
|
|
345
417
|
}
|
|
346
418
|
|
|
347
419
|
fun isRewardedReady(adUnitId: String, promise: Promise) {
|
|
348
|
-
|
|
420
|
+
onUiThread {
|
|
421
|
+
promise.resolve(retrieveRewarded(adUnitId).isAdReady)
|
|
422
|
+
}
|
|
349
423
|
}
|
|
350
424
|
|
|
351
425
|
fun showRewarded(adUnitId: String, placement: String?, customData: String?) {
|
|
352
|
-
|
|
426
|
+
onUiThread {
|
|
353
427
|
val rewarded = retrieveRewarded(adUnitId)
|
|
354
428
|
val activity = maybeGetCurrentActivity()
|
|
355
429
|
if (activity == null) {
|
|
@@ -358,14 +432,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
358
432
|
CloudXAdEvents.ON_REWARDED_AD_DISPLAY_FAILED_EVENT,
|
|
359
433
|
getNoActivityDisplayFailedInfo(adUnitId),
|
|
360
434
|
)
|
|
361
|
-
return@
|
|
435
|
+
return@onUiThread
|
|
362
436
|
}
|
|
363
437
|
rewarded.show(activity, placement, customData)
|
|
364
438
|
}
|
|
365
439
|
}
|
|
366
440
|
|
|
367
441
|
fun destroyRewarded(adUnitId: String) {
|
|
368
|
-
|
|
442
|
+
onUiThread {
|
|
369
443
|
rewardedAds.remove(adUnitId)?.let {
|
|
370
444
|
it.listener = null
|
|
371
445
|
it.revenueListener = null
|
|
@@ -513,7 +587,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
513
587
|
|
|
514
588
|
private fun createAdView(adUnitId: String, adFormat: CloudXAdFormat, position: String, xOffset: Double, yOffset: Double) {
|
|
515
589
|
// Run on main thread to ensure there are no concurrency issues with other ad view methods
|
|
516
|
-
|
|
590
|
+
onUiThread {
|
|
517
591
|
// Intentionally load the ad view while detached from any window.
|
|
518
592
|
// Attaching-then-hiding-then-loading causes the underlying banner
|
|
519
593
|
// to take a prefetch code path whose hidden->visible transition
|
|
@@ -522,7 +596,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
522
596
|
// (~30s). Detached loads use the "display when added to a window"
|
|
523
597
|
// path, so showAdView attaches and displays immediately.
|
|
524
598
|
val adView = retrieveAdView(adUnitId, adFormat, position, Pair(xOffset.toFloat(), yOffset.toFloat()))
|
|
525
|
-
?: return@
|
|
599
|
+
?: return@onUiThread
|
|
526
600
|
|
|
527
601
|
adViewAdFormats[adUnitId] = adFormat
|
|
528
602
|
applyPendingExtraParameters(adUnitId, adView)
|
|
@@ -538,27 +612,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
538
612
|
}
|
|
539
613
|
|
|
540
614
|
private fun setAdViewPlacement(adUnitId: String, adFormat: CloudXAdFormat, placement: String?) {
|
|
541
|
-
|
|
542
|
-
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@
|
|
615
|
+
onUiThread {
|
|
616
|
+
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@onUiThread
|
|
543
617
|
adView.setPlacement(placement)
|
|
544
618
|
}
|
|
545
619
|
}
|
|
546
620
|
|
|
547
621
|
private fun setAdViewCustomData(adUnitId: String, adFormat: CloudXAdFormat, customData: String?) {
|
|
548
|
-
|
|
549
|
-
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@
|
|
622
|
+
onUiThread {
|
|
623
|
+
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@onUiThread
|
|
550
624
|
adView.setCustomData(customData)
|
|
551
625
|
}
|
|
552
626
|
}
|
|
553
627
|
|
|
554
628
|
private fun setAdViewExtraParameters(adUnitId: String, adFormat: CloudXAdFormat, extraParameters: ReadableMap) {
|
|
555
|
-
|
|
629
|
+
onUiThread {
|
|
556
630
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
557
631
|
if (adView != null) {
|
|
558
632
|
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
559
633
|
adView.setExtraParameter(key, value)
|
|
560
634
|
}
|
|
561
|
-
return@
|
|
635
|
+
return@onUiThread
|
|
562
636
|
}
|
|
563
637
|
|
|
564
638
|
val pending = adViewExtraParameters.getOrPut(adUnitId) { ConcurrentHashMap() }
|
|
@@ -840,21 +914,29 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
840
914
|
override val adValues: Map<String, String>,
|
|
841
915
|
) : CloudXAd
|
|
842
916
|
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
917
|
+
/*
|
|
918
|
+
* A null [position] or [offsetsDp] means "keep the current value". The current value is read
|
|
919
|
+
* inside the posted block, so a position update followed by an offsets update from JS cannot
|
|
920
|
+
* overwrite the first call's position with the value that was current before it ran.
|
|
921
|
+
*/
|
|
922
|
+
private fun updateAdViewPosition(adUnitId: String, adFormat: CloudXAdFormat, position: String?, offsetsDp: Pair<Float, Float>?) {
|
|
923
|
+
onUiThread {
|
|
924
|
+
val adView = retrieveAdView(adUnitId, adFormat) ?: return@onUiThread
|
|
925
|
+
adViewPositions[adUnitId] = position ?: adViewPositions[adUnitId] ?: return@onUiThread
|
|
926
|
+
adViewOffsetsDp[adUnitId] = offsetsDp ?: adViewOffsetsDp[adUnitId] ?: DEFAULT_AD_VIEW_OFFSET_DP
|
|
848
927
|
positionAdView(adUnitId, adFormat)
|
|
849
928
|
}
|
|
850
929
|
}
|
|
851
930
|
|
|
931
|
+
@VisibleForTesting
|
|
932
|
+
internal fun adViewPositionForTesting(adUnitId: String): String? = adViewPositions[adUnitId]
|
|
933
|
+
|
|
852
934
|
private fun showAdView(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
853
|
-
|
|
935
|
+
onUiThread {
|
|
854
936
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
855
937
|
if (adView == null) {
|
|
856
938
|
adUnitIdsToShowAfterCreate.add(adUnitId)
|
|
857
|
-
return@
|
|
939
|
+
return@onUiThread
|
|
858
940
|
}
|
|
859
941
|
|
|
860
942
|
// Lazily attach and position on first show. Attaching here — not
|
|
@@ -872,18 +954,18 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
872
954
|
}
|
|
873
955
|
|
|
874
956
|
private fun hideAdView(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
875
|
-
|
|
957
|
+
onUiThread {
|
|
876
958
|
adUnitIdsToShowAfterCreate.remove(adUnitId)
|
|
877
|
-
val adView = retrieveAdView(adUnitId, adFormat) ?: return@
|
|
959
|
+
val adView = retrieveAdView(adUnitId, adFormat) ?: return@onUiThread
|
|
878
960
|
adView.visibility = View.GONE
|
|
879
961
|
adView.stopAutoRefresh()
|
|
880
962
|
}
|
|
881
963
|
}
|
|
882
964
|
|
|
883
965
|
private fun destroyAdView(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
884
|
-
|
|
966
|
+
onUiThread {
|
|
885
967
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
886
|
-
if (adView == null) return@
|
|
968
|
+
if (adView == null) return@onUiThread
|
|
887
969
|
|
|
888
970
|
val parent = adView.parent
|
|
889
971
|
if (parent is ViewGroup) {
|
|
@@ -904,8 +986,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
904
986
|
}
|
|
905
987
|
|
|
906
988
|
private fun setAdViewBackgroundColor(adUnitId: String, adFormat: CloudXAdFormat, hexColorString: String) {
|
|
907
|
-
|
|
908
|
-
val adView = retrieveAdView(adUnitId, adFormat) ?: return@
|
|
989
|
+
onUiThread {
|
|
990
|
+
val adView = retrieveAdView(adUnitId, adFormat) ?: return@onUiThread
|
|
909
991
|
try {
|
|
910
992
|
adView.setBackgroundColor(Color.parseColor(hexColorString))
|
|
911
993
|
} catch (e: IllegalArgumentException) {
|
|
@@ -915,11 +997,11 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
915
997
|
}
|
|
916
998
|
|
|
917
999
|
private fun startAdViewAutoRefresh(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
918
|
-
|
|
1000
|
+
onUiThread { retrieveAdView(adUnitId, adFormat)?.startAutoRefresh() }
|
|
919
1001
|
}
|
|
920
1002
|
|
|
921
1003
|
private fun stopAdViewAutoRefresh(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
922
|
-
|
|
1004
|
+
onUiThread { retrieveAdView(adUnitId, adFormat)?.stopAutoRefresh() }
|
|
923
1005
|
}
|
|
924
1006
|
|
|
925
1007
|
// =========================================================================
|
|
@@ -1099,13 +1181,15 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
1099
1181
|
override fun onHostPause() {}
|
|
1100
1182
|
|
|
1101
1183
|
override fun onHostDestroy() {
|
|
1184
|
+
// React Native drops its Activity here, so the cached one must go too.
|
|
1185
|
+
currentActivity = null
|
|
1102
1186
|
// Make copy because destroyAdView() removes from adViews
|
|
1103
1187
|
val adViewsCopy = HashMap(adViewAdFormats)
|
|
1104
1188
|
for ((adUnitId, adFormat) in adViewsCopy) {
|
|
1105
1189
|
destroyAdView(adUnitId, adFormat)
|
|
1106
1190
|
}
|
|
1107
1191
|
|
|
1108
|
-
|
|
1192
|
+
onUiThread {
|
|
1109
1193
|
for (interstitial in interstitials.values) {
|
|
1110
1194
|
interstitial.destroy()
|
|
1111
1195
|
}
|
|
@@ -17,6 +17,7 @@ class CloudXModule(reactContext: ReactApplicationContext) :
|
|
|
17
17
|
|
|
18
18
|
@ReactMethod override fun isInitialized(promise: Promise) = impl.isInitialized(promise)
|
|
19
19
|
@ReactMethod override fun initialize(pluginVersion: String, appKey: String, promise: Promise) = impl.initialize(pluginVersion, appKey, promise)
|
|
20
|
+
@ReactMethod override fun showMediationDebugger(promise: Promise) = impl.showMediationDebugger(promise)
|
|
20
21
|
@ReactMethod override fun isTablet(promise: Promise) = impl.isTablet(promise)
|
|
21
22
|
@ReactMethod override fun getVersion(promise: Promise) = impl.getVersion(promise)
|
|
22
23
|
|
|
@@ -16,6 +16,7 @@ class CloudXModule(reactContext: ReactApplicationContext) :
|
|
|
16
16
|
|
|
17
17
|
@ReactMethod fun isInitialized(promise: Promise) = impl.isInitialized(promise)
|
|
18
18
|
@ReactMethod fun initialize(pluginVersion: String, appKey: String, promise: Promise) = impl.initialize(pluginVersion, appKey, promise)
|
|
19
|
+
@ReactMethod fun showMediationDebugger(promise: Promise) = impl.showMediationDebugger(promise)
|
|
19
20
|
@ReactMethod fun isTablet(promise: Promise) = impl.isTablet(promise)
|
|
20
21
|
@ReactMethod fun getVersion(promise: Promise) = impl.getVersion(promise)
|
|
21
22
|
|
|
@@ -141,7 +141,7 @@ class CloudXModuleImplArbiterBidsTest {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
@Test
|
|
144
|
-
fun `
|
|
144
|
+
fun `drops a negative manual price`() {
|
|
145
145
|
val bids = bidsFrom(
|
|
146
146
|
mapOf(
|
|
147
147
|
"platform" to "ADMOB",
|
|
@@ -150,8 +150,8 @@ class CloudXModuleImplArbiterBidsTest {
|
|
|
150
150
|
)
|
|
151
151
|
)
|
|
152
152
|
|
|
153
|
-
// The wrapper
|
|
154
|
-
|
|
153
|
+
// The wrapper forwards the value unchanged; the native AdMob bid factory drops negative prices.
|
|
154
|
+
assertNull(bids[0].field("manualRevenuePerImpressionUSD"))
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
@Test
|