From 2c0665cbde57b9cbd099bbaff8e258960fefac4f Mon Sep 17 00:00:00 2001 From: Kyle Date: Thu, 10 Nov 2022 10:21:40 -0800 Subject: [PATCH 1/9] chore(analytics): migrate legacy data Extract endpoint id from Amplify iOS and Android Analytics --- .../amplify_analytics_pinpoint/.metadata | 45 +++++++ .../analysis_options.yaml | 7 +- .../android/.gitignore | 8 ++ .../android/build.gradle | 52 +++++++ .../android/settings.gradle | 1 + .../android/src/main/AndroidManifest.xml | 3 + .../amplify_analytics_pinpoint/Messages.java | 127 ++++++++++++++++++ .../AmplifyAnalyticsPinpointPlugin.kt | 54 ++++++++ .../lib/src/analytics_plugin_impl.dart | 4 + .../flutter_path_provider.dart | 4 + .../flutter_path_provider_html.dart | 2 +- .../flutter_path_provider_io.dart | 2 +- .../flutter_path_provider_stub.dart | 2 +- .../data_provider.android.dart | 36 +++++ .../data_provider.ios.dart | 41 ++++++ .../flutter_legacy_native_data_provider.dart | 53 ++++++++ ...pigeon_legacy_data_provider.android.g.dart | 76 +++++++++++ .../pigeons/copyright.txt | 14 ++ .../pigeons/pigeon_config_android.dart | 40 ++++++ .../amplify_analytics_pinpoint/pubspec.yaml | 9 ++ .../lib/amplify_analytics_pinpoint_dart.dart | 1 + .../lib/src/analytics_plugin_impl.dart | 38 +++++- .../legacy_native_data_provider.dart | 10 ++ 23 files changed, 617 insertions(+), 12 deletions(-) create mode 100644 packages/analytics/amplify_analytics_pinpoint/.metadata create mode 100644 packages/analytics/amplify_analytics_pinpoint/android/.gitignore create mode 100644 packages/analytics/amplify_analytics_pinpoint/android/build.gradle create mode 100644 packages/analytics/amplify_analytics_pinpoint/android/settings.gradle create mode 100644 packages/analytics/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml create mode 100644 packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java create mode 100644 packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt create mode 100644 packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt create mode 100644 packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart diff --git a/packages/analytics/amplify_analytics_pinpoint/.metadata b/packages/analytics/amplify_analytics_pinpoint/.metadata new file mode 100644 index 0000000000..c519b0887d --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled. + +version: + revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + channel: stable + +project_type: plugin + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + - platform: android + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + - platform: ios + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + - platform: linux + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + - platform: macos + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + - platform: web + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + - platform: windows + create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml b/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml index eb7b6bab52..36582ff7dd 100644 --- a/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml +++ b/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml @@ -1,5 +1,6 @@ include: package:amplify_lints/library.yaml -analyzer: - errors: - implementation_imports: error #TODO(equartey): Remove when lint is enforced project-wide +analyzer: + exclude: + implementation_imports: error #TODO(equartey): Remove when lint is enforced project-wide + - "**/**/**/*.g.dart" diff --git a/packages/analytics/amplify_analytics_pinpoint/android/.gitignore b/packages/analytics/amplify_analytics_pinpoint/android/.gitignore new file mode 100644 index 0000000000..26659750ab --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/android/.gitignore @@ -0,0 +1,8 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures \ No newline at end of file diff --git a/packages/analytics/amplify_analytics_pinpoint/android/build.gradle b/packages/analytics/amplify_analytics_pinpoint/android/build.gradle new file mode 100644 index 0000000000..48e5c76cc3 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/android/build.gradle @@ -0,0 +1,52 @@ +group 'com.amazonaws.amplify.amplify_analytics_pinpoint.amplify_analytics_pinpoint' +version '1.0-SNAPSHOT' + +buildscript { + ext.kotlin_version = '1.6.10' + repositories { + google() + mavenCentral() + } + + dependencies { + classpath 'com.android.tools.build:gradle:7.1.3' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +rootProject.allprojects { + repositories { + google() + mavenCentral() + } +} + +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 33 + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = '1.8' + } + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + defaultConfig { + minSdkVersion 23 + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + implementation 'androidx.security:security-crypto:1.0.0' +} + diff --git a/packages/analytics/amplify_analytics_pinpoint/android/settings.gradle b/packages/analytics/amplify_analytics_pinpoint/android/settings.gradle new file mode 100644 index 0000000000..828ffda158 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/android/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'amplify_analytics_pinpoint' diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml b/packages/analytics/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..178b72183e --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java b/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java new file mode 100644 index 0000000000..b0e1a07592 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java @@ -0,0 +1,127 @@ +// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// 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. +// +// Autogenerated from Pigeon (v4.2.14), do not edit directly. +// See also: https://pub.dev/packages/pigeon + +package com.amazonaws.amplify.amplify_analytics_pinpoint.amplify_analytics_pinpoint; + +import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import io.flutter.plugin.common.BasicMessageChannel; +import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.plugin.common.MessageCodec; +import io.flutter.plugin.common.StandardMessageCodec; +import java.io.ByteArrayOutputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +/** Generated class from Pigeon. */ +@SuppressWarnings({"unused", "unchecked", "CodeBlock2Expr", "RedundantSuppression"}) +public class Messages { + + public interface Result { + void success(T result); + void error(Throwable error); + } + /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ + public interface PigeonLegacyDataProvider { + void initialize(@NonNull String pinpointAppId, Result result); + void getEndpointId(Result result); + + /** The codec used by PigeonLegacyDataProvider. */ + static MessageCodec getCodec() { + return new StandardMessageCodec(); } + /**Sets up an instance of `PigeonLegacyDataProvider` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, PigeonLegacyDataProvider api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.PigeonLegacyDataProvider.initialize", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + try { + ArrayList args = (ArrayList)message; + assert args != null; + String pinpointAppIdArg = (String)args.get(0); + if (pinpointAppIdArg == null) { + throw new NullPointerException("pinpointAppIdArg unexpectedly null."); + } + Result resultCallback = new Result() { + public void success(Void result) { + wrapped.add(0, null); + reply.reply(wrapped); + } + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.initialize(pinpointAppIdArg, resultCallback); + } + catch (Error | RuntimeException exception) { + ArrayList wrappedError = wrapError(exception); + reply.reply(wrappedError); + } + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.PigeonLegacyDataProvider.getEndpointId", getCodec()); + if (api != null) { + channel.setMessageHandler((message, reply) -> { + ArrayList wrapped = new ArrayList<>(); + try { + Result resultCallback = new Result() { + public void success(String result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.getEndpointId(resultCallback); + } + catch (Error | RuntimeException exception) { + ArrayList wrappedError = wrapError(exception); + reply.reply(wrappedError); + } + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + @NonNull private static ArrayList wrapError(@NonNull Throwable exception) { + ArrayList errorList = new ArrayList<>(3); + errorList.add(exception.toString()); + errorList.add(exception.getClass().getSimpleName()); + errorList.add("Cause: " + exception.getCause() + ", Stacktrace: " + Log.getStackTraceString(exception)); + return errorList; + } +} diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt new file mode 100644 index 0000000000..9602cd5dc2 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +package com.amazonaws.amplify.amplify_analytics_pinpoint.amplify_analytics_pinpoint + +import android.content.Context +import android.content.SharedPreferences +import androidx.annotation.NonNull +import io.flutter.embedding.engine.plugins.FlutterPlugin + +class AmplifyAnalyticsPinpointPlugin: FlutterPlugin, Messages.PigeonLegacyDataProvider { + + lateinit var context: Context + lateinit var sharedPrefs: SharedPreferences + + companion object { + private const val PINPOINT_SHARED_PREFS_SUFFIX = "515d6767-01b7-49e5-8273-c8d11b0f331d" + private const val UNIQUE_ID_KEY = "UniqueId"; + } + + override fun onAttachedToEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + context = binding.applicationContext + Messages.PigeonLegacyDataProvider.setup(binding.binaryMessenger, this) + } + + override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { + Messages.PigeonLegacyDataProvider.setup(binding.binaryMessenger, null) + } + + override fun initialize(pinpointAppId: String, result: Messages.Result){ + sharedPrefs = context.getSharedPreferences( + "${pinpointAppId}$PINPOINT_SHARED_PREFS_SUFFIX", + Context.MODE_PRIVATE + ) + result.success(null) + } + + override fun getEndpointId(result: Messages.Result){ + result.success(sharedPrefs.getString(UNIQUE_ID_KEY, null)) + } + +} \ No newline at end of file diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart index 536a55094e..d54959ede2 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart @@ -4,6 +4,7 @@ import 'package:amplify_analytics_pinpoint/src/device_context_info_provider/flutter_device_context_info_provider.dart'; import 'package:amplify_analytics_pinpoint/src/flutter_app_lifecycle_provider.dart'; import 'package:amplify_analytics_pinpoint/src/flutter_path_provider/flutter_path_provider.dart'; +import 'package:amplify_analytics_pinpoint/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart'; import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; import 'package:amplify_db_common/amplify_db_common.dart' as db_common; import 'package:amplify_secure_storage/amplify_secure_storage.dart'; @@ -19,6 +20,7 @@ class AmplifyAnalyticsPinpoint extends AmplifyAnalyticsPinpointDart { @visibleForTesting CachedEventsPathProvider? pathProvider, @visibleForTesting AppLifecycleProvider? appLifecycleProvider, @visibleForTesting DeviceContextInfoProvider? deviceContextInfoProvider, + @visibleForTesting LegacyNativeDataProvider? legacyNativeDataProvider, }) : super( endpointInfoStore: endpointInfoStore ?? AmplifySecureStorage( @@ -31,6 +33,8 @@ class AmplifyAnalyticsPinpoint extends AmplifyAnalyticsPinpointDart { appLifecycleProvider ?? FlutterAppLifecycleProvider(), deviceContextInfoProvider: deviceContextInfoProvider ?? const FlutterDeviceContextInfoProvider(), + legacyNativeDataProvider: + legacyNativeDataProvider ?? FlutterLegacyNativeDataProvider(), dbConnectFunction: db_common.connect, ); } diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider.dart index 3c9a363beb..f60aa28c0a 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider.dart @@ -7,6 +7,10 @@ /// Multi platform class that provides storage location path /// Requires Flutter specific dependencies + +/// {@template amplify_analytics_pinpoint.flutter_path_provider} +/// Provides device storage location +/// {@endtemplate} export 'flutter_path_provider_stub.dart' if (dart.library.html) 'flutter_path_provider_html.dart' if (dart.library.io) 'flutter_path_provider_io.dart'; diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_html.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_html.dart index 620508d086..15d0475d67 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_html.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_html.dart @@ -3,7 +3,7 @@ import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; -/// {@template amplify_analytics_pinpoint.flutter_path_provider} +/// {@macro amplify_analytics_pinpoint.flutter_path_provider} class FlutterPathProvider extends CachedEventsPathProvider { @override Future getApplicationSupportPath() async { diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_io.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_io.dart index f1cfa06f3f..60c7699b58 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_io.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_io.dart @@ -4,7 +4,7 @@ import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; import 'package:path_provider/path_provider.dart'; -/// {@template amplify_analytics_pinpoint.flutter_path_provider} +/// {@macro amplify_analytics_pinpoint.flutter_path_provider} class FlutterPathProvider extends CachedEventsPathProvider { @override Future getApplicationSupportPath() async { diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_stub.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_stub.dart index f37bca2fea..a8ec5db5be 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_stub.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/flutter_path_provider/flutter_path_provider_stub.dart @@ -3,7 +3,7 @@ import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; -// ignore: public_member_api_docs +/// {@macro amplify_analytics_pinpoint.flutter_path_provider} class FlutterPathProvider extends CachedEventsPathProvider { @override Future getApplicationSupportPath() async { diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart new file mode 100644 index 0000000000..560a886b9a --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart @@ -0,0 +1,36 @@ +// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// 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 'dart:async'; + +import 'package:amplify_analytics_pinpoint/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart'; +import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; + +/// {@macro amplify_analytics_pinpoint.flutter_legacy_native_data_provider} +class DataProviderAndroid implements LegacyNativeDataProvider { + /// {@macro amplify_analytics_pinpoint.flutter_legacy_native_data_provider} + DataProviderAndroid() : _pigeonDataProvider = PigeonLegacyDataProvider(); + + final PigeonLegacyDataProvider _pigeonDataProvider; + + @override + Future initialize(String pinpointAppId) { + return _pigeonDataProvider.initialize(pinpointAppId); + } + + @override + Future getEndpointId() { + return _pigeonDataProvider.getEndpointId(); + } +} diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart new file mode 100644 index 0000000000..92c972abc4 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart @@ -0,0 +1,41 @@ +// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// 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 'dart:async'; + +import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; +import 'package:amplify_secure_storage/amplify_secure_storage.dart'; + +/// {@macro amplify_analytics_pinpoint.flutter_legacy_native_data_provider} +class DataProviderIos implements LegacyNativeDataProvider { + /// {@macro amplify_analytics_pinpoint.flutter_legacy_native_data_provider} + DataProviderIos() + : _keyValueStore = AmplifySecureStorage( + config: AmplifySecureStorageConfig.byNamespace(namespace: _context), + ); + + static const _context = 'com.amazonaws.AWSPinpointContext'; + static const _key = 'com.amazonaws.AWSPinpointContextKeychainUniqueIdKey'; + + final AmplifySecureStorage _keyValueStore; + + @override + Future initialize(String pinpointAppId) async {} + + @override + Future getEndpointId() async { + final endpointId = await _keyValueStore.read(key: _key); + return endpointId; + } +} diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart new file mode 100644 index 0000000000..b5cb586582 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart @@ -0,0 +1,53 @@ +// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// 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 'dart:async'; +import 'dart:io' show Platform; + +import 'package:amplify_analytics_pinpoint/src/legacy_native_data_provider/data_provider.android.dart'; +import 'package:amplify_analytics_pinpoint/src/legacy_native_data_provider/data_provider.ios.dart'; +import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; + +/// {@template amplify_analytics_pinpoint.flutter_legacy_native_data_provider} +/// Provides legacy data stored by Amplify Analytics iOS and Android. +/// {@endtemplate} +class FlutterLegacyNativeDataProvider implements LegacyNativeDataProvider { + /// {@macro amplify_analytics_pinpoint.flutter_legacy_native_data_provider} + factory FlutterLegacyNativeDataProvider() { + LegacyNativeDataProvider? provider; + + if (Platform.isIOS) { + provider = DataProviderIos(); + } else if (Platform.isAndroid) { + provider = DataProviderAndroid(); + } + + return FlutterLegacyNativeDataProvider._(provider); + } + + FlutterLegacyNativeDataProvider._(this._nativeDataProvider); + + final LegacyNativeDataProvider? _nativeDataProvider; + + @override + Future initialize(String pinpointAppId) async { + return _nativeDataProvider?.initialize(pinpointAppId); + } + + @override + Future getEndpointId() async { + if (_nativeDataProvider == null) return null; + return _nativeDataProvider!.getEndpointId(); + } +} diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart new file mode 100644 index 0000000000..04fb49b914 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart @@ -0,0 +1,76 @@ +// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// 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. +// +// Autogenerated from Pigeon (v4.2.14), do not edit directly. +// See also: https://pub.dev/packages/pigeon +// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import +import 'dart:async'; +import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; + +import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; +import 'package:flutter/services.dart'; + +class PigeonLegacyDataProvider { + /// Constructor for [PigeonLegacyDataProvider]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + PigeonLegacyDataProvider({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future initialize(String arg_pinpointAppId) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PigeonLegacyDataProvider.initialize', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_pinpointAppId]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } + + Future getEndpointId() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.PigeonLegacyDataProvider.getEndpointId', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return (replyList[0] as String?); + } + } +} diff --git a/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt b/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt new file mode 100644 index 0000000000..96ebfc1126 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt @@ -0,0 +1,14 @@ +Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +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. + diff --git a/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart b/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart new file mode 100644 index 0000000000..bddde6c45f --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart @@ -0,0 +1,40 @@ +// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// 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. + +// To regenerate, run `make pigeons`. + +import 'package:pigeon/pigeon.dart'; + +@ConfigurePigeon( + PigeonOptions( + dartOut: + 'lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart', + javaOut: + 'android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java', + javaOptions: JavaOptions( + className: 'Messages', + package: + 'com.amazonaws.amplify.amplify_analytics_pinpoint.amplify_analytics_pinpoint', + ), + copyrightHeader: 'pigeons/copyright.txt', + ), +) +@HostApi() +abstract class PigeonLegacyDataProvider { + @async + void initialize(String pinpointAppId); + + @async + String? getEndpointId(); +} diff --git a/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml b/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml index dffb496ece..d5b71220c2 100644 --- a/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml +++ b/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml @@ -35,3 +35,12 @@ dev_dependencies: amplify_lints: ^2.0.0 flutter_test: sdk: flutter + pigeon: ^4.2.5 + +# The following section is specific to Flutter. +flutter: + plugin: + platforms: + android: + package: com.amazonaws.amplify.amplify_analytics_pinpoint.amplify_analytics_pinpoint + pluginClass: AmplifyAnalyticsPinpointPlugin diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/amplify_analytics_pinpoint_dart.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/amplify_analytics_pinpoint_dart.dart index e0adf2d728..8114db7a27 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/amplify_analytics_pinpoint_dart.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/amplify_analytics_pinpoint_dart.dart @@ -9,3 +9,4 @@ export 'src/analytics_plugin_impl.dart'; export 'src/impl/flutter_provider_interfaces/app_lifecycle_provider.dart'; export 'src/impl/flutter_provider_interfaces/cached_events_path_provider.dart'; export 'src/impl/flutter_provider_interfaces/device_context_info_provider.dart'; +export 'src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart'; diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart index 1283037702..d1d939de0d 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart @@ -18,7 +18,6 @@ import 'package:amplify_core/amplify_core.dart'; import 'package:amplify_db_common_dart/amplify_db_common_dart.dart'; import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart'; import 'package:meta/meta.dart'; -import 'package:uuid/uuid.dart'; /// The Analytics Pinpoint session start event type. @visibleForTesting @@ -41,6 +40,7 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { CachedEventsPathProvider? pathProvider, AppLifecycleProvider? appLifecycleProvider, DeviceContextInfoProvider? deviceContextInfoProvider, + LegacyNativeDataProvider? legacyNativeDataProvider, required Connect dbConnectFunction, }) : _endpointInfoStore = endpointInfoStore ?? AmplifySecureStorageWorker( @@ -51,6 +51,7 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { _pathProvider = pathProvider, _appLifecycleProvider = appLifecycleProvider, _deviceContextInfoProvider = deviceContextInfoProvider, + _legacyNativeDataProvider = legacyNativeDataProvider, _dbConnectFunction = dbConnectFunction; void _ensureConfigured() { @@ -69,9 +70,15 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { /// Storage key for the static Pinpoint endpoint id @visibleForTesting static const String endpointIdStorageKey = 'UniqueId'; + static const String _endpointInformationVersionKey = + 'EndpointInformationVersionKey'; static const String _endpointGlobalAttrsKey = 'EndpointGlobalAttributesKey'; static const String _endpointGlobalMetricsKey = 'EndpointGlobalMetricsKey'; + /// Version of metadata stored into the `endpointInfoStore` + /// If stored data changes, increment this value + static const String _endpointInformationCurrentVersionValue = '0'; + late final EventCreator _eventCreator; late final EndpointClient _endpointClient; late final EventClient _eventClient; @@ -88,6 +95,7 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { final CachedEventsPathProvider? _pathProvider; final AppLifecycleProvider? _appLifecycleProvider; final DeviceContextInfoProvider? _deviceContextInfoProvider; + final LegacyNativeDataProvider? _legacyNativeDataProvider; final Connect _dbConnectFunction; static final _logger = AmplifyLogger.category(Category.analytics); @@ -138,15 +146,33 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { ); // Retrieve Unique ID - final savedFixedEndpointId = - await _endpointInfoStore.read(key: endpointIdStorageKey); - final fixedEndpointId = savedFixedEndpointId ?? const Uuid().v1(); - if (savedFixedEndpointId == null) { + final endpointInformationVersion = + await _endpointInfoStore.read(key: _endpointInformationVersionKey); + String? retrievedEndpointId; + + await _legacyNativeDataProvider?.initialize(appId); + retrievedEndpointId = await _legacyNativeDataProvider?.getEndpointId(); + print('retrieved id: ${retrievedEndpointId ?? 'null'}'); + + if (endpointInformationVersion == null) { + _endpointInfoStore.write( + key: _endpointInformationVersionKey, + value: _endpointInformationCurrentVersionValue, + ); + + await _legacyNativeDataProvider?.initialize(appId); + retrievedEndpointId = await _legacyNativeDataProvider?.getEndpointId(); + + retrievedEndpointId ??= uuid(); await _endpointInfoStore.write( key: endpointIdStorageKey, - value: fixedEndpointId, + value: retrievedEndpointId, ); + } else { + retrievedEndpointId = + await _endpointInfoStore.read(key: endpointIdStorageKey); } + final fixedEndpointId = retrievedEndpointId!; final endpoint = PublicEndpoint( effectiveDate: DateTime.now().toUtc().toIso8601String(), diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart new file mode 100644 index 0000000000..d5e89fe58e --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart @@ -0,0 +1,10 @@ +import 'dart:async'; + +/// {@template amplify_analytics_pinpoint.flutter_legacy_native_data_provider} +abstract class LegacyNativeDataProvider { + /// Setup + Future initialize(String pinpointAppId); + + /// Get stored Pinpoint Endpoint Id + Future getEndpointId(); +} From 9798577d95d24aee61e6fb7cacd277d8959f1318 Mon Sep 17 00:00:00 2001 From: kc Date: Tue, 3 Jan 2023 14:41:35 -0800 Subject: [PATCH 2/9] Update packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt Co-authored-by: Jordan Nelson --- .../AmplifyAnalyticsPinpointPlugin.kt | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt index 9602cd5dc2..5b55da3c0e 100644 --- a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -1,17 +1,5 @@ -/* - * Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file 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. - */ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 package com.amazonaws.amplify.amplify_analytics_pinpoint.amplify_analytics_pinpoint From 994e5e9f6c39fb6f557b56d4b6c69d64d87d6632 Mon Sep 17 00:00:00 2001 From: kc Date: Tue, 3 Jan 2023 14:41:50 -0800 Subject: [PATCH 3/9] Update packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml Co-authored-by: Jordan Nelson From 2be1ff2df3bd4e56c3b907f6096a76210bed75a4 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 3 Jan 2023 22:36:45 -0800 Subject: [PATCH 4/9] PR Comments --- .../lib/amplify_analytics_pinpoint.dart | 5 +- .../lib/src/analytics_plugin_impl.dart | 11 +- .../amplify_analytics_pinpoint/pubspec.yaml | 1 - .../lib/src/analytics_plugin_impl.dart | 75 ++++---- .../endpoint_client/endpoint_store_keys.dart | 14 ++ .../endpoint_store_manager.dart | 0 .../legacy_native_data_provider.dart | 3 + .../analytics_legacy_native_data_test.dart | 177 ++++++++++++++++++ 8 files changed, 239 insertions(+), 47 deletions(-) create mode 100644 packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_manager.dart create mode 100644 packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart b/packages/analytics/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart index 24f7571f13..50f3035e14 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart @@ -6,10 +6,7 @@ library amplify_analytics_pinpoint; /// Overridable Flutter injected dependencies export 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart' - show - AppLifecycleProvider, - CachedEventsPathProvider, - DeviceContextInfoProvider; + show AppLifecycleProvider; /// Category Implementation export 'src/analytics_plugin_impl.dart'; diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart index d54959ede2..22519638ae 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/analytics_plugin_impl.dart @@ -17,10 +17,7 @@ class AmplifyAnalyticsPinpoint extends AmplifyAnalyticsPinpointDart { /// {@macro amplify_analytics_pinpoint.analytics_plugin_impl} AmplifyAnalyticsPinpoint({ @visibleForTesting SecureStorageInterface? endpointInfoStore, - @visibleForTesting CachedEventsPathProvider? pathProvider, @visibleForTesting AppLifecycleProvider? appLifecycleProvider, - @visibleForTesting DeviceContextInfoProvider? deviceContextInfoProvider, - @visibleForTesting LegacyNativeDataProvider? legacyNativeDataProvider, }) : super( endpointInfoStore: endpointInfoStore ?? AmplifySecureStorage( @@ -28,13 +25,11 @@ class AmplifyAnalyticsPinpoint extends AmplifyAnalyticsPinpointDart { scope: 'analyticsPinpoint', ), ), - pathProvider: pathProvider ?? FlutterPathProvider(), + pathProvider: FlutterPathProvider(), appLifecycleProvider: appLifecycleProvider ?? FlutterAppLifecycleProvider(), - deviceContextInfoProvider: deviceContextInfoProvider ?? - const FlutterDeviceContextInfoProvider(), - legacyNativeDataProvider: - legacyNativeDataProvider ?? FlutterLegacyNativeDataProvider(), + deviceContextInfoProvider: const FlutterDeviceContextInfoProvider(), + legacyNativeDataProvider: FlutterLegacyNativeDataProvider(), dbConnectFunction: db_common.connect, ); } diff --git a/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml b/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml index d5b71220c2..f210db8dab 100644 --- a/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml +++ b/packages/analytics/amplify_analytics_pinpoint/pubspec.yaml @@ -37,7 +37,6 @@ dev_dependencies: sdk: flutter pigeon: ^4.2.5 -# The following section is specific to Flutter. flutter: plugin: platforms: diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart index d1d939de0d..30d369e321 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart @@ -7,6 +7,7 @@ import 'dart:convert'; import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_client.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_global_fields_manager.dart'; +import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/event_client/event_client.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/event_client/event_storage_adapter.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/event_creator/event_creator.dart'; @@ -70,15 +71,9 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { /// Storage key for the static Pinpoint endpoint id @visibleForTesting static const String endpointIdStorageKey = 'UniqueId'; - static const String _endpointInformationVersionKey = - 'EndpointInformationVersionKey'; static const String _endpointGlobalAttrsKey = 'EndpointGlobalAttributesKey'; static const String _endpointGlobalMetricsKey = 'EndpointGlobalMetricsKey'; - /// Version of metadata stored into the `endpointInfoStore` - /// If stored data changes, increment this value - static const String _endpointInformationCurrentVersionValue = '0'; - late final EventCreator _eventCreator; late final EndpointClient _endpointClient; late final EventClient _eventClient; @@ -145,34 +140,11 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { deviceContextInfo: deviceContextInfo, ); - // Retrieve Unique ID - final endpointInformationVersion = - await _endpointInfoStore.read(key: _endpointInformationVersionKey); - String? retrievedEndpointId; - - await _legacyNativeDataProvider?.initialize(appId); - retrievedEndpointId = await _legacyNativeDataProvider?.getEndpointId(); - print('retrieved id: ${retrievedEndpointId ?? 'null'}'); - - if (endpointInformationVersion == null) { - _endpointInfoStore.write( - key: _endpointInformationVersionKey, - value: _endpointInformationCurrentVersionValue, - ); - - await _legacyNativeDataProvider?.initialize(appId); - retrievedEndpointId = await _legacyNativeDataProvider?.getEndpointId(); - - retrievedEndpointId ??= uuid(); - await _endpointInfoStore.write( - key: endpointIdStorageKey, - value: retrievedEndpointId, - ); - } else { - retrievedEndpointId = - await _endpointInfoStore.read(key: endpointIdStorageKey); - } - final fixedEndpointId = retrievedEndpointId!; + final fixedEndpointId = await retrieveEndpointId( + pinpointAppId: appId, + store: _endpointInfoStore, + legacyDataProvider: _legacyNativeDataProvider, + ); final endpoint = PublicEndpoint( effectiveDate: DateTime.now().toUtc().toIso8601String(), @@ -349,4 +321,39 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { await _eventClient.close(); await _eventStorageAdapter.close(); } + + @visibleForTesting + + /// Retrieve the stored pinpoint endpoint id + static Future retrieveEndpointId({ + required String pinpointAppId, + required SecureStorageInterface store, + LegacyNativeDataProvider? legacyDataProvider, + }) async { + // Retrieve Unique ID + final endpointInformationVersion = + await store.read(key: EndpointStoreKey.version.name); + String? retrievedEndpointId; + + // First time app load + if (endpointInformationVersion == null) { + store.write( + key: EndpointStoreKey.version.name, + value: EndpointStoreVersion.v1.name, + ); + + // Attempt to retrieve legacy data, else generate random uuid + await legacyDataProvider?.initialize(pinpointAppId); + retrievedEndpointId = await legacyDataProvider?.getEndpointId(); + + retrievedEndpointId ??= uuid(); + await store.write( + key: endpointIdStorageKey, + value: retrievedEndpointId, + ); + } else { + retrievedEndpointId = await store.read(key: endpointIdStorageKey); + } + return retrievedEndpointId!; + } } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart new file mode 100644 index 0000000000..6c02cfd39c --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart @@ -0,0 +1,14 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +/// Keys used to store info about the endpoint version store. +enum EndpointStoreKey { + /// The current version of the endpoint version store + version, +} + +/// The endpoint store version. +enum EndpointStoreVersion { + /// The initial implementation of endpoint version store in Amplify Flutter Analytics. + v1, +} diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_manager.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_manager.dart new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart index d5e89fe58e..ef4cc0e3f0 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart @@ -1,3 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:async'; /// {@template amplify_analytics_pinpoint.flutter_legacy_native_data_provider} diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart new file mode 100644 index 0000000000..da56f01bf9 --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart @@ -0,0 +1,177 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:async'; + +import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; +import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart'; +import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart'; +import 'package:test/test.dart'; + +void main() { + group('Analytics Legacy Native Data Tests', () { + test('First app load, no legacy data, writes proper values', () async { + var readCalls = 0; + var writeCalls = 0; + + final legacyDataProvider = MockLegacyNativeDataProvider(); + final store = MockSecureStorage( + writeCallback: (key, value) { + // version written + if (writeCalls == 0) { + expect(key, EndpointStoreKey.version.name); + expect(value, EndpointStoreVersion.v1.name); + } + // endpoint written + else if (writeCalls == 1) { + expect(key, AmplifyAnalyticsPinpointDart.endpointIdStorageKey); + } + writeCalls++; + }, + readCallback: (key) { + if (key == EndpointStoreKey.version.name) { + readCalls++; + return null; + } + fail('Read should not be called: $key'); + }, + deleteCallback: (key) { + fail('Delete should not be called: $key'); + }, + ); + + await AmplifyAnalyticsPinpointDart.retrieveEndpointId( + pinpointAppId: 'appId', + store: store, + legacyDataProvider: legacyDataProvider); + + expect(writeCalls, 2); + expect(readCalls, 1); + }); + + test('First app load, legacy data, writes proper values', () async { + var readCalls = 0; + var writeCalls = 0; + const endpointId = 'endpointId'; + + final legacyDataProvider = MockLegacyNativeDataProvider( + endpointId: endpointId, + ); + + final store = MockSecureStorage( + writeCallback: (key, value) { + // version written + if (writeCalls == 0) { + expect(key, EndpointStoreKey.version.name); + expect(value, EndpointStoreVersion.v1.name); + } + // endpoint written + else if (writeCalls == 1) { + expect(key, AmplifyAnalyticsPinpointDart.endpointIdStorageKey); + expect(value, endpointId); + } + writeCalls++; + }, + readCallback: (key) { + if (key == EndpointStoreKey.version.name) { + readCalls++; + return null; + } + fail('Read called with wrong key: $key'); + }, + deleteCallback: (key) { + fail('Delete should not be called: $key'); + }, + ); + + await AmplifyAnalyticsPinpointDart.retrieveEndpointId( + pinpointAppId: 'appId', + store: store, + legacyDataProvider: legacyDataProvider); + + expect(writeCalls, 2); + expect(readCalls, 1); + }); + + test('Second app load, only read is called', () async { + var readCalls = 0; + + final legacyDataProvider = MockLegacyNativeDataProvider( + getEndpointIdCallback: () { + fail('GetEndpointId should not be called'); + }, + ); + final store = MockSecureStorage( + readCallback: (key) { + if (key == AmplifyAnalyticsPinpointDart.endpointIdStorageKey) { + readCalls++; + return 'storedEndpointId'; + } else if (key == EndpointStoreKey.version.name) { + readCalls++; + return EndpointStoreVersion.v1.name; + } + fail('Read called with wrong key: $key'); + }, + writeCallback: (key, value) { + fail('Write should not be called: $key / $value'); + }, + deleteCallback: (key) { + fail('Delete should not be called: $key'); + }, + ); + + await AmplifyAnalyticsPinpointDart.retrieveEndpointId( + pinpointAppId: 'appId', + store: store, + legacyDataProvider: legacyDataProvider, + ); + + expect(readCalls, 2); + }); + }); +} + +class MockLegacyNativeDataProvider implements LegacyNativeDataProvider { + MockLegacyNativeDataProvider({ + this.endpointId, + this.getEndpointIdCallback, + }); + final void Function()? getEndpointIdCallback; + + final String? endpointId; + + @override + Future getEndpointId() async { + getEndpointIdCallback?.call(); + return endpointId; + } + + @override + Future initialize(String pinpointAppId) async {} +} + +class MockSecureStorage implements SecureStorageInterface { + MockSecureStorage({ + this.deleteCallback, + this.readCallback, + this.writeCallback, + }); + final void Function(String)? deleteCallback; + final String? Function(String)? readCallback; + final void Function(String, String)? writeCallback; + + @override + FutureOr delete({required String key}) { + deleteCallback?.call(key); + } + + @override + FutureOr read({required String key}) { + return readCallback?.call(key); + } + + @override + FutureOr write({required String key, required String value}) { + writeCallback?.call(key, value); + } +} From d668333a424d05778d7a9b0d2f42d716fa35eb84 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 3 Jan 2023 22:46:18 -0800 Subject: [PATCH 5/9] Change implementation --- .../lib/src/analytics_plugin_impl.dart | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart index 30d369e321..307aab3a69 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart @@ -323,7 +323,6 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { } @visibleForTesting - /// Retrieve the stored pinpoint endpoint id static Future retrieveEndpointId({ required String pinpointAppId, @@ -333,27 +332,42 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { // Retrieve Unique ID final endpointInformationVersion = await store.read(key: EndpointStoreKey.version.name); - String? retrievedEndpointId; - // First time app load + // Attempt migration if version is null. if (endpointInformationVersion == null) { - store.write( + await legacyDataProvider?.initialize(pinpointAppId); + final legacyEndpointId = await legacyDataProvider?.getEndpointId(); + // Migrate legacy data if it is non-null + if (legacyEndpointId != null) { + await store.write( + key: endpointIdStorageKey, + value: legacyEndpointId, + ); + } + // Update the version to prevent future legacy data migrations. + await store.write( key: EndpointStoreKey.version.name, value: EndpointStoreVersion.v1.name, ); + } - // Attempt to retrieve legacy data, else generate random uuid - await legacyDataProvider?.initialize(pinpointAppId); - retrievedEndpointId = await legacyDataProvider?.getEndpointId(); + // Read the existing ID. + final currentEndpointId = await store.read( + key: endpointIdStorageKey, + ); + + final String fixedEndpointId; - retrievedEndpointId ??= uuid(); + // Generate a new ID if one does not exist. + if (currentEndpointId == null) { + fixedEndpointId = uuid(); await store.write( key: endpointIdStorageKey, - value: retrievedEndpointId, + value: fixedEndpointId, ); } else { - retrievedEndpointId = await store.read(key: endpointIdStorageKey); + fixedEndpointId = currentEndpointId; } - return retrievedEndpointId!; - } + + return fixedEndpointId; } From 99e6d4d6a29fccf487aae18c1100bec636afa729 Mon Sep 17 00:00:00 2001 From: kc Date: Thu, 5 Jan 2023 18:59:08 -0800 Subject: [PATCH 6/9] PR Comments 2 Co-authored-by: Jordan Nelson --- .../amplify_analytics_pinpoint/Messages.java | 52 +---- .../AmplifyAnalyticsPinpointPlugin.kt | 12 +- .../auto_session_tracking_test.dart | 14 +- .../integration_test/enable_disable_test.dart | 14 +- .../integration_test/identify_user_test.dart | 14 +- .../utils/mock_key_value_store.dart | 15 +- .../utils/mock_lifecycle_provider.dart | 14 +- .../integration_test/utils/test_event.dart | 15 +- .../data_provider.android.dart | 24 +-- .../data_provider.ios.dart | 20 +- .../flutter_legacy_native_data_provider.dart | 24 +-- ...pigeon_legacy_data_provider.android.g.dart | 41 +--- .../pigeons/copyright.txt | 16 +- .../pigeons/pigeon_config_android.dart | 20 +- .../lib/src/analytics_plugin_impl.dart | 7 +- .../endpoint_store_manager.dart | 0 .../legacy_native_data_provider.dart | 5 +- .../pubspec.yaml | 1 + .../analytics_legacy_native_data_test.dart | 195 +++++++----------- 19 files changed, 116 insertions(+), 387 deletions(-) delete mode 100644 packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_manager.dart diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java b/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java index b0e1a07592..cebacf407c 100644 --- a/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/java/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/Messages.java @@ -1,17 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. -// +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 // Autogenerated from Pigeon (v4.2.14), do not edit directly. // See also: https://pub.dev/packages/pigeon @@ -43,8 +31,7 @@ public interface Result { } /** Generated interface from Pigeon that represents a handler of messages from Flutter. */ public interface PigeonLegacyDataProvider { - void initialize(@NonNull String pinpointAppId, Result result); - void getEndpointId(Result result); + void getEndpointId(@NonNull String pinpointAppId, Result result); /** The codec used by PigeonLegacyDataProvider. */ static MessageCodec getCodec() { @@ -53,7 +40,7 @@ static MessageCodec getCodec() { static void setup(BinaryMessenger binaryMessenger, PigeonLegacyDataProvider api) { { BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.PigeonLegacyDataProvider.initialize", getCodec()); + new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.PigeonLegacyDataProvider.getEndpointId", getCodec()); if (api != null) { channel.setMessageHandler((message, reply) -> { ArrayList wrapped = new ArrayList<>(); @@ -64,35 +51,6 @@ static void setup(BinaryMessenger binaryMessenger, PigeonLegacyDataProvider api) if (pinpointAppIdArg == null) { throw new NullPointerException("pinpointAppIdArg unexpectedly null."); } - Result resultCallback = new Result() { - public void success(Void result) { - wrapped.add(0, null); - reply.reply(wrapped); - } - public void error(Throwable error) { - ArrayList wrappedError = wrapError(error); - reply.reply(wrappedError); - } - }; - - api.initialize(pinpointAppIdArg, resultCallback); - } - catch (Error | RuntimeException exception) { - ArrayList wrappedError = wrapError(exception); - reply.reply(wrappedError); - } - }); - } else { - channel.setMessageHandler(null); - } - } - { - BasicMessageChannel channel = - new BasicMessageChannel<>(binaryMessenger, "dev.flutter.pigeon.PigeonLegacyDataProvider.getEndpointId", getCodec()); - if (api != null) { - channel.setMessageHandler((message, reply) -> { - ArrayList wrapped = new ArrayList<>(); - try { Result resultCallback = new Result() { public void success(String result) { wrapped.add(0, result); @@ -104,7 +62,7 @@ public void error(Throwable error) { } }; - api.getEndpointId(resultCallback); + api.getEndpointId(pinpointAppIdArg, resultCallback); } catch (Error | RuntimeException exception) { ArrayList wrappedError = wrapError(exception); diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt index 5b55da3c0e..530084569c 100644 --- a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -11,7 +11,7 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin class AmplifyAnalyticsPinpointPlugin: FlutterPlugin, Messages.PigeonLegacyDataProvider { lateinit var context: Context - lateinit var sharedPrefs: SharedPreferences + var sharedPrefs: SharedPreferences? = null companion object { private const val PINPOINT_SHARED_PREFS_SUFFIX = "515d6767-01b7-49e5-8273-c8d11b0f331d" @@ -27,16 +27,12 @@ class AmplifyAnalyticsPinpointPlugin: FlutterPlugin, Messages.PigeonLegacyDataPr Messages.PigeonLegacyDataProvider.setup(binding.binaryMessenger, null) } - override fun initialize(pinpointAppId: String, result: Messages.Result){ - sharedPrefs = context.getSharedPreferences( + override fun getEndpointId(pinpointAppId: String, result: Messages.Result){ + sharedPrefs = sharedPrefs ?: context.getSharedPreferences( "${pinpointAppId}$PINPOINT_SHARED_PREFS_SUFFIX", Context.MODE_PRIVATE ) - result.success(null) - } - - override fun getEndpointId(result: Messages.Result){ - result.success(sharedPrefs.getString(UNIQUE_ID_KEY, null)) + result.success(sharedPrefs!!.getString(UNIQUE_ID_KEY, null)) } } \ No newline at end of file diff --git a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/auto_session_tracking_test.dart b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/auto_session_tracking_test.dart index f64b23d2f4..28e112ad3b 100644 --- a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/auto_session_tracking_test.dart +++ b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/auto_session_tracking_test.dart @@ -1,15 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"). -// You may not use this file except in compliance with the License. -// A copy of the License is located at -// -// http://aws.amazon.com/apache2.0 -// -// or in the "license" file accompanying this file. This file 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; diff --git a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/enable_disable_test.dart b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/enable_disable_test.dart index e4a256e194..9b2ac910fa 100644 --- a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/enable_disable_test.dart +++ b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/enable_disable_test.dart @@ -1,15 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"). -// You may not use this file except in compliance with the License. -// A copy of the License is located at -// -// http://aws.amazon.com/apache2.0 -// -// or in the "license" file accompanying this file. This file 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; diff --git a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/identify_user_test.dart b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/identify_user_test.dart index 19d6bcdcc2..4216809e43 100644 --- a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/identify_user_test.dart +++ b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/identify_user_test.dart @@ -1,15 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"). -// You may not use this file except in compliance with the License. -// A copy of the License is located at -// -// http://aws.amazon.com/apache2.0 -// -// or in the "license" file accompanying this file. This file 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; diff --git a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_key_value_store.dart b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_key_value_store.dart index 16f736acd8..a1ab009bc6 100644 --- a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_key_value_store.dart +++ b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_key_value_store.dart @@ -1,16 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; diff --git a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_lifecycle_provider.dart b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_lifecycle_provider.dart index f7f64d2d73..cd2ca677e5 100644 --- a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_lifecycle_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/mock_lifecycle_provider.dart @@ -1,15 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"). -// You may not use this file except in compliance with the License. -// A copy of the License is located at -// -// http://aws.amazon.com/apache2.0 -// -// or in the "license" file accompanying this file. This file 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'package:amplify_analytics_pinpoint/amplify_analytics_pinpoint.dart'; diff --git a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/test_event.dart b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/test_event.dart index 3461dc567f..05127786d8 100644 --- a/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/test_event.dart +++ b/packages/analytics/amplify_analytics_pinpoint/example/integration_test/utils/test_event.dart @@ -1,16 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'package:amplify_analytics_pinpoint_dart/src/sdk/pinpoint.dart' show EndpointResponse; diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart index 560a886b9a..886cf036de 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.android.dart @@ -1,16 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; @@ -25,12 +14,7 @@ class DataProviderAndroid implements LegacyNativeDataProvider { final PigeonLegacyDataProvider _pigeonDataProvider; @override - Future initialize(String pinpointAppId) { - return _pigeonDataProvider.initialize(pinpointAppId); - } - - @override - Future getEndpointId() { - return _pigeonDataProvider.getEndpointId(); + Future getEndpointId(String pinpointAppId) { + return _pigeonDataProvider.getEndpointId(pinpointAppId); } } diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart index 92c972abc4..91deed2e92 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/data_provider.ios.dart @@ -1,16 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; @@ -31,10 +20,7 @@ class DataProviderIos implements LegacyNativeDataProvider { final AmplifySecureStorage _keyValueStore; @override - Future initialize(String pinpointAppId) async {} - - @override - Future getEndpointId() async { + Future getEndpointId(String pinpointAppId) async { final endpointId = await _keyValueStore.read(key: _key); return endpointId; } diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart index b5cb586582..c866040a2c 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart @@ -1,16 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io' show Platform; @@ -41,13 +30,8 @@ class FlutterLegacyNativeDataProvider implements LegacyNativeDataProvider { final LegacyNativeDataProvider? _nativeDataProvider; @override - Future initialize(String pinpointAppId) async { - return _nativeDataProvider?.initialize(pinpointAppId); - } - - @override - Future getEndpointId() async { + Future getEndpointId(String pinpointAppId) async { if (_nativeDataProvider == null) return null; - return _nativeDataProvider!.getEndpointId(); + return _nativeDataProvider!.getEndpointId(pinpointAppId); } } diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart index 04fb49b914..cfaa5bdc4f 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart @@ -1,17 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. -// +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 // Autogenerated from Pigeon (v4.2.14), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import @@ -31,33 +19,12 @@ class PigeonLegacyDataProvider { static const MessageCodec codec = StandardMessageCodec(); - Future initialize(String arg_pinpointAppId) async { + Future getEndpointId(String arg_pinpointAppId) async { final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.PigeonLegacyDataProvider.initialize', codec, + 'dev.flutter.pigeon.PigeonLegacyDataProvider.getEndpointId', codec, binaryMessenger: _binaryMessenger); final List? replyList = await channel.send([arg_pinpointAppId]) as List?; - if (replyList == null) { - throw PlatformException( - code: 'channel-error', - message: 'Unable to establish connection on channel.', - ); - } else if (replyList.length > 1) { - throw PlatformException( - code: replyList[0]! as String, - message: replyList[1] as String?, - details: replyList[2], - ); - } else { - return; - } - } - - Future getEndpointId() async { - final BasicMessageChannel channel = BasicMessageChannel( - 'dev.flutter.pigeon.PigeonLegacyDataProvider.getEndpointId', codec, - binaryMessenger: _binaryMessenger); - final List? replyList = await channel.send(null) as List?; if (replyList == null) { throw PlatformException( code: 'channel-error', diff --git a/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt b/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt index 96ebfc1126..478e610532 100644 --- a/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt +++ b/packages/analytics/amplify_analytics_pinpoint/pigeons/copyright.txt @@ -1,14 +1,2 @@ -Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -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. - +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart b/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart index bddde6c45f..f7cc9baf58 100644 --- a/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart +++ b/packages/analytics/amplify_analytics_pinpoint/pigeons/pigeon_config_android.dart @@ -1,16 +1,5 @@ -// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. -// -// 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. +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 // To regenerate, run `make pigeons`. @@ -33,8 +22,5 @@ import 'package:pigeon/pigeon.dart'; @HostApi() abstract class PigeonLegacyDataProvider { @async - void initialize(String pinpointAppId); - - @async - String? getEndpointId(); + String? getEndpointId(String pinpointAppId); } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart index 307aab3a69..5f60bc5c51 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart @@ -322,8 +322,8 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { await _eventStorageAdapter.close(); } - @visibleForTesting /// Retrieve the stored pinpoint endpoint id + @visibleForTesting static Future retrieveEndpointId({ required String pinpointAppId, required SecureStorageInterface store, @@ -335,8 +335,8 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { // Attempt migration if version is null. if (endpointInformationVersion == null) { - await legacyDataProvider?.initialize(pinpointAppId); - final legacyEndpointId = await legacyDataProvider?.getEndpointId(); + final legacyEndpointId = + await legacyDataProvider?.getEndpointId(pinpointAppId); // Migrate legacy data if it is non-null if (legacyEndpointId != null) { await store.write( @@ -370,4 +370,5 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { } return fixedEndpointId; + } } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_manager.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/analytics_client/endpoint_client/endpoint_store_manager.dart deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart index ef4cc0e3f0..9fb9e4717c 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/impl/flutter_provider_interfaces/legacy_native_data_provider.dart @@ -5,9 +5,6 @@ import 'dart:async'; /// {@template amplify_analytics_pinpoint.flutter_legacy_native_data_provider} abstract class LegacyNativeDataProvider { - /// Setup - Future initialize(String pinpointAppId); - /// Get stored Pinpoint Endpoint Id - Future getEndpointId(); + Future getEndpointId(String pinpointAppId); } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/pubspec.yaml b/packages/analytics/amplify_analytics_pinpoint_dart/pubspec.yaml index 5a9bf9e2f2..dd7a1d1faa 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/pubspec.yaml +++ b/packages/analytics/amplify_analytics_pinpoint_dart/pubspec.yaml @@ -32,6 +32,7 @@ dev_dependencies: build_version: ^2.0.0 built_value_generator: 8.4.2 drift_dev: ^2.2.0+1 + mocktail: ^0.3.0 test: ^1.16.0 # TODO - use cipher libraries for encrypted cached Analytics Events diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart index da56f01bf9..29226b4097 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart @@ -6,172 +6,115 @@ import 'dart:async'; import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart'; import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart'; +import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; +import 'package:uuid/uuid.dart'; void main() { group('Analytics Legacy Native Data Tests', () { + late MockLegacyNativeDataProvider legacyDataProvider; + late MockSecureStorage store; + + const appId = 'appId'; + const legacyEndpointId = 'legacy-endpointId'; + + setUp(() { + legacyDataProvider = MockLegacyNativeDataProvider(); + store = MockSecureStorage(); + }); + test('First app load, no legacy data, writes proper values', () async { - var readCalls = 0; - var writeCalls = 0; - - final legacyDataProvider = MockLegacyNativeDataProvider(); - final store = MockSecureStorage( - writeCallback: (key, value) { - // version written - if (writeCalls == 0) { - expect(key, EndpointStoreKey.version.name); - expect(value, EndpointStoreVersion.v1.name); - } - // endpoint written - else if (writeCalls == 1) { - expect(key, AmplifyAnalyticsPinpointDart.endpointIdStorageKey); - } - writeCalls++; - }, - readCallback: (key) { - if (key == EndpointStoreKey.version.name) { - readCalls++; - return null; - } - fail('Read should not be called: $key'); - }, - deleteCallback: (key) { - fail('Delete should not be called: $key'); - }, - ); + when(() => legacyDataProvider.getEndpointId(appId)) + .thenAnswer((_) => Future.value()); await AmplifyAnalyticsPinpointDart.retrieveEndpointId( - pinpointAppId: 'appId', - store: store, - legacyDataProvider: legacyDataProvider); + pinpointAppId: appId, + store: store, + legacyDataProvider: legacyDataProvider, + ); - expect(writeCalls, 2); - expect(readCalls, 1); + final storeVersion = await store.read( + key: EndpointStoreKey.version.name, + ); + expect(storeVersion, EndpointStoreVersion.v1.name); + + final migratedEndpointId = await store.read( + key: AmplifyAnalyticsPinpointDart.endpointIdStorageKey, + ); + expect(migratedEndpointId, isNotNull); + + verify(() => legacyDataProvider.getEndpointId(appId)).called(1); }); test('First app load, legacy data, writes proper values', () async { - var readCalls = 0; - var writeCalls = 0; - const endpointId = 'endpointId'; + when(() => legacyDataProvider.getEndpointId(appId)) + .thenAnswer((_) => Future.value(legacyEndpointId)); - final legacyDataProvider = MockLegacyNativeDataProvider( - endpointId: endpointId, + await AmplifyAnalyticsPinpointDart.retrieveEndpointId( + pinpointAppId: appId, + store: store, + legacyDataProvider: legacyDataProvider, ); - final store = MockSecureStorage( - writeCallback: (key, value) { - // version written - if (writeCalls == 0) { - expect(key, EndpointStoreKey.version.name); - expect(value, EndpointStoreVersion.v1.name); - } - // endpoint written - else if (writeCalls == 1) { - expect(key, AmplifyAnalyticsPinpointDart.endpointIdStorageKey); - expect(value, endpointId); - } - writeCalls++; - }, - readCallback: (key) { - if (key == EndpointStoreKey.version.name) { - readCalls++; - return null; - } - fail('Read called with wrong key: $key'); - }, - deleteCallback: (key) { - fail('Delete should not be called: $key'); - }, + final storeVersion = await store.read( + key: EndpointStoreKey.version.name, ); + expect(storeVersion, EndpointStoreVersion.v1.name); - await AmplifyAnalyticsPinpointDart.retrieveEndpointId( - pinpointAppId: 'appId', - store: store, - legacyDataProvider: legacyDataProvider); + final migratedEndpointId = await store.read( + key: AmplifyAnalyticsPinpointDart.endpointIdStorageKey, + ); + expect(migratedEndpointId, legacyEndpointId); - expect(writeCalls, 2); - expect(readCalls, 1); + verify(() => legacyDataProvider.getEndpointId(appId)).called(1); }); - test('Second app load, only read is called', () async { - var readCalls = 0; + test('Second app load, legacy data is ignored', () async { + const legacyEndpointId = 'legacy-endpointId'; + when(() => legacyDataProvider.getEndpointId(appId)) + .thenAnswer((_) => Future.value(legacyEndpointId)); - final legacyDataProvider = MockLegacyNativeDataProvider( - getEndpointIdCallback: () { - fail('GetEndpointId should not be called'); - }, - ); - final store = MockSecureStorage( - readCallback: (key) { - if (key == AmplifyAnalyticsPinpointDart.endpointIdStorageKey) { - readCalls++; - return 'storedEndpointId'; - } else if (key == EndpointStoreKey.version.name) { - readCalls++; - return EndpointStoreVersion.v1.name; - } - fail('Read called with wrong key: $key'); - }, - writeCallback: (key, value) { - fail('Write should not be called: $key / $value'); - }, - deleteCallback: (key) { - fail('Delete should not be called: $key'); - }, - ); + final endpointId = const Uuid().v1(); + store.seedData({ + EndpointStoreKey.version.name: EndpointStoreVersion.v1.name, + AmplifyAnalyticsPinpointDart.endpointIdStorageKey: endpointId + }); await AmplifyAnalyticsPinpointDart.retrieveEndpointId( - pinpointAppId: 'appId', + pinpointAppId: appId, store: store, legacyDataProvider: legacyDataProvider, ); - expect(readCalls, 2); + final migratedEndpointId = await store.read( + key: AmplifyAnalyticsPinpointDart.endpointIdStorageKey, + ); + expect(migratedEndpointId, endpointId); + + verifyNever(() => legacyDataProvider.getEndpointId(captureAny())); }); }); } -class MockLegacyNativeDataProvider implements LegacyNativeDataProvider { - MockLegacyNativeDataProvider({ - this.endpointId, - this.getEndpointIdCallback, - }); - final void Function()? getEndpointIdCallback; +class MockLegacyNativeDataProvider extends Mock + implements LegacyNativeDataProvider {} - final String? endpointId; +class MockSecureStorage extends Mock implements SecureStorageInterface { + MockSecureStorage(); - @override - Future getEndpointId() async { - getEndpointIdCallback?.call(); - return endpointId; - } - - @override - Future initialize(String pinpointAppId) async {} -} + final Map _data = {}; -class MockSecureStorage implements SecureStorageInterface { - MockSecureStorage({ - this.deleteCallback, - this.readCallback, - this.writeCallback, - }); - final void Function(String)? deleteCallback; - final String? Function(String)? readCallback; - final void Function(String, String)? writeCallback; - - @override - FutureOr delete({required String key}) { - deleteCallback?.call(key); + void seedData(Map data) { + _data.addAll(data); } @override FutureOr read({required String key}) { - return readCallback?.call(key); + return _data[key]; } @override FutureOr write({required String key, required String value}) { - writeCallback?.call(key, value); + _data[key] = value; } } From f2f9e2833c825673e44c7199c77fcd2771605ee8 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 9 Jan 2023 22:07:03 -0800 Subject: [PATCH 7/9] PR comments --- packages/analytics/amplify_analytics_pinpoint/Makefile | 4 ++++ .../flutter_legacy_native_data_provider.dart | 5 ++++- .../test/analytics_legacy_native_data_test.dart | 6 +++--- 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 packages/analytics/amplify_analytics_pinpoint/Makefile diff --git a/packages/analytics/amplify_analytics_pinpoint/Makefile b/packages/analytics/amplify_analytics_pinpoint/Makefile new file mode 100644 index 0000000000..ab34e2e8cb --- /dev/null +++ b/packages/analytics/amplify_analytics_pinpoint/Makefile @@ -0,0 +1,4 @@ +.PHONY: pigeons +pigeons: + flutter pub run pigeon --input pigeons/pigeon_config_android.dart + flutter format --fix lib/src/legacy_native_data_provider/pigeon_legacy_data_provider.android.g.dart \ No newline at end of file diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart index c866040a2c..bfe9cc4361 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart @@ -7,6 +7,7 @@ import 'dart:io' show Platform; import 'package:amplify_analytics_pinpoint/src/legacy_native_data_provider/data_provider.android.dart'; import 'package:amplify_analytics_pinpoint/src/legacy_native_data_provider/data_provider.ios.dart'; import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; +import 'package:aws_common/aws_common.dart'; /// {@template amplify_analytics_pinpoint.flutter_legacy_native_data_provider} /// Provides legacy data stored by Amplify Analytics iOS and Android. @@ -16,7 +17,9 @@ class FlutterLegacyNativeDataProvider implements LegacyNativeDataProvider { factory FlutterLegacyNativeDataProvider() { LegacyNativeDataProvider? provider; - if (Platform.isIOS) { + if (zIsWeb) { + return FlutterLegacyNativeDataProvider._(provider); + } else if (Platform.isIOS) { provider = DataProviderIos(); } else if (Platform.isAndroid) { provider = DataProviderAndroid(); diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart index 29226b4097..c8eb40a13d 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart @@ -5,10 +5,10 @@ import 'dart:async'; import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart'; +import 'package:amplify_core/amplify_core.dart'; import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; -import 'package:uuid/uuid.dart'; void main() { group('Analytics Legacy Native Data Tests', () { @@ -74,7 +74,7 @@ void main() { when(() => legacyDataProvider.getEndpointId(appId)) .thenAnswer((_) => Future.value(legacyEndpointId)); - final endpointId = const Uuid().v1(); + final endpointId = UUID.getUUID(); store.seedData({ EndpointStoreKey.version.name: EndpointStoreVersion.v1.name, AmplifyAnalyticsPinpointDart.endpointIdStorageKey: endpointId @@ -91,7 +91,7 @@ void main() { ); expect(migratedEndpointId, endpointId); - verifyNever(() => legacyDataProvider.getEndpointId(captureAny())); + verifyNever(() => legacyDataProvider.getEndpointId(any())); }); }); } From 9432eb364d551ec5ddb516275293f347537b56d0 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 10 Jan 2023 19:47:55 -0800 Subject: [PATCH 8/9] Dillon PR comment --- .../analysis_options.yaml | 3 +- .../AmplifyAnalyticsPinpointPlugin.kt | 1 + .../flutter_legacy_native_data_provider.dart | 13 ++--- .../lib/src/analytics_plugin_impl.dart | 30 ++++------- .../analytics_legacy_native_data_test.dart | 51 +++++++++++++------ 5 files changed, 55 insertions(+), 43 deletions(-) diff --git a/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml b/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml index 36582ff7dd..d51bda94fb 100644 --- a/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml +++ b/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml @@ -2,5 +2,6 @@ include: package:amplify_lints/library.yaml analyzer: exclude: - implementation_imports: error #TODO(equartey): Remove when lint is enforced project-wide - "**/**/**/*.g.dart" + errors: + implementation_imports: error #TODO(equartey): Remove when lint is enforced project-wide diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt index 530084569c..8f392580cf 100644 --- a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -25,6 +25,7 @@ class AmplifyAnalyticsPinpointPlugin: FlutterPlugin, Messages.PigeonLegacyDataPr override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) { Messages.PigeonLegacyDataProvider.setup(binding.binaryMessenger, null) + context = null } override fun getEndpointId(pinpointAppId: String, result: Messages.Result){ diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart index bfe9cc4361..74fbcb3c1f 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart @@ -15,11 +15,13 @@ import 'package:aws_common/aws_common.dart'; class FlutterLegacyNativeDataProvider implements LegacyNativeDataProvider { /// {@macro amplify_analytics_pinpoint.flutter_legacy_native_data_provider} factory FlutterLegacyNativeDataProvider() { + if (zIsWeb || !(Platform.isIOS || Platform.isAndroid)) { + return const FlutterLegacyNativeDataProvider._(); + } + LegacyNativeDataProvider? provider; - if (zIsWeb) { - return FlutterLegacyNativeDataProvider._(provider); - } else if (Platform.isIOS) { + if (Platform.isIOS) { provider = DataProviderIos(); } else if (Platform.isAndroid) { provider = DataProviderAndroid(); @@ -28,13 +30,12 @@ class FlutterLegacyNativeDataProvider implements LegacyNativeDataProvider { return FlutterLegacyNativeDataProvider._(provider); } - FlutterLegacyNativeDataProvider._(this._nativeDataProvider); + const FlutterLegacyNativeDataProvider._([this._nativeDataProvider]); final LegacyNativeDataProvider? _nativeDataProvider; @override Future getEndpointId(String pinpointAppId) async { - if (_nativeDataProvider == null) return null; - return _nativeDataProvider!.getEndpointId(pinpointAppId); + return _nativeDataProvider?.getEndpointId(pinpointAppId); } } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart index 5f60bc5c51..102b936cec 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart @@ -142,8 +142,6 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { final fixedEndpointId = await retrieveEndpointId( pinpointAppId: appId, - store: _endpointInfoStore, - legacyDataProvider: _legacyNativeDataProvider, ); final endpoint = PublicEndpoint( @@ -324,51 +322,43 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { /// Retrieve the stored pinpoint endpoint id @visibleForTesting - static Future retrieveEndpointId({ + Future retrieveEndpointId({ required String pinpointAppId, - required SecureStorageInterface store, - LegacyNativeDataProvider? legacyDataProvider, }) async { // Retrieve Unique ID final endpointInformationVersion = - await store.read(key: EndpointStoreKey.version.name); + await _endpointInfoStore.read(key: EndpointStoreKey.version.name); - // Attempt migration if version is null. + String? fixedEndpointId; if (endpointInformationVersion == null) { final legacyEndpointId = - await legacyDataProvider?.getEndpointId(pinpointAppId); + await _legacyNativeDataProvider?.getEndpointId(pinpointAppId); // Migrate legacy data if it is non-null if (legacyEndpointId != null) { - await store.write( + fixedEndpointId = legacyEndpointId; + await _endpointInfoStore.write( key: endpointIdStorageKey, value: legacyEndpointId, ); } // Update the version to prevent future legacy data migrations. - await store.write( + await _endpointInfoStore.write( key: EndpointStoreKey.version.name, value: EndpointStoreVersion.v1.name, ); } - // Read the existing ID. - final currentEndpointId = await store.read( + fixedEndpointId ??= await _endpointInfoStore.read( key: endpointIdStorageKey, ); - - final String fixedEndpointId; - // Generate a new ID if one does not exist. - if (currentEndpointId == null) { + if (fixedEndpointId == null) { fixedEndpointId = uuid(); - await store.write( + await _endpointInfoStore.write( key: endpointIdStorageKey, value: fixedEndpointId, ); - } else { - fixedEndpointId = currentEndpointId; } - return fixedEndpointId; } } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart index c8eb40a13d..7bd9f4ba0d 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/test/analytics_legacy_native_data_test.dart @@ -2,11 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 import 'dart:async'; +import 'dart:io'; import 'package:amplify_analytics_pinpoint_dart/amplify_analytics_pinpoint_dart.dart'; import 'package:amplify_analytics_pinpoint_dart/src/impl/analytics_client/endpoint_client/endpoint_store_keys.dart'; import 'package:amplify_core/amplify_core.dart'; import 'package:amplify_secure_storage_dart/amplify_secure_storage_dart.dart'; +import 'package:drift/drift.dart' show LazyDatabase; +import 'package:drift/native.dart'; import 'package:mocktail/mocktail.dart'; import 'package:test/test.dart'; @@ -25,13 +28,16 @@ void main() { test('First app load, no legacy data, writes proper values', () async { when(() => legacyDataProvider.getEndpointId(appId)) - .thenAnswer((_) => Future.value()); - - await AmplifyAnalyticsPinpointDart.retrieveEndpointId( - pinpointAppId: appId, - store: store, - legacyDataProvider: legacyDataProvider, + .thenAnswer((_) async => null); + + final analyticsPlugin = AmplifyAnalyticsPinpointDart( + endpointInfoStore: store, + legacyNativeDataProvider: legacyDataProvider, + dbConnectFunction: ({required String name, FutureOr? path}) { + return _openConnection(); + }, ); + await analyticsPlugin.retrieveEndpointId(pinpointAppId: appId); final storeVersion = await store.read( key: EndpointStoreKey.version.name, @@ -50,11 +56,14 @@ void main() { when(() => legacyDataProvider.getEndpointId(appId)) .thenAnswer((_) => Future.value(legacyEndpointId)); - await AmplifyAnalyticsPinpointDart.retrieveEndpointId( - pinpointAppId: appId, - store: store, - legacyDataProvider: legacyDataProvider, + final analyticsPlugin = AmplifyAnalyticsPinpointDart( + endpointInfoStore: store, + legacyNativeDataProvider: legacyDataProvider, + dbConnectFunction: ({required String name, FutureOr? path}) { + return _openConnection(); + }, ); + await analyticsPlugin.retrieveEndpointId(pinpointAppId: appId); final storeVersion = await store.read( key: EndpointStoreKey.version.name, @@ -70,21 +79,23 @@ void main() { }); test('Second app load, legacy data is ignored', () async { - const legacyEndpointId = 'legacy-endpointId'; when(() => legacyDataProvider.getEndpointId(appId)) .thenAnswer((_) => Future.value(legacyEndpointId)); - final endpointId = UUID.getUUID(); + final endpointId = uuid(); store.seedData({ EndpointStoreKey.version.name: EndpointStoreVersion.v1.name, AmplifyAnalyticsPinpointDart.endpointIdStorageKey: endpointId }); - await AmplifyAnalyticsPinpointDart.retrieveEndpointId( - pinpointAppId: appId, - store: store, - legacyDataProvider: legacyDataProvider, + final analyticsPlugin = AmplifyAnalyticsPinpointDart( + endpointInfoStore: store, + legacyNativeDataProvider: legacyDataProvider, + dbConnectFunction: ({required String name, FutureOr? path}) { + return _openConnection(); + }, ); + await analyticsPlugin.retrieveEndpointId(pinpointAppId: appId); final migratedEndpointId = await store.read( key: AmplifyAnalyticsPinpointDart.endpointIdStorageKey, @@ -96,6 +107,14 @@ void main() { }); } +LazyDatabase _openConnection() { + // the LazyDatabase util lets us find the right location for the file async. + return LazyDatabase(() async { + final file = File('db.sqlite'); + return NativeDatabase.createInBackground(file); + }); +} + class MockLegacyNativeDataProvider extends Mock implements LegacyNativeDataProvider {} From af4aa889d22ff8420a9b09633afe17b5f07841fe Mon Sep 17 00:00:00 2001 From: Dillon Nys Date: Wed, 11 Jan 2023 11:05:16 -0700 Subject: [PATCH 9/9] Clean up --- .../amplify_analytics_pinpoint/analysis_options.yaml | 4 ++-- .../amplify_analytics_pinpoint/android/build.gradle | 1 - .../AmplifyAnalyticsPinpointPlugin.kt | 10 +++++++--- .../flutter_legacy_native_data_provider.dart | 5 ++--- .../lib/src/analytics_plugin_impl.dart | 3 +++ 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml b/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml index d51bda94fb..a806cb6753 100644 --- a/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml +++ b/packages/analytics/amplify_analytics_pinpoint/analysis_options.yaml @@ -1,7 +1,7 @@ include: package:amplify_lints/library.yaml analyzer: - exclude: - - "**/**/**/*.g.dart" errors: implementation_imports: error #TODO(equartey): Remove when lint is enforced project-wide + exclude: + - "**/*.g.dart" diff --git a/packages/analytics/amplify_analytics_pinpoint/android/build.gradle b/packages/analytics/amplify_analytics_pinpoint/android/build.gradle index 48e5c76cc3..ff76d95f44 100644 --- a/packages/analytics/amplify_analytics_pinpoint/android/build.gradle +++ b/packages/analytics/amplify_analytics_pinpoint/android/build.gradle @@ -47,6 +47,5 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.security:security-crypto:1.0.0' } diff --git a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt index 8f392580cf..a08ca3570d 100644 --- a/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt +++ b/packages/analytics/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -10,8 +10,8 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin class AmplifyAnalyticsPinpointPlugin: FlutterPlugin, Messages.PigeonLegacyDataProvider { - lateinit var context: Context - var sharedPrefs: SharedPreferences? = null + private var context: Context? = null + private var sharedPrefs: SharedPreferences? = null companion object { private const val PINPOINT_SHARED_PREFS_SUFFIX = "515d6767-01b7-49e5-8273-c8d11b0f331d" @@ -29,7 +29,11 @@ class AmplifyAnalyticsPinpointPlugin: FlutterPlugin, Messages.PigeonLegacyDataPr } override fun getEndpointId(pinpointAppId: String, result: Messages.Result){ - sharedPrefs = sharedPrefs ?: context.getSharedPreferences( + if (context == null) { + result.error(Exception("Application context is null")) + return + } + sharedPrefs = sharedPrefs ?: context!!.getSharedPreferences( "${pinpointAppId}$PINPOINT_SHARED_PREFS_SUFFIX", Context.MODE_PRIVATE ) diff --git a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart index 74fbcb3c1f..aca9bc90ea 100644 --- a/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart +++ b/packages/analytics/amplify_analytics_pinpoint/lib/src/legacy_native_data_provider/flutter_legacy_native_data_provider.dart @@ -19,11 +19,10 @@ class FlutterLegacyNativeDataProvider implements LegacyNativeDataProvider { return const FlutterLegacyNativeDataProvider._(); } - LegacyNativeDataProvider? provider; - + final LegacyNativeDataProvider provider; if (Platform.isIOS) { provider = DataProviderIos(); - } else if (Platform.isAndroid) { + } else { provider = DataProviderAndroid(); } diff --git a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart index 102b936cec..b228d7006a 100644 --- a/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart +++ b/packages/analytics/amplify_analytics_pinpoint_dart/lib/src/analytics_plugin_impl.dart @@ -347,10 +347,12 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { value: EndpointStoreVersion.v1.name, ); } + // Read the existing ID. fixedEndpointId ??= await _endpointInfoStore.read( key: endpointIdStorageKey, ); + // Generate a new ID if one does not exist. if (fixedEndpointId == null) { fixedEndpointId = uuid(); @@ -359,6 +361,7 @@ class AmplifyAnalyticsPinpointDart extends AnalyticsPluginInterface { value: fixedEndpointId, ); } + return fixedEndpointId; } }