Skip to content
Draft
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
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ dependencies {
implementation 'org.slf4j:slf4j-api:2.0.7'

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.0"
implementation "com.optimizely.ab:android-sdk:5.0.1"
implementation "com.optimizely.ab:android-sdk:5.1.0"
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2'
implementation ('com.google.guava:guava:19.0') {
exclude group:'com.google.guava', module:'listenablefuture'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
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;
import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.TIMEOUT_FOR_SEGMENT_FETCH_IN_SECONDS;
import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.CMAB_CONFIG;
import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.CMAB_CACHE_SIZE;
import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.CMAB_CACHE_TIMEOUT_IN_SECS;
import static com.optimizely.optimizely_flutter_sdk.helper_classes.Constants.RequestParameterKey.CMAB_PREDICTION_ENDPOINT;
import static com.optimizely.optimizely_flutter_sdk.helper_classes.Utils.getNotificationListenerType;

import java.util.Collections;
Expand Down Expand Up @@ -187,6 +191,25 @@ protected void initializeOptimizely(@NonNull ArgumentsParser argumentsParser, @N
optimizelyManagerBuilder.withVuidEnabled();
}

// CMAB Config
Map<String, Object> cmabConfig = argumentsParser.getCmabConfig();
if (cmabConfig != null) {
if (cmabConfig.containsKey(CMAB_CACHE_SIZE)) {
Integer cmabCacheSize = (Integer) cmabConfig.get(CMAB_CACHE_SIZE);
optimizelyManagerBuilder.withCmabCacheSize(cmabCacheSize);
}
if (cmabConfig.containsKey(CMAB_CACHE_TIMEOUT_IN_SECS)) {
Integer cmabCacheTimeout = (Integer) cmabConfig.get(CMAB_CACHE_TIMEOUT_IN_SECS);
optimizelyManagerBuilder.withCmabCacheTimeout(cmabCacheTimeout, TimeUnit.SECONDS);
}
if (cmabConfig.containsKey(CMAB_PREDICTION_ENDPOINT)) {
String endpoint = (String) cmabConfig.get(CMAB_PREDICTION_ENDPOINT);
// Convert platform-agnostic placeholder {ruleId} to Android format %s
String androidEndpoint = endpoint.replace("{ruleId}", "%s");
optimizelyManagerBuilder.withCmabPredictionEndpoint(androidEndpoint);
}
}

OptimizelyManager optimizelyManager = optimizelyManagerBuilder.build(context);

optimizelyManager.initialize(context, null, (OptimizelyClient client) -> {
Expand Down Expand Up @@ -364,6 +387,55 @@ protected void decide(ArgumentsParser argumentsParser, @NonNull Result result) {
result.success(createResponse(s));
}

protected void decideAsync(ArgumentsParser argumentsParser, @NonNull Result result) {
String sdkKey = argumentsParser.getSdkKey();
OptimizelyUserContext userContext = getUserContext(argumentsParser);
if (!isUserContextValid(sdkKey, userContext, result)) {
return;
}

List<String> decideKeys = argumentsParser.getDecideKeys();
List<OptimizelyDecideOption> decideOptions = argumentsParser.getDecideOptions();

// Determine which async method to call based on keys
if (decideKeys == null || decideKeys.isEmpty()) {
// decideAllAsync
userContext.decideAllAsync(decideOptions, decisions -> {
Map<String, OptimizelyDecisionResponse> optimizelyDecisionResponseMap = new HashMap<>();
if (decisions != null) {
for (Map.Entry<String, OptimizelyDecision> entry : decisions.entrySet()) {
optimizelyDecisionResponseMap.put(entry.getKey(), new OptimizelyDecisionResponse(entry.getValue()));
}
}
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> s = mapper.convertValue(optimizelyDecisionResponseMap, LinkedHashMap.class);
result.success(createResponse(s));
});
} else if (decideKeys.size() == 1) {
// decideAsync for single key
userContext.decideAsync(decideKeys.get(0), decideOptions, decision -> {
Map<String, OptimizelyDecisionResponse> optimizelyDecisionResponseMap = new HashMap<>();
optimizelyDecisionResponseMap.put(decideKeys.get(0), new OptimizelyDecisionResponse(decision));
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> s = mapper.convertValue(optimizelyDecisionResponseMap, LinkedHashMap.class);
result.success(createResponse(s));
});
} else {
// decideForKeysAsync for multiple keys
userContext.decideForKeysAsync(decideKeys, decideOptions, decisions -> {
Map<String, OptimizelyDecisionResponse> optimizelyDecisionResponseMap = new HashMap<>();
if (decisions != null) {
for (Map.Entry<String, OptimizelyDecision> entry : decisions.entrySet()) {
optimizelyDecisionResponseMap.put(entry.getKey(), new OptimizelyDecisionResponse(entry.getValue()));
}
}
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> s = mapper.convertValue(optimizelyDecisionResponseMap, LinkedHashMap.class);
result.success(createResponse(s));
});
}
}

protected void setForcedDecision(ArgumentsParser argumentsParser, @NonNull Result result) {
String sdkKey = argumentsParser.getSdkKey();
OptimizelyUserContext userContext = getUserContext(argumentsParser);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
decide(argumentsParser, result);
break;
}
case APIs.DECIDE_ASYNC: {
decideAsync(argumentsParser, result);
break;
}
case APIs.SET_FORCED_DECISION: {
setForcedDecision(argumentsParser, result);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,8 @@ public List<ODPSegmentOption> getSegmentOptions() {
public Map<String, Object> getOptimizelySdkSettings() {
return (Map<String, Object>) arguments.get(Constants.RequestParameterKey.OPTIMIZELY_SDK_SETTINGS);
}

public Map<String, Object> getCmabConfig() {
return (Map<String, Object>) arguments.get(Constants.RequestParameterKey.CMAB_CONFIG);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public static class APIs {
public static final String SET_FORCED_DECISION = "setForcedDecision";
public static final String TRACK_EVENT = "trackEvent";
public static final String DECIDE = "decide";
public static final String DECIDE_ASYNC = "decideAsync";
public static final String ADD_NOTIFICATION_LISTENER = "addNotificationListener";
public static final String REMOVE_NOTIFICATION_LISTENER = "removeNotificationListener";
public static final String CLEAR_ALL_NOTIFICATION_LISTENERS = "clearAllNotificationListeners";
Expand Down Expand Up @@ -97,6 +98,12 @@ public static class RequestParameterKey {
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";

// CMAB Config
public static final String CMAB_CONFIG = "cmabConfig";
public static final String CMAB_CACHE_SIZE = "cmabCacheSize";
public static final String CMAB_CACHE_TIMEOUT_IN_SECS = "cmabCacheTimeoutInSecs";
public static final String CMAB_PREDICTION_ENDPOINT = "cmabPredictionEndpoint";
}

public static class ErrorMessage {
Expand Down
14 changes: 8 additions & 6 deletions example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -68,7 +68,6 @@
8E60C66DA76D705E5A9DCACA /* Pods-Runner.release.xcconfig */,
3D86A8B550CB0FBA7A8F2A03 /* Pods-Runner.profile.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
Expand Down Expand Up @@ -156,7 +155,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
Expand Down Expand Up @@ -200,10 +199,12 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
Expand Down Expand Up @@ -231,6 +232,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down Expand Up @@ -356,7 +358,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 6CHVYYTX7N;
DEVELOPMENT_TEAM = BDMC9C2X5M;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
Expand Down Expand Up @@ -486,7 +488,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 6CHVYYTX7N;
DEVELOPMENT_TEAM = BDMC9C2X5M;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
Expand All @@ -510,7 +512,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 6CHVYYTX7N;
DEVELOPMENT_TEAM = BDMC9C2X5M;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1510"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
shouldUseLaunchSchemeArgsEnv = "YES">
<MacroExpansion>
<BuildableReference
Expand All @@ -43,11 +44,13 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
Expand Down
33 changes: 32 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:async';
import 'dart:math';
import 'package:optimizely_flutter_sdk/optimizely_flutter_sdk.dart';
import 'package:optimizely_flutter_sdk_example/custom_logger.dart';
import 'package:optimizely_flutter_sdk_example/sample_api.dart';

void main() {
runApp(const MyApp());
Expand Down Expand Up @@ -143,6 +144,18 @@ class _MyAppState extends State<MyApp> {
if (!mounted) return;
}

Future<void> _runCmabExamples() async {
setState(() {
uiResponse = 'Running CMAB examples... Check console for output.';
});

await CmabSampleApi.runAllCmabExamples();

setState(() {
uiResponse = 'CMAB examples completed! Check console for detailed output.';
});
}

@override
Widget build(BuildContext context) {
return MaterialApp(
Expand All @@ -151,7 +164,25 @@ class _MyAppState extends State<MyApp> {
title: const Text('Plugin example app'),
),
body: Center(
child: Text(uiResponse),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: SingleChildScrollView(
child: Text(uiResponse),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: _runCmabExamples,
child: const Text('Run CMAB Examples'),
),
const SizedBox(height: 10),
],
),
),
),
),
);
Expand Down
Loading
Loading