diff --git a/android/build.gradle b/android/build.gradle index a9da1978..720b34c9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -17,6 +17,7 @@ buildscript { apply plugin: "com.android.library" apply plugin: "kotlin-android" +apply plugin: "com.facebook.react" def getExtOrDefault(name) { return project.properties["Didomi_" + name].toString() @@ -26,12 +27,16 @@ def getExtOrIntegerDefault(name) { return project.properties["Didomi_" + name].toInteger() } +def isNewArchitectureEnabled() { + return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true" +} + def parsedPackage = new JsonSlurper().parseText(file("../package.json").text) android { compileSdk getExtOrIntegerDefault("compileSdkVersion") namespace "io.didomi.reactnative" - + defaultConfig { minSdk getExtOrIntegerDefault("minSdkVersion") targetSdk getExtOrIntegerDefault("targetSdkVersion") @@ -39,6 +44,22 @@ android { versionName "${parsedPackage.version}" multiDexEnabled = true + + buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() + } + + buildFeatures { + buildConfig = true + } + + sourceSets { + main { + if (isNewArchitectureEnabled()) { + java.srcDirs += ['src/newarch/java'] + } else { + java.srcDirs += ['src/oldarch/java'] + } + } } buildTypes { @@ -60,6 +81,12 @@ android { } +react { + jsRootDir = file("../src/specs") + libraryName = "RNDidomiSpec" + codegenJavaPackageName = "io.didomi.reactnative" +} + repositories { google() mavenLocal() diff --git a/android/src/main/java/io/didomi/reactnative/DidomiModule.kt b/android/src/main/java/io/didomi/reactnative/DidomiModule.kt index b2ba22a0..5941c53a 100644 --- a/android/src/main/java/io/didomi/reactnative/DidomiModule.kt +++ b/android/src/main/java/io/didomi/reactnative/DidomiModule.kt @@ -24,7 +24,11 @@ import org.json.JSONArray import org.json.JSONException import org.json.JSONObject -class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { +class DidomiModule(reactContext: ReactApplicationContext) : DidomiModuleSpec(reactContext) { + + companion object { + const val NAME = "Didomi" + } val gson = Gson() @@ -247,7 +251,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava private val syncAcknowledgedCallbacks: MutableMap Boolean> = mutableMapOf() private var syncAcknowledgedCallbackIndex = 0 - override fun getName() = "Didomi" + override fun getName() = NAME override fun getConstants(): Map { val map = mutableMapOf() @@ -327,7 +331,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun initialize( + override fun initialize( userAgentName: String, userAgentVersion: String, apiKey: String, @@ -375,7 +379,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun initializeWithParameters( + override fun initializeWithParameters( userAgentName: String, userAgentVersion: String, jsonParameters: String, @@ -399,19 +403,19 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun onReady(promise: Promise) { + override fun onReady(promise: Promise) { Didomi.getInstance().onReady { prepareEvent(EventTypes.READY_CALLBACK.event, null) } promise.resolve(0) } @ReactMethod - fun onError(promise: Promise) { + override fun onError(promise: Promise) { Didomi.getInstance().onError { prepareEvent(EventTypes.ERROR_CALLBACK.event, null) } promise.resolve(0) } @ReactMethod - fun setupUI(promise: Promise) { + override fun setupUI(promise: Promise) { try { runOnUiThread { Didomi.getInstance().setupUI(reactContext.currentActivity as? FragmentActivity) @@ -424,9 +428,9 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setLogLevel(level: Int, promise: Promise) { + override fun setLogLevel(level: Double, promise: Promise) { Didomi.getInstance().setLogLevel( - when (level) { + when (level.toInt()) { 0 -> Log.INFO 1 -> Log.DEBUG 2 -> Log.WARN @@ -439,7 +443,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getJavaScriptForWebView(extra: String?, promise: Promise) { + override fun getJavaScriptForWebView(extra: String?, promise: Promise) { try { extra?.also { promise.resolve(Didomi.getInstance().getJavaScriptForWebView(extra)) @@ -452,7 +456,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getQueryStringForWebView(promise: Promise) { + override fun getQueryStringForWebView(promise: Promise) { try { promise.resolve(Didomi.getInstance().queryStringForWebView) } catch (e: DidomiNotReadyException) { @@ -461,7 +465,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getPurpose(purposeId: String, promise: Promise) { + override fun getPurpose(purposeId: String, promise: Promise) { try { promise.resolve(objectToWritableMap(Didomi.getInstance().getPurpose(purposeId))) } catch (e: DidomiNotReadyException) { @@ -470,7 +474,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getRequiredPurposes(promise: Promise) { + override fun getRequiredPurposes(promise: Promise) { try { promise.resolve(setToWritableArray(Didomi.getInstance().requiredPurposes)) } catch (e: DidomiNotReadyException) { @@ -479,7 +483,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getRequiredPurposeIds(promise: Promise) { + override fun getRequiredPurposeIds(promise: Promise) { try { promise.resolve(setOfStringToWritableArray(Didomi.getInstance().requiredPurposeIds)) } catch (e: DidomiNotReadyException) { @@ -488,7 +492,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getVendor(vendorId: String, promise: Promise) { + override fun getVendor(vendorId: String, promise: Promise) { try { promise.resolve(objectToWritableMap(Didomi.getInstance().getVendor(vendorId))) } catch (e: DidomiNotReadyException) { @@ -497,7 +501,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getTotalVendorCount(promise: Promise) { + override fun getTotalVendorCount(promise: Promise) { try { promise.resolve(Didomi.getInstance().getTotalVendorCount()) } catch (e: DidomiNotReadyException) { @@ -506,7 +510,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getIabVendorCount(promise: Promise) { + override fun getIabVendorCount(promise: Promise) { try { promise.resolve(Didomi.getInstance().getIabVendorCount()) } catch (e: DidomiNotReadyException) { @@ -515,7 +519,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getNonIabVendorCount(promise: Promise) { + override fun getNonIabVendorCount(promise: Promise) { try { promise.resolve(Didomi.getInstance().getNonIabVendorCount()) } catch (e: DidomiNotReadyException) { @@ -524,7 +528,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getRequiredVendors(promise: Promise) { + override fun getRequiredVendors(promise: Promise) { try { promise.resolve(setToWritableArray(Didomi.getInstance().requiredVendors)) } catch (e: DidomiNotReadyException) { @@ -533,7 +537,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getRequiredVendorIds(promise: Promise) { + override fun getRequiredVendorIds(promise: Promise) { try { promise.resolve(setOfStringToWritableArray(Didomi.getInstance().requiredVendorIds)) } catch (e: DidomiNotReadyException) { @@ -542,7 +546,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getText(textKey: String, promise: Promise) { + override fun getText(textKey: String, promise: Promise) { try { val map = Didomi.getInstance().getText(textKey) val writableMap = WritableNativeMap() @@ -558,7 +562,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getTranslatedText(key: String, promise: Promise) { + override fun getTranslatedText(key: String, promise: Promise) { try { promise.resolve(Didomi.getInstance().getTranslatedText(key)) } catch (e: DidomiNotReadyException) { @@ -567,7 +571,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getCurrentUserStatus(promise: Promise) { + override fun getCurrentUserStatus(promise: Promise) { try { promise.resolve(objectToWritableMap(Didomi.getInstance().currentUserStatus)) } catch (e: DidomiNotReadyException) { @@ -576,7 +580,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getUserStatus(promise: Promise) { + override fun getUserStatus(promise: Promise) { try { promise.resolve(objectToWritableMap(Didomi.getInstance().userStatus)) } catch (e: DidomiNotReadyException) { @@ -585,7 +589,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun getApplicableRegulation(promise: Promise) { + override fun getApplicableRegulation(promise: Promise) { try { promise.resolve(Didomi.getInstance().applicableRegulation.value) } catch (e: DidomiNotReadyException) { @@ -594,7 +598,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun hideNotice(promise: Promise) { + override fun hideNotice(promise: Promise) { try { Didomi.getInstance().hideNotice() promise.resolve(0) @@ -604,7 +608,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun hidePreferences(promise: Promise) { + override fun hidePreferences(promise: Promise) { try { Didomi.getInstance().hidePreferences() promise.resolve(0) @@ -614,7 +618,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun isConsentRequired(promise: Promise) { + override fun isConsentRequired(promise: Promise) { try { promise.resolve(Didomi.getInstance().isConsentRequired) } catch (e: DidomiNotReadyException) { @@ -623,7 +627,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun shouldUserStatusBeCollected(promise: Promise) { + override fun shouldUserStatusBeCollected(promise: Promise) { try { promise.resolve(Didomi.getInstance().shouldUserStatusBeCollected()) } catch (e: DidomiNotReadyException) { @@ -632,7 +636,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun isUserConsentStatusPartial(promise: Promise) { + override fun isUserConsentStatusPartial(promise: Promise) { try { promise.resolve(Didomi.getInstance().isUserConsentStatusPartial) } catch (e: DidomiNotReadyException) { @@ -641,7 +645,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun isUserStatusPartial(promise: Promise) { + override fun isUserStatusPartial(promise: Promise) { try { promise.resolve(Didomi.getInstance().isUserStatusPartial) } catch (e: DidomiNotReadyException) { @@ -650,7 +654,16 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun isNoticeVisible(promise: Promise) { + override fun isUserLegitimateInterestStatusPartial(promise: Promise) { + try { + promise.resolve(Didomi.getInstance().isUserLegitimateInterestStatusPartial) + } catch (e: DidomiNotReadyException) { + promise.reject(e) + } + } + + @ReactMethod + override fun isNoticeVisible(promise: Promise) { try { promise.resolve(Didomi.getInstance().isNoticeVisible()) } catch (e: DidomiNotReadyException) { @@ -659,7 +672,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun isPreferencesVisible(promise: Promise) { + override fun isPreferencesVisible(promise: Promise) { try { promise.resolve(Didomi.getInstance().isPreferencesVisible()) } catch (e: DidomiNotReadyException) { @@ -668,35 +681,35 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun isError(promise: Promise) { + override fun isError(promise: Promise) { promise.resolve(Didomi.getInstance().isError) } @ReactMethod - fun isReady(promise: Promise) { + override fun isReady(promise: Promise) { promise.resolve(Didomi.getInstance().isReady) } @ReactMethod - fun clearUser(promise: Promise) { + override fun clearUser(promise: Promise) { Didomi.getInstance().clearUser() promise.resolve(0) } @ReactMethod - fun setUser(organizationUserId: String, promise: Promise) { + override fun setUser(organizationUserId: String, promise: Promise) { Didomi.getInstance().setUser(organizationUserId) promise.resolve(0) } @ReactMethod - fun setUserAndSetupUI(organizationUserId: String, promise: Promise) { + override fun setUserAndSetupUI(organizationUserId: String, promise: Promise) { Didomi.getInstance().setUser(organizationUserId, reactContext.currentActivity as? FragmentActivity) promise.resolve(0) } @ReactMethod - fun setUserWithHashAuth( + override fun setUserWithHashAuth( organizationUserId: String, algorithm: String, secretId: String, @@ -717,7 +730,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithHashAuthAndSetupUI( + override fun setUserWithHashAuthAndSetupUI( organizationUserId: String, algorithm: String, secretId: String, @@ -739,13 +752,13 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithHashAuthWithExpiration( + override fun setUserWithHashAuthWithExpiration( organizationUserId: String, algorithm: String, secretId: String, digest: String, salt: String?, - expiration: Int, + expiration: Double, promise: Promise ) { Didomi.getInstance().setUser( @@ -762,13 +775,13 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithHashAuthWithExpirationAndSetupUI( + override fun setUserWithHashAuthWithExpirationAndSetupUI( organizationUserId: String, algorithm: String, secretId: String, digest: String, salt: String?, - expiration: Int, + expiration: Double, promise: Promise ) { Didomi.getInstance().setUser( @@ -786,7 +799,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithEncryptionAuth( + override fun setUserWithEncryptionAuth( organizationUserId: String, algorithm: String, secretId: String, @@ -805,7 +818,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithEncryptionAuthAndSetupUI( + override fun setUserWithEncryptionAuthAndSetupUI( organizationUserId: String, algorithm: String, secretId: String, @@ -825,12 +838,12 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithEncryptionAuthWithExpiration( + override fun setUserWithEncryptionAuthWithExpiration( organizationUserId: String, algorithm: String, secretId: String, initializationVector: String, - expiration: Int, + expiration: Double, promise: Promise ) { Didomi.getInstance().setUser( @@ -846,12 +859,12 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithEncryptionAuthWithExpirationAndSetupUI( + override fun setUserWithEncryptionAuthWithExpirationAndSetupUI( organizationUserId: String, algorithm: String, secretId: String, initializationVector: String, - expiration: Int, + expiration: Double, promise: Promise ) { Didomi.getInstance().setUser( @@ -868,7 +881,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithAuthParams( + override fun setUserWithAuthParams( jsonUserAuthParams: String, jsonSynchronizedUsers: String?, promise: Promise @@ -895,7 +908,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithAuthParamsAndSetupUI( + override fun setUserWithAuthParamsAndSetupUI( jsonUserAuthParams: String, jsonSynchronizedUsers: String?, promise: Promise @@ -923,7 +936,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithParameters( + override fun setUserWithParameters( jsonUserParameters: String, promise: Promise ) { @@ -938,7 +951,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserWithParametersAndSetupUI( + override fun setUserWithParametersAndSetupUI( jsonUserParameters: String, promise: Promise ) { @@ -954,7 +967,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun showNotice(promise: Promise) { + override fun showNotice(promise: Promise) { try { runOnUiThread { Didomi.getInstance().showNotice(reactContext.currentActivity as? FragmentActivity) @@ -967,7 +980,20 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun showPreferences(view: String?, promise: Promise) { + override fun forceShowNotice(promise: Promise) { + try { + runOnUiThread { + Didomi.getInstance().forceShowNotice(reactContext.currentActivity as? FragmentActivity) + } + promise.resolve(0) + } catch (e: Exception) { + Log.e("forceShowNotice", "An error occurred while force-showing the notice", e) + promise.reject(e) + } + } + + @ReactMethod + override fun showPreferences(view: String?, promise: Promise) { try { runOnUiThread { view?.also { @@ -982,7 +1008,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun reset(promise: Promise) { + override fun reset(promise: Promise) { try { Didomi.getInstance().reset() promise.resolve(0) @@ -992,7 +1018,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserAgreeToAll(promise: Promise) { + override fun setUserAgreeToAll(promise: Promise) { try { promise.resolve(Didomi.getInstance().setUserAgreeToAll()) } catch (e: DidomiNotReadyException) { @@ -1001,7 +1027,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserDisagreeToAll(promise: Promise) { + override fun setUserDisagreeToAll(promise: Promise) { try { promise.resolve(Didomi.getInstance().setUserDisagreeToAll()) } catch (e: DidomiNotReadyException) { @@ -1010,7 +1036,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setCurrentUserStatus( + override fun setCurrentUserStatus( currentUserStatusAsString: String, promise: Promise ) { @@ -1025,7 +1051,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserStatus( + override fun setUserStatus( purposesConsentStatus: Boolean, purposesLIStatus: Boolean, vendorsConsentStatus: Boolean, @@ -1047,7 +1073,34 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun setUserStatusSets( + override fun setUserConsentStatus( + enabledPurposeIds: ReadableArray, + disabledPurposeIds: ReadableArray, + enabledVendorIds: ReadableArray, + disabledVendorIds: ReadableArray, + promise: Promise + ) { + try { + @Suppress("DEPRECATION") + promise.resolve( + Didomi.getInstance().setUserStatus( + enabledPurposeIds.toSet(), + disabledPurposeIds.toSet(), + emptySet(), + emptySet(), + enabledVendorIds.toSet(), + disabledVendorIds.toSet(), + emptySet(), + emptySet() + ) + ) + } catch (e: DidomiNotReadyException) { + promise.reject(e) + } + } + + @ReactMethod + override fun setUserStatusSets( enabledConsentPurposeIds: ReadableArray, disabledConsentPurposeIds: ReadableArray, enabledLIPurposeIds: ReadableArray, @@ -1077,7 +1130,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun shouldConsentBeCollected(promise: Promise) { + override fun shouldConsentBeCollected(promise: Promise) { try { @Suppress("DEPRECATION") promise.resolve(Didomi.getInstance().shouldConsentBeCollected()) @@ -1087,7 +1140,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun updateSelectedLanguage(languageCode: String, promise: Promise) { + override fun updateSelectedLanguage(languageCode: String, promise: Promise) { try { Didomi.getInstance().updateSelectedLanguage(languageCode) promise.resolve(0) @@ -1098,18 +1151,18 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava @Suppress("UNUSED_PARAMETER") @ReactMethod - fun addListener(eventName: String) { + override fun addListener(eventName: String) { // Keep: Required for RN built in Event Emitter Calls. } @Suppress("UNUSED_PARAMETER") @ReactMethod - fun removeListeners(count: Int) { + override fun removeListeners(count: Double) { // Keep: Required for RN built in Event Emitter Calls. } @ReactMethod - fun listenToVendorStatus(vendorId: String) { + override fun listenToVendorStatus(vendorId: String, promise: Promise) { if (!vendorStatusListeners.contains(vendorId)) { Didomi.getInstance().addVendorStatusListener(vendorId) { vendorStatus -> val statusAsMap = objectToWritableMap(vendorStatus) @@ -1117,18 +1170,20 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } vendorStatusListeners.add(vendorId) } + promise.resolve(0) } @ReactMethod - fun stopListeningToVendorStatus(vendorId: String) { + override fun stopListeningToVendorStatus(vendorId: String, promise: Promise) { if (vendorStatusListeners.contains(vendorId)) { Didomi.getInstance().removeVendorStatusListener(vendorId) vendorStatusListeners.remove(vendorId) } + promise.resolve(0) } @ReactMethod - fun commitCurrentUserStatusTransaction( + override fun commitCurrentUserStatusTransaction( enabledPurposes: ReadableArray, disabledPurposes: ReadableArray, enabledVendors: ReadableArray, @@ -1144,9 +1199,10 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun syncAcknowledged(callbackIndex: Int, promise: Promise) { - val result = syncAcknowledgedCallbacks[callbackIndex]?.let { it() } - syncAcknowledgedCallbacks.remove(callbackIndex) + override fun syncAcknowledged(callbackIndex: Double, promise: Promise) { + val index = callbackIndex.toInt() + val result = syncAcknowledgedCallbacks[index]?.let { it() } + syncAcknowledgedCallbacks.remove(index) if (result != null) { promise.resolve(result) } else { @@ -1155,8 +1211,8 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } @ReactMethod - fun removeSyncAcknowledgedCallback(callbackIndex: Int, promise: Promise) { - syncAcknowledgedCallbacks.remove(callbackIndex) + override fun removeSyncAcknowledgedCallback(callbackIndex: Double, promise: Promise) { + syncAcknowledgedCallbacks.remove(callbackIndex.toInt()) promise.resolve(0) } diff --git a/android/src/main/java/io/didomi/reactnative/DidomiPackage.kt b/android/src/main/java/io/didomi/reactnative/DidomiPackage.kt index 1daa798e..f63e492f 100644 --- a/android/src/main/java/io/didomi/reactnative/DidomiPackage.kt +++ b/android/src/main/java/io/didomi/reactnative/DidomiPackage.kt @@ -1,16 +1,27 @@ package io.didomi.reactnative -import com.facebook.react.ReactPackage +import com.facebook.react.TurboReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext -import com.facebook.react.uimanager.ViewManager +import com.facebook.react.module.model.ReactModuleInfo +import com.facebook.react.module.model.ReactModuleInfoProvider -class DidomiPackage : ReactPackage { - override fun createNativeModules(reactContext: ReactApplicationContext): List { - return listOf(DidomiModule(reactContext)) - } +class DidomiPackage : TurboReactPackage() { + + override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = + if (name == DidomiModule.NAME) DidomiModule(reactContext) else null - override fun createViewManagers(reactContext: ReactApplicationContext): List> { - return emptyList() + override fun getReactModuleInfoProvider() = ReactModuleInfoProvider { + mapOf( + DidomiModule.NAME to ReactModuleInfo( + DidomiModule.NAME, + DidomiModule.NAME, + false, // canOverrideExistingModule + false, // needsEagerInit + true, // hasConstants — DidomiModule.getConstants() exposes event registration names + false, // isCxxModule + BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + ) + ) } } diff --git a/android/src/newarch/java/io/didomi/reactnative/DidomiModuleSpec.kt b/android/src/newarch/java/io/didomi/reactnative/DidomiModuleSpec.kt new file mode 100644 index 00000000..79f76d9b --- /dev/null +++ b/android/src/newarch/java/io/didomi/reactnative/DidomiModuleSpec.kt @@ -0,0 +1,6 @@ +package io.didomi.reactnative + +import com.facebook.react.bridge.ReactApplicationContext + +abstract class DidomiModuleSpec(reactContext: ReactApplicationContext) : + NativeDidomiSpec(reactContext) diff --git a/android/src/oldarch/java/io/didomi/reactnative/DidomiModuleSpec.kt b/android/src/oldarch/java/io/didomi/reactnative/DidomiModuleSpec.kt new file mode 100644 index 00000000..65de652d --- /dev/null +++ b/android/src/oldarch/java/io/didomi/reactnative/DidomiModuleSpec.kt @@ -0,0 +1,222 @@ +package io.didomi.reactnative + +import com.facebook.react.bridge.Promise +import com.facebook.react.bridge.ReactApplicationContext +import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReadableArray + +/** + * Old-architecture base class. + * + * Under the new architecture this class is replaced (via Gradle source-set selection) + * by one that extends the codegen-generated `NativeDidomiSpec`. The codegen base declares + * all spec methods as `open`, so subclasses must mark them `override`. To keep + * `DidomiModule` source identical between architectures, the old-arch variant of + * `DidomiModuleSpec` declares the same methods here as `open` stubs that throw + * if not overridden — they are always overridden by `DidomiModule`. + */ +abstract class DidomiModuleSpec(reactContext: ReactApplicationContext) : + ReactContextBaseJavaModule(reactContext) { + + private fun stub(): Nothing = + throw NotImplementedError("DidomiModuleSpec stub: subclass must override") + + open fun initialize( + userAgentName: String, + userAgentVersion: String, + apiKey: String, + localConfigurationPath: String?, + remoteConfigurationUrl: String?, + providerId: String?, + disableDidomiRemoteConfig: Boolean, + languageCode: String?, + noticeId: String?, + androidTvNoticeId: String?, + androidTvEnabled: Boolean, + countryCode: String?, + regionCode: String?, + promise: Promise + ): Unit = stub() + + open fun initializeWithParameters( + userAgentName: String, + userAgentVersion: String, + jsonParameters: String, + promise: Promise + ): Unit = stub() + + open fun onReady(promise: Promise): Unit = stub() + open fun onError(promise: Promise): Unit = stub() + open fun setupUI(promise: Promise): Unit = stub() + open fun setLogLevel(level: Double, promise: Promise): Unit = stub() + open fun getJavaScriptForWebView(extra: String?, promise: Promise): Unit = stub() + open fun getQueryStringForWebView(promise: Promise): Unit = stub() + open fun getPurpose(purposeId: String, promise: Promise): Unit = stub() + open fun getRequiredPurposes(promise: Promise): Unit = stub() + open fun getRequiredPurposeIds(promise: Promise): Unit = stub() + open fun getVendor(vendorId: String, promise: Promise): Unit = stub() + open fun getTotalVendorCount(promise: Promise): Unit = stub() + open fun getIabVendorCount(promise: Promise): Unit = stub() + open fun getNonIabVendorCount(promise: Promise): Unit = stub() + open fun getRequiredVendors(promise: Promise): Unit = stub() + open fun getRequiredVendorIds(promise: Promise): Unit = stub() + open fun getText(textKey: String, promise: Promise): Unit = stub() + open fun getTranslatedText(key: String, promise: Promise): Unit = stub() + open fun getCurrentUserStatus(promise: Promise): Unit = stub() + open fun getUserStatus(promise: Promise): Unit = stub() + open fun getApplicableRegulation(promise: Promise): Unit = stub() + open fun hideNotice(promise: Promise): Unit = stub() + open fun hidePreferences(promise: Promise): Unit = stub() + open fun isConsentRequired(promise: Promise): Unit = stub() + open fun shouldUserStatusBeCollected(promise: Promise): Unit = stub() + open fun isUserConsentStatusPartial(promise: Promise): Unit = stub() + open fun isUserStatusPartial(promise: Promise): Unit = stub() + open fun isUserLegitimateInterestStatusPartial(promise: Promise): Unit = stub() + open fun isNoticeVisible(promise: Promise): Unit = stub() + open fun isPreferencesVisible(promise: Promise): Unit = stub() + open fun isError(promise: Promise): Unit = stub() + open fun isReady(promise: Promise): Unit = stub() + open fun clearUser(promise: Promise): Unit = stub() + open fun setUser(organizationUserId: String, promise: Promise): Unit = stub() + open fun setUserAndSetupUI(organizationUserId: String, promise: Promise): Unit = stub() + + open fun setUserWithHashAuth( + organizationUserId: String, + algorithm: String, + secretId: String, + digest: String, + salt: String?, + promise: Promise + ): Unit = stub() + + open fun setUserWithHashAuthAndSetupUI( + organizationUserId: String, + algorithm: String, + secretId: String, + digest: String, + salt: String?, + promise: Promise + ): Unit = stub() + + open fun setUserWithHashAuthWithExpiration( + organizationUserId: String, + algorithm: String, + secretId: String, + digest: String, + salt: String?, + expiration: Double, + promise: Promise + ): Unit = stub() + + open fun setUserWithHashAuthWithExpirationAndSetupUI( + organizationUserId: String, + algorithm: String, + secretId: String, + digest: String, + salt: String?, + expiration: Double, + promise: Promise + ): Unit = stub() + + open fun setUserWithEncryptionAuth( + organizationUserId: String, + algorithm: String, + secretId: String, + initializationVector: String, + promise: Promise + ): Unit = stub() + + open fun setUserWithEncryptionAuthAndSetupUI( + organizationUserId: String, + algorithm: String, + secretId: String, + initializationVector: String, + promise: Promise + ): Unit = stub() + + open fun setUserWithEncryptionAuthWithExpiration( + organizationUserId: String, + algorithm: String, + secretId: String, + initializationVector: String, + expiration: Double, + promise: Promise + ): Unit = stub() + + open fun setUserWithEncryptionAuthWithExpirationAndSetupUI( + organizationUserId: String, + algorithm: String, + secretId: String, + initializationVector: String, + expiration: Double, + promise: Promise + ): Unit = stub() + + open fun setUserWithAuthParams( + jsonUserAuthParams: String, + jsonSynchronizedUsers: String?, + promise: Promise + ): Unit = stub() + + open fun setUserWithAuthParamsAndSetupUI( + jsonUserAuthParams: String, + jsonSynchronizedUsers: String?, + promise: Promise + ): Unit = stub() + + open fun setUserWithParameters(jsonUserParameters: String, promise: Promise): Unit = stub() + open fun setUserWithParametersAndSetupUI(jsonUserParameters: String, promise: Promise): Unit = stub() + open fun showNotice(promise: Promise): Unit = stub() + open fun forceShowNotice(promise: Promise): Unit = stub() + open fun showPreferences(view: String?, promise: Promise): Unit = stub() + open fun reset(promise: Promise): Unit = stub() + open fun setUserAgreeToAll(promise: Promise): Unit = stub() + open fun setUserDisagreeToAll(promise: Promise): Unit = stub() + open fun setCurrentUserStatus(currentUserStatusAsString: String, promise: Promise): Unit = stub() + + open fun setUserStatus( + purposesConsentStatus: Boolean, + purposesLIStatus: Boolean, + vendorsConsentStatus: Boolean, + vendorsLIStatus: Boolean, + promise: Promise + ): Unit = stub() + + open fun setUserConsentStatus( + enabledPurposeIds: ReadableArray, + disabledPurposeIds: ReadableArray, + enabledVendorIds: ReadableArray, + disabledVendorIds: ReadableArray, + promise: Promise + ): Unit = stub() + + open fun setUserStatusSets( + enabledConsentPurposeIds: ReadableArray, + disabledConsentPurposeIds: ReadableArray, + enabledLIPurposeIds: ReadableArray, + disabledLIPurposeIds: ReadableArray, + enabledConsentVendorIds: ReadableArray, + disabledConsentVendorIds: ReadableArray, + enabledLIVendorIds: ReadableArray, + disabledLIVendorIds: ReadableArray, + promise: Promise + ): Unit = stub() + + open fun shouldConsentBeCollected(promise: Promise): Unit = stub() + open fun updateSelectedLanguage(languageCode: String, promise: Promise): Unit = stub() + open fun addListener(eventName: String): Unit = stub() + open fun removeListeners(count: Double): Unit = stub() + open fun listenToVendorStatus(vendorId: String, promise: Promise): Unit = stub() + open fun stopListeningToVendorStatus(vendorId: String, promise: Promise): Unit = stub() + + open fun commitCurrentUserStatusTransaction( + enabledPurposes: ReadableArray, + disabledPurposes: ReadableArray, + enabledVendors: ReadableArray, + disabledVendors: ReadableArray, + promise: Promise + ): Unit = stub() + + open fun syncAcknowledged(callbackIndex: Double, promise: Promise): Unit = stub() + open fun removeSyncAcknowledgedCallback(callbackIndex: Double, promise: Promise): Unit = stub() +} diff --git a/ios/Didomi.m b/ios/Didomi.m index ce91cfc6..b69f41b9 100644 --- a/ios/Didomi.m +++ b/ios/Didomi.m @@ -50,6 +50,12 @@ @interface RCT_EXTERN_MODULE(Didomi, RCTEventEmitter) RCT_EXTERN_METHOD(isUserLegitimateInterestStatusPartial:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(isUserConsentStatusPartial:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) + +RCT_EXTERN_METHOD(isError:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) + RCT_EXTERN_METHOD(isUserStatusPartial:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) diff --git a/ios/RNDidomi+TurboModule.mm b/ios/RNDidomi+TurboModule.mm new file mode 100644 index 00000000..152b0af0 --- /dev/null +++ b/ios/RNDidomi+TurboModule.mm @@ -0,0 +1,24 @@ +#ifdef RCT_NEW_ARCH_ENABLED + +#import +#import +#import +#import "RNDidomiSpec/RNDidomiSpec.h" + +@interface Didomi : RCTEventEmitter +@end + +@interface Didomi (TurboModule) +@end + +@implementation Didomi (TurboModule) + +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return std::make_shared(params); +} + +@end + +#endif diff --git a/ios/RNDidomi.swift b/ios/RNDidomi.swift index 8afd9053..b66c79d8 100644 --- a/ios/RNDidomi.swift +++ b/ios/RNDidomi.swift @@ -121,6 +121,11 @@ class RNDidomi: RCTEventEmitter { resolve(Didomi.shared.isUserConsentStatusPartial()) } + @objc(isError:reject:) + func isError(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) { + resolve(Didomi.shared.isError()) + } + @objc(isUserStatusPartial:reject:) func isUserStatusPartial(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) { resolve(Didomi.shared.isUserStatusPartial()) diff --git a/package.json b/package.json index dc900397..b39d997c 100644 --- a/package.json +++ b/package.json @@ -98,5 +98,14 @@ "plugins": [ "./plugin/withDidomi.js" ] + }, + "codegenConfig": { + "name": "RNDidomiSpec", + "type": "modules", + "jsSrcsDir": "src/specs", + "android": { + "javaPackageName": "io.didomi.reactnative" + }, + "includesGeneratedCode": false } } diff --git a/react-native-didomi.podspec b/react-native-didomi.podspec index 023d478b..8c99baeb 100644 --- a/react-native-didomi.podspec +++ b/react-native-didomi.podspec @@ -15,6 +15,7 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" - s.dependency "React-Core" s.dependency "Didomi-XCFramework", "2.42.0" + + install_modules_dependencies(s) end diff --git a/src/Didomi.ts b/src/Didomi.ts index 1d0e03f2..26acfd57 100644 --- a/src/Didomi.ts +++ b/src/Didomi.ts @@ -1,10 +1,10 @@ -import { NativeModules } from 'react-native'; +import NativeDidomi from './specs/NativeDidomi'; import { DidomiListener } from './DidomiListener'; import { DidomiEventType, Purpose, Vendor, UserStatus, CurrentUserStatus, VendorStatus, UserAuthParams, DidomiInitializeParameters, DidomiUserParameters, UserAuthWithEncryptionParams, UserAuthWithHashParams, DidomiMultiUserParameters } from './DidomiTypes'; import { DIDOMI_USER_AGENT_NAME, DIDOMI_VERSION } from './Constants'; import { CurrentUserStatusTransaction, createCurrentUserStatusTransaction } from './CurrentUserStatusTransaction'; -const { Didomi: RNDidomi } = NativeModules; +const RNDidomi = NativeDidomi as any; export const Didomi = { /** diff --git a/src/DidomiListener.ts b/src/DidomiListener.ts index 2d73626a..11405c65 100644 --- a/src/DidomiListener.ts +++ b/src/DidomiListener.ts @@ -1,7 +1,8 @@ -import { NativeModules, NativeEventEmitter } from 'react-native'; +import { NativeEventEmitter } from 'react-native'; +import NativeDidomi from './specs/NativeDidomi'; import { DidomiEventType, VendorStatus } from './DidomiTypes'; -const { Didomi: RNDidomi } = NativeModules; +const RNDidomi = NativeDidomi as any; enum InternalEventType { READY_CALLBACK = 'on_ready_callback', diff --git a/src/__tests__/DidomiListener.test.ts b/src/__tests__/DidomiListener.test.ts index ebe813c0..dbb48c8b 100644 --- a/src/__tests__/DidomiListener.test.ts +++ b/src/__tests__/DidomiListener.test.ts @@ -1,9 +1,20 @@ -import { DidomiListener } from '../DidomiListener'; -import { DidomiEventType } from '../DidomiTypes'; - // Mocked NativeEventEmitter jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter'); +// Mock the spec module so TurboModuleRegistry.getEnforcing doesn't throw in unit tests +jest.mock('../specs/NativeDidomi', () => ({ + __esModule: true, + default: { + addListener: jest.fn(), + removeListeners: jest.fn(), + syncAcknowledged: jest.fn(), + removeSyncAcknowledgedCallback: jest.fn(), + }, +})); + +import { DidomiListener } from '../DidomiListener'; +import { DidomiEventType } from '../DidomiTypes'; + describe('test add listener', () => { it('add listener', () => { DidomiListener.addEventListener(DidomiEventType.READY, () => {}); diff --git a/src/specs/NativeDidomi.ts b/src/specs/NativeDidomi.ts new file mode 100644 index 00000000..95c021a9 --- /dev/null +++ b/src/specs/NativeDidomi.ts @@ -0,0 +1,187 @@ +import type { TurboModule } from 'react-native'; +import { TurboModuleRegistry } from 'react-native'; + +export interface Spec extends TurboModule { + initialize( + userAgentName: string, + userAgentVersion: string, + apiKey: string, + localConfigurationPath: string | null, + remoteConfigurationURL: string | null, + providerId: string | null, + disableDidomiRemoteConfig: boolean, + languageCode: string | null, + noticeId: string | null, + androidTvNoticeId: string | null, + androidTvEnabled: boolean, + countryCode: string | null, + regionCode: string | null + ): Promise; + + initializeWithParameters( + userAgentName: string, + userAgentVersion: string, + parameters: string + ): Promise; + + onReady(): Promise; + onError(): Promise; + isReady(): Promise; + isError(): Promise; + reset(): Promise; + clearUser(): Promise; + + setupUI(): Promise; + forceShowNotice(): Promise; + showNotice(): Promise; + hideNotice(): Promise; + isNoticeVisible(): Promise; + showPreferences(view: string | null): Promise; + hidePreferences(): Promise; + isPreferencesVisible(): Promise; + + isConsentRequired(): Promise; + shouldUserStatusBeCollected(): Promise; + shouldConsentBeCollected(): Promise; + isUserConsentStatusPartial(): Promise; + isUserStatusPartial(): Promise; + isUserLegitimateInterestStatusPartial(): Promise; + + getCurrentUserStatus(): Promise; + setCurrentUserStatus(currentUserStatusAsString: string): Promise; + getUserStatus(): Promise; + setUserStatus( + purposesConsentStatus: boolean, + purposesLIStatus: boolean, + vendorsConsentStatus: boolean, + vendorsLIStatus: boolean + ): Promise; + setUserStatusSets( + enabledConsentPurposeIds: Array, + disabledConsentPurposeIds: Array, + enabledLIPurposeIds: Array, + disabledLIPurposeIds: Array, + enabledConsentVendorIds: Array, + disabledConsentVendorIds: Array, + enabledLIVendorIds: Array, + disabledLIVendorIds: Array + ): Promise; + setUserConsentStatus( + enabledPurposeIds: Array, + disabledPurposeIds: Array, + enabledVendorIds: Array, + disabledVendorIds: Array + ): Promise; + setUserAgreeToAll(): Promise; + setUserDisagreeToAll(): Promise; + + getApplicableRegulation(): Promise; + getPurpose(purposeId: string): Promise; + getRequiredPurposes(): Promise; + getRequiredPurposeIds(): Promise>; + getVendor(vendorId: string): Promise; + getRequiredVendors(): Promise; + getRequiredVendorIds(): Promise>; + getTotalVendorCount(): Promise; + getIabVendorCount(): Promise; + getNonIabVendorCount(): Promise; + + getText(key: string): Promise; + getTranslatedText(key: string): Promise; + getJavaScriptForWebView(extra: string | null): Promise; + getQueryStringForWebView(): Promise; + updateSelectedLanguage(languageCode: string): Promise; + + setLogLevel(level: number): Promise; + + setUser(id: string): Promise; + setUserAndSetupUI(id: string): Promise; + + setUserWithHashAuth( + id: string, + algorithm: string, + secretId: string, + digest: string, + salt: string | null + ): Promise; + setUserWithHashAuthAndSetupUI( + id: string, + algorithm: string, + secretId: string, + digest: string, + salt: string | null + ): Promise; + setUserWithHashAuthWithExpiration( + id: string, + algorithm: string, + secretId: string, + digest: string, + salt: string | null, + expiration: number + ): Promise; + setUserWithHashAuthWithExpirationAndSetupUI( + id: string, + algorithm: string, + secretId: string, + digest: string, + salt: string | null, + expiration: number + ): Promise; + + setUserWithEncryptionAuth( + id: string, + algorithm: string, + secretId: string, + initializationVector: string + ): Promise; + setUserWithEncryptionAuthAndSetupUI( + id: string, + algorithm: string, + secretId: string, + initializationVector: string + ): Promise; + setUserWithEncryptionAuthWithExpiration( + id: string, + algorithm: string, + secretId: string, + initializationVector: string, + expiration: number + ): Promise; + setUserWithEncryptionAuthWithExpirationAndSetupUI( + id: string, + algorithm: string, + secretId: string, + initializationVector: string, + expiration: number + ): Promise; + + setUserWithAuthParams( + jsonUserAuthParams: string, + jsonSynchronizedUsers: string | null + ): Promise; + setUserWithAuthParamsAndSetupUI( + jsonUserAuthParams: string, + jsonSynchronizedUsers: string | null + ): Promise; + + setUserWithParameters(jsonParameters: string): Promise; + setUserWithParametersAndSetupUI(jsonParameters: string): Promise; + + listenToVendorStatus(vendorId: string): Promise; + stopListeningToVendorStatus(vendorId: string): Promise; + + commitCurrentUserStatusTransaction( + enabledPurposes: Array, + disabledPurposes: Array, + enabledVendors: Array, + disabledVendors: Array + ): Promise; + + syncAcknowledged(callbackIndex: number): Promise; + removeSyncAcknowledgedCallback(callbackIndex: number): Promise; + + addListener(eventName: string): void; + removeListeners(count: number): void; +} + +export default TurboModuleRegistry.getEnforcing('Didomi');