From 3d4a3d248334f3cc5215ed5fbf51f7a333de19a4 Mon Sep 17 00:00:00 2001 From: Anush-Shand <127097095+Anush-Shand@users.noreply.github.com> Date: Tue, 17 Feb 2026 10:15:02 +0530 Subject: [PATCH] task(SDK-5520) - Release v3.9.0 (#494) * task(SDK-5520) - Release v3.9.0 Inaction and NestedObject support * task(SDK-5520) - Fixes a minor bump in nested object date ingestion * task(SDK-5520) - Fixes changelog date --- CHANGELOG.md | 13 +++ Example/app/App.js | 12 +++ Example/app/app-utils.js | 97 +++++++++++++++++++ Example/app/constants.js | 5 +- android/build.gradle | 6 +- .../clevertap/react/CleverTapModuleImpl.java | 27 ++++++ clevertap-react-native.podspec | 2 +- package.json | 2 +- src/index.js | 16 ++- 9 files changed, 172 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ddbb1c..330dd3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ Change Log ========== +Version 3.9.0 *(February 17 2026)* +------------------------------------------- +**What's new** +* **[Android Platform]** + * Supports [CleverTap Android SDK v7.8.0](https://github.com/CleverTap/clevertap-android-sdk/blob/master/docs/CTCORECHANGELOG.md#version-780-january-22-2026). + +* **[iOS Platform]** + * Supports [CleverTap iOS SDK v7.5.0](https://github.com/CleverTap/clevertap-ios-sdk/blob/master/CHANGELOG.md#version-750-february-9-2026). + +* **[Android and iOS Platform]** + * Adds support for inaction in-app notifications. This server-side feature allows triggering in-app notifications when users do not perform specific actions within a defined timeframe. + * Adds support for nested objects ingestion in event and profile properties, enabling more complex data structures for richer user profiling and event tracking. + Version 3.8.1 *(January 14 2026)* ------------------------------------------- **What's new** diff --git a/Example/app/App.js b/Example/app/App.js index 17384a6..736c00b 100644 --- a/Example/app/App.js +++ b/Example/app/App.js @@ -125,6 +125,7 @@ export default class App extends Component { categoryName: 'User Properties', subCategory: [ { action: Actions.SET_USER_PROFILE, name: 'pushProfile' }, + { action: Actions.PROFILE_PUSH_WITH_NESTED_PROPERTIES, name: 'pushProfile with nested properties' }, { action: Actions.SET_MULTI_VALUES, name: 'set Multi Values For Key' }, { action: Actions.REMOVE_MULTI_VALUE, @@ -139,6 +140,7 @@ export default class App extends Component { categoryName: 'Identity Management', subCategory: [ { action: Actions.USER_LOGIN, name: 'onUserLogin' }, + { action: Actions.USER_LOGIN_WITH_NESTED_PROPERTIES, name: 'onUserLogin with nested properties' }, { action: Actions.CLEVERTAP_ID, name: 'getCleverTapID' }, ], }, @@ -153,6 +155,7 @@ export default class App extends Component { categoryName: 'Events', subCategory: [ { action: Actions.PUSH_EVENT, name: 'pushEvent' }, + { action: Actions.RECORD_EVENT_WITH_NESTED_PROPERTIES, name: 'recordEvent with nested properties' }, { action: Actions.PUSH_CHARGED_EVENT, name: 'pushChargedEvent' }, ], }, @@ -430,6 +433,9 @@ export default class App extends Component { case Actions.SET_USER_PROFILE: AppUtils.set_userProfile(); break; + case Actions.PROFILE_PUSH_WITH_NESTED_PROPERTIES: + AppUtils.set_userProfileWithNestedProperties(); + break; case Actions.SET_MULTI_VALUES: CleverTap.profileSetMultiValuesForKey(['a', 'b', 'c'], 'letters'); break; @@ -458,6 +464,9 @@ export default class App extends Component { case Actions.USER_LOGIN: AppUtils.onUser_Login(); break; + case Actions.USER_LOGIN_WITH_NESTED_PROPERTIES: + AppUtils.onUser_LoginWithNestedProperties(); + break; case Actions.CLEVERTAP_ID: AppUtils.getCleverTap_id(); break; @@ -506,6 +515,9 @@ export default class App extends Component { case Actions.PUSH_EVENT: AppUtils.pushevent(); break; + case Actions.RECORD_EVENT_WITH_NESTED_PROPERTIES: + AppUtils.recordEventWithNestedProperties(); + break; case Actions.PUSH_CHARGED_EVENT: AppUtils.pushChargedEvent(); break; diff --git a/Example/app/app-utils.js b/Example/app/app-utils.js index 11bc6df..6ec0603 100644 --- a/Example/app/app-utils.js +++ b/Example/app/app-utils.js @@ -50,6 +50,40 @@ export const set_userProfile = () => { }); }; +export const set_userProfileWithNestedProperties = () => { + const profile = { + Name: 'testUserNested', + Identity: '123456', + Email: 'nested@test.com', + JoiningDate : new Date('2025-03-03T06:35:31'), + Address: { + street: '123 Main St', + city: 'San Francisco', + state: 'CA', + zipCode: 94105, + coordinates: { + lat: 37.7749, + lng: -122.4194 + } + }, + Preferences: { + newsletter: true, + notifications: { + email: true, + push: false, + sms: true + }, + subscriptionDate: new Date('2026-03-03T06:35:31'), + categories: ['sports', 'tech', 'news'], + dateProps: [new Date('2025-03-03T06:35:31'), new Date('2026-03-03T06:35:31'), new Date('2025-03-03T06:35:31')] + } + }; + + showToast('User Profile with Nested Properties', JSON.stringify(profile)); + console.log('Profile Push with nested properties: ', JSON.stringify(profile)); + CleverTap.profileSet(profile); +}; + // Identity_Management export const onUser_Login = () => { showToast('User Profile Updated'); @@ -64,6 +98,35 @@ export const onUser_Login = () => { }); }; +export const onUser_LoginWithNestedProperties = () => { + const profile = { + Name: 'testUserLogin', + Identity: new Date().getTime() + '', + Email: new Date().getTime() + 'logintest@test.com', + Company: { + name: 'TechCorp', + department: 'Engineering', + role: 'Senior Developer', + location: { + office: 'HQ', + floor: 5 + } + }, + Settings: { + theme: 'dark', + language: 'en', + privacy: { + shareData: false, + analytics: true + } + } + }; + + showToast('User Login with Nested Properties', JSON.stringify(profile)); + console.log('OnUserLogin with nested properties: ', JSON.stringify(profile)); + CleverTap.onUserLogin(profile); +}; + export const getCleverTap_id = () => { // Below method is deprecated since 0.6.0, please check index.js for deprecation, instead use CleverTap.getCleverTapID() /*CleverTap.profileGetCleverTapID((err, res) => { @@ -103,6 +166,40 @@ export const pushevent = () => { CleverTap.recordEvent('pushEvent'); }; +export const recordEventWithNestedProperties = () => { + const eventProps = { + 'Product Name': 'Premium Subscription', + 'Amount': 99.99, + 'Currency': 'USD', + 'Payment Details': { + method: 'credit_card', + provider: 'Stripe', + cardType: 'Visa', + lastFourDigits: '4242', + billingAddress: { + street: '456 Market St', + city: 'New York', + state: 'NY', + zipCode: 10001 + } + }, + 'User Metadata': { + isPremium: true, + tier: 'gold', + features: ['feature1', 'feature2', 'feature3'], + limits: { + apiCalls: 10000, + storage: 100 + } + }, + 'timestamp': new Date() + }; + + showToast('Event with Nested Properties', 'Product Purchased'); + console.log('Recording event with nested properties: ', JSON.stringify(eventProps)); + CleverTap.recordEvent('Product Purchased', eventProps); +}; + export const pushChargedEvent = () => { showToast('Charged Event Recorded'); diff --git a/Example/app/constants.js b/Example/app/constants.js index 5ce1919..b591cf0 100644 --- a/Example/app/constants.js +++ b/Example/app/constants.js @@ -97,5 +97,8 @@ export const Actions = { SYNC_CUSTOM_TEMPLATES_PROD: 'SYNC_CUSTOM_TEMPLATES_PROD', FILE_CHANGED: 'FILE_CHANGED', FILES_VARIABLES_CHANGED_AND_DOWNLOADED:'FILES_VARIABLES_CHANGED_AND_DOWNLOADED', - FILES_VARIABLES_CHANGED_AND_DOWNLOADED_ONCE:'FILES_VARIABLES_CHANGED_AND_DOWNLOADED_ONCE' + FILES_VARIABLES_CHANGED_AND_DOWNLOADED_ONCE:'FILES_VARIABLES_CHANGED_AND_DOWNLOADED_ONCE', + RECORD_EVENT_WITH_NESTED_PROPERTIES: 'RECORD_EVENT_WITH_NESTED_PROPERTIES', + PROFILE_PUSH_WITH_NESTED_PROPERTIES: 'PROFILE_PUSH_WITH_NESTED_PROPERTIES', + USER_LOGIN_WITH_NESTED_PROPERTIES: 'USER_LOGIN_WITH_NESTED_PROPERTIES' }; \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index a6ee61b..d35656a 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -35,8 +35,8 @@ android { defaultConfig { minSdkVersion 21 targetSdkVersion 35 - versionCode 381 - versionName "3.8.1" + versionCode 390 + versionName "3.9.0" buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()) } @@ -54,7 +54,7 @@ android { } dependencies { - api 'com.clevertap.android:clevertap-android-sdk:7.7.1' + api 'com.clevertap.android:clevertap-android-sdk:7.8.0' implementation 'com.android.installreferrer:installreferrer:2.2' //compile 'com.android.support:appcompat-v7:28.0.0' implementation 'com.facebook.react:react-native:+' diff --git a/android/src/main/java/com/clevertap/react/CleverTapModuleImpl.java b/android/src/main/java/com/clevertap/react/CleverTapModuleImpl.java index 55bfc62..5f4aa99 100644 --- a/android/src/main/java/com/clevertap/react/CleverTapModuleImpl.java +++ b/android/src/main/java/com/clevertap/react/CleverTapModuleImpl.java @@ -1606,6 +1606,24 @@ private HashMap eventPropsFromReadableMap(ReadableMap propsMap, C Log.e(TAG, "Unhandled ReadableType.Number from ReadableMap"); } } + } else if (readableType == ReadableType.Map) { + try { + ReadableMap nestedMap = propsMap.getMap(key); + if (nestedMap != null) { + props.put(key, tClass.cast(CleverTapUtils.MapUtil.toMap(nestedMap))); + } + } catch (Throwable t) { + Log.e(TAG, "Unhandled ReadableType.Map from ReadableMap"); + } + } else if (readableType == ReadableType.Array) { + try { + ReadableArray nestedArray = propsMap.getArray(key); + if (nestedArray != null) { + props.put(key, tClass.cast(CleverTapUtils.MapUtil.ArrayUtil.toArray(nestedArray))); + } + } catch (Throwable t) { + Log.e(TAG, "Unhandled ReadableType.Array from ReadableMap"); + } } else { Log.e(TAG, "Unhandled event property ReadableType"); } @@ -1721,6 +1739,15 @@ private HashMap profileFromReadableMap(ReadableMap profileMap) { } catch (Throwable t) { Log.e(TAG, "Unhandled ReadableType.Array from ReadableMap"); } + } else if (readableType == ReadableType.Map) { + try { + ReadableMap nestedMap = profileMap.getMap(key); + if (nestedMap != null) { + profile.put(key, CleverTapUtils.MapUtil.toMap(nestedMap)); + } + } catch (Throwable t) { + Log.e(TAG, "Unhandled ReadableType.Map from ReadableMap"); + } } else { Log.e(TAG, "Unhandled profile property ReadableType"); } diff --git a/clevertap-react-native.podspec b/clevertap-react-native.podspec index c4fdaa5..9ca527a 100644 --- a/clevertap-react-native.podspec +++ b/clevertap-react-native.podspec @@ -24,7 +24,7 @@ Pod::Spec.new do |s| s.dependency 'React-Core' end - s.dependency 'CleverTap-iOS-SDK', '7.4.2' + s.dependency 'CleverTap-iOS-SDK', '7.5.0' if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then s.pod_target_xcconfig = { diff --git a/package.json b/package.json index b9acbc9..cb9552b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "clevertap-react-native", - "version": "3.8.1", + "version": "3.9.0", "description": "CleverTap React Native SDK.", "main": "src/index.js", "types": "src/index.d.ts", diff --git a/src/index.js b/src/index.js index 86611af..f545e4e 100644 --- a/src/index.js +++ b/src/index.js @@ -12,7 +12,7 @@ const EventEmitter = Platform.select({ * @param {int} libVersion - The updated library version. If current version is 1.1.0 then pass as 10100 */ const libName = 'React-Native'; -const libVersion = 30801; +const libVersion = 30900; CleverTapReact.setLibrary(libName,libVersion); function defaultCallback(method, err, res) { @@ -1244,12 +1244,24 @@ var CleverTap = { function convertDateToEpochInProperties(map) { /** * Conversion of date object in suitable CleverTap format(Epoch) + * Recursively handles nested objects and arrays */ if (map) { for (let [key, value] of Object.entries(map)) { if (Object.prototype.toString.call(value) === '[object Date]') { map[key] = "$D_" + Math.floor(value.getTime() / 1000); - } + } else if (value !== null && typeof value === 'object' && !Array.isArray(value)) { + // Recursively convert dates in nested objects + convertDateToEpochInProperties(value); + } else if (Array.isArray(value)) { + value.forEach((item, index) => { + if (Object.prototype.toString.call(item) === '[object Date]') { + value[index] = "$D_" + Math.floor(item.getTime() / 1000); + } else if (item !== null && typeof item === 'object') { + convertDateToEpochInProperties(item); + } + }); + } } }