Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class _MyAppState extends State<MyApp> {
var randomUserName = "${rng.nextInt(1000)}";

// Create user context
var userContext = await flutterSDK.createUserContext(randomUserName);
var userContext =
await flutterSDK.createUserContext(userId: randomUserName);

// Set attributes
response = await userContext!.setAttributes({
Expand Down
64 changes: 47 additions & 17 deletions lib/optimizely_flutter_sdk.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// **************************************************************************
/// Copyright 2022, Optimizely, Inc. and contributors *
/// Copyright 2022-2023, Optimizely, Inc. and contributors *
/// *
/// Licensed under the Apache License, Version 2.0 (the "License"); *
/// you may not use this file except in compliance with the License. *
Expand All @@ -21,6 +21,8 @@ import 'package:optimizely_flutter_sdk/src/data_objects/activate_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/base_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/datafile_options.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/event_options.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/get_vuid_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/sdk_settings.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/get_variation_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/optimizely_config_response.dart';
import 'package:optimizely_flutter_sdk/src/optimizely_client_wrapper.dart';
Expand All @@ -33,7 +35,7 @@ export 'package:optimizely_flutter_sdk/src/user_context/optimizely_forced_decisi
export 'package:optimizely_flutter_sdk/src/user_context/optimizely_decision_context.dart'
show OptimizelyDecisionContext;
export 'package:optimizely_flutter_sdk/src/user_context/optimizely_user_context.dart'
show OptimizelyUserContext, OptimizelyDecideOption;
show OptimizelyUserContext, OptimizelyDecideOption, OptimizelySegmentOption;
export 'package:optimizely_flutter_sdk/src/data_objects/decide_response.dart'
show Decision;
export 'package:optimizely_flutter_sdk/src/data_objects/track_listener_response.dart'
Expand All @@ -44,6 +46,8 @@ export 'package:optimizely_flutter_sdk/src/data_objects/logevent_listener_respon
show LogEventListenerResponse;
export 'package:optimizely_flutter_sdk/src/data_objects/event_options.dart'
show EventOptions;
export 'package:optimizely_flutter_sdk/src/data_objects/sdk_settings.dart'
show SDKSettings;
export 'package:optimizely_flutter_sdk/src/data_objects/datafile_options.dart'
show DatafileHostOptions;

Expand All @@ -59,17 +63,19 @@ class OptimizelyFlutterSdk {
final int _datafilePeriodicDownloadInterval;
final Map<ClientPlatform, DatafileHostOptions> _datafileHostOptions;
final Set<OptimizelyDecideOption> _defaultDecideOptions;
OptimizelyFlutterSdk(
this._sdkKey, {
EventOptions eventOptions = const EventOptions(),
int datafilePeriodicDownloadInterval =
10 * 60, // Default time interval in seconds
Map<ClientPlatform, DatafileHostOptions> datafileHostOptions = const {},
Set<OptimizelyDecideOption> defaultDecideOptions = const {},
}) : _eventOptions = eventOptions,
final SDKSettings _sdkSettings;
OptimizelyFlutterSdk(this._sdkKey,
{EventOptions eventOptions = const EventOptions(),
int datafilePeriodicDownloadInterval =
10 * 60, // Default time interval in seconds
Map<ClientPlatform, DatafileHostOptions> datafileHostOptions = const {},
Set<OptimizelyDecideOption> defaultDecideOptions = const {},
SDKSettings sdkSettings = const SDKSettings()})
: _eventOptions = eventOptions,
_datafilePeriodicDownloadInterval = datafilePeriodicDownloadInterval,
_datafileHostOptions = datafileHostOptions,
_defaultDecideOptions = defaultDecideOptions;
_defaultDecideOptions = defaultDecideOptions,
_sdkSettings = sdkSettings;

/// Starts Optimizely SDK (Synchronous) with provided sdkKey.
Future<BaseResponse> initializeClient() async {
Expand All @@ -78,7 +84,8 @@ class OptimizelyFlutterSdk {
_eventOptions,
_datafilePeriodicDownloadInterval,
_datafileHostOptions,
_defaultDecideOptions);
_defaultDecideOptions,
_sdkSettings);
}

/// Use the activate method to start an experiment.
Expand Down Expand Up @@ -140,17 +147,40 @@ class OptimizelyFlutterSdk {
return await OptimizelyClientWrapper.getOptimizelyConfig(_sdkKey);
}

/// Send an event to the ODP server.
///
/// Takes [action] The event action name.
/// Optional [type] The event type (default = "fullstack").
/// Optional [identifiers] A dictionary for identifiers.
/// Optional [data] A dictionary for associated data. The default event data will be added to this data before sending to the ODP server.
/// Returns [BaseResponse] A object containing success result or reason of failure.
Future<BaseResponse> sendOdpEvent(String action,
{String? type,
Map<String, String> identifiers = const {},
Map<String, dynamic> data = const {}}) async {
return await OptimizelyClientWrapper.sendOdpEvent(_sdkKey, action,
type: type, identifiers: identifiers, data: data);
}

/// Returns the device vuid.
///
/// Returns [GetVuidResponse] A object containing device vuid
Future<GetVuidResponse> getVuid() async {
return await OptimizelyClientWrapper.getVuid(_sdkKey);
}

/// Creates a context of the user for which decision APIs will be called.
///
/// NOTE: A user context will only be created successfully when the SDK is fully configured using initializeClient.
///
/// Takes [userId] the [String] user ID to be used for bucketing.
/// Optional [userId] the [String] user ID to be used for bucketing.
/// The device vuid will be used as an userId when userId is not provided.
/// Takes [attributes] An Optional [Map] of attribute names to current user attribute values.
/// Returns An [OptimizelyUserContext] associated with this OptimizelyClient.
Future<OptimizelyUserContext?> createUserContext(String userId,
[Map<String, dynamic> attributes = const {}]) async {
return await OptimizelyClientWrapper.createUserContext(
_sdkKey, userId, attributes);
Future<OptimizelyUserContext?> createUserContext(
{String? userId, Map<String, dynamic> attributes = const {}}) async {
return await OptimizelyClientWrapper.createUserContext(_sdkKey,
userId: userId, attributes: attributes);
}

/// Allows user to remove notification listener using id.
Expand Down
32 changes: 32 additions & 0 deletions lib/src/data_objects/get_qualified_segments_response.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/// **************************************************************************
/// Copyright 2023, Optimizely, Inc. and contributors *
/// *
/// Licensed under the Apache License, Version 2.0 (the "License"); *
/// you may not use this file except in compliance with the License. *
/// You may obtain a copy of the License at *
/// *
/// http://www.apache.org/licenses/LICENSE-2.0 *
/// *
/// Unless required by applicable law or agreed to in writing, software *
/// distributed under the License is distributed on an "AS IS" BASIS, *
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
/// See the License for the specific language governing permissions and *
/// limitations under the License. *
///**************************************************************************/

import 'package:optimizely_flutter_sdk/src/data_objects/base_response.dart';
import 'package:optimizely_flutter_sdk/src/utils/constants.dart';

class GetQualifiedSegmentsResponse extends BaseResponse {
List<String> qualifiedSegments = [];

GetQualifiedSegmentsResponse(Map<String, dynamic> json) : super(json) {
if (json[Constants.responseResult] is Map<dynamic, dynamic>) {
var response = Map<String, dynamic>.from(json[Constants.responseResult]);
if (response[Constants.qualifiedSegments] is List<dynamic>) {
qualifiedSegments =
List<String>.from(response[Constants.qualifiedSegments]);
}
}
}
}
31 changes: 31 additions & 0 deletions lib/src/data_objects/get_vuid_response.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/// **************************************************************************
/// Copyright 2023, Optimizely, Inc. and contributors *
/// *
/// Licensed under the Apache License, Version 2.0 (the "License"); *
/// you may not use this file except in compliance with the License. *
/// You may obtain a copy of the License at *
/// *
/// http://www.apache.org/licenses/LICENSE-2.0 *
/// *
/// Unless required by applicable law or agreed to in writing, software *
/// distributed under the License is distributed on an "AS IS" BASIS, *
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
/// See the License for the specific language governing permissions and *
/// limitations under the License. *
///**************************************************************************/

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 = "";

GetVuidResponse(Map<String, dynamic> json) : super(json) {
if (json[Constants.responseResult] is Map<dynamic, dynamic>) {
var response = Map<String, dynamic>.from(json[Constants.responseResult]);
if (response[Constants.vuid] is String) {
vuid = response[Constants.vuid];
}
}
}
}
37 changes: 37 additions & 0 deletions lib/src/data_objects/sdk_settings.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/// **************************************************************************
/// Copyright 2023, Optimizely, Inc. and contributors *
/// *
/// Licensed under the Apache License, Version 2.0 (the "License"); *
/// you may not use this file except in compliance with the License. *
/// You may obtain a copy of the License at *
/// *
/// http://www.apache.org/licenses/LICENSE-2.0 *
/// *
/// Unless required by applicable law or agreed to in writing, software *
/// distributed under the License is distributed on an "AS IS" BASIS, *
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
/// See the License for the specific language governing permissions and *
/// limitations under the License. *
///**************************************************************************/

class SDKSettings {
// The maximum size of audience segments cache (optional. default = 100). Set to zero to disable caching.
final int segmentsCacheSize;
// The timeout in seconds of audience segments cache (optional. default = 600). Set to zero to disable timeout.
final int segmentsCacheTimeoutInSecs;
// The timeout in seconds of odp segment fetch (optional. default = 10) - OS default timeout will be used if this is set to zero.
final int timeoutForSegmentFetchInSecs;
// The timeout in seconds of odp event dispatch (optional. default = 10) - OS default timeout will be used if this is set to zero.
final int timeoutForOdpEventInSecs;
// Set this flag to true (default = false) to disable ODP features
final bool disableOdp;

const SDKSettings({
this.segmentsCacheSize = 100, // Default segmentsCacheSize
this.segmentsCacheTimeoutInSecs = 600, // Default segmentsCacheTimeoutInSecs
this.timeoutForSegmentFetchInSecs =
10, // Default timeoutForSegmentFetchInSecs
this.timeoutForOdpEventInSecs = 10, // Default timeoutForOdpEventInSecs
this.disableOdp = false, // Default disableOdp
});
}
63 changes: 54 additions & 9 deletions lib/src/optimizely_client_wrapper.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// **************************************************************************
/// Copyright 2022, Optimizely, Inc. and contributors *
/// Copyright 2022-2023, Optimizely, Inc. and contributors *
/// *
/// Licensed under the Apache License, Version 2.0 (the "License"); *
/// you may not use this file except in compliance with the License. *
Expand All @@ -22,6 +22,7 @@ import 'package:optimizely_flutter_sdk/src/data_objects/activate_listener_respon
import 'package:optimizely_flutter_sdk/src/data_objects/activate_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/base_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/get_variation_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/get_vuid_response.dart';
import 'package:optimizely_flutter_sdk/src/data_objects/optimizely_config_response.dart';
import 'package:optimizely_flutter_sdk/src/utils/constants.dart';
import 'package:optimizely_flutter_sdk/src/utils/utils.dart';
Expand Down Expand Up @@ -59,7 +60,8 @@ class OptimizelyClientWrapper {
EventOptions eventOptions,
int datafilePeriodicDownloadInterval,
Map<ClientPlatform, DatafileHostOptions> datafileHostOptions,
Set<OptimizelyDecideOption> defaultDecideOptions) async {
Set<OptimizelyDecideOption> defaultDecideOptions,
SDKSettings sdkSettings) async {
_channel.setMethodCallHandler(methodCallHandler);
final convertedOptions = Utils.convertDecideOptions(defaultDecideOptions);
Map<String, dynamic> requestDict = {
Expand All @@ -72,6 +74,18 @@ class OptimizelyClientWrapper {
Constants.eventMaxQueueSize: eventOptions.maxQueueSize,
};

// Odp Request params
Map<String, dynamic> optimizelySdkSettings = {
Constants.segmentsCacheSize: sdkSettings.segmentsCacheSize,
Constants.segmentsCacheTimeoutInSecs:
sdkSettings.segmentsCacheTimeoutInSecs,
Constants.timeoutForSegmentFetchInSecs:
sdkSettings.timeoutForSegmentFetchInSecs,
Constants.timeoutForOdpEventInSecs: sdkSettings.timeoutForOdpEventInSecs,
Constants.disableOdp: sdkSettings.disableOdp,
};
requestDict[Constants.optimizelySdkSettings] = optimizelySdkSettings;

// clearing notification listeners, if they are mapped to the same sdkKey.
activateCallbacksById.remove(sdkKey);
decisionCallbacksById.remove(sdkKey);
Expand Down Expand Up @@ -164,6 +178,35 @@ class OptimizelyClientWrapper {
return OptimizelyConfigResponse(result);
}

/// Send an event to the ODP server.
static Future<BaseResponse> sendOdpEvent(String sdkKey, String action,
{String? type,
Map<String, String> identifiers = const {},
Map<String, dynamic> data = const {}}) async {
Map<String, dynamic> request = {
Constants.sdkKey: sdkKey,
Constants.action: action,
Constants.identifiers: identifiers,
Constants.data: Utils.convertToTypedMap(data)
};
if (type != null) {
request[Constants.type] = type;
}

final result = Map<String, dynamic>.from(
await _channel.invokeMethod(Constants.sendOdpEventMethod, request));
return BaseResponse(result);
}

/// Returns the device vuid (read only)
static Future<GetVuidResponse> getVuid(String sdkKey) async {
final result = Map<String, dynamic>.from(
await _channel.invokeMethod(Constants.getVuidMethod, {
Constants.sdkKey: sdkKey,
}));
return GetVuidResponse(result);
}

/// Remove notification listener by notification id.
static Future<BaseResponse> removeNotificationListener(
String sdkKey, int id) async {
Expand Down Expand Up @@ -217,15 +260,17 @@ class OptimizelyClientWrapper {
/// Creates a context of the user for which decision APIs will be called.
///
/// A user context will only be created successfully when the SDK is fully configured using initializeClient.
static Future<OptimizelyUserContext?> createUserContext(
String sdkKey, String userId,
[Map<String, dynamic> attributes = const {}]) async {
final result = Map<String, dynamic>.from(
await _channel.invokeMethod(Constants.createUserContextMethod, {
static Future<OptimizelyUserContext?> createUserContext(String sdkKey,
{String? userId, Map<String, dynamic> attributes = const {}}) async {
Map<String, dynamic> request = {
Constants.sdkKey: sdkKey,
Constants.userId: userId,
Constants.attributes: Utils.convertToTypedMap(attributes)
}));
};
if (userId != null) {
request[Constants.userId] = userId;
}
final result = Map<String, dynamic>.from(await _channel.invokeMethod(
Constants.createUserContextMethod, request));

if (result[Constants.responseSuccess] == true) {
final response =
Expand Down
Loading