diff --git a/android/build.gradle b/android/build.gradle index 1c885ba8..bc69b3ea 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -124,5 +124,5 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation "io.didomi.sdk:android:1.88.0" + implementation "io.didomi.sdk:android:1.89.0" } diff --git a/android/src/main/java/com/reactnativedidomi/DidomiModule.kt b/android/src/main/java/com/reactnativedidomi/DidomiModule.kt index 05e1ea1a..985f1a70 100644 --- a/android/src/main/java/com/reactnativedidomi/DidomiModule.kt +++ b/android/src/main/java/com/reactnativedidomi/DidomiModule.kt @@ -615,6 +615,15 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava } } + @ReactMethod + fun getCurrentUserStatus(promise: Promise) { + try { + promise.resolve(objectToWritableMap(Didomi.getInstance().currentUserStatus)) + } catch (e: DidomiNotReadyException) { + promise.reject(e) + } + } + @ReactMethod fun getUserStatus(promise: Promise) { try { @@ -1082,6 +1091,7 @@ class DidomiModule(reactContext: ReactApplicationContext) : ReactContextBaseJava @ReactMethod fun shouldConsentBeCollected(promise: Promise) { try { + @Suppress("DEPRECATION") promise.resolve(Didomi.getInstance().shouldConsentBeCollected()) } catch (e: DidomiNotReadyException) { promise.reject(e) diff --git a/ios/Didomi.m b/ios/Didomi.m index 7464e894..054e7fd0 100644 --- a/ios/Didomi.m +++ b/ios/Didomi.m @@ -53,6 +53,9 @@ @interface RCT_EXTERN_MODULE(Didomi, RCTEventEmitter) resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) +RCT_EXTERN_METHOD(getCurrentUserStatus:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) + RCT_EXTERN_METHOD(getUserStatus:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) diff --git a/ios/RNDidomi.swift b/ios/RNDidomi.swift index 39f574c1..91c96052 100644 --- a/ios/RNDidomi.swift +++ b/ios/RNDidomi.swift @@ -97,6 +97,13 @@ class RNDidomi: RCTEventEmitter { resolve(consentStatus.rawValue.consentStatusBool) } + @objc(getCurrentUserStatus:reject:) + func getCurrentUserStatus(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) { + let encoder = JSONEncoder() + let currentUserStatus = try? JSONSerialization.jsonObject(with: encoder.encode(Didomi.shared.getCurrentUserStatus())) as? [String: Any] + resolve(currentUserStatus) + } + @objc(getUserStatus:reject:) func getUserStatus(resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock) { let encoder = JSONEncoder() diff --git a/react-native-didomi.podspec b/react-native-didomi.podspec index 30d9a032..552dd957 100644 --- a/react-native-didomi.podspec +++ b/react-native-didomi.podspec @@ -16,5 +16,5 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" s.dependency "React-Core" - s.dependency "Didomi-XCFramework", "1.97.0" + s.dependency "Didomi-XCFramework", "1.98.0" end diff --git a/sampleApp/android/app/build.gradle b/sampleApp/android/app/build.gradle index b9fe0e73..6386d3f9 100644 --- a/sampleApp/android/app/build.gradle +++ b/sampleApp/android/app/build.gradle @@ -255,6 +255,9 @@ android { } } } + buildFeatures { + buildConfig = true + } } dependencies { diff --git a/sampleApp/android/build.gradle b/sampleApp/android/build.gradle index a2b13ddf..8b22fcb8 100644 --- a/sampleApp/android/build.gradle +++ b/sampleApp/android/build.gradle @@ -23,7 +23,7 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.0.4") + classpath("com.android.tools.build:gradle:7.4.2") classpath("com.facebook.react:react-native-gradle-plugin") classpath("de.undercouch:gradle-download-task:4.1.2") // NOTE: Do not place your application dependencies here; they belong diff --git a/sampleApp/android/gradle/wrapper/gradle-wrapper.jar b/sampleApp/android/gradle/wrapper/gradle-wrapper.jar index 7454180f..249e5832 100644 Binary files a/sampleApp/android/gradle/wrapper/gradle-wrapper.jar and b/sampleApp/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/sampleApp/android/gradle/wrapper/gradle-wrapper.properties b/sampleApp/android/gradle/wrapper/gradle-wrapper.properties index 669386b8..2ec77e51 100644 --- a/sampleApp/android/gradle/wrapper/gradle-wrapper.properties +++ b/sampleApp/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/sampleApp/android/gradlew b/sampleApp/android/gradlew index 1b6c7873..a69d9cb6 100755 --- a/sampleApp/android/gradlew +++ b/sampleApp/android/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/sampleApp/android/gradlew.bat b/sampleApp/android/gradlew.bat index ac1b06f9..53a6b238 100644 --- a/sampleApp/android/gradlew.bat +++ b/sampleApp/android/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/sampleApp/src/Getters.tsx b/sampleApp/src/Getters.tsx index e2bd7bef..14f30672 100644 --- a/sampleApp/src/Getters.tsx +++ b/sampleApp/src/Getters.tsx @@ -96,6 +96,16 @@ export default function Getters() { }} /> + { + return await Didomi.getCurrentUserStatus(); + }} + test={() => { + return true; + }} + /> + {/* getJavaScriptForWebView getQueryStringForWebView diff --git a/src/Didomi.ts b/src/Didomi.ts index 348d383b..179a4d5d 100644 --- a/src/Didomi.ts +++ b/src/Didomi.ts @@ -1,6 +1,6 @@ import { NativeModules } from 'react-native'; import { DidomiListener } from './DidomiListener'; -import { DidomiEventType, Purpose, UserStatus, Vendor } from './DidomiTypes'; +import { DidomiEventType, Purpose, Vendor, UserStatus, CurrentUserStatus } from './DidomiTypes'; import { DIDOMI_USER_AGENT_NAME, DIDOMI_VERSION } from './Constants'; const { Didomi: RNDidomi } = NativeModules; @@ -318,6 +318,12 @@ export const Didomi = { */ getUserLegitimateInterestStatusForVendorAndRequiredPurposes: (vendorId: string): boolean => RNDidomi.getUserLegitimateInterestStatusForVendorAndRequiredPurposes(vendorId), + /** + * Get the current user consent status. + * @returns: status that represents current user consent. + */ + getCurrentUserStatus: (): Promise => RNDidomi.getCurrentUserStatus(), + /** * Get the user consent status. * @returns: status that represents user consent. diff --git a/src/DidomiTypes.ts b/src/DidomiTypes.ts index cd02c03e..eb677aa6 100644 --- a/src/DidomiTypes.ts +++ b/src/DidomiTypes.ts @@ -149,3 +149,25 @@ export interface UserStatusIds { disabled: string[]; enabled: string[]; } + +export interface CurrentUserStatus { + purposes: Map; + vendors: Map; + user_id: string; + created: string; + updated: string; + consent_string: string; + addtl_consent: string; + didomi_dcs: string; + regulation: string; +} + +export interface PurposeStatus { + id: string; + enabled: boolean; +} + +export interface VendorStatus { + id: string; + enabled: boolean; +} diff --git a/testApp/android/app/build.gradle b/testApp/android/app/build.gradle index 224e4797..b7c24b13 100644 --- a/testApp/android/app/build.gradle +++ b/testApp/android/app/build.gradle @@ -142,8 +142,10 @@ android { versionCode 1 versionName "1.0" - multiDexEnabled true - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled = true + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArguments["clearPackageData"] = "true" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { @@ -256,6 +258,13 @@ android { } } } + buildFeatures { + buildConfig = true + } + testOptions { + animationsDisabled = true + execution = "ANDROIDX_TEST_ORCHESTRATOR" + } } dependencies { @@ -302,6 +311,8 @@ dependencies { androidTestImplementation "androidx.test.ext:junit-ktx:1.1.5" androidTestImplementation "androidx.test:rules:1.5.0" androidTestImplementation "androidx.test:runner:1.5.2" + + androidTestUtil("androidx.test:orchestrator:1.4.2") } if (isNewArchitectureEnabled()) { diff --git a/testApp/android/app/src/androidTest/java/com/example/reactnativedidomi/UIGettersTest.kt b/testApp/android/app/src/androidTest/java/com/example/reactnativedidomi/UIGettersTest.kt index c43c646a..f25f6f6e 100644 --- a/testApp/android/app/src/androidTest/java/com/example/reactnativedidomi/UIGettersTest.kt +++ b/testApp/android/app/src/androidTest/java/com/example/reactnativedidomi/UIGettersTest.kt @@ -113,11 +113,17 @@ class UIGettersTest: BaseUITest() { tapButton("reset") tapButton("isUserStatusPartial") + + // There might be a delay to get this string. + Thread.sleep(500L) assertText("true") disagreeToAll() tapButton("isUserStatusPartial") + + // There might be a delay to get this string. + Thread.sleep(500L) assertText("false") } @@ -126,14 +132,22 @@ class UIGettersTest: BaseUITest() { tapButton("reset") tapButton("shouldUserStatusBeCollected") + + // There might be a delay to get this string. + Thread.sleep(500L) assertText("true") disagreeToAll() tapButton("shouldUserStatusBeCollected") + + // There might be a delay to get this string. + Thread.sleep(500L) assertText("false") } + /** getUserStatus */ + @Test fun test_getUserStatus() { tapButton("getUserStatus") @@ -198,4 +212,26 @@ class UIGettersTest: BaseUITest() { assertTextContains(",\"disabled\":[".trim()) assertTextContains("]}".trim()) } + + /** getCurrentUserStatus */ + + @Test + fun test_getCurrentUserStatus() { + tapButton("getCurrentUserStatus") + + // There might be a delay to get this string. + Thread.sleep(1_000L) + + // The text might change every time we call the getCurrentUserStatus method + // so we'll only assert the first level parameters of the resulting json string. + assertTextContains("\"addtl_consent\":\"\"".trim()) + assertTextContains("\"consent_string\":\"".trim()) + assertTextContains("\"purposes\":{\"".trim()) + assertTextContains("\"vendors\":{\"".trim()) + assertTextContains("\"user_id\":\"".trim()) + assertTextContains("\"created\":\"".trim()) + assertTextContains("\"updated\":\"".trim()) + assertTextContains("\"didomi_dcs\":\"\"".trim()) // DCS feature flag is disabled (empty string) + assertTextContains("\"regulation\":\"gdpr\"".trim()) + } } diff --git a/testApp/android/build.gradle b/testApp/android/build.gradle index a2b13ddf..8b22fcb8 100644 --- a/testApp/android/build.gradle +++ b/testApp/android/build.gradle @@ -23,7 +23,7 @@ buildscript { mavenCentral() } dependencies { - classpath("com.android.tools.build:gradle:7.0.4") + classpath("com.android.tools.build:gradle:7.4.2") classpath("com.facebook.react:react-native-gradle-plugin") classpath("de.undercouch:gradle-download-task:4.1.2") // NOTE: Do not place your application dependencies here; they belong diff --git a/testApp/android/gradle/wrapper/gradle-wrapper.jar b/testApp/android/gradle/wrapper/gradle-wrapper.jar index 7454180f..249e5832 100644 Binary files a/testApp/android/gradle/wrapper/gradle-wrapper.jar and b/testApp/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/testApp/android/gradle/wrapper/gradle-wrapper.properties b/testApp/android/gradle/wrapper/gradle-wrapper.properties index 669386b8..2ec77e51 100644 --- a/testApp/android/gradle/wrapper/gradle-wrapper.properties +++ b/testApp/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/testApp/android/gradlew b/testApp/android/gradlew index 1b6c7873..a69d9cb6 100755 --- a/testApp/android/gradlew +++ b/testApp/android/gradlew @@ -205,6 +205,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/testApp/android/gradlew.bat b/testApp/android/gradlew.bat index ac1b06f9..53a6b238 100644 --- a/testApp/android/gradlew.bat +++ b/testApp/android/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/testApp/ios/DidomiExampleUITests/DidomiExampleUITests.swift b/testApp/ios/DidomiExampleUITests/DidomiExampleUITests.swift index d7e24737..c9e4a6e2 100644 --- a/testApp/ios/DidomiExampleUITests/DidomiExampleUITests.swift +++ b/testApp/ios/DidomiExampleUITests/DidomiExampleUITests.swift @@ -278,6 +278,8 @@ class DidomiExampleUITests: XCTestCase { tapButton(in: app, name: "shouldUserStatusBeCollected") assertResult(in: app, name: "shouldUserStatusBeCollected", expected: "false") } + + // MARK: GetUserStatus func testGetUserStatus() throws { let app = initApp() @@ -293,14 +295,21 @@ class DidomiExampleUITests: XCTestCase { // so we'll only assert the first level parameters of the resulting json string. XCTAssertTrue(actual.contains("\"addtl_consent\":\"\"")) XCTAssertTrue(actual.contains("\"consent_string\":\"")) - XCTAssertTrue(actual.contains("\"purposes\":{\"legitimate_interest\":{\"enabled\":[")) - XCTAssertTrue(actual.contains("\"vendors\":{\"consent\":{\"enabled\":[")) + XCTAssertTrue(actual.contains("\"purposes\":{")) + XCTAssertTrue(actual.contains("\"legitimate_interest\":{\"enabled\":[")) // Purposes child - can change position + XCTAssertTrue(actual.contains("\"consent\":{\"enabled\":[")) // Purposes child - can change position + XCTAssertTrue(actual.contains("\"global\":{\"enabled\":[")) // Purposes child - can change position + XCTAssertTrue(actual.contains("\"vendors\":{")) + XCTAssertTrue(actual.contains("\"consent\":{\"enabled\":[")) // Vendors child - can change position + XCTAssertTrue(actual.contains("\"global\":{\"enabled\":[")) // Vendors child - can change position + XCTAssertTrue(actual.contains("\"global_consent\":{\"enabled\":[")) // Vendors child - can change position + XCTAssertTrue(actual.contains("\"global_li\":{\"enabled\":[")) // Vendors child - can change position + XCTAssertTrue(actual.contains("\"legitimate_interest\":{\"enabled\":[")) // Vendors child - can change position XCTAssertTrue(actual.contains("\"user_id\":\"")) XCTAssertTrue(actual.contains("\"created\":\"")) XCTAssertTrue(actual.contains("\"updated\":\"")) XCTAssertTrue(actual.contains("\"didomi_dcs\":\"\"")) // DCS feature flag is disabled (empty string) XCTAssertTrue(actual.contains("\"regulation\":\"gdpr\"")) - } func testGetUserStatus_Purposes() throws { @@ -356,6 +365,35 @@ class DidomiExampleUITests: XCTestCase { XCTAssertTrue(actual.contains(",\"disabled\":[")) XCTAssertTrue(actual.contains("]}")) } + + // MARK: GetCurrentUserStatus + + func testGetCurrentUserStatus() throws { + let app = initApp() + + tapButton(in: app, name: "getCurrentUserStatus") + + let staticText = app.staticTexts["getCurrentUserStatus-result"] + staticText.wait() + + let actual = staticText.label + + // The text might change every time we call the getCurrentUserStatus method + // so we'll only assert the first level parameters of the resulting json string. + XCTAssertTrue(actual.contains("\"addtl_consent\":\"\"")) + XCTAssertTrue(actual.contains("\"consent_string\":\"")) + XCTAssertTrue(actual.contains("\"purposes\":{\"")) + XCTAssertTrue(actual.contains("\"measure_content_performance\":")) // Key + XCTAssertTrue(actual.contains("\"id\":\"measure_content_performance\"")) // Value - id only because id/enabled can change position + XCTAssertTrue(actual.contains("\"vendors\":{\"")) + XCTAssertTrue(actual.contains("\"ipromote\":")) // Key + XCTAssertTrue(actual.contains("\"id\":\"ipromote\"")) // Value - id only because id/enabled can change position + XCTAssertTrue(actual.contains("\"user_id\":\"")) + XCTAssertTrue(actual.contains("\"created\":\"")) + XCTAssertTrue(actual.contains("\"updated\":\"")) + XCTAssertTrue(actual.contains("\"didomi_dcs\":\"\"")) // DCS feature flag is disabled (empty string) + XCTAssertTrue(actual.contains("\"regulation\":\"gdpr\"")) + } // MARK: GETTERS WITH PARAMS diff --git a/testApp/scripts/ios/run-ui-tests-locally-ios.sh b/testApp/scripts/ios/run-ui-tests-locally-ios.sh index 9ea084f6..07c35c6d 100755 --- a/testApp/scripts/ios/run-ui-tests-locally-ios.sh +++ b/testApp/scripts/ios/run-ui-tests-locally-ios.sh @@ -4,5 +4,5 @@ cd ios && TEST=1 && RCT_NO_LAUNCH_PACKAGER=1 xcodebuild \ -workspace DidomiExample.xcworkspace \ -scheme DidomiExample \ -sdk iphonesimulator \ --destination "platform=iOS Simulator,name=iPhone 11,OS=15.5" \ +-destination "platform=iOS Simulator,name=iPhone 15" \ clean test diff --git a/testApp/src/Getters.tsx b/testApp/src/Getters.tsx index 61135ff0..629ed573 100644 --- a/testApp/src/Getters.tsx +++ b/testApp/src/Getters.tsx @@ -166,6 +166,16 @@ export default function Getters() { }} /> + { + return await Didomi.getCurrentUserStatus(); + }} + test={() => { + return true; + }} + /> + {/* getJavaScriptForWebView getQueryStringForWebView