Add Simplified Initialize support#129
Conversation
Add Initialize API support for TS and Android
update main.dart
Update logging to trace
Add MobileCore.initialize(appId: "Your_APP_ID") API
...p/src/main/java/com/adobe/marketing/mobile/flutter/flutter_aepsdk_example/MyApplication.java
Outdated
Show resolved
Hide resolved
| class InitOptions { | ||
| String? appId; | ||
| String? filePath; | ||
| bool lifecycleAutomaticTracking; |
There was a problem hiding this comment.
Make this optional and avoid setting a default value. This allows the wrapper to defer to the default value provided by the underlying platform.
| @@ -0,0 +1,29 @@ | |||
| class InitOptions { | |||
| String? appId; | |||
There was a problem hiding this comment.
Can you add some comments for each property here?
| this.lifecycleAutomaticTracking = true, // Default value set to true | ||
| this.lifecycleAdditionalContextData = null, // Default value set to null | ||
| this.appGroupIOS = null, // Default value set to null | ||
| }) : assert(appId != null || filePath != null, |
There was a problem hiding this comment.
If neither value is set, the SDK will default to the bundled configuration.
You should assert that both values are not set at the same time.
| /// @param initOptions The [InitOptions] to configure the SDK. | ||
| /// @param appId The AEP SDK App ID. | ||
| /// @throws [ArgumentError] if neither `initOptions` nor `appId` is provided, or if both | ||
| static Future<void> initialize({InitOptions? initOptions, String? appId}) { |
There was a problem hiding this comment.
Split it into two APIs:
initialize()
initializeWithAppId()
For initializeWithAppId(), create an InitOptions object using the provided appId, and then call the initialize() API.
| result.success(MobileCore.extensionVersion()); | ||
| } else if ("initialize".equals(call.method)) { | ||
| handleInitialize(result, call.arguments); | ||
| } else if ("initializeWithAppId".equals(call.method)) { |
There was a problem hiding this comment.
You can remove this binding.
|
|
||
| private void handleInitialize(Result result, Object arguments) { | ||
| if (!(arguments instanceof Map)) { | ||
| result.error("INVALID_ARGUMENT", "Initialize failed because arguments is not a Map", null); |
There was a problem hiding this comment.
Define INVALID_ARGUMENT and other strings as constants.
| return; | ||
| } | ||
|
|
||
| if (application == null) { |
There was a problem hiding this comment.
You do this check in Line 113. Can you remove this?
| return; | ||
| } | ||
|
|
||
| Map initOptionsMap = (Map) arguments; |
There was a problem hiding this comment.
Perform a safe cast.
if (arguments instanceof Map) {
Map initOptionsMap = (Map) arguments;
}
I also recommend moving this logic to FlutterAEPCoreDataBridge.initOptionsFromMap()
Incorporate review comments
| /// The file path for the local configuration file | ||
| String? filePath; | ||
| /// Flag indicating whether automatic lifecycle tracking is enabled | ||
| bool? lifecycleAutomaticTracking; |
There was a problem hiding this comment.
Can you rename this to lifecycleAutomaticTrackingEnabled to make it consistent with Android and iOS?
example/lib/main.dart
Outdated
| appGroupIOS: "group.com.example", | ||
| ); | ||
|
|
||
| await MobileCore.initialize(initOptions: initOptions); |
There was a problem hiding this comment.
This is incorrect, as it will delay the app load until the SDK initializes. Could you move this to a more relevant place?
There was a problem hiding this comment.
I think you need to move this to the initState() function of the HomePage class. See my example in the spec.
https://wiki.corp.adobe.com/pages/viewpage.action?spaceKey=adms&title=004+%3A+SDK+Initialization+Simplification#id-004:SDKInitializationSimplification-Wrappers
Add iOS implementation for Simplified initialization
| } else if (filePath != null) { | ||
| options = InitOptions.configureWithFileInPath(filePath); | ||
| } else { | ||
| return null; // Either appId or filePath must be provided |
There was a problem hiding this comment.
Don't return here. Instead use options = InitOptions() and remove the comment.
If both appID and filePath are absent, we use bundled config.
| return AEP_PRIVACY_STATUS_UNKNOWN; | ||
| } | ||
|
|
||
| static InitOptions initOptionsFromMap(final Object option) { |
There was a problem hiding this comment.
nit: Can you fix the variable names.
option -> arguments
optionsAsMap -> argumentsAsMap
initOptionMap -> initOptionsMap
| } else { | ||
| return null; // Either appId or filePath must be provided | ||
| } | ||
| options.setLifecycleAutomaticTrackingEnabled(lifecycleAutomaticTrackingEnabled != null ? lifecycleAutomaticTrackingEnabled : true); |
There was a problem hiding this comment.
if (lifecycleAutomaticTrackingEnabled != null) {
options.setLifecycleAutomaticTrackingEnabled(lifecycleAutomaticTrackingEnabled)
}
| String appId = getNullableString(initOptionMap, APPID_KEY); | ||
| String filePath = getNullableString(initOptionMap, FILE_PATH_KEY); | ||
| Boolean lifecycleAutomaticTrackingEnabled = getNullableBoolean(initOptionMap, LIFECYCLE_AUTOMATION_TRACKING_KEY); | ||
| Map<String, String> lifecycleAdditionalContextData = getNullableMap(initOptionMap, LIFECYCLE_ADDITIONAL_CONTEXTDATA_KEY); |
There was a problem hiding this comment.
This cast is incorrect. Can you add getNullableStringMap() which verifies the keys and values are all String?
| public void onAttachedToEngine(@NonNull final FlutterPluginBinding binding) { | ||
| channel = new MethodChannel(binding.getBinaryMessenger(), "flutter_aepcore"); | ||
| channel.setMethodCallHandler(new FlutterAEPCorePlugin()); | ||
| application = (Application) binding.getApplicationContext(); |
There was a problem hiding this comment.
Context appContext = binding.getApplicationContext()
if (appContext instanceof Application) {
application = (Application) appContext;
}
| result([AEPMobileCore extensionVersion]); | ||
| } else if ([@"initialize" isEqualToString:call.method]) { | ||
| [self handleInitialize:call result:result]; | ||
| result(nil); |
There was a problem hiding this comment.
result(nil) should be called from inside the callback passed to initialize API.
| AEPInitOptions *initOptions = [FlutterAEPCoreDataBridge initOptionsFromMap:arguments]; | ||
| if (!initOptions) { | ||
| result([FlutterError errorWithCode:@"INVALID_ARGUMENT" | ||
| message:@"Initialize failed because initOptions is not a dictionary" |
There was a problem hiding this comment.
Initialize failed because InitOptions is not valid.
| InitOptions({ | ||
| this.appId, | ||
| this.filePath, | ||
| this.lifecycleAutomaticTrackingEnabled = true, |
There was a problem hiding this comment.
this.lifecycleAutomaticTrackingEnabled = null
| this.lifecycleAutomaticTrackingEnabled = true, | ||
| this.lifecycleAdditionalContextData = null, | ||
| this.appGroup = null, | ||
| }) : assert(!(appId != null && filePath != null), |
There was a problem hiding this comment.
Can you change your assertion to appId == null || filePath == null?
| /// Additional context data to be included in lifecycle start event. | ||
| Map<String, String>? lifecycleAdditionalContextData; | ||
| /// App group used to share user defaults and files among containing app and extension apps on iOS | ||
| String? appGroup; |
| retMap['filePath'] = filePath; | ||
| retMap['lifecycleAutomaticTrackingEnabled'] = lifecycleAutomaticTrackingEnabled; | ||
| retMap['lifecycleAdditionalContextData'] = lifecycleAdditionalContextData; | ||
| retMap['appGroup'] = appGroup; |
Incorporate review comments
update format
Update for the missing import for context
Update for the null and isKindOfClass check for appId on iOS
There was a problem hiding this comment.
Is this file still needed? Can you remove it?
There was a problem hiding this comment.
I am not able to remove AppDelegate files with error for the example app. I think we can keep it here. I will test with a brand new app to make sure the initialize API works there.
There was a problem hiding this comment.
Are you able to remove the AppDelegate altogether?
example/lib/main.dart
Outdated
| appGroupIOS: "group.com.example", | ||
| ); | ||
|
|
||
| await MobileCore.initialize(initOptions: initOptions); |
There was a problem hiding this comment.
I think you need to move this to the initState() function of the HomePage class. See my example in the spec.
https://wiki.corp.adobe.com/pages/viewpage.action?spaceKey=adms&title=004+%3A+SDK+Initialization+Simplification#id-004:SDKInitializationSimplification-Wrappers
|
|
||
| private final static String APPID_KEY = "appId"; | ||
| private final static String FILE_PATH_KEY = "filePath"; | ||
| private final static String LIFECYCLE_AUTOMATION_TRACKING_KEY = "lifecycleAutomaticTrackingEnabled"; |
Fixing typo
Remove filePath parameter in initialize API
| } | ||
|
|
||
| Map rawMap = (Map) data.get(key); | ||
| Map<String, String> stringMap = new HashMap<>(); |
There was a problem hiding this comment.
Don't create a new map. Instead, after validation, your return value on line 186 should be (Map<String, String>) rawMap.
| Context appContext = binding.getApplicationContext(); | ||
| if (appContext instanceof Application) { | ||
| application = (Application) appContext; | ||
| } |
There was a problem hiding this comment.
Can you also add a call to MobileCore.setWrapperType(WrapperType.Flutter) here?
Additionally, include the same API call within the registerWithRegistrar method of your iOS wrapper.
…per Type Flutter for Android and iOS. Update SDK initialize in initState() in the example app, add AEP Wrapper Type Flutter for Android and iOS. Fix return map in Core DataBridge Java file.
| NSString *appGroup = initOptionsMap[@"appGroup"]; | ||
|
|
||
| AEPInitOptions *initOptions; | ||
| if (appId != nil && ![appId isKindOfClass:[NSNull class]]) { |
There was a problem hiding this comment.
Instead of testing if appId is not NSNull class, can you check if it is NSString class?
if (appId != nil && [appId isKindOfClass:[NSString class]])
| if (lifecycleAdditionalContextData != nil && [lifecycleAdditionalContextData isKindOfClass:[NSDictionary class]]) { | ||
| initOptions.lifecycleAdditionalContextData = lifecycleAdditionalContextData; | ||
| } else { | ||
| NSLog(@"lifecycleAdditionalContextData is nil or not a dictionary"); |
There was a problem hiding this comment.
I'd recommend removing this log entry as it's probably more common to not set additional context data. Plus, the Android implementation doesn't log here either.
| if (appGroup != nil && [appGroup isKindOfClass:[NSString class]]) { | ||
| initOptions.appGroup = appGroup; | ||
| } else { | ||
| NSLog(@"appGroup is nil or not a string"); |
There was a problem hiding this comment.
I'd recommend removing this log entry as it's probably more common to not set an app group.
Update AEPCoreDataBridge
Add MobileCore.initialize(appId: "Your_APP_ID")
TODO:
Description
Related Issue
Motivation and Context
How Has This Been Tested?
Screenshots (if appropriate):
Types of changes
Checklist: