cloudx-react-native 3.6.1 → 3.8.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 +92 -2
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +2 -2
- package/android/src/main/java/com/cloudxreactnative/CloudXAdViewManagerImpl.kt +6 -6
- package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +208 -102
- package/android/src/test/java/com/cloudxreactnative/CloudXModuleImplArbiterBidsTest.kt +254 -0
- package/android/src/test/java/com/cloudxreactnative/CloudXModuleImplThreadingTest.kt +170 -0
- package/android/src/test/java/com/cloudxreactnative/FakeReadable.kt +101 -0
- package/cloudx-react-native.podspec +1 -1
- package/ios/CloudX.mm +62 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/types/Arbiter.js +27 -0
- package/lib/commonjs/types/Arbiter.js.map +1 -1
- package/lib/commonjs/types/RevenueData.js +1 -0
- package/lib/commonjs/types/RevenueData.js.map +1 -1
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/types/Arbiter.js +27 -0
- package/lib/module/types/Arbiter.js.map +1 -1
- package/lib/module/types/RevenueData.js +1 -0
- package/lib/module/types/RevenueData.js.map +1 -1
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types/Arbiter.d.ts +45 -2
- package/lib/typescript/src/types/Arbiter.d.ts.map +1 -1
- package/lib/typescript/src/types/RevenueData.d.ts +1 -0
- package/lib/typescript/src/types/RevenueData.d.ts.map +1 -1
- package/lib/typescript/src/types/index.d.ts +1 -1
- package/lib/typescript/src/types/index.d.ts.map +1 -1
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/types/Arbiter.ts +61 -2
- package/src/types/RevenueData.ts +1 -0
- package/src/types/index.ts +2 -0
- package/src/version.ts +1 -1
|
@@ -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
|
|
@@ -71,6 +72,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
71
72
|
|
|
72
73
|
companion object {
|
|
73
74
|
private const val TAG = "CloudX"
|
|
75
|
+
private const val ADMOB_DEFAULT_NETWORK_NAME = "admob"
|
|
76
|
+
private const val GAM_DEFAULT_NETWORK_NAME = "gam"
|
|
74
77
|
const val MODULE_NAME = "CloudX"
|
|
75
78
|
}
|
|
76
79
|
|
|
@@ -85,42 +88,67 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
85
88
|
return currentActivity
|
|
86
89
|
}
|
|
87
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
|
+
|
|
88
108
|
// =========================================================================
|
|
89
109
|
// Initialization
|
|
90
110
|
// =========================================================================
|
|
91
111
|
|
|
92
112
|
fun isInitialized(promise: Promise) {
|
|
93
|
-
|
|
113
|
+
onUiThread {
|
|
114
|
+
promise.resolve(CloudX.isInitialized())
|
|
115
|
+
}
|
|
94
116
|
}
|
|
95
117
|
|
|
96
118
|
fun initialize(pluginVersion: String, appKey: String, promise: Promise) {
|
|
97
|
-
|
|
98
|
-
.
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
119
|
+
onUiThread {
|
|
120
|
+
val config = CloudXInitializationConfiguration.builder(appKey)
|
|
121
|
+
.setPluginVersion(pluginVersion)
|
|
122
|
+
.build()
|
|
123
|
+
|
|
124
|
+
CloudX.initialize(reactApplicationContext, config, object : CloudXInitializationListener {
|
|
125
|
+
override fun onInitialized(configuration: CloudXSdkConfiguration) {
|
|
126
|
+
setupOrientationListener()
|
|
127
|
+
val result = Arguments.createMap()
|
|
128
|
+
result.putBoolean("success", true)
|
|
129
|
+
result.putString("message", "SDK initialized successfully")
|
|
130
|
+
promise.resolve(result)
|
|
131
|
+
}
|
|
109
132
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
133
|
+
override fun onInitializationFailed(cloudXError: CloudXError) {
|
|
134
|
+
Log.e(TAG, "CloudX SDK initialization failed: ${cloudXError.message}")
|
|
135
|
+
promise.reject(cloudXError.code.name, cloudXError.message, null)
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
}
|
|
115
139
|
}
|
|
116
140
|
|
|
117
141
|
fun isTablet(promise: Promise) {
|
|
118
|
-
|
|
119
|
-
|
|
142
|
+
onUiThread {
|
|
143
|
+
val isTablet = reactApplicationContext.resources.configuration.smallestScreenWidthDp >= 600
|
|
144
|
+
promise.resolve(isTablet)
|
|
145
|
+
}
|
|
120
146
|
}
|
|
121
147
|
|
|
122
148
|
fun getVersion(promise: Promise) {
|
|
123
|
-
|
|
149
|
+
onUiThread {
|
|
150
|
+
promise.resolve(CloudX.getVersion())
|
|
151
|
+
}
|
|
124
152
|
}
|
|
125
153
|
|
|
126
154
|
// =========================================================================
|
|
@@ -128,16 +156,18 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
128
156
|
// =========================================================================
|
|
129
157
|
|
|
130
158
|
fun setMinLogLevel(level: String) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
159
|
+
onUiThread {
|
|
160
|
+
val logLevel = when (level.lowercase()) {
|
|
161
|
+
"verbose" -> CloudXLogLevel.VERBOSE
|
|
162
|
+
"debug" -> CloudXLogLevel.DEBUG
|
|
163
|
+
"info" -> CloudXLogLevel.INFO
|
|
164
|
+
"warn" -> CloudXLogLevel.WARN
|
|
165
|
+
"error" -> CloudXLogLevel.ERROR
|
|
166
|
+
"none" -> CloudXLogLevel.NONE
|
|
167
|
+
else -> CloudXLogLevel.INFO
|
|
168
|
+
}
|
|
169
|
+
CloudX.setMinLogLevel(logLevel)
|
|
139
170
|
}
|
|
140
|
-
CloudX.setMinLogLevel(logLevel)
|
|
141
171
|
}
|
|
142
172
|
|
|
143
173
|
fun setVisualDebuggingEnabled(enabled: Boolean) {
|
|
@@ -149,19 +179,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
149
179
|
// =========================================================================
|
|
150
180
|
|
|
151
181
|
fun setHashedUserID(hashedUserID: String) {
|
|
152
|
-
|
|
182
|
+
onUiThread {
|
|
183
|
+
CloudX.setHashedUserId(hashedUserID)
|
|
184
|
+
}
|
|
153
185
|
}
|
|
154
186
|
|
|
155
187
|
fun setUserKeyValue(key: String, value: String) {
|
|
156
|
-
|
|
188
|
+
onUiThread {
|
|
189
|
+
CloudX.setUserKeyValue(key, value)
|
|
190
|
+
}
|
|
157
191
|
}
|
|
158
192
|
|
|
159
193
|
fun setAppKeyValue(key: String, value: String) {
|
|
160
|
-
|
|
194
|
+
onUiThread {
|
|
195
|
+
CloudX.setAppKeyValue(key, value)
|
|
196
|
+
}
|
|
161
197
|
}
|
|
162
198
|
|
|
163
199
|
fun clearAllKeyValues() {
|
|
164
|
-
|
|
200
|
+
onUiThread {
|
|
201
|
+
CloudX.clearAllKeyValues()
|
|
202
|
+
}
|
|
165
203
|
}
|
|
166
204
|
|
|
167
205
|
// =========================================================================
|
|
@@ -169,11 +207,15 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
169
207
|
// =========================================================================
|
|
170
208
|
|
|
171
209
|
fun setHasUserConsent(hasUserConsent: Boolean?) {
|
|
172
|
-
|
|
210
|
+
onUiThread {
|
|
211
|
+
CloudX.setHasUserConsent(hasUserConsent)
|
|
212
|
+
}
|
|
173
213
|
}
|
|
174
214
|
|
|
175
215
|
fun setDoNotSell(isDoNotSell: Boolean?) {
|
|
176
|
-
|
|
216
|
+
onUiThread {
|
|
217
|
+
CloudX.setDoNotSell(isDoNotSell)
|
|
218
|
+
}
|
|
177
219
|
}
|
|
178
220
|
|
|
179
221
|
// =========================================================================
|
|
@@ -181,27 +223,31 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
181
223
|
// =========================================================================
|
|
182
224
|
|
|
183
225
|
fun arbiter(configuration: ReadableMap, promise: Promise) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
val arbiterConfiguration = CloudXArbiterConfiguration.builder(bids).build()
|
|
191
|
-
CloudX.arbiter(arbiterConfiguration, object : CloudXArbiterListener {
|
|
192
|
-
override fun onCompleted(result: CloudXArbiterResult) {
|
|
193
|
-
promise.resolve(result.toWritableMap())
|
|
226
|
+
onUiThread {
|
|
227
|
+
val bids = arbiterBids(configuration)
|
|
228
|
+
if (bids.isEmpty()) {
|
|
229
|
+
promise.resolve(emptyArbiterResult())
|
|
230
|
+
return@onUiThread
|
|
194
231
|
}
|
|
195
|
-
|
|
232
|
+
|
|
233
|
+
val arbiterConfiguration = CloudXArbiterConfiguration.builder(bids).build()
|
|
234
|
+
CloudX.arbiter(arbiterConfiguration, object : CloudXArbiterListener {
|
|
235
|
+
override fun onCompleted(result: CloudXArbiterResult) {
|
|
236
|
+
promise.resolve(result.toWritableMap())
|
|
237
|
+
}
|
|
238
|
+
})
|
|
239
|
+
}
|
|
196
240
|
}
|
|
197
241
|
|
|
198
242
|
fun reportRevenueData(data: ReadableMap, promise: Promise) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
243
|
+
onUiThread {
|
|
244
|
+
val revenueData = data.toRevenueData()
|
|
245
|
+
if (revenueData == null) {
|
|
246
|
+
promise.resolve(false)
|
|
247
|
+
return@onUiThread
|
|
248
|
+
}
|
|
249
|
+
promise.resolve(CloudX.reportRevenueData(revenueData))
|
|
203
250
|
}
|
|
204
|
-
promise.resolve(CloudX.reportRevenueData(revenueData))
|
|
205
251
|
}
|
|
206
252
|
|
|
207
253
|
// =========================================================================
|
|
@@ -214,8 +260,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
214
260
|
fun setBannerPlacement(adUnitId: String, placement: String?) = setAdViewPlacement(adUnitId, CloudXAdFormat.BANNER, placement)
|
|
215
261
|
fun setBannerCustomData(adUnitId: String, customData: String?) = setAdViewCustomData(adUnitId, CloudXAdFormat.BANNER, customData)
|
|
216
262
|
fun setBannerExtraParameters(adUnitId: String, extraParameters: ReadableMap) = setAdViewExtraParameters(adUnitId, CloudXAdFormat.BANNER, extraParameters)
|
|
217
|
-
fun updateBannerPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER, position,
|
|
218
|
-
fun updateBannerOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER,
|
|
263
|
+
fun updateBannerPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER, position, null)
|
|
264
|
+
fun updateBannerOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.BANNER, null, Pair(xOffset.toFloat(), yOffset.toFloat()))
|
|
219
265
|
fun startBannerAutoRefresh(adUnitId: String) = startAdViewAutoRefresh(adUnitId, CloudXAdFormat.BANNER)
|
|
220
266
|
fun stopBannerAutoRefresh(adUnitId: String) = stopAdViewAutoRefresh(adUnitId, CloudXAdFormat.BANNER)
|
|
221
267
|
fun showBanner(adUnitId: String) = showAdView(adUnitId, CloudXAdFormat.BANNER)
|
|
@@ -232,8 +278,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
232
278
|
fun setMRECPlacement(adUnitId: String, placement: String?) = setAdViewPlacement(adUnitId, CloudXAdFormat.MREC, placement)
|
|
233
279
|
fun setMRECCustomData(adUnitId: String, customData: String?) = setAdViewCustomData(adUnitId, CloudXAdFormat.MREC, customData)
|
|
234
280
|
fun setMRECExtraParameters(adUnitId: String, extraParameters: ReadableMap) = setAdViewExtraParameters(adUnitId, CloudXAdFormat.MREC, extraParameters)
|
|
235
|
-
fun updateMRECPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC, position,
|
|
236
|
-
fun updateMRECOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC,
|
|
281
|
+
fun updateMRECPosition(adUnitId: String, position: String) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC, position, null)
|
|
282
|
+
fun updateMRECOffsets(adUnitId: String, xOffset: Double, yOffset: Double) = updateAdViewPosition(adUnitId, CloudXAdFormat.MREC, null, Pair(xOffset.toFloat(), yOffset.toFloat()))
|
|
237
283
|
fun startMRECAutoRefresh(adUnitId: String) = startAdViewAutoRefresh(adUnitId, CloudXAdFormat.MREC)
|
|
238
284
|
fun stopMRECAutoRefresh(adUnitId: String) = stopAdViewAutoRefresh(adUnitId, CloudXAdFormat.MREC)
|
|
239
285
|
fun showMREC(adUnitId: String) = showAdView(adUnitId, CloudXAdFormat.MREC)
|
|
@@ -245,21 +291,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
245
291
|
// =========================================================================
|
|
246
292
|
|
|
247
293
|
fun loadInterstitial(adUnitId: String) {
|
|
248
|
-
|
|
294
|
+
onUiThread {
|
|
295
|
+
retrieveInterstitial(adUnitId).load()
|
|
296
|
+
}
|
|
249
297
|
}
|
|
250
298
|
|
|
251
299
|
fun setInterstitialExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
252
|
-
|
|
253
|
-
|
|
300
|
+
onUiThread {
|
|
301
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
302
|
+
retrieveInterstitial(adUnitId).setExtraParameter(key, value)
|
|
303
|
+
}
|
|
254
304
|
}
|
|
255
305
|
}
|
|
256
306
|
|
|
257
307
|
fun isInterstitialReady(adUnitId: String, promise: Promise) {
|
|
258
|
-
|
|
308
|
+
onUiThread {
|
|
309
|
+
promise.resolve(retrieveInterstitial(adUnitId).isAdReady)
|
|
310
|
+
}
|
|
259
311
|
}
|
|
260
312
|
|
|
261
313
|
fun showInterstitial(adUnitId: String, placement: String?, customData: String?) {
|
|
262
|
-
|
|
314
|
+
onUiThread {
|
|
263
315
|
val interstitial = retrieveInterstitial(adUnitId)
|
|
264
316
|
val activity = maybeGetCurrentActivity()
|
|
265
317
|
if (activity == null) {
|
|
@@ -268,14 +320,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
268
320
|
CloudXAdEvents.ON_INTERSTITIAL_DISPLAY_FAILED_EVENT,
|
|
269
321
|
getNoActivityDisplayFailedInfo(adUnitId),
|
|
270
322
|
)
|
|
271
|
-
return@
|
|
323
|
+
return@onUiThread
|
|
272
324
|
}
|
|
273
325
|
interstitial.show(activity, placement, customData)
|
|
274
326
|
}
|
|
275
327
|
}
|
|
276
328
|
|
|
277
329
|
fun destroyInterstitial(adUnitId: String) {
|
|
278
|
-
|
|
330
|
+
onUiThread {
|
|
279
331
|
interstitials.remove(adUnitId)?.let {
|
|
280
332
|
it.listener = null
|
|
281
333
|
it.revenueListener = null
|
|
@@ -289,21 +341,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
289
341
|
// =========================================================================
|
|
290
342
|
|
|
291
343
|
fun loadAppOpen(adUnitId: String) {
|
|
292
|
-
|
|
344
|
+
onUiThread {
|
|
345
|
+
retrieveAppOpen(adUnitId).load()
|
|
346
|
+
}
|
|
293
347
|
}
|
|
294
348
|
|
|
295
349
|
fun setAppOpenExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
296
|
-
|
|
297
|
-
|
|
350
|
+
onUiThread {
|
|
351
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
352
|
+
retrieveAppOpen(adUnitId).setExtraParameter(key, value)
|
|
353
|
+
}
|
|
298
354
|
}
|
|
299
355
|
}
|
|
300
356
|
|
|
301
357
|
fun isAppOpenReady(adUnitId: String, promise: Promise) {
|
|
302
|
-
|
|
358
|
+
onUiThread {
|
|
359
|
+
promise.resolve(retrieveAppOpen(adUnitId).isAdReady)
|
|
360
|
+
}
|
|
303
361
|
}
|
|
304
362
|
|
|
305
363
|
fun showAppOpen(adUnitId: String, placement: String?, customData: String?) {
|
|
306
|
-
|
|
364
|
+
onUiThread {
|
|
307
365
|
val appOpen = retrieveAppOpen(adUnitId)
|
|
308
366
|
val activity = maybeGetCurrentActivity()
|
|
309
367
|
if (activity == null) {
|
|
@@ -312,14 +370,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
312
370
|
CloudXAdEvents.ON_APPOPEN_DISPLAY_FAILED_EVENT,
|
|
313
371
|
getNoActivityDisplayFailedInfo(adUnitId),
|
|
314
372
|
)
|
|
315
|
-
return@
|
|
373
|
+
return@onUiThread
|
|
316
374
|
}
|
|
317
375
|
appOpen.show(activity, placement, customData)
|
|
318
376
|
}
|
|
319
377
|
}
|
|
320
378
|
|
|
321
379
|
fun destroyAppOpen(adUnitId: String) {
|
|
322
|
-
|
|
380
|
+
onUiThread {
|
|
323
381
|
appOpenAds.remove(adUnitId)?.let {
|
|
324
382
|
it.listener = null
|
|
325
383
|
it.revenueListener = null
|
|
@@ -333,21 +391,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
333
391
|
// =========================================================================
|
|
334
392
|
|
|
335
393
|
fun loadRewarded(adUnitId: String) {
|
|
336
|
-
|
|
394
|
+
onUiThread {
|
|
395
|
+
retrieveRewarded(adUnitId).load()
|
|
396
|
+
}
|
|
337
397
|
}
|
|
338
398
|
|
|
339
399
|
fun setRewardedExtraParameters(adUnitId: String, extraParameters: ReadableMap) {
|
|
340
|
-
|
|
341
|
-
|
|
400
|
+
onUiThread {
|
|
401
|
+
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
402
|
+
retrieveRewarded(adUnitId).setExtraParameter(key, value)
|
|
403
|
+
}
|
|
342
404
|
}
|
|
343
405
|
}
|
|
344
406
|
|
|
345
407
|
fun isRewardedReady(adUnitId: String, promise: Promise) {
|
|
346
|
-
|
|
408
|
+
onUiThread {
|
|
409
|
+
promise.resolve(retrieveRewarded(adUnitId).isAdReady)
|
|
410
|
+
}
|
|
347
411
|
}
|
|
348
412
|
|
|
349
413
|
fun showRewarded(adUnitId: String, placement: String?, customData: String?) {
|
|
350
|
-
|
|
414
|
+
onUiThread {
|
|
351
415
|
val rewarded = retrieveRewarded(adUnitId)
|
|
352
416
|
val activity = maybeGetCurrentActivity()
|
|
353
417
|
if (activity == null) {
|
|
@@ -356,14 +420,14 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
356
420
|
CloudXAdEvents.ON_REWARDED_AD_DISPLAY_FAILED_EVENT,
|
|
357
421
|
getNoActivityDisplayFailedInfo(adUnitId),
|
|
358
422
|
)
|
|
359
|
-
return@
|
|
423
|
+
return@onUiThread
|
|
360
424
|
}
|
|
361
425
|
rewarded.show(activity, placement, customData)
|
|
362
426
|
}
|
|
363
427
|
}
|
|
364
428
|
|
|
365
429
|
fun destroyRewarded(adUnitId: String) {
|
|
366
|
-
|
|
430
|
+
onUiThread {
|
|
367
431
|
rewardedAds.remove(adUnitId)?.let {
|
|
368
432
|
it.listener = null
|
|
369
433
|
it.revenueListener = null
|
|
@@ -511,7 +575,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
511
575
|
|
|
512
576
|
private fun createAdView(adUnitId: String, adFormat: CloudXAdFormat, position: String, xOffset: Double, yOffset: Double) {
|
|
513
577
|
// Run on main thread to ensure there are no concurrency issues with other ad view methods
|
|
514
|
-
|
|
578
|
+
onUiThread {
|
|
515
579
|
// Intentionally load the ad view while detached from any window.
|
|
516
580
|
// Attaching-then-hiding-then-loading causes the underlying banner
|
|
517
581
|
// to take a prefetch code path whose hidden->visible transition
|
|
@@ -520,7 +584,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
520
584
|
// (~30s). Detached loads use the "display when added to a window"
|
|
521
585
|
// path, so showAdView attaches and displays immediately.
|
|
522
586
|
val adView = retrieveAdView(adUnitId, adFormat, position, Pair(xOffset.toFloat(), yOffset.toFloat()))
|
|
523
|
-
?: return@
|
|
587
|
+
?: return@onUiThread
|
|
524
588
|
|
|
525
589
|
adViewAdFormats[adUnitId] = adFormat
|
|
526
590
|
applyPendingExtraParameters(adUnitId, adView)
|
|
@@ -536,27 +600,27 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
536
600
|
}
|
|
537
601
|
|
|
538
602
|
private fun setAdViewPlacement(adUnitId: String, adFormat: CloudXAdFormat, placement: String?) {
|
|
539
|
-
|
|
540
|
-
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@
|
|
603
|
+
onUiThread {
|
|
604
|
+
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@onUiThread
|
|
541
605
|
adView.setPlacement(placement)
|
|
542
606
|
}
|
|
543
607
|
}
|
|
544
608
|
|
|
545
609
|
private fun setAdViewCustomData(adUnitId: String, adFormat: CloudXAdFormat, customData: String?) {
|
|
546
|
-
|
|
547
|
-
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@
|
|
610
|
+
onUiThread {
|
|
611
|
+
val adView = retrieveAdView(adUnitId, adFormat, "", DEFAULT_AD_VIEW_OFFSET_DP) ?: return@onUiThread
|
|
548
612
|
adView.setCustomData(customData)
|
|
549
613
|
}
|
|
550
614
|
}
|
|
551
615
|
|
|
552
616
|
private fun setAdViewExtraParameters(adUnitId: String, adFormat: CloudXAdFormat, extraParameters: ReadableMap) {
|
|
553
|
-
|
|
617
|
+
onUiThread {
|
|
554
618
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
555
619
|
if (adView != null) {
|
|
556
620
|
CloudXExtraParameters.forEach(extraParameters) { key, value ->
|
|
557
621
|
adView.setExtraParameter(key, value)
|
|
558
622
|
}
|
|
559
|
-
return@
|
|
623
|
+
return@onUiThread
|
|
560
624
|
}
|
|
561
625
|
|
|
562
626
|
val pending = adViewExtraParameters.getOrPut(adUnitId) { ConcurrentHashMap() }
|
|
@@ -575,7 +639,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
575
639
|
CloudXExtraParameters.applyToAdView(adView, pending)
|
|
576
640
|
}
|
|
577
641
|
|
|
578
|
-
private
|
|
642
|
+
// internal rather than private so unit tests can exercise bid parsing directly.
|
|
643
|
+
internal fun arbiterBids(configuration: ReadableMap): List<CloudXArbiterBid> {
|
|
579
644
|
if (!configuration.hasKey("bids") || configuration.getType("bids") != ReadableType.Array) {
|
|
580
645
|
return emptyList()
|
|
581
646
|
}
|
|
@@ -603,6 +668,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
603
668
|
"LEVELPLAY" -> levelPlayArbiterBid(index)
|
|
604
669
|
"PUBMATIC" -> pubMaticArbiterBid(index)
|
|
605
670
|
"CUSTOM" -> customArbiterBid(index)
|
|
671
|
+
"ADMOB" -> adMobArbiterBid(index)
|
|
672
|
+
"GAM" -> gamArbiterBid(index)
|
|
606
673
|
else -> {
|
|
607
674
|
Log.w(TAG, "arbiter: ignoring bid with unsupported platform=$platform at index=$index")
|
|
608
675
|
null
|
|
@@ -687,6 +754,36 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
687
754
|
)
|
|
688
755
|
}
|
|
689
756
|
|
|
757
|
+
private fun ReadableMap.adMobArbiterBid(index: Int): CloudXArbiterBid? {
|
|
758
|
+
val adUnitId = stringValue("adUnitId")
|
|
759
|
+
if (adUnitId.isNullOrBlank()) {
|
|
760
|
+
Log.w(TAG, "arbiter: ignoring ADMOB bid with missing adUnitId at index=$index")
|
|
761
|
+
return null
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
return CloudXArbiterBid.adMob(
|
|
765
|
+
adUnitId = adUnitId,
|
|
766
|
+
networkName = optionalStringValue("networkName") ?: ADMOB_DEFAULT_NETWORK_NAME,
|
|
767
|
+
manualRevenuePerImpressionUSD = doubleValue("manualRevenuePerImpressionUSD"),
|
|
768
|
+
extras = stringMapValue("extras"),
|
|
769
|
+
)
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
private fun ReadableMap.gamArbiterBid(index: Int): CloudXArbiterBid? {
|
|
773
|
+
val adUnitId = stringValue("adUnitId")
|
|
774
|
+
if (adUnitId.isNullOrBlank()) {
|
|
775
|
+
Log.w(TAG, "arbiter: ignoring GAM bid with missing adUnitId at index=$index")
|
|
776
|
+
return null
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
return CloudXArbiterBid.gam(
|
|
780
|
+
adUnitId = adUnitId,
|
|
781
|
+
networkName = optionalStringValue("networkName") ?: GAM_DEFAULT_NETWORK_NAME,
|
|
782
|
+
manualRevenuePerImpressionUSD = doubleValue("manualRevenuePerImpressionUSD"),
|
|
783
|
+
extras = stringMapValue("extras"),
|
|
784
|
+
)
|
|
785
|
+
}
|
|
786
|
+
|
|
690
787
|
private fun ReadableMap.toRevenueData(): CloudXRevenueData? {
|
|
691
788
|
val platform = stringValue("platform")
|
|
692
789
|
val revenuePlatform = platform?.toRevenuePlatformOrNull()
|
|
@@ -723,6 +820,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
723
820
|
if (platform.isBlank()) return null
|
|
724
821
|
return when {
|
|
725
822
|
platform.equals("AdMob", ignoreCase = true) -> CloudXRevenuePlatform.ADMOB
|
|
823
|
+
platform.equals("GAM", ignoreCase = true) -> CloudXRevenuePlatform.GAM
|
|
726
824
|
platform.equals("InMobi", ignoreCase = true) -> CloudXRevenuePlatform.INMOBI
|
|
727
825
|
else -> CloudXRevenuePlatform.custom(platform)
|
|
728
826
|
}
|
|
@@ -804,21 +902,29 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
804
902
|
override val adValues: Map<String, String>,
|
|
805
903
|
) : CloudXAd
|
|
806
904
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
905
|
+
/*
|
|
906
|
+
* A null [position] or [offsetsDp] means "keep the current value". The current value is read
|
|
907
|
+
* inside the posted block, so a position update followed by an offsets update from JS cannot
|
|
908
|
+
* overwrite the first call's position with the value that was current before it ran.
|
|
909
|
+
*/
|
|
910
|
+
private fun updateAdViewPosition(adUnitId: String, adFormat: CloudXAdFormat, position: String?, offsetsDp: Pair<Float, Float>?) {
|
|
911
|
+
onUiThread {
|
|
912
|
+
val adView = retrieveAdView(adUnitId, adFormat) ?: return@onUiThread
|
|
913
|
+
adViewPositions[adUnitId] = position ?: adViewPositions[adUnitId] ?: return@onUiThread
|
|
914
|
+
adViewOffsetsDp[adUnitId] = offsetsDp ?: adViewOffsetsDp[adUnitId] ?: DEFAULT_AD_VIEW_OFFSET_DP
|
|
812
915
|
positionAdView(adUnitId, adFormat)
|
|
813
916
|
}
|
|
814
917
|
}
|
|
815
918
|
|
|
919
|
+
@VisibleForTesting
|
|
920
|
+
internal fun adViewPositionForTesting(adUnitId: String): String? = adViewPositions[adUnitId]
|
|
921
|
+
|
|
816
922
|
private fun showAdView(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
817
|
-
|
|
923
|
+
onUiThread {
|
|
818
924
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
819
925
|
if (adView == null) {
|
|
820
926
|
adUnitIdsToShowAfterCreate.add(adUnitId)
|
|
821
|
-
return@
|
|
927
|
+
return@onUiThread
|
|
822
928
|
}
|
|
823
929
|
|
|
824
930
|
// Lazily attach and position on first show. Attaching here — not
|
|
@@ -836,18 +942,18 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
836
942
|
}
|
|
837
943
|
|
|
838
944
|
private fun hideAdView(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
839
|
-
|
|
945
|
+
onUiThread {
|
|
840
946
|
adUnitIdsToShowAfterCreate.remove(adUnitId)
|
|
841
|
-
val adView = retrieveAdView(adUnitId, adFormat) ?: return@
|
|
947
|
+
val adView = retrieveAdView(adUnitId, adFormat) ?: return@onUiThread
|
|
842
948
|
adView.visibility = View.GONE
|
|
843
949
|
adView.stopAutoRefresh()
|
|
844
950
|
}
|
|
845
951
|
}
|
|
846
952
|
|
|
847
953
|
private fun destroyAdView(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
848
|
-
|
|
954
|
+
onUiThread {
|
|
849
955
|
val adView = retrieveAdView(adUnitId, adFormat)
|
|
850
|
-
if (adView == null) return@
|
|
956
|
+
if (adView == null) return@onUiThread
|
|
851
957
|
|
|
852
958
|
val parent = adView.parent
|
|
853
959
|
if (parent is ViewGroup) {
|
|
@@ -868,8 +974,8 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
868
974
|
}
|
|
869
975
|
|
|
870
976
|
private fun setAdViewBackgroundColor(adUnitId: String, adFormat: CloudXAdFormat, hexColorString: String) {
|
|
871
|
-
|
|
872
|
-
val adView = retrieveAdView(adUnitId, adFormat) ?: return@
|
|
977
|
+
onUiThread {
|
|
978
|
+
val adView = retrieveAdView(adUnitId, adFormat) ?: return@onUiThread
|
|
873
979
|
try {
|
|
874
980
|
adView.setBackgroundColor(Color.parseColor(hexColorString))
|
|
875
981
|
} catch (e: IllegalArgumentException) {
|
|
@@ -879,11 +985,11 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
879
985
|
}
|
|
880
986
|
|
|
881
987
|
private fun startAdViewAutoRefresh(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
882
|
-
|
|
988
|
+
onUiThread { retrieveAdView(adUnitId, adFormat)?.startAutoRefresh() }
|
|
883
989
|
}
|
|
884
990
|
|
|
885
991
|
private fun stopAdViewAutoRefresh(adUnitId: String, adFormat: CloudXAdFormat) {
|
|
886
|
-
|
|
992
|
+
onUiThread { retrieveAdView(adUnitId, adFormat)?.stopAutoRefresh() }
|
|
887
993
|
}
|
|
888
994
|
|
|
889
995
|
// =========================================================================
|
|
@@ -1069,7 +1175,7 @@ class CloudXModuleImpl(private val reactApplicationContext: ReactApplicationCont
|
|
|
1069
1175
|
destroyAdView(adUnitId, adFormat)
|
|
1070
1176
|
}
|
|
1071
1177
|
|
|
1072
|
-
|
|
1178
|
+
onUiThread {
|
|
1073
1179
|
for (interstitial in interstitials.values) {
|
|
1074
1180
|
interstitial.destroy()
|
|
1075
1181
|
}
|