cm-sdk-react-native-v3 3.6.6 → 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 +315 -130
- package/ios/CmSdkReactNativeV3.mm +20 -0
- package/ios/CmSdkReactNativeV3.swift +204 -26
- package/lib/commonjs/NativeCmSdkReactNativeV3.js.map +1 -1
- package/lib/commonjs/index.js +49 -12
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/NativeCmSdkReactNativeV3.js.map +1 -1
- package/lib/module/index.js +38 -9
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/commonjs/src/NativeCmSdkReactNativeV3.d.ts +25 -3
- package/lib/typescript/commonjs/src/NativeCmSdkReactNativeV3.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/index.d.ts +10 -2
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/NativeCmSdkReactNativeV3.d.ts +25 -3
- package/lib/typescript/module/src/NativeCmSdkReactNativeV3.d.ts.map +1 -1
- package/lib/typescript/module/src/index.d.ts +10 -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 +33 -4
- package/src/index.tsx +57 -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,47 @@ 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()
|
|
289
|
+
|
|
290
|
+
consentModeStatus.forEach { (key, value) ->
|
|
291
|
+
result.putString(key, value)
|
|
292
|
+
}
|
|
263
293
|
|
|
264
|
-
|
|
265
|
-
|
|
294
|
+
promise.resolve(result)
|
|
295
|
+
} catch (e: Exception) {
|
|
296
|
+
promise.reject("ERROR", "Failed to get Google Consent Mode status: ${e.message}", e)
|
|
266
297
|
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
267
300
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
301
|
+
/**
|
|
302
|
+
* Checks if consent is required without opening the consent UI
|
|
303
|
+
*/
|
|
304
|
+
@ReactMethod
|
|
305
|
+
fun isConsentRequired(promise: Promise) {
|
|
306
|
+
scope.launch {
|
|
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
|
+
}
|
|
321
|
+
}
|
|
322
|
+
} catch (e: Exception) {
|
|
323
|
+
promise.reject("ERROR", "Failed to check if consent is required: ${e.message}", e)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
271
326
|
}
|
|
272
327
|
}
|
|
273
328
|
|
|
@@ -277,18 +332,24 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
277
332
|
@ReactMethod
|
|
278
333
|
fun forceOpen(jumpToSettings: Boolean, promise: Promise) {
|
|
279
334
|
scope.launch {
|
|
280
|
-
|
|
281
|
-
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
|
+
}
|
|
282
340
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
+
}
|
|
288
349
|
}
|
|
350
|
+
} catch (e: Exception) {
|
|
351
|
+
promise.reject("ERROR", "Failed to force open consent layer: ${e.message}", e)
|
|
289
352
|
}
|
|
290
|
-
} catch (e: Exception) {
|
|
291
|
-
promise.reject("ERROR", "Failed to force open consent layer: ${e.message}", e)
|
|
292
353
|
}
|
|
293
354
|
}
|
|
294
355
|
}
|
|
@@ -299,18 +360,24 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
299
360
|
@ReactMethod
|
|
300
361
|
fun checkAndOpen(jumpToSettings: Boolean, promise: Promise) {
|
|
301
362
|
scope.launch {
|
|
302
|
-
|
|
303
|
-
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
|
+
}
|
|
304
368
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
+
}
|
|
310
377
|
}
|
|
378
|
+
} catch (e: Exception) {
|
|
379
|
+
promise.reject("ERROR", "Failed to check and open consent: ${e.message}", e)
|
|
311
380
|
}
|
|
312
|
-
} catch (e: Exception) {
|
|
313
|
-
promise.reject("ERROR", "Failed to check and open consent: ${e.message}", e)
|
|
314
381
|
}
|
|
315
382
|
}
|
|
316
383
|
}
|
|
@@ -321,16 +388,18 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
321
388
|
@ReactMethod
|
|
322
389
|
fun importCMPInfo(cmpString: String, promise: Promise) {
|
|
323
390
|
scope.launch {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
+
}
|
|
330
399
|
}
|
|
400
|
+
} catch (e: Exception) {
|
|
401
|
+
promise.reject("ERROR", "Failed to import CMP info: ${e.message}", e)
|
|
331
402
|
}
|
|
332
|
-
} catch (e: Exception) {
|
|
333
|
-
promise.reject("ERROR", "Failed to import CMP info: ${e.message}", e)
|
|
334
403
|
}
|
|
335
404
|
}
|
|
336
405
|
}
|
|
@@ -340,34 +409,44 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
340
409
|
*/
|
|
341
410
|
@ReactMethod
|
|
342
411
|
fun resetConsentManagementData(promise: Promise) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
+
}
|
|
348
423
|
}
|
|
349
424
|
}
|
|
350
425
|
|
|
351
426
|
@ReactMethod
|
|
352
427
|
fun exportCMPInfo(promise: Promise) {
|
|
353
|
-
promise
|
|
428
|
+
withCmpManager(promise) { manager ->
|
|
429
|
+
promise.resolve(manager.exportCMPInfo())
|
|
430
|
+
}
|
|
354
431
|
}
|
|
355
432
|
|
|
356
433
|
@ReactMethod
|
|
357
434
|
fun acceptVendors(vendors: ReadableArray, promise: Promise) {
|
|
358
435
|
scope.launch {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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
|
+
}
|
|
367
446
|
}
|
|
447
|
+
} catch (e: Exception) {
|
|
448
|
+
promise.reject("ERROR", "Failed to accept vendors: ${e.message}", e)
|
|
368
449
|
}
|
|
369
|
-
} catch (e: Exception) {
|
|
370
|
-
promise.reject("ERROR", "Failed to accept vendors: ${e.message}", e)
|
|
371
450
|
}
|
|
372
451
|
}
|
|
373
452
|
}
|
|
@@ -375,17 +454,19 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
375
454
|
@ReactMethod
|
|
376
455
|
fun rejectVendors(vendors: ReadableArray, promise: Promise) {
|
|
377
456
|
scope.launch {
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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
|
+
}
|
|
385
466
|
}
|
|
467
|
+
} catch (e: Exception) {
|
|
468
|
+
promise.reject("ERROR", "Failed to reject vendors: ${e.message}", e)
|
|
386
469
|
}
|
|
387
|
-
} catch (e: Exception) {
|
|
388
|
-
promise.reject("ERROR", "Failed to reject vendors: ${e.message}", e)
|
|
389
470
|
}
|
|
390
471
|
}
|
|
391
472
|
}
|
|
@@ -393,18 +474,20 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
393
474
|
@ReactMethod
|
|
394
475
|
fun acceptPurposes(purposes: ReadableArray, updatePurpose: Boolean, promise: Promise) {
|
|
395
476
|
scope.launch {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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
|
+
}
|
|
404
487
|
}
|
|
488
|
+
} catch (e: Exception) {
|
|
489
|
+
promise.reject("ERROR", "Failed to accept purposes: ${e.message}", e)
|
|
405
490
|
}
|
|
406
|
-
} catch (e: Exception) {
|
|
407
|
-
promise.reject("ERROR", "Failed to accept purposes: ${e.message}", e)
|
|
408
491
|
}
|
|
409
492
|
}
|
|
410
493
|
}
|
|
@@ -412,17 +495,19 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
412
495
|
@ReactMethod
|
|
413
496
|
fun rejectPurposes(purposes: ReadableArray, updateVendor: Boolean, promise: Promise) {
|
|
414
497
|
scope.launch {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
+
}
|
|
422
507
|
}
|
|
508
|
+
} catch (e: Exception) {
|
|
509
|
+
promise.reject("ERROR", "Failed to reject purposes: ${e.message}", e)
|
|
423
510
|
}
|
|
424
|
-
} catch (e: Exception) {
|
|
425
|
-
promise.reject("ERROR", "Failed to reject purposes: ${e.message}", e)
|
|
426
511
|
}
|
|
427
512
|
}
|
|
428
513
|
}
|
|
@@ -430,16 +515,18 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
430
515
|
@ReactMethod
|
|
431
516
|
fun rejectAll(promise: Promise) {
|
|
432
517
|
scope.launch {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
+
}
|
|
439
526
|
}
|
|
527
|
+
} catch (e: Exception) {
|
|
528
|
+
promise.reject("ERROR", "Failed to reject all: ${e.message}", e)
|
|
440
529
|
}
|
|
441
|
-
} catch (e: Exception) {
|
|
442
|
-
promise.reject("ERROR", "Failed to reject all: ${e.message}", e)
|
|
443
530
|
}
|
|
444
531
|
}
|
|
445
532
|
}
|
|
@@ -447,19 +534,98 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
447
534
|
@ReactMethod
|
|
448
535
|
fun acceptAll(promise: Promise) {
|
|
449
536
|
scope.launch {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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
|
+
}
|
|
456
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)
|
|
457
573
|
}
|
|
574
|
+
promise.resolve(result)
|
|
458
575
|
} catch (e: Exception) {
|
|
459
|
-
promise.reject("ERROR", "Failed to
|
|
576
|
+
promise.reject("ERROR", "Failed to update third-party consent: ${e.message}", e)
|
|
460
577
|
}
|
|
461
578
|
}
|
|
462
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
|
+
}
|
|
463
629
|
private fun ReadableArray.toListOfStrings(): List<String> {
|
|
464
630
|
val list = mutableListOf<String>()
|
|
465
631
|
for (i in 0 until this.size()) {
|
|
@@ -505,6 +671,20 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
505
671
|
}
|
|
506
672
|
}
|
|
507
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
|
+
|
|
508
688
|
companion object {
|
|
509
689
|
const val NAME = "CmSdkReactNativeV3"
|
|
510
690
|
private var globalCMPManager: CMPManager? = null
|
|
@@ -513,6 +693,11 @@ class CmSdkReactNativeV3Module(reactContext: ReactApplicationContext) :
|
|
|
513
693
|
|
|
514
694
|
override fun didReceiveConsent(consent: String, jsonObject: Map<String, Any>) {
|
|
515
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
|
+
|
|
516
701
|
val params = Arguments.createMap().apply {
|
|
517
702
|
putString("consent", consent)
|
|
518
703
|
putMap("jsonObject", convertMapToWritableMap(jsonObject))
|