From f81e78921175a89952d76870524d83ea740a93b9 Mon Sep 17 00:00:00 2001 From: Nicolas CHAIX Date: Mon, 3 Aug 2026 18:51:15 +0200 Subject: [PATCH] feat: add showWidget and hideWidget events Update native SDKs to 2.47.0 (iOS and Android) and expose the new widget events, mirroring didomi/flutter#157. - Add SHOW_WIDGET / HIDE_WIDGET to DidomiEventType, with a ShowWidgetEvent payload type (widgetId, layerName). - Bridge the events on both platforms. The iOS SDK names the property `widgetID` while Android names it `widgetId`; the event key is normalized to `widgetId` so the JS type matches on both platforms. - Register the events in the sample and test apps, and cover the new event types in DidomiListener tests. --- android/build.gradle | 2 +- .../io/didomi/reactnative/DidomiModule.kt | 22 ++++++++++++ .../java/io/didomi/reactnative/EventTypes.kt | 6 +++- ios/RNDidomi.swift | 19 +++++++++- package.json | 2 +- react-native-didomi.podspec | 2 +- sample/src/App.tsx | 2 ++ src/Constants.ts | 2 +- src/DidomiTypes.ts | 21 +++++++++++ src/__tests__/DidomiListener.test.ts | 36 +++++++++++++++++++ src/index.tsx | 3 +- test/src/App.tsx | 2 ++ 12 files changed, 112 insertions(+), 7 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 15112509..d9994047 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -158,5 +158,5 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation("com.google.code.gson:gson:2.13.1") - implementation "io.didomi.sdk:android:2.46.0" + implementation "io.didomi.sdk:android:2.47.0" } diff --git a/android/src/main/java/io/didomi/reactnative/DidomiModule.kt b/android/src/main/java/io/didomi/reactnative/DidomiModule.kt index a0eed0ea..7043818d 100644 --- a/android/src/main/java/io/didomi/reactnative/DidomiModule.kt +++ b/android/src/main/java/io/didomi/reactnative/DidomiModule.kt @@ -245,6 +245,16 @@ class DidomiModule(reactContext: ReactApplicationContext) : DidomiModuleSpec(rea * Error while using an external SDK integration */ override fun integrationError(event: IntegrationErrorEvent) = prepareIntegrationErrorEvent(event) + + /** + * A widget was displayed + */ + override fun showWidget(event: ShowWidgetEvent) = prepareShowWidgetEvent(event) + + /** + * A widget was hidden + */ + override fun hideWidget(event: HideWidgetEvent) = prepareEvent(EventTypes.HIDE_WIDGET.event, null) } private val vendorStatusListeners: MutableSet = mutableSetOf() @@ -1250,6 +1260,18 @@ class DidomiModule(reactContext: ReactApplicationContext) : DidomiModuleSpec(rea .emit(eventName, params) } + private fun prepareShowWidgetEvent(event: ShowWidgetEvent) { + val eventName = EventTypes.SHOW_WIDGET.event + Log.d("prepareEvent", "Sending $eventName") + val params = WritableNativeMap().apply { + putString("widgetId", event.widgetId) + putString("layerName", event.layerName) + } + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) + .emit(eventName, params) + } + // Required to transform from array to variadic. private fun readableArrayToStringArray(readableArray: ReadableArray) = readableArray.toSet().toTypedArray() diff --git a/android/src/main/java/io/didomi/reactnative/EventTypes.kt b/android/src/main/java/io/didomi/reactnative/EventTypes.kt index 4dc60a4a..7b887a2f 100644 --- a/android/src/main/java/io/didomi/reactnative/EventTypes.kt +++ b/android/src/main/java/io/didomi/reactnative/EventTypes.kt @@ -68,5 +68,9 @@ enum class EventTypes(val event: String) { VENDOR_STATUS_CHANGE_PREFIX("on_vendor_status_change_"), // Integrations - INTEGRATION_ERROR_EVENT("on_integration_error") + INTEGRATION_ERROR_EVENT("on_integration_error"), + + // Widgets + SHOW_WIDGET("on_show_widget"), + HIDE_WIDGET("on_hide_widget") } diff --git a/ios/RNDidomi.swift b/ios/RNDidomi.swift index 364d8ed4..3f237539 100644 --- a/ios/RNDidomi.swift +++ b/ios/RNDidomi.swift @@ -763,7 +763,10 @@ extension RNDidomi { "on_language_updated", "on_language_update_failed", // Integrations - "on_integration_error" + "on_integration_error", + // Widgets + "on_show_widget", + "on_hide_widget" ]) vendorStatusListeners.forEach { eventsSet.insert("on_vendor_status_change_\($0)") @@ -953,6 +956,20 @@ extension RNDidomi { self?.dispatchEvent(withName: "on_integration_error", body: result) } + // The iOS SDK names the property `widgetID` while Android names it `widgetId`. + // The event key must stay `widgetId` so both platforms match the JS type. + didomiEventListener.onShowWidget = { [weak self] event in + let result: [String: Any] = [ + "widgetId": event.widgetID as Any, + "layerName": event.layerName as Any + ] + self?.dispatchEvent(withName: "on_show_widget", body: result) + } + + didomiEventListener.onHideWidget = { [weak self] event in + self?.dispatchEvent(withName: "on_hide_widget", body: "") + } + Didomi.shared.addEventListener(listener: didomiEventListener) } diff --git a/package.json b/package.json index 13748fa8..d44c2d1e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@didomi/react-native", - "version": "2.31.0", + "version": "2.32.0", "description": "Didomi React Native SDK", "main": "lib/commonjs/index", "module": "lib/module/index", diff --git a/react-native-didomi.podspec b/react-native-didomi.podspec index 763ea81d..665d5582 100644 --- a/react-native-didomi.podspec +++ b/react-native-didomi.podspec @@ -15,7 +15,7 @@ Pod::Spec.new do |s| s.source_files = "ios/**/*.{h,m,mm,swift}" - s.dependency "Didomi-XCFramework", "2.46.0" + s.dependency "Didomi-XCFramework", "2.47.0" install_modules_dependencies(s) end diff --git a/sample/src/App.tsx b/sample/src/App.tsx index 7411f6c8..b7ff1b7e 100644 --- a/sample/src/App.tsx +++ b/sample/src/App.tsx @@ -65,6 +65,8 @@ function App() { registerListener(DidomiEventType.PREFERENCES_CLICK_VIEW_VENDORS); registerListener(DidomiEventType.LANGUAGE_UPDATED); registerListener(DidomiEventType.LANGUAGE_UPDATE_FAILED); + registerListener(DidomiEventType.SHOW_WIDGET); + registerListener(DidomiEventType.HIDE_WIDGET); Didomi.onReady().then(() => { console.log('ready'); diff --git a/src/Constants.ts b/src/Constants.ts index f84e3997..463ab2b1 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -1,4 +1,4 @@ // User agent name export const DIDOMI_USER_AGENT_NAME = "Didomi React-Native SDK" // User agent version -export const DIDOMI_VERSION = "2.31.0" +export const DIDOMI_VERSION = "2.32.0" diff --git a/src/DidomiTypes.ts b/src/DidomiTypes.ts index 12cfd383..0e3c10b4 100644 --- a/src/DidomiTypes.ts +++ b/src/DidomiTypes.ts @@ -77,6 +77,9 @@ export enum DidomiEventType { LANGUAGE_UPDATE_FAILED = "on_language_update_failed", // Integrations INTEGRATION_ERROR = "on_integration_error", + // Widgets + SHOW_WIDGET = "on_show_widget", + HIDE_WIDGET = "on_hide_widget", } export interface Vendor { @@ -190,6 +193,24 @@ export interface IntegrationErrorEvent { reason: string; } +/** + * A widget was displayed. + * Emitted with the {@link DidomiEventType#SHOW_WIDGET} event type. + * @interface + */ +export interface ShowWidgetEvent { + /** + * Identifier of the widget that was displayed, as resolved by the Rules Engine. + * @property + */ + widgetId?: string; + /** + * Name of the layer at which the widget was displayed. + * @property + */ + layerName?: string; +} + export interface UserAuth { id: string; } diff --git a/src/__tests__/DidomiListener.test.ts b/src/__tests__/DidomiListener.test.ts index dbb48c8b..67c78de1 100644 --- a/src/__tests__/DidomiListener.test.ts +++ b/src/__tests__/DidomiListener.test.ts @@ -31,3 +31,39 @@ describe('test remove listener', () => { expect(DidomiListener.listeners.get(DidomiEventType.ERROR).length).toBe(0); }); }); + +describe('test widget listeners', () => { + it('add and remove show widget listener', () => { + const callback = () => {}; + DidomiListener.addEventListener(DidomiEventType.SHOW_WIDGET, callback); + expect( + DidomiListener.listeners.get(DidomiEventType.SHOW_WIDGET).length + ).toBe(1); + DidomiListener.removeEventListener(DidomiEventType.SHOW_WIDGET, callback); + expect( + DidomiListener.listeners.get(DidomiEventType.SHOW_WIDGET).length + ).toBe(0); + }); + + it('add and remove hide widget listener', () => { + const callback = () => {}; + DidomiListener.addEventListener(DidomiEventType.HIDE_WIDGET, callback); + expect( + DidomiListener.listeners.get(DidomiEventType.HIDE_WIDGET).length + ).toBe(1); + DidomiListener.removeEventListener(DidomiEventType.HIDE_WIDGET, callback); + expect( + DidomiListener.listeners.get(DidomiEventType.HIDE_WIDGET).length + ).toBe(0); + }); + + it('registers the widget events with the native event emitter', () => { + DidomiListener.eventEmitter.addListener = jest.fn(); + DidomiListener.init(); + const registered = ( + DidomiListener.eventEmitter.addListener as jest.Mock + ).mock.calls.map((call) => call[0]); + expect(registered).toContain('on_show_widget'); + expect(registered).toContain('on_hide_widget'); + }); +}); diff --git a/src/index.tsx b/src/index.tsx index 65d71bf6..fd51dad0 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -13,5 +13,6 @@ export { VendorStatus, UserAuthWithEncryptionParams, UserAuthWithHashParams, - DidomiInitializeParameters + DidomiInitializeParameters, + ShowWidgetEvent } from './DidomiTypes'; diff --git a/test/src/App.tsx b/test/src/App.tsx index 57ffb74b..97de1c15 100644 --- a/test/src/App.tsx +++ b/test/src/App.tsx @@ -77,6 +77,8 @@ function App() { registerListener(DidomiEventType.LANGUAGE_UPDATED); registerListener(DidomiEventType.LANGUAGE_UPDATE_FAILED); registerListener(DidomiEventType.INTEGRATION_ERROR); + registerListener(DidomiEventType.SHOW_WIDGET); + registerListener(DidomiEventType.HIDE_WIDGET); }, [registerListener]); React.useEffect(() => {