diff --git a/android/build.gradle b/android/build.gradle index 03427ea..9934507 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -83,7 +83,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-beta2" + implementation "com.optimizely.ab:android-sdk:4.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 82e3384..c571c2f 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 @@ -78,6 +78,8 @@ public class OptimizelyFlutterClient { protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @NonNull Result result) { String sdkKey = argumentsParser.getSdkKey(); + String sdkName = Utils.sdkName; + String sdkVersion = argumentsParser.getSdkVersion(); if (sdkKey == null) { result.success(createResponse(ErrorMessage.INVALID_PARAMS)); return; @@ -172,7 +174,8 @@ protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @N .withODPSegmentCacheTimeout(segmentsCacheTimeoutInSecs, TimeUnit.SECONDS) .withTimeoutForODPSegmentFetch(timeoutForSegmentFetchInSecs) .withTimeoutForODPEventDispatch(timeoutForOdpEventInSecs) - .withSDKKey(sdkKey); + .withSDKKey(sdkKey) + .withClientInfo(sdkName, sdkVersion); if (disableOdp) { optimizelyManagerBuilder.withODPDisabled(); } diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java index 88087c7..6d2741f 100644 --- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java +++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/ArgumentsParser.java @@ -31,6 +31,10 @@ public ArgumentsParser(Map arguments) { public String getSdkKey() { return (String) arguments.get(Constants.RequestParameterKey.SDK_KEY); } + + public String getSdkVersion() { + return (String) arguments.get(Constants.RequestParameterKey.SDK_VERSION); + } public Integer getNotificationID() { return (Integer) arguments.get(Constants.RequestParameterKey.NOTIFICATION_ID); 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 453b1d6..0c73d32 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 @@ -58,6 +58,7 @@ public static class NotificationType { public static class RequestParameterKey { public static final String SDK_KEY = "sdkKey"; + public static final String SDK_VERSION = "sdkVersion"; public static final String USER_ID = "userId"; public static final String USER_CONTEXT_ID = "userContextId"; public static final String NOTIFICATION_ID = "id"; diff --git a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java index b3020f1..ba4e5a4 100644 --- a/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java +++ b/android/src/main/java/com/optimizely/optimizely_flutter_sdk/helper_classes/Utils.java @@ -37,7 +37,8 @@ import ch.qos.logback.classic.Logger; public class Utils { - + public static String sdkName = "flutter/android-sdk"; + public static String getRandomUUID() { return UUID.randomUUID().toString(); } diff --git a/example/android/build.gradle b/example/android/build.gradle index c133c66..58051f6 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -11,7 +11,7 @@ buildscript { } } ext { - android_sdk_version = "4.0.0-beta3" + android_sdk_version = "4.0.0" } allprojects { repositories { diff --git a/ios/Classes/HelperClasses/Constants.swift b/ios/Classes/HelperClasses/Constants.swift index e5be618..f3ca6d5 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 sdkVersion = "sdkVersion"; } struct ResponseKey { diff --git a/ios/Classes/HelperClasses/Utils.swift b/ios/Classes/HelperClasses/Utils.swift index 6cac144..41b39c1 100644 --- a/ios/Classes/HelperClasses/Utils.swift +++ b/ios/Classes/HelperClasses/Utils.swift @@ -18,7 +18,7 @@ import Foundation import Optimizely public class Utils: NSObject { - + static var sdkName = "flutter/swift-sdk" /// Converts and returns dart map to native map static func getTypedMap(arguments: Any?) -> [String: Any]? { guard let args = arguments as? Dictionary else { diff --git a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift index 287b056..8a2fd75 100644 --- a/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift +++ b/ios/Classes/SwiftOptimizelyFlutterSdkPlugin.swift @@ -118,6 +118,9 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { var timeoutForSegmentFetchInSecs: Int = 10 var timeoutForOdpEventInSecs: Int = 10 var disableOdp: Bool = false + var sdkVersion = parameters[RequestParameterKey.sdkVersion] as? String + var sdkName = Utils.sdkName + if let sdkSettings = parameters[RequestParameterKey.optimizelySdkSettings] as? Dictionary { if let cacheSize = sdkSettings[RequestParameterKey.segmentsCacheSize] as? Int { segmentsCacheSize = cacheSize @@ -135,7 +138,7 @@ public class SwiftOptimizelyFlutterSdkPlugin: NSObject, FlutterPlugin { disableOdp = isOdpDisabled } } - let optimizelySdkSettings = OptimizelySdkSettings(segmentsCacheSize: segmentsCacheSize, segmentsCacheTimeoutInSecs: segmentsCacheTimeoutInSecs, timeoutForSegmentFetchInSecs: timeoutForSegmentFetchInSecs, timeoutForOdpEventInSecs: timeoutForOdpEventInSecs, disableOdp: disableOdp) + let optimizelySdkSettings = OptimizelySdkSettings(segmentsCacheSize: segmentsCacheSize, segmentsCacheTimeoutInSecs: segmentsCacheTimeoutInSecs, timeoutForSegmentFetchInSecs: timeoutForSegmentFetchInSecs, timeoutForOdpEventInSecs: timeoutForOdpEventInSecs, disableOdp: disableOdp, sdkName: sdkName, sdkVersion: sdkVersion) // Datafile Download Interval var datafilePeriodicDownloadInterval = 10 * 60 // seconds diff --git a/ios/optimizely_flutter_sdk.podspec b/ios/optimizely_flutter_sdk.podspec index 2a528d5..4da4408 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-beta' + s.dependency 'OptimizelySwiftSDK', '4.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/package_info.dart b/lib/package_info.dart new file mode 100644 index 0000000..4c8df19 --- /dev/null +++ b/lib/package_info.dart @@ -0,0 +1,7 @@ +// Purpose: Package information for the Optimizely Flutter SDK +// Note: This info should be synced with pubspec.yaml + +class PackageInfo { + static const String name = 'optimizely_flutter_sdk'; + static const String version = '2.0.0-beta'; +} \ No newline at end of file diff --git a/lib/src/optimizely_client_wrapper.dart b/lib/src/optimizely_client_wrapper.dart index f96ad24..590d17c 100644 --- a/lib/src/optimizely_client_wrapper.dart +++ b/lib/src/optimizely_client_wrapper.dart @@ -18,6 +18,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:optimizely_flutter_sdk/optimizely_flutter_sdk.dart'; +import 'package:optimizely_flutter_sdk/package_info.dart'; import 'package:optimizely_flutter_sdk/src/data_objects/activate_listener_response.dart'; import 'package:optimizely_flutter_sdk/src/data_objects/activate_response.dart'; import 'package:optimizely_flutter_sdk/src/data_objects/base_response.dart'; @@ -66,8 +67,11 @@ class OptimizelyClientWrapper { _channel.setMethodCallHandler(methodCallHandler); final convertedOptions = Utils.convertDecideOptions(defaultDecideOptions); final convertedLogLevel = Utils.convertLogLevel(defaultLogLevel); + final sdkVersion = PackageInfo.version; + Map requestDict = { Constants.sdkKey: sdkKey, + Constants.sdkVersion: sdkVersion, Constants.datafilePeriodicDownloadInterval: datafilePeriodicDownloadInterval, Constants.optimizelyDecideOption: convertedOptions, diff --git a/lib/src/utils/constants.dart b/lib/src/utils/constants.dart index d5bc3ff..7ef9547 100644 --- a/lib/src/utils/constants.dart +++ b/lib/src/utils/constants.dart @@ -58,6 +58,7 @@ class Constants { // Request parameter keys static const String id = "id"; static const String sdkKey = "sdkKey"; + static const String sdkVersion = "sdkVersion"; static const String userContextId = "userContextId"; static const String userContext = "userContext"; static const String experiment = "experiment"; diff --git a/lib/src/utils/utils.dart b/lib/src/utils/utils.dart index 782178e..8b18b13 100644 --- a/lib/src/utils/utils.dart +++ b/lib/src/utils/utils.dart @@ -15,7 +15,6 @@ ///**************************************************************************/ import 'dart:io' show Platform; - import 'package:optimizely_flutter_sdk/src/user_context/optimizely_user_context.dart'; import 'package:optimizely_flutter_sdk/src/utils/constants.dart'; import 'package:optimizely_flutter_sdk/src/data_objects/log_level.dart'; @@ -101,4 +100,5 @@ class Utils { // OptimizelyLogLevel.debug -> "debug" return logLevel.toString().split('.').last; } + } diff --git a/test/optimizely_flutter_sdk_test.dart b/test/optimizely_flutter_sdk_test.dart index debf769..dd6bd7a 100644 --- a/test/optimizely_flutter_sdk_test.dart +++ b/test/optimizely_flutter_sdk_test.dart @@ -23,7 +23,6 @@ import 'package:optimizely_flutter_sdk/src/utils/constants.dart'; import 'package:optimizely_flutter_sdk/src/utils/utils.dart'; import 'dart:io'; import 'dart:convert'; - import 'test_utils.dart'; void main() { @@ -557,7 +556,8 @@ void main() { }); test("with a valid defaultLogLevel parameter", () async { - var sdk = OptimizelyFlutterSdk(testSDKKey, defaultLogLevel: OptimizelyLogLevel.debug); + var sdk = OptimizelyFlutterSdk(testSDKKey, + defaultLogLevel: OptimizelyLogLevel.debug); var response = await sdk.initializeClient(); @@ -1553,4 +1553,76 @@ void main() { }); }); }); + + group("Test client_name and client_version event parsing", () { + test("Test track event with swift sdk name and version", () async { + var sdk = OptimizelyFlutterSdk(testSDKKey); + + TrackListenerResponse? response; + + await sdk.addTrackNotificationListener((msg) { + response = msg; + }); + var callHandler = OptimizelyClientWrapper.methodCallHandler; + tester?.setMockMethodCallHandler(channel, callHandler); + TestUtils.sendTestTrackClientNameAndVersion( + callHandler, 0, testSDKKey, "flutter/swift-sdk", "2.0.0"); + + expect(response == null, false); + + expect(response!.eventTags!["client_name"], "flutter/swift-sdk"); + + }); + + test("Test track event with android sdk name and version", () async { + var sdk = OptimizelyFlutterSdk(testSDKKey); + + var responses = []; + + await sdk.addTrackNotificationListener((msg) { + responses.add(msg); + }); + + var callHandler = OptimizelyClientWrapper.methodCallHandler; + tester?.setMockMethodCallHandler(channel, callHandler); + + TestUtils.sendTestTrackClientNameAndVersion( + callHandler, 0, testSDKKey, "flutter/swift-sdk", "2.0.0"); + TestUtils.sendTestTrackClientNameAndVersion( + callHandler, 0, testSDKKey, "flutter/android-sdk", "2.0.0-beta"); + + expect(responses.length == 2, true); + + expect(responses[0]!.eventTags!["client_name"], "flutter/swift-sdk"); + expect(responses[0]!.eventTags!["client_version"], "2.0.0"); + expect(responses[1]!.eventTags!["client_name"], "flutter/android-sdk"); + expect(responses[1]!.eventTags!["client_version"], "2.0.0-beta"); + + }); + + test("Test log event with client sdk name and version", () async { + var sdk = OptimizelyFlutterSdk(testSDKKey); + + var responses = []; + + await sdk.addLogEventNotificationListener((msg) { + responses.add(msg); + }); + var callHandler = OptimizelyClientWrapper.methodCallHandler; + tester?.setMockMethodCallHandler(channel, callHandler); + TestUtils.sendTestClientNameAndVersionLogEventNotification( + callHandler, 0, testSDKKey, "flutter/android-sdk", "2.0.0-beta"); + + TestUtils.sendTestClientNameAndVersionLogEventNotification( + callHandler, 0, testSDKKey, "flutter/swift-sdk", "2.0.0"); + + expect(responses.length == 2, true); + + expect(responses[0]!.params!["client_name"], "flutter/android-sdk"); + expect(responses[0]!.params!["client_version"], "2.0.0-beta"); + expect(responses[1]!.params!["client_name"], "flutter/swift-sdk"); + expect(responses[1]!.params!["client_version"], "2.0.0"); + }); + + }); } diff --git a/test/test_utils.dart b/test/test_utils.dart index e08eb73..986bd8e 100644 --- a/test/test_utils.dart +++ b/test/test_utils.dart @@ -106,6 +106,23 @@ class TestUtils { })); } + static sendTestClientNameAndVersionLogEventNotification( + Function(MethodCall message) handler, int id, String sdkKey, String clientName, String sdkVersion) { + var payload = { + Constants.url: "$id", + Constants.params: { + "test": id, + "client_name": clientName, + "client_version": sdkVersion + } + }; + handler(MethodCall(Constants.logEventCallbackListener, { + Constants.id: id, + Constants.sdkKey: sdkKey, + Constants.payload: payload + })); + } + static sendTestTrackNotifications( Function(MethodCall message) handler, int id, String sdkKey) { var payload = { @@ -121,6 +138,24 @@ class TestUtils { })); } + static sendTestTrackClientNameAndVersion(Function(MethodCall message) handler, int id, String sdkKey, String clientName, String sdkVersion) { + var payload = { + Constants.eventKey: "$id", + Constants.userId: "test", + Constants.attributes: {"test": id}, + Constants.eventTags: { + "testTag": id, + "client_name": clientName, + "client_version": sdkVersion + } + }; + handler(MethodCall(Constants.trackCallBackListener, { + Constants.id: id, + Constants.sdkKey: sdkKey, + Constants.payload: payload + })); + } + static sendTestUpdateConfigNotifications( Function(MethodCall message) handler, int id, String sdkKey) { handler(MethodCall(Constants.configUpdateCallBackListener, {