cm-sdk-react-native-v3 3.8.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/README.md +1 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/cmsdkreactnativev3/CmSdkReactNativeV3Module.kt +304 -139
- package/ios/CmSdkReactNativeV3.mm +17 -0
- package/ios/CmSdkReactNativeV3.swift +193 -26
- package/lib/commonjs/NativeCmSdkReactNativeV3.js.map +1 -1
- package/lib/commonjs/index.js +44 -11
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/NativeCmSdkReactNativeV3.js.map +1 -1
- package/lib/module/index.js +35 -9
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/NativeCmSdkReactNativeV3.d.ts +24 -3
- package/lib/typescript/commonjs/src/NativeCmSdkReactNativeV3.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +9 -2
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/NativeCmSdkReactNativeV3.d.ts +24 -3
- package/lib/typescript/module/src/NativeCmSdkReactNativeV3.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +9 -2
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/react-native-cm-sdk-react-native-v3.podspec +1 -1
- package/src/NativeCmSdkReactNativeV3.ts +32 -4
- package/src/index.tsx +53 -14
package/README.md
CHANGED
package/android/build.gradle
CHANGED
|
@@ -89,5 +89,5 @@ dependencies {
|
|
|
89
89
|
implementation "androidx.lifecycle:lifecycle-common-java8:2.6.1"
|
|
90
90
|
|
|
91
91
|
// consentmanager's underlying native Android SDK dependency
|
|
92
|
-
implementation "net.consentmanager.sdkv3:cmsdkv3:3.
|
|
92
|
+
implementation "net.consentmanager.sdkv3:cmsdkv3:3.10.0"
|
|
93
93
|
}
|
|
@@ -4,6 +4,8 @@ import android.os.Handler
|
|
|
4
4
|
import android.os.Looper
|
|
5
5
|
import android.util.Log
|
|
6
6
|
import android.app.Activity
|
|
7
|
+
import android.webkit.CookieManager
|
|
8
|
+
import android.webkit.WebStorage
|
|
7
9
|
import com.facebook.react.bridge.Arguments
|
|
8
10
|
import com.facebook.react.bridge.LifecycleEventListener
|
|
9
11
|
import com.facebook.react.bridge.Promise
|
|
@@ -24,7 +26,7 @@ import net.consentmanager.cm_sdk_android_v3.CMPManagerDelegate
|
|
|
24
26
|
import net.consentmanager.cm_sdk_android_v3.ConsentLayerUIConfig
|
|
25
27
|
import net.consentmanager.cm_sdk_android_v3.ConsentStatus
|
|
26
28
|
import net.consentmanager.cm_sdk_android_v3.UrlConfig
|
|
27
|
-
import net.consentmanager.cm_sdk_android_v3.
|
|
29
|
+
import net.consentmanager.cm_sdk_android_v3.UserChoiceStatus
|
|
28
30
|
|
|
29
31
|
class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
30
32
|
ReactContextBaseJavaModule(reactContext), LifecycleEventListener, CMPManagerDelegate {
|
|
@@ -37,6 +39,7 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
37
39
|
private var isInitialized = false
|
|
38
40
|
private var storedATTStatus: Int = 0
|
|
39
41
|
private var isWebViewConfigSet = false
|
|
42
|
+
private var automaticConsentUpdatesEnabled = true
|
|
40
43
|
|
|
41
44
|
|
|
42
45
|
init {
|
|
@@ -113,11 +116,13 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
113
116
|
|
|
114
117
|
this.webViewConfig = ConsentLayerUIConfig(
|
|
115
118
|
position = position,
|
|
116
|
-
backgroundStyle =
|
|
119
|
+
backgroundStyle = mapBackgroundStyle(config),
|
|
117
120
|
cornerRadius = cornerRadius,
|
|
118
121
|
respectsSafeArea = if (config.hasKey("respectsSafeArea")) config.getBoolean("respectsSafeArea") else true,
|
|
119
122
|
isCancelable = false,
|
|
120
|
-
allowsOrientationChanges = if (config.hasKey("allowsOrientationChanges")) config.getBoolean("allowsOrientationChanges") else true
|
|
123
|
+
allowsOrientationChanges = if (config.hasKey("allowsOrientationChanges")) config.getBoolean("allowsOrientationChanges") else true,
|
|
124
|
+
darkMode = if (config.hasKey("darkMode")) config.getBoolean("darkMode") else false,
|
|
125
|
+
navigationBarColor = readOptionalColor(config, "navigationBarColor")
|
|
121
126
|
)
|
|
122
127
|
isWebViewConfigSet = true
|
|
123
128
|
|
|
@@ -135,9 +140,21 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
135
140
|
val domain = config.getString("domain") ?: throw IllegalArgumentException("Missing 'domain'")
|
|
136
141
|
val language = config.getString("language") ?: throw IllegalArgumentException("Missing 'language'")
|
|
137
142
|
val appName = config.getString("appName") ?: throw IllegalArgumentException("Missing 'appName'")
|
|
143
|
+
val jsonConfig = if (config.hasKey("jsonConfig")) config.getString("jsonConfig") else null
|
|
138
144
|
val noHash = if (config.hasKey("noHash")) config.getBoolean("noHash") else false
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
val webViewConnectionTimeoutMillis = if (config.hasKey("webViewConnectionTimeoutMillis")) config.getDouble("webViewConnectionTimeoutMillis").toLong() else 3000L
|
|
146
|
+
val forceRegulation = if (config.hasKey("forceRegulation")) config.getString("forceRegulation") else null
|
|
147
|
+
|
|
148
|
+
this.urlConfig = UrlConfig(
|
|
149
|
+
id = id,
|
|
150
|
+
domain = domain,
|
|
151
|
+
language = language,
|
|
152
|
+
appName = appName,
|
|
153
|
+
jsonConfig = jsonConfig,
|
|
154
|
+
noHash = noHash,
|
|
155
|
+
webViewConnectionTimeoutMillis = webViewConnectionTimeoutMillis,
|
|
156
|
+
forceRegulation = forceRegulation
|
|
157
|
+
)
|
|
141
158
|
// Ensure we initialize manager only once and with whatever webViewConfig is currently set
|
|
142
159
|
if (!::cmpManager.isInitialized) {
|
|
143
160
|
initializeCMPManager()
|
|
@@ -151,7 +168,7 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
151
168
|
}
|
|
152
169
|
|
|
153
170
|
private fun initializeCMPManager() {
|
|
154
|
-
val activity = currentActivitySafe ?: throw IllegalStateException("Current activity is null")
|
|
171
|
+
val activity = currentActivitySafe ?: throw IllegalStateException("Current activity is null. Wait until the app is active before calling setUrlConfig().")
|
|
155
172
|
Log.d("CmSdkReactNativeV3", "Initializing CMPManager with activity: $activity, delegate: $this")
|
|
156
173
|
|
|
157
174
|
cmpManager = CMPManager.getInstance(
|
|
@@ -194,30 +211,34 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
194
211
|
*/
|
|
195
212
|
@ReactMethod
|
|
196
213
|
fun getUserStatus(promise: Promise) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
withCmpManager(promise) { manager ->
|
|
215
|
+
try {
|
|
216
|
+
val userStatus = manager.getUserStatus()
|
|
217
|
+
val normalizedStatus = mapUserChoiceStatus(userStatus.hasUserChoice)
|
|
218
|
+
val result = Arguments.createMap().apply {
|
|
219
|
+
putString("status", normalizedStatus)
|
|
220
|
+
putString("hasUserChoice", normalizedStatus)
|
|
221
|
+
putString("tcf", userStatus.tcf)
|
|
222
|
+
putString("addtlConsent", userStatus.addtlConsent)
|
|
223
|
+
putString("regulation", userStatus.regulation)
|
|
224
|
+
|
|
225
|
+
val vendorsMap = Arguments.createMap()
|
|
226
|
+
userStatus.vendors.forEach { (vendorId, status) ->
|
|
227
|
+
vendorsMap.putString(vendorId, mapConsentStatus(status))
|
|
228
|
+
}
|
|
229
|
+
putMap("vendors", vendorsMap)
|
|
210
230
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
231
|
+
val purposesMap = Arguments.createMap()
|
|
232
|
+
userStatus.purposes.forEach { (purposeId, status) ->
|
|
233
|
+
purposesMap.putString(purposeId, mapConsentStatus(status))
|
|
234
|
+
}
|
|
235
|
+
putMap("purposes", purposesMap)
|
|
214
236
|
}
|
|
215
|
-
putMap("purposes", purposesMap)
|
|
216
|
-
}
|
|
217
237
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
238
|
+
promise.resolve(result)
|
|
239
|
+
} catch (e: Exception) {
|
|
240
|
+
promise.reject("ERROR", "Failed to get user status: ${e.message}", e)
|
|
241
|
+
}
|
|
221
242
|
}
|
|
222
243
|
}
|
|
223
244
|
|
|
@@ -231,11 +252,13 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
231
252
|
*/
|
|
232
253
|
@ReactMethod
|
|
233
254
|
fun getStatusForPurpose(purposeId: String, promise: Promise) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
255
|
+
withCmpManager(promise) { manager ->
|
|
256
|
+
try {
|
|
257
|
+
val status = manager.getStatusForPurpose(purposeId)
|
|
258
|
+
promise.resolve(mapConsentStatus(status))
|
|
259
|
+
} catch (e: Exception) {
|
|
260
|
+
promise.reject("ERROR", "Failed to get status for purpose: ${e.message}", e)
|
|
261
|
+
}
|
|
239
262
|
}
|
|
240
263
|
}
|
|
241
264
|
|
|
@@ -244,11 +267,13 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
244
267
|
*/
|
|
245
268
|
@ReactMethod
|
|
246
269
|
fun getStatusForVendor(vendorId: String, promise: Promise) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
270
|
+
withCmpManager(promise) { manager ->
|
|
271
|
+
try {
|
|
272
|
+
val status = manager.getStatusForVendor(vendorId)
|
|
273
|
+
promise.resolve(mapConsentStatus(status))
|
|
274
|
+
} catch (e: Exception) {
|
|
275
|
+
promise.reject("ERROR", "Failed to get status for vendor: ${e.message}", e)
|
|
276
|
+
}
|
|
252
277
|
}
|
|
253
278
|
}
|
|
254
279
|
|
|
@@ -257,17 +282,19 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
257
282
|
*/
|
|
258
283
|
@ReactMethod
|
|
259
284
|
fun getGoogleConsentModeStatus(promise: Promise) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
285
|
+
withCmpManager(promise) { manager ->
|
|
286
|
+
try {
|
|
287
|
+
val consentModeStatus = manager.getGoogleConsentModeStatus()
|
|
288
|
+
val result = Arguments.createMap()
|
|
263
289
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
290
|
+
consentModeStatus.forEach { (key, value) ->
|
|
291
|
+
result.putString(key, value)
|
|
292
|
+
}
|
|
267
293
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
294
|
+
promise.resolve(result)
|
|
295
|
+
} catch (e: Exception) {
|
|
296
|
+
promise.reject("ERROR", "Failed to get Google Consent Mode status: ${e.message}", e)
|
|
297
|
+
}
|
|
271
298
|
}
|
|
272
299
|
}
|
|
273
300
|
|
|
@@ -277,16 +304,24 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
277
304
|
@ReactMethod
|
|
278
305
|
fun isConsentRequired(promise: Promise) {
|
|
279
306
|
scope.launch {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
307
|
+
withCmpManager(promise) { manager ->
|
|
308
|
+
val activity = currentActivitySafe ?: run {
|
|
309
|
+
promise.reject("NO_ACTIVITY", "Current activity is null. Wait until the app is active before calling isConsentRequired().")
|
|
310
|
+
return@withCmpManager
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
try {
|
|
314
|
+
manager.setActivity(activity)
|
|
315
|
+
manager.isConsentRequired { result ->
|
|
316
|
+
if (result.isSuccess) {
|
|
317
|
+
promise.resolve(result.getOrNull() ?: false)
|
|
318
|
+
} else {
|
|
319
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
320
|
+
}
|
|
286
321
|
}
|
|
322
|
+
} catch (e: Exception) {
|
|
323
|
+
promise.reject("ERROR", "Failed to check if consent is required: ${e.message}", e)
|
|
287
324
|
}
|
|
288
|
-
} catch (e: Exception) {
|
|
289
|
-
promise.reject("ERROR", "Failed to check if consent is required: ${e.message}", e)
|
|
290
325
|
}
|
|
291
326
|
}
|
|
292
327
|
}
|
|
@@ -297,18 +332,24 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
297
332
|
@ReactMethod
|
|
298
333
|
fun forceOpen(jumpToSettings: Boolean, promise: Promise) {
|
|
299
334
|
scope.launch {
|
|
300
|
-
|
|
301
|
-
currentActivitySafe
|
|
335
|
+
withCmpManager(promise) { manager ->
|
|
336
|
+
val activity = currentActivitySafe ?: run {
|
|
337
|
+
promise.reject("NO_ACTIVITY", "Current activity is null. Wait until the app is active before calling forceOpen().")
|
|
338
|
+
return@withCmpManager
|
|
339
|
+
}
|
|
302
340
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
341
|
+
try {
|
|
342
|
+
manager.setActivity(activity)
|
|
343
|
+
manager.forceOpen(jumpToSettings) { result ->
|
|
344
|
+
if (result.isSuccess) {
|
|
345
|
+
promise.resolve(true)
|
|
346
|
+
} else {
|
|
347
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
348
|
+
}
|
|
308
349
|
}
|
|
350
|
+
} catch (e: Exception) {
|
|
351
|
+
promise.reject("ERROR", "Failed to force open consent layer: ${e.message}", e)
|
|
309
352
|
}
|
|
310
|
-
} catch (e: Exception) {
|
|
311
|
-
promise.reject("ERROR", "Failed to force open consent layer: ${e.message}", e)
|
|
312
353
|
}
|
|
313
354
|
}
|
|
314
355
|
}
|
|
@@ -319,18 +360,24 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
319
360
|
@ReactMethod
|
|
320
361
|
fun checkAndOpen(jumpToSettings: Boolean, promise: Promise) {
|
|
321
362
|
scope.launch {
|
|
322
|
-
|
|
323
|
-
currentActivitySafe
|
|
363
|
+
withCmpManager(promise) { manager ->
|
|
364
|
+
val activity = currentActivitySafe ?: run {
|
|
365
|
+
promise.reject("NO_ACTIVITY", "Current activity is null. Wait until the app is active before calling checkAndOpen().")
|
|
366
|
+
return@withCmpManager
|
|
367
|
+
}
|
|
324
368
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
369
|
+
try {
|
|
370
|
+
manager.setActivity(activity)
|
|
371
|
+
manager.checkAndOpen(jumpToSettings) { result ->
|
|
372
|
+
if (result.isSuccess) {
|
|
373
|
+
promise.resolve(true)
|
|
374
|
+
} else {
|
|
375
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
376
|
+
}
|
|
330
377
|
}
|
|
378
|
+
} catch (e: Exception) {
|
|
379
|
+
promise.reject("ERROR", "Failed to check and open consent: ${e.message}", e)
|
|
331
380
|
}
|
|
332
|
-
} catch (e: Exception) {
|
|
333
|
-
promise.reject("ERROR", "Failed to check and open consent: ${e.message}", e)
|
|
334
381
|
}
|
|
335
382
|
}
|
|
336
383
|
}
|
|
@@ -341,16 +388,18 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
341
388
|
@ReactMethod
|
|
342
389
|
fun importCMPInfo(cmpString: String, promise: Promise) {
|
|
343
390
|
scope.launch {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
391
|
+
withCmpManager(promise) { manager ->
|
|
392
|
+
try {
|
|
393
|
+
manager.importCMPInfo(cmpString) { result ->
|
|
394
|
+
if (result.isSuccess) {
|
|
395
|
+
promise.resolve(true)
|
|
396
|
+
} else {
|
|
397
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
398
|
+
}
|
|
350
399
|
}
|
|
400
|
+
} catch (e: Exception) {
|
|
401
|
+
promise.reject("ERROR", "Failed to import CMP info: ${e.message}", e)
|
|
351
402
|
}
|
|
352
|
-
} catch (e: Exception) {
|
|
353
|
-
promise.reject("ERROR", "Failed to import CMP info: ${e.message}", e)
|
|
354
403
|
}
|
|
355
404
|
}
|
|
356
405
|
}
|
|
@@ -360,34 +409,44 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
360
409
|
*/
|
|
361
410
|
@ReactMethod
|
|
362
411
|
fun resetConsentManagementData(promise: Promise) {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
412
|
+
withCmpManager(promise) { manager ->
|
|
413
|
+
runOnUiThread {
|
|
414
|
+
try {
|
|
415
|
+
manager.resetConsentManagementData()
|
|
416
|
+
clearWebViewStorage {
|
|
417
|
+
promise.resolve(true)
|
|
418
|
+
}
|
|
419
|
+
} catch (e: Exception) {
|
|
420
|
+
promise.reject("ERROR", "Failed to reset consent management data: ${e.message}", e)
|
|
421
|
+
}
|
|
422
|
+
}
|
|
368
423
|
}
|
|
369
424
|
}
|
|
370
425
|
|
|
371
426
|
@ReactMethod
|
|
372
427
|
fun exportCMPInfo(promise: Promise) {
|
|
373
|
-
promise
|
|
428
|
+
withCmpManager(promise) { manager ->
|
|
429
|
+
promise.resolve(manager.exportCMPInfo())
|
|
430
|
+
}
|
|
374
431
|
}
|
|
375
432
|
|
|
376
433
|
@ReactMethod
|
|
377
434
|
fun acceptVendors(vendors: ReadableArray, promise: Promise) {
|
|
378
435
|
scope.launch {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
436
|
+
withCmpManager(promise) { manager ->
|
|
437
|
+
try {
|
|
438
|
+
Log.d("CmSdkReactNativeV3", "Accepting vendors: $vendors")
|
|
439
|
+
|
|
440
|
+
manager.acceptVendors(vendors.toListOfStrings()) { result ->
|
|
441
|
+
if (result.isSuccess) {
|
|
442
|
+
promise.resolve(true)
|
|
443
|
+
} else {
|
|
444
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
445
|
+
}
|
|
387
446
|
}
|
|
447
|
+
} catch (e: Exception) {
|
|
448
|
+
promise.reject("ERROR", "Failed to accept vendors: ${e.message}", e)
|
|
388
449
|
}
|
|
389
|
-
} catch (e: Exception) {
|
|
390
|
-
promise.reject("ERROR", "Failed to accept vendors: ${e.message}", e)
|
|
391
450
|
}
|
|
392
451
|
}
|
|
393
452
|
}
|
|
@@ -395,17 +454,19 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
395
454
|
@ReactMethod
|
|
396
455
|
fun rejectVendors(vendors: ReadableArray, promise: Promise) {
|
|
397
456
|
scope.launch {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
457
|
+
withCmpManager(promise) { manager ->
|
|
458
|
+
try {
|
|
459
|
+
Log.d("CmSdkReactNativeV3", "Rejecting vendors: $vendors")
|
|
460
|
+
manager.rejectVendors(vendors.toListOfStrings()) { result ->
|
|
461
|
+
if (result.isSuccess) {
|
|
462
|
+
promise.resolve(true)
|
|
463
|
+
} else {
|
|
464
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
465
|
+
}
|
|
405
466
|
}
|
|
467
|
+
} catch (e: Exception) {
|
|
468
|
+
promise.reject("ERROR", "Failed to reject vendors: ${e.message}", e)
|
|
406
469
|
}
|
|
407
|
-
} catch (e: Exception) {
|
|
408
|
-
promise.reject("ERROR", "Failed to reject vendors: ${e.message}", e)
|
|
409
470
|
}
|
|
410
471
|
}
|
|
411
472
|
}
|
|
@@ -413,18 +474,20 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
413
474
|
@ReactMethod
|
|
414
475
|
fun acceptPurposes(purposes: ReadableArray, updatePurpose: Boolean, promise: Promise) {
|
|
415
476
|
scope.launch {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
477
|
+
withCmpManager(promise) { manager ->
|
|
478
|
+
try {
|
|
479
|
+
Log.d("Cmsdkreactnativev3", "Accepting purposes: $purposes")
|
|
480
|
+
|
|
481
|
+
manager.acceptPurposes(purposes.toListOfStrings(), updatePurpose) { result ->
|
|
482
|
+
if (result.isSuccess) {
|
|
483
|
+
promise.resolve(true)
|
|
484
|
+
} else {
|
|
485
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
486
|
+
}
|
|
424
487
|
}
|
|
488
|
+
} catch (e: Exception) {
|
|
489
|
+
promise.reject("ERROR", "Failed to accept purposes: ${e.message}", e)
|
|
425
490
|
}
|
|
426
|
-
} catch (e: Exception) {
|
|
427
|
-
promise.reject("ERROR", "Failed to accept purposes: ${e.message}", e)
|
|
428
491
|
}
|
|
429
492
|
}
|
|
430
493
|
}
|
|
@@ -432,17 +495,19 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
432
495
|
@ReactMethod
|
|
433
496
|
fun rejectPurposes(purposes: ReadableArray, updateVendor: Boolean, promise: Promise) {
|
|
434
497
|
scope.launch {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
498
|
+
withCmpManager(promise) { manager ->
|
|
499
|
+
try {
|
|
500
|
+
Log.d("Cmsdkreactnativev3", "Rejecting purposes: $purposes")
|
|
501
|
+
manager.rejectPurposes(purposes.toListOfStrings(), updateVendor) { result ->
|
|
502
|
+
if (result.isSuccess) {
|
|
503
|
+
promise.resolve(true)
|
|
504
|
+
} else {
|
|
505
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
506
|
+
}
|
|
442
507
|
}
|
|
508
|
+
} catch (e: Exception) {
|
|
509
|
+
promise.reject("ERROR", "Failed to reject purposes: ${e.message}", e)
|
|
443
510
|
}
|
|
444
|
-
} catch (e: Exception) {
|
|
445
|
-
promise.reject("ERROR", "Failed to reject purposes: ${e.message}", e)
|
|
446
511
|
}
|
|
447
512
|
}
|
|
448
513
|
}
|
|
@@ -450,16 +515,18 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
450
515
|
@ReactMethod
|
|
451
516
|
fun rejectAll(promise: Promise) {
|
|
452
517
|
scope.launch {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
518
|
+
withCmpManager(promise) { manager ->
|
|
519
|
+
try {
|
|
520
|
+
manager.rejectAll { result ->
|
|
521
|
+
if (result.isSuccess) {
|
|
522
|
+
promise.resolve(true)
|
|
523
|
+
} else {
|
|
524
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
525
|
+
}
|
|
459
526
|
}
|
|
527
|
+
} catch (e: Exception) {
|
|
528
|
+
promise.reject("ERROR", "Failed to reject all: ${e.message}", e)
|
|
460
529
|
}
|
|
461
|
-
} catch (e: Exception) {
|
|
462
|
-
promise.reject("ERROR", "Failed to reject all: ${e.message}", e)
|
|
463
530
|
}
|
|
464
531
|
}
|
|
465
532
|
}
|
|
@@ -467,19 +534,98 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
467
534
|
@ReactMethod
|
|
468
535
|
fun acceptAll(promise: Promise) {
|
|
469
536
|
scope.launch {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
537
|
+
withCmpManager(promise) { manager ->
|
|
538
|
+
try {
|
|
539
|
+
manager.acceptAll { result ->
|
|
540
|
+
if (result.isSuccess) {
|
|
541
|
+
promise.resolve(true)
|
|
542
|
+
} else {
|
|
543
|
+
promise.reject("ERROR", result.exceptionOrNull()?.message ?: "Unknown error")
|
|
544
|
+
}
|
|
476
545
|
}
|
|
546
|
+
} catch (e: Exception) {
|
|
547
|
+
promise.reject("ERROR", "Failed to accept all: ${e.message}", e)
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
@ReactMethod
|
|
554
|
+
fun setAutomaticConsentUpdatesEnabled(enabled: Boolean, promise: Promise) {
|
|
555
|
+
withCmpManager(promise) { manager ->
|
|
556
|
+
try {
|
|
557
|
+
automaticConsentUpdatesEnabled = enabled
|
|
558
|
+
manager.setAutomaticConsentUpdatesEnabled(enabled)
|
|
559
|
+
promise.resolve(null)
|
|
560
|
+
} catch (e: Exception) {
|
|
561
|
+
promise.reject("ERROR", "Failed to set automatic consent updates: ${e.message}", e)
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
@ReactMethod
|
|
567
|
+
fun updateThirdPartyConsent(promise: Promise) {
|
|
568
|
+
withCmpManager(promise) { manager ->
|
|
569
|
+
try {
|
|
570
|
+
val result = Arguments.createMap()
|
|
571
|
+
manager.updateThirdPartyConsent(reactApplicationContext).forEach { (key, value) ->
|
|
572
|
+
result.putBoolean(key, value)
|
|
477
573
|
}
|
|
574
|
+
promise.resolve(result)
|
|
478
575
|
} catch (e: Exception) {
|
|
479
|
-
promise.reject("ERROR", "Failed to
|
|
576
|
+
promise.reject("ERROR", "Failed to update third-party consent: ${e.message}", e)
|
|
480
577
|
}
|
|
481
578
|
}
|
|
482
579
|
}
|
|
580
|
+
|
|
581
|
+
private fun mapBackgroundStyle(config: ReadableMap): ConsentLayerUIConfig.BackgroundStyle {
|
|
582
|
+
val backgroundConfig = if (config.hasKey("backgroundStyle")) config.getMap("backgroundStyle") else null
|
|
583
|
+
val type = backgroundConfig?.getString("type") ?: return ConsentLayerUIConfig.BackgroundStyle.dimmed(android.graphics.Color.BLACK, 0.5f)
|
|
584
|
+
|
|
585
|
+
return when (type) {
|
|
586
|
+
"dimmed" -> ConsentLayerUIConfig.BackgroundStyle.dimmed(
|
|
587
|
+
readOptionalColor(backgroundConfig, "color") ?: android.graphics.Color.BLACK,
|
|
588
|
+
if (backgroundConfig.hasKey("opacity")) backgroundConfig.getDouble("opacity").toFloat() else 0.5f
|
|
589
|
+
)
|
|
590
|
+
"color" -> ConsentLayerUIConfig.BackgroundStyle.solid(
|
|
591
|
+
readOptionalColor(backgroundConfig, "color") ?: android.graphics.Color.BLACK
|
|
592
|
+
)
|
|
593
|
+
"blur" -> ConsentLayerUIConfig.BackgroundStyle.blur(
|
|
594
|
+
readOptionalColor(backgroundConfig, "fallbackColor") ?: android.graphics.Color.BLACK,
|
|
595
|
+
if (backgroundConfig.hasKey("fallbackOpacity")) backgroundConfig.getDouble("fallbackOpacity").toFloat() else 0.5f
|
|
596
|
+
)
|
|
597
|
+
"none" -> ConsentLayerUIConfig.BackgroundStyle.none()
|
|
598
|
+
else -> ConsentLayerUIConfig.BackgroundStyle.dimmed(android.graphics.Color.BLACK, 0.5f)
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
private fun readOptionalColor(config: ReadableMap, key: String): Int? {
|
|
603
|
+
return if (config.hasKey(key) && !config.isNull(key)) config.getDouble(key).toInt() else null
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
private fun mapConsentStatus(status: ConsentStatus): String {
|
|
607
|
+
return when (status) {
|
|
608
|
+
ConsentStatus.CHOICE_DOESNT_EXIST -> "choiceDoesntExist"
|
|
609
|
+
ConsentStatus.GRANTED -> "granted"
|
|
610
|
+
ConsentStatus.DENIED -> "denied"
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
private fun mapUserChoiceStatus(status: UserChoiceStatus): String {
|
|
615
|
+
return when (status) {
|
|
616
|
+
UserChoiceStatus.CHOICE_EXISTS -> "choiceExists"
|
|
617
|
+
UserChoiceStatus.CHOICE_DOESNT_EXIST -> "choiceDoesntExist"
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
private fun withCmpManager(promise: Promise, block: (CMPManager) -> Unit) {
|
|
622
|
+
if (!::cmpManager.isInitialized) {
|
|
623
|
+
promise.reject("NOT_INITIALIZED", "CMPManager is not initialized. Call setUrlConfig() first.")
|
|
624
|
+
return
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
block(cmpManager)
|
|
628
|
+
}
|
|
483
629
|
private fun ReadableArray.toListOfStrings(): List<String> {
|
|
484
630
|
val list = mutableListOf<String>()
|
|
485
631
|
for (i in 0 until this.size()) {
|
|
@@ -525,6 +671,20 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
525
671
|
}
|
|
526
672
|
}
|
|
527
673
|
|
|
674
|
+
private fun clearWebViewStorage(onComplete: () -> Unit) {
|
|
675
|
+
try {
|
|
676
|
+
val cookieManager = CookieManager.getInstance()
|
|
677
|
+
cookieManager.removeAllCookies {
|
|
678
|
+
cookieManager.flush()
|
|
679
|
+
WebStorage.getInstance().deleteAllData()
|
|
680
|
+
onComplete()
|
|
681
|
+
}
|
|
682
|
+
} catch (e: Exception) {
|
|
683
|
+
Log.w("CmSdkReactNativeV3", "Failed to clear WebView storage: ${e.message}")
|
|
684
|
+
onComplete()
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
528
688
|
companion object {
|
|
529
689
|
const val NAME = "CmSdkReactNativeV3"
|
|
530
690
|
private var globalCMPManager: CMPManager? = null
|
|
@@ -533,6 +693,11 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
533
693
|
|
|
534
694
|
override fun didReceiveConsent(consent: String, jsonObject: Map<String, Any>) {
|
|
535
695
|
Log.d("CmSdkReactNativeV3", "didReceiveConsent called from native SDK with consent: ${consent.take(50)}...")
|
|
696
|
+
Log.d("CmSdkReactNativeV3", "Consent string length: ${consent.length}")
|
|
697
|
+
Log.d("CmSdkReactNativeV3", "Consent string class: ${consent.javaClass.name}")
|
|
698
|
+
Log.d("CmSdkReactNativeV3", "First char code: ${if (consent.isNotEmpty()) consent[0].code else "empty"}")
|
|
699
|
+
Log.d("CmSdkReactNativeV3", "Last char code: ${if (consent.isNotEmpty()) consent[consent.length - 1].code else "empty"}")
|
|
700
|
+
|
|
536
701
|
val params = Arguments.createMap().apply {
|
|
537
702
|
putString("consent", consent)
|
|
538
703
|
putMap("jsonObject", convertMapToWritableMap(jsonObject))
|