From 8598e932bde5a318798f704e3264217bae8fae1f Mon Sep 17 00:00:00 2001 From: Farhan Anjum Date: Fri, 27 Sep 2024 22:25:57 +0600 Subject: [PATCH 1/5] [FSSDK-10665] fix: Github Actions YAML files vulnerable to script injections corrected (#77) --- .github/workflows/flutter.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index ed8d977..89d9093 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -37,14 +37,18 @@ jobs: path: 'home/runner/travisci-tools' ref: 'master' - name: set SDK Branch if PR + env: + HEAD_REF: ${{ github.head_ref }} if: ${{ github.event_name == 'pull_request' }} run: | - echo "SDK_BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV + echo "SDK_BRANCH=$HEAD_REF" >> $GITHUB_ENV - name: set SDK Branch if not pull request + env: + REF_NAME: ${{ github.ref_name }} if: ${{ github.event_name != 'pull_request' }} run: | - echo "SDK_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV - echo "TRAVIS_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV + echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV + echo "TRAVIS_BRANCH=$REF_NAME" >> $GITHUB_ENV - name: Trigger build env: SDK: android @@ -75,14 +79,18 @@ jobs: path: 'home/runner/travisci-tools' ref: 'master' - name: set SDK Branch if PR + env: + HEAD_REF: ${{ github.head_ref }} if: ${{ github.event_name == 'pull_request' }} run: | - echo "SDK_BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV + echo "SDK_BRANCH=$HEAD_REF" >> $GITHUB_ENV - name: set SDK Branch if not pull request + env: + REF_NAME: ${{ github.ref_name }} if: ${{ github.event_name != 'pull_request' }} run: | - echo "SDK_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV - echo "TRAVIS_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV + echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV + echo "TRAVIS_BRANCH=$REF_NAME" >> $GITHUB_ENV - name: Trigger build env: SDK: ios From dc4afe8d5108aa813cf8742614e33bed72453165 Mon Sep 17 00:00:00 2001 From: Muzahidul Islam <129880873+muzahidul-opti@users.noreply.github.com> Date: Thu, 28 Nov 2024 20:29:12 +0600 Subject: [PATCH 2/5] [FSSDK-10759] feat: make vuid optln (#78) VUID optln implemented for flutter --- .github/workflows/flutter.yml | 25 ++++++++++ android/build.gradle | 2 +- .../OptimizelyFlutterClient.java | 10 +++- .../helper_classes/Constants.java | 1 + ios/Classes/HelperClasses/Constants.swift | 1 + .../SwiftOptimizelyFlutterSdkPlugin.swift | 10 ++-- ios/optimizely_flutter_sdk.podspec | 2 +- lib/src/data_objects/get_vuid_response.dart | 2 +- lib/src/data_objects/sdk_settings.dart | 3 ++ lib/src/optimizely_client_wrapper.dart | 1 + lib/src/utils/constants.dart | 1 + test/optimizely_flutter_sdk_test.dart | 48 +++++++++++++++---- 12 files changed, 91 insertions(+), 15 deletions(-) diff --git a/.github/workflows/flutter.yml b/.github/workflows/flutter.yml index 89d9093..fe24b49 100644 --- a/.github/workflows/flutter.yml +++ b/.github/workflows/flutter.yml @@ -5,6 +5,16 @@ on: branches: [ "master" ] pull_request: branches: [ "master" ] + # workflow_dispatch: + # inputs: + # sdk_branch: + # description: "Specify the SDK branch" + # required: false + # default: "master" + # testapp_branch: + # description: "Specify the test app branch" + # required: false + # default: "master" jobs: unit_test_coverage: @@ -36,6 +46,21 @@ jobs: repository: 'optimizely/travisci-tools' path: 'home/runner/travisci-tools' ref: 'master' + # Set SDK Branch based on input or PR/Push + # - name: Set SDK Branch and Test App Branch + # run: | + # # If manually triggered + # if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + # echo "SDK_BRANCH=${{ github.event.inputs.sdk_branch || 'master' }}" >> $GITHUB_ENV + # echo "TESTAPP_BRANCH=${{ github.event.inputs.testapp_branch || 'master' }}" >> $GITHUB_ENV + # # If triggered by PR + # elif [[ "${{ github.event_name }}" == "pull_request" ]]; then + # echo "SDK_BRANCH=${{ github.head_ref }}" >> $GITHUB_ENV + # # If triggered by push + # else + # echo "SDK_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV + # echo "TRAVIS_BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV + # fi - name: set SDK Branch if PR env: HEAD_REF: ${{ github.head_ref }} diff --git a/android/build.gradle b/android/build.gradle index cdec407..12f972d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -74,7 +74,7 @@ dependencies { implementation 'org.slf4j:slf4j-api:2.0.7' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10" - implementation "com.optimizely.ab:android-sdk:4.0.0" + implementation "com.optimizely.ab:android-sdk:5.0.0" implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4' implementation ('com.google.guava:guava:19.0') { exclude group:'com.google.guava', module:'listenablefuture' diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java index c571c2f..cf85e3d 100644 --- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java +++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/OptimizelyFlutterClient.java @@ -55,6 +55,7 @@ import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.*; import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.DISABLE_ODP; +import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.ENABLE_VUID; import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.SEGMENTS_CACHE_SIZE; import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.SEGMENTS_CACHE_TIMEOUT_IN_SECONDS; import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.TIMEOUT_FOR_ODP_EVENT_IN_SECONDS; @@ -144,6 +145,7 @@ protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @N int timeoutForSegmentFetchInSecs = 10; int timeoutForOdpEventInSecs = 10; boolean disableOdp = false; + boolean enableVuid = false; Map sdkSettings = argumentsParser.getOptimizelySdkSettings(); if (sdkSettings != null) { if (sdkSettings.containsKey(SEGMENTS_CACHE_SIZE)) { @@ -161,6 +163,9 @@ protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @N if (sdkSettings.containsKey(DISABLE_ODP)) { disableOdp = (boolean) sdkSettings.get(DISABLE_ODP); } + if (sdkSettings.containsKey(ENABLE_VUID)) { + enableVuid = (boolean) sdkSettings.get(ENABLE_VUID); + } } // Creating new instance OptimizelyManager.Builder optimizelyManagerBuilder = OptimizelyManager.builder() @@ -179,6 +184,9 @@ protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @N if (disableOdp) { optimizelyManagerBuilder.withODPDisabled(); } + if (enableVuid) { + optimizelyManagerBuilder.withVuidEnabled(); + } OptimizelyManager optimizelyManager = optimizelyManagerBuilder.build(context); optimizelyManager.initialize(context, null, (OptimizelyClient client) -> { @@ -471,7 +479,7 @@ protected void getVuid(ArgumentsParser argumentsParser, @NonNull Result result) if (!isOptimizelyClientValid(sdkKey, optimizelyClient, result)) { return; } - result.success(createResponse(true, Collections.singletonMap(RequestParameterKey.VUID, optimizelyClient.getVuid()), "")); + result.success(createResponse(optimizelyClient.getVuid() != null, Collections.singletonMap(RequestParameterKey.VUID, optimizelyClient.getVuid()), "")); } /// Checks if the user is qualified for the given segment. diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java index 0c73d32..62f0ce9 100644 --- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java +++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Constants.java @@ -96,6 +96,7 @@ public static class RequestParameterKey { public static final String TIMEOUT_FOR_SEGMENT_FETCH_IN_SECONDS = "timeoutForSegmentFetchInSecs"; public static final String TIMEOUT_FOR_ODP_EVENT_IN_SECONDS = "timeoutForOdpEventInSecs"; public static final String DISABLE_ODP = "disableOdp"; + public static final String ENABLE_VUID = "enableVuid"; } public static class ErrorMessage { diff --git a/ios/Classes/HelperClasses/Constants.swift b/ios/Classes/HelperClasses/Constants.swift index f3ca6d5..a29370a 100644 --- a/ios/Classes/HelperClasses/Constants.swift +++ b/ios/Classes/HelperClasses/Constants.swift @@ -114,6 +114,7 @@ struct RequestParameterKey { static let timeoutForSegmentFetchInSecs = "timeoutForSegmentFetchInSecs" static let timeoutForOdpEventInSecs = "timeoutForOdpEventInSecs" static let disableOdp = "disableOdp" + static let enableVuid = "enableVuid" static let sdkVersion = "sdkVersion"; } diff --git a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift index 8a2fd75..7c093c4 100644 --- a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift +++ b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift @@ -118,6 +118,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { var timeoutForSegmentFetchInSecs: Int = 10 var timeoutForOdpEventInSecs: Int = 10 var disableOdp: Bool = false + var enableVuid: Bool = false var sdkVersion = parameters[RequestParameterKey.sdkVersion] as? String var sdkName = Utils.sdkName @@ -137,8 +138,11 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { if let isOdpDisabled = sdkSettings[RequestParameterKey.disableOdp] as? Bool { disableOdp = isOdpDisabled } + if let isEnableVuid = sdkSettings[RequestParameterKey.enableVuid] as? Bool { + enableVuid = isEnableVuid + } } - let optimizelySdkSettings = OptimizelySdkSettings(segmentsCacheSize: segmentsCacheSize, segmentsCacheTimeoutInSecs: segmentsCacheTimeoutInSecs, timeoutForSegmentFetchInSecs: timeoutForSegmentFetchInSecs, timeoutForOdpEventInSecs: timeoutForOdpEventInSecs, disableOdp: disableOdp, sdkName: sdkName, sdkVersion: sdkVersion) + let optimizelySdkSettings = OptimizelySdkSettings(segmentsCacheSize: segmentsCacheSize, segmentsCacheTimeoutInSecs: segmentsCacheTimeoutInSecs, timeoutForSegmentFetchInSecs: timeoutForSegmentFetchInSecs, timeoutForOdpEventInSecs: timeoutForOdpEventInSecs, disableOdp: disableOdp, enableVuid: enableVuid, sdkName: sdkName, sdkVersion: sdkVersion) // Datafile Download Interval var datafilePeriodicDownloadInterval = 10 * 60 // seconds @@ -374,7 +378,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { } else { userContextsTracker[sdkKey] = [userContextId: userContext] } - result(self.createResponse(success: true, result: [RequestParameterKey.userContextId: userContextId])) + result(self.createResponse(success: userContext != nil, result: [RequestParameterKey.userContextId: userContextId])) } /// Returns userId for the user context. @@ -442,7 +446,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { guard let optimizelyClient = getOptimizelyClient(sdkKey: sdkKey, result: result) else { return } - result(self.createResponse(success: true, result: [RequestParameterKey.vuid: optimizelyClient.vuid])) + result(self.createResponse(success: optimizelyClient.vuid != nil, result: [RequestParameterKey.vuid: optimizelyClient.vuid])) } /// Checks if the user is qualified for the given segment. diff --git a/ios/optimizely_flutter_sdk.podspec b/ios/optimizely_flutter_sdk.podspec index 4da4408..14f4dbc 100644 --- a/ios/optimizely_flutter_sdk.podspec +++ b/ios/optimizely_flutter_sdk.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'OptimizelySwiftSDK', '4.0.0' + s.dependency 'OptimizelySwiftSDK', '5.0.0' s.platform = :ios, '10.0' # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } diff --git a/lib/src/data_objects/get_vuid_response.dart b/lib/src/data_objects/get_vuid_response.dart index 4be045b..e5fcfb0 100644 --- a/lib/src/data_objects/get_vuid_response.dart +++ b/lib/src/data_objects/get_vuid_response.dart @@ -18,7 +18,7 @@ import 'package:optimizely_flutter_sdk/src/data_objects/base_response.dart'; import 'package:optimizely_flutter_sdk/src/utils/constants.dart'; class GetVuidResponse extends BaseResponse { - String vuid = ""; + String? vuid; GetVuidResponse(Map json) : super(json) { if (json[Constants.responseResult] is Map) { diff --git a/lib/src/data_objects/sdk_settings.dart b/lib/src/data_objects/sdk_settings.dart index 412432a..448a2e8 100644 --- a/lib/src/data_objects/sdk_settings.dart +++ b/lib/src/data_objects/sdk_settings.dart @@ -25,6 +25,8 @@ class SDKSettings { final int timeoutForOdpEventInSecs; // Set this flag to true (default = false) to disable ODP features final bool disableOdp; + // Set this flag to true (default = false) to enable VUID feature + final bool enableVuid; const SDKSettings({ this.segmentsCacheSize = 100, // Default segmentsCacheSize @@ -33,5 +35,6 @@ class SDKSettings { 10, // Default timeoutForSegmentFetchInSecs this.timeoutForOdpEventInSecs = 10, // Default timeoutForOdpEventInSecs this.disableOdp = false, // Default disableOdp + this.enableVuid = false, // Default disableVuid }); } diff --git a/lib/src/optimizely_client_wrapper.dart b/lib/src/optimizely_client_wrapper.dart index 4d6e0c0..fb4fce0 100644 --- a/lib/src/optimizely_client_wrapper.dart +++ b/lib/src/optimizely_client_wrapper.dart @@ -90,6 +90,7 @@ class OptimizelyClientWrapper { sdkSettings.timeoutForSegmentFetchInSecs, Constants.timeoutForOdpEventInSecs: sdkSettings.timeoutForOdpEventInSecs, Constants.disableOdp: sdkSettings.disableOdp, + Constants.enableVuid: sdkSettings.enableVuid, }; requestDict[Constants.optimizelySdkSettings] = optimizelySdkSettings; diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index 7ef9547..fb33033 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -131,6 +131,7 @@ class Constants { "timeoutForSegmentFetchInSecs"; static const String timeoutForOdpEventInSecs = "timeoutForOdpEventInSecs"; static const String disableOdp = "disableOdp"; + static const String enableVuid = "enableVuid"; // Response keys static const String responseSuccess = "success"; diff --git a/test/optimizely_flutter_sdk_test.dart b/test/optimizely_flutter_sdk_test.dart index 821e234..862c4b0 100644 --- a/test/optimizely_flutter_sdk_test.dart +++ b/test/optimizely_flutter_sdk_test.dart @@ -56,7 +56,6 @@ void main() { SDKSettings sdkSettings = const SDKSettings(); int datafilePeriodicDownloadInterval = 0; String defaultLogLevel = "error"; - const MethodChannel channel = MethodChannel("optimizely_flutter_sdk"); dynamic mockOptimizelyConfig; @@ -106,6 +105,7 @@ void main() { timeoutForOdpEventInSecs: settings[Constants.timeoutForOdpEventInSecs], disableOdp: settings[Constants.disableOdp], + enableVuid: settings[Constants.enableVuid], ); } @@ -175,9 +175,19 @@ void main() { }; case Constants.createUserContextMethod: expect(methodCall.arguments[Constants.sdkKey], isNotEmpty); - if (methodCall.arguments[Constants.userId] != null) { + var resultUserId = userContextId; + if (methodCall.arguments[Constants.userId] == null) { + if (sdkSettings.enableVuid) { + resultUserId = vuid; + } else { + return { + Constants.responseSuccess: false, + }; + } + } else if (methodCall.arguments[Constants.userId] != null) { expect(methodCall.arguments[Constants.userId], equals(userId)); } + if (methodCall.arguments[Constants.attributes]["abc"] != null) { expect(methodCall.arguments[Constants.attributes]["abc"], equals(attributes["abc"])); @@ -185,7 +195,7 @@ void main() { expect(methodCall.arguments[Constants.userContextId], isNull); return { Constants.responseSuccess: true, - Constants.responseResult: {Constants.userContextId: userContextId}, + Constants.responseResult: {Constants.userContextId: resultUserId}, }; case Constants.getUserIdMethod: expect(methodCall.arguments[Constants.sdkKey], isNotEmpty); @@ -266,6 +276,8 @@ void main() { case Constants.getVuidMethod: expect(methodCall.arguments[Constants.sdkKey], isNotEmpty); expect(methodCall.arguments[Constants.userContextId], isNull); + expect(methodCall.arguments[Constants.vuid], isNull); + var vuid = sdkSettings.enableVuid ? "vuid_123" : null; return { Constants.responseSuccess: true, Constants.responseResult: {Constants.vuid: vuid}, @@ -376,6 +388,7 @@ void main() { tearDown(() { tester?.setMockMethodCallHandler(channel, null); + sdkSettings = const SDKSettings(); }); group("Integration: OptimizelyFlutterSdk MethodChannel", () { @@ -650,8 +663,17 @@ void main() { expect(userContext, isNotNull); }); - test("should succeed null userId", () async { + test("should fail when disable vuid and userId null", () async { var sdk = OptimizelyFlutterSdk(testSDKKey); + sdk.initializeClient(); + var userContext = await sdk.createUserContext(attributes: attributes); + expect(userContext, isNull); + }); + + test("should succed when enable vuid and userId null", () async { + const settings = SDKSettings(enableVuid: true); + var sdk = OptimizelyFlutterSdk(testSDKKey, sdkSettings: settings); + sdk.initializeClient(); var userContext = await sdk.createUserContext(attributes: attributes); expect(userContext, isNotNull); }); @@ -662,10 +684,11 @@ void main() { expect(userContext, isNotNull); }); - test("should succeed null userId and attributes", () async { + test("should not succeed null userId and attributes", () async { var sdk = OptimizelyFlutterSdk(testSDKKey); + sdk.initializeClient(); var userContext = await sdk.createUserContext(); - expect(userContext, isNotNull); + expect(userContext, isNull); }); }); @@ -769,11 +792,20 @@ void main() { }); group("getVuid()", () { - test("should succeed", () async { + test("by default should return null vuid", () async { var sdk = OptimizelyFlutterSdk(testSDKKey); + sdk.initializeClient(); + var response = await sdk.getVuid(); + expect(response.success, isTrue); + expect(response.vuid, isNull); + }); + test("should return vuid when enableVuid true", () async { + const settings = SDKSettings(enableVuid: true); + var sdk = OptimizelyFlutterSdk(testSDKKey, sdkSettings: settings); + sdk.initializeClient(); var response = await sdk.getVuid(); expect(response.success, isTrue); - expect(response.vuid, equals(vuid)); + expect(response.vuid, "vuid_123"); }); }); From 48c1b5c58acadcb353c9ac489276f7f0140da37c Mon Sep 17 00:00:00 2001 From: Muzahidul Islam <129880873+muzahidul-opti@users.noreply.github.com> Date: Thu, 28 Nov 2024 22:55:30 +0600 Subject: [PATCH 3/5] chore: version updated (#79) --- CHANGELOG.md | 11 +++++++++++ README.md | 2 +- lib/package_info.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cf3ba9..8c2f2b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Optimizely Flutter SDK Changelog +## 3.0.0 +November 28th, 2024 + +### Breaking Changes +* VUID configuration is now independent of ODP ([#78](https://github.com/optimizely/optimizely-flutter-sdk/pull/78)) +* When VUID is disabled: + * `vuid` is not generated or saved. + * `client-initialized` event will not auto fired on SDK init. + * `vuid` is not included in the odp events as a default attribute. + * `createUserContext()` will be rejected if `userId` is not provided. + ## 2.0.1 July 25, 2024 diff --git a/README.md b/README.md index 9fbc097..c851ae5 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Other Flutter platforms are not currently supported by this SDK. To add the flutter-sdk to your project dependencies, include the following in your app's pubspec.yaml: ``` - optimizely_flutter_sdk: ^2.0.1 + optimizely_flutter_sdk: ^3.0.0 ``` Then run diff --git a/lib/package_info.dart b/lib/package_info.dart index 2ccb4b5..cbf0165 100644 --- a/lib/package_info.dart +++ b/lib/package_info.dart @@ -3,5 +3,5 @@ class PackageInfo { static const String name = 'optimizely_flutter_sdk'; - static const String version = '2.0.1'; + static const String version = '3.0.0'; } diff --git a/pubspec.yaml b/pubspec.yaml index 53e822c..fb899c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: optimizely_flutter_sdk description: This repository houses the Flutter SDK for use with Optimizely Feature Experimentation, Optimizely Full Stack (legacy), and Optimizely Rollouts. -version: 2.0.1 +version: 3.0.0 homepage: https://github.com/optimizely/optimizely-flutter-sdk environment: From 4b3c53c27a3dc9bad19e6d33a13a37f705b56bbe Mon Sep 17 00:00:00 2001 From: Muzahidul Islam <129880873+muzahidul-opti@users.noreply.github.com> Date: Wed, 4 Jun 2025 00:16:29 +0600 Subject: [PATCH 4/5] [FSSDK-11465] chore: add netspring support (#80) --- android/build.gradle | 2 +- ios/optimizely_flutter_sdk.podspec | 2 +- lib/src/optimizely_client_wrapper.dart | 4 ---- lib/src/utils/constants.dart | 2 ++ test/test_utils.dart | 31 +++++++++++++++++++++++--- 5 files changed, 32 insertions(+), 9 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 12f972d..5d4e3ff 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -74,7 +74,7 @@ dependencies { implementation 'org.slf4j:slf4j-api:2.0.7' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10" - implementation "com.optimizely.ab:android-sdk:5.0.0" + implementation "com.optimizely.ab:android-sdk:5.0.1" implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4' implementation ('com.google.guava:guava:19.0') { exclude group:'com.google.guava', module:'listenablefuture' diff --git a/ios/optimizely_flutter_sdk.podspec b/ios/optimizely_flutter_sdk.podspec index 14f4dbc..2aa6953 100644 --- a/ios/optimizely_flutter_sdk.podspec +++ b/ios/optimizely_flutter_sdk.podspec @@ -13,7 +13,7 @@ Pod::Spec.new do |s| s.source = { :path => '.' } s.source_files = 'Classes/**/*' s.dependency 'Flutter' - s.dependency 'OptimizelySwiftSDK', '5.0.0' + s.dependency 'OptimizelySwiftSDK', '5.1.1' s.platform = :ios, '10.0' # Flutter.framework does not contain a i386 slice. s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' } diff --git a/lib/src/optimizely_client_wrapper.dart b/lib/src/optimizely_client_wrapper.dart index fb4fce0..a0869b9 100644 --- a/lib/src/optimizely_client_wrapper.dart +++ b/lib/src/optimizely_client_wrapper.dart @@ -371,7 +371,6 @@ class OptimizelyClientWrapper { if (checkCallBackExist(sdkKey, callback)) { // ignore: avoid_print - print("callback already exists."); return -1; } @@ -417,7 +416,6 @@ class OptimizelyClientWrapper { if (checkCallBackExist(sdkKey, callback)) { // ignore: avoid_print - print("callback already exists."); return -1; } @@ -440,7 +438,6 @@ class OptimizelyClientWrapper { if (checkCallBackExist(sdkKey, callback)) { // ignore: avoid_print - print("callback already exists."); return -1; } @@ -464,7 +461,6 @@ class OptimizelyClientWrapper { if (checkCallBackExist(sdkKey, callback)) { // ignore: avoid_print - print("callback already exists."); return -1; } diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index fb33033..2bb5421 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -62,7 +62,9 @@ class Constants { static const String userContextId = "userContextId"; static const String userContext = "userContext"; static const String experiment = "experiment"; + static const String experimentId = "experimentId"; static const String variation = "variation"; + static const String variationId = "variationId"; static const String userId = "userId"; static const String vuid = "vuid"; static const String experimentKey = "experimentKey"; diff --git a/test/test_utils.dart b/test/test_utils.dart index 986bd8e..350c35e 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -89,7 +89,14 @@ class TestUtils { handler(MethodCall(Constants.decisionCallBackListener, { Constants.id: id, Constants.sdkKey: sdkKey, - Constants.payload: {Constants.type: "$id", Constants.userId: "test"} + Constants.payload: { + Constants.type: "$id", + Constants.userId: "test", + Constants.decisionInfo: const { + Constants.experimentId: "experiment_12345", + Constants.variationId: "variation_12345", + }, + } })); } @@ -129,7 +136,15 @@ class TestUtils { Constants.eventKey: "$id", Constants.userId: "test", Constants.attributes: {"test": id}, - Constants.eventTags: {"testTag": id} + Constants.eventTags: { + "testTag": id, + "nestedTag": { + "string_key": "stringValue", + "int_key": 123, + "double_key": 123.456, + "bool_key": true + } + } }; handler(MethodCall(Constants.trackCallBackListener, { Constants.id: id, @@ -145,6 +160,12 @@ class TestUtils { Constants.attributes: {"test": id}, Constants.eventTags: { "testTag": id, + "nestedTag": { + "string_key": "stringValue", + "int_key": 123, + "double_key": 123.456, + "bool_key": true + }, "client_name": clientName, "client_version": sdkVersion } @@ -179,7 +200,11 @@ class TestUtils { static bool testDecisionNotificationPayload( List notifications, int id, int actualID) { if (notifications[id].type != "$actualID" || - notifications[id].userId != "test") { + notifications[id].userId != "test" || + notifications[id].decisionInfo[Constants.experimentId] != + "experiment_12345" || + notifications[id].decisionInfo[Constants.variationId] != + "variation_12345") { return false; } return true; From bbb47903d00babd488b20af9f806b926d215c967 Mon Sep 17 00:00:00 2001 From: Muzahidul Islam <129880873+muzahidul-opti@users.noreply.github.com> Date: Fri, 13 Jun 2025 00:45:15 +0600 Subject: [PATCH 5/5] [FSSDK-11453] chore: prepare for release 3.0.1 (#81) * Update doc for release 3.0.1 * update change log --- CHANGELOG.md | 7 +++++++ README.md | 2 +- lib/package_info.dart | 2 +- pubspec.yaml | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c2f2b8..6e530c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Optimizely Flutter SDK Changelog +## 3.0.1 +Jun 4th, 2025 + +### Functionality Enhancements + +* Add experiment id and variation id added into decision notification payload ([#80](https://github.com/optimizely/optimizely-flutter-sdk/pull/80)) + ## 3.0.0 November 28th, 2024 diff --git a/README.md b/README.md index c851ae5..1b125d5 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Other Flutter platforms are not currently supported by this SDK. To add the flutter-sdk to your project dependencies, include the following in your app's pubspec.yaml: ``` - optimizely_flutter_sdk: ^3.0.0 + optimizely_flutter_sdk: ^3.0.1 ``` Then run diff --git a/lib/package_info.dart b/lib/package_info.dart index cbf0165..0bdd780 100644 --- a/lib/package_info.dart +++ b/lib/package_info.dart @@ -3,5 +3,5 @@ class PackageInfo { static const String name = 'optimizely_flutter_sdk'; - static const String version = '3.0.0'; + static const String version = '3.0.1'; } diff --git a/pubspec.yaml b/pubspec.yaml index fb899c2..188939d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: optimizely_flutter_sdk description: This repository houses the Flutter SDK for use with Optimizely Feature Experimentation, Optimizely Full Stack (legacy), and Optimizely Rollouts. -version: 3.0.0 +version: 3.0.1 homepage: https://github.com/optimizely/optimizely-flutter-sdk environment: