From c2f099a96a5a2f1748af5c44ff45dbcf4f3570e6 Mon Sep 17 00:00:00 2001 From: Dillon Nys Date: Thu, 29 Jul 2021 17:11:42 -0700 Subject: [PATCH 1/5] Force session start --- .../android/src/main/AndroidManifest.xml | 12 ++++- .../AmplifyAnalyticsPinpointPlugin.kt | 44 +++++++++++-------- .../EmptyActivity.kt | 13 ++++++ .../lib/amplify_analytics_pinpoint.dart | 7 +++ .../lib/method_channel_amplify.dart | 13 ++++++ .../amplify_analytics_plugin_interface.dart | 4 ++ .../lib/method_channel_amplify.dart | 10 ++++- 7 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/EmptyActivity.kt diff --git a/packages/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml b/packages/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml index 022861b3c0..cbccdca9ab 100644 --- a/packages/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml +++ b/packages/amplify_analytics_pinpoint/android/src/main/AndroidManifest.xml @@ -1,3 +1,11 @@ + - + package="com.amazonaws.amplify.amplify_analytics_pinpoint"> + + + + + + \ No newline at end of file diff --git a/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt index 7b1b5f3b1b..82a26f990d 100644 --- a/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt +++ b/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -16,11 +16,9 @@ package com.amazonaws.amplify.amplify_analytics_pinpoint import android.app.Activity -import android.app.Application import android.content.Context -import android.util.Log +import android.content.Intent import androidx.annotation.NonNull -import com.amplifyframework.analytics.pinpoint.AWSPinpointAnalyticsPlugin import com.amplifyframework.core.Amplify import io.flutter.embedding.engine.plugins.FlutterPlugin import io.flutter.embedding.engine.plugins.activity.ActivityAware @@ -29,36 +27,26 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result -import io.flutter.plugin.common.PluginRegistry.Registrar -public class AmplifyAnalyticsPinpointPlugin : FlutterPlugin, ActivityAware, MethodCallHandler { +class AmplifyAnalyticsPinpointPlugin : FlutterPlugin, ActivityAware, MethodCallHandler { private lateinit var channel: MethodChannel private var mainActivity: Activity? = null private lateinit var context: Context override fun onAttachedToEngine( - @NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) { + @NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding + ) { - channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), - "com.amazonaws.amplify/analytics_pinpoint") + channel = MethodChannel(flutterPluginBinding.binaryMessenger, + "com.amazonaws.amplify/analytics_pinpoint") channel.setMethodCallHandler(this) - context = flutterPluginBinding.applicationContext; + context = flutterPluginBinding.applicationContext } - // This static function is optional and equivalent to onAttachedToEngine. It supports the old - // pre-Flutter-1.12 Android projects. companion object { const val TAG = "AmplifyAnalyticsPinpointPlugin" val LOG = Amplify.Logging.forNamespace("amplify:flutter:analytics_pinpoint") - - @JvmStatic - fun registerWith(registrar: Registrar) { - val channel = - MethodChannel(registrar.messenger(), "com.amazonaws.amplify/analytics_pinpoint") - Amplify.addPlugin(AWSPinpointAnalyticsPlugin(registrar.activity().application)) - LOG.info("Added AnalyticsPinpoint plugin") - } } // Handle methods received via MethodChannel @@ -67,6 +55,24 @@ public class AmplifyAnalyticsPinpointPlugin : FlutterPlugin, ActivityAware, Meth when (call.method) { "addPlugin" -> AmplifyAnalyticsBridge.addPlugin(result, context) + "startSession" -> { + // Hack: The AutoSessionTracker in the Pinpoint plugin listens for lifecycle changes and + // starts and stops session tracking accordingly. It is registered during the call + // to Amplify.configure. In native Android apps, this call is made before launching + // the main activity and thus receives the initial onResume event, kicking off session + // tracking. However, in Flutter, the call to Amplify.configure is made sometime later. + // The initial onResume call is not received by the AutoSessionTracker, and no session + // tracking occurs. + // + // The startSession/stopSession calls made by the AutoSessionTracker are not available + // via the escape hatch, the AWS SDK, or reflection, so this hack must be used to + // force an onPause/onResume cycle. + // + // This method is invoked in the Flutter SDK just after Amplify.configure. + val intent = Intent(mainActivity, EmptyActivity::class.java) + mainActivity?.startActivity(intent) + result.success(null) + } "recordEvent" -> AmplifyAnalyticsBridge.recordEvent(call.arguments, result) "flushEvents" -> diff --git a/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/EmptyActivity.kt b/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/EmptyActivity.kt new file mode 100644 index 0000000000..99f5b67a83 --- /dev/null +++ b/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/EmptyActivity.kt @@ -0,0 +1,13 @@ +package com.amazonaws.amplify.amplify_analytics_pinpoint + +import android.app.Activity +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle + +/// Empty activity used to force lifecycle events in the user's app. +class EmptyActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + finish() + } +} \ No newline at end of file diff --git a/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart b/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart index 23ecae6949..46dae7a04e 100644 --- a/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart +++ b/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart @@ -77,4 +77,11 @@ class AmplifyAnalyticsPinpoint extends AnalyticsPluginInterface { required AnalyticsUserProfile userProfile}) async { return _instance.identifyUser(userId: userId, userProfile: userProfile); } + + // Internal + + @override + Future onConfigure() { + return _instance.onConfigure(); + } } diff --git a/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart b/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart index 19b8639f47..b6c5b1cb18 100644 --- a/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart +++ b/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +import 'dart:io'; + import 'package:amplify_analytics_plugin_interface/amplify_analytics_plugin_interface.dart'; import 'package:amplify_core/types/exception/AmplifyException.dart'; import 'package:amplify_core/types/exception/AmplifyExceptionMessages.dart'; @@ -41,6 +43,17 @@ class AmplifyAnalyticsPinpointMethodChannel extends AmplifyAnalyticsPinpoint { } } + @override + Future onConfigure() async { + try { + if (Platform.isAndroid) { + await _channel.invokeMethod('startSession'); + } + } on Exception { + // TODO: log, but should not happen + } + } + @override Future recordEvent({required AnalyticsEvent event}) async { var name = event.name; diff --git a/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart b/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart index ef672cf073..3403d5579e 100644 --- a/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart +++ b/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart @@ -63,4 +63,8 @@ abstract class AnalyticsPluginInterface extends AmplifyPluginInterface { required AnalyticsUserProfile userProfile}) async { throw UnimplementedError('identifyUser() has not been implemented.'); } + + // Internal + + Future onConfigure() async {} } diff --git a/packages/amplify_flutter/lib/method_channel_amplify.dart b/packages/amplify_flutter/lib/method_channel_amplify.dart index 97d3c67265..0b28bd45d0 100644 --- a/packages/amplify_flutter/lib/method_channel_amplify.dart +++ b/packages/amplify_flutter/lib/method_channel_amplify.dart @@ -22,13 +22,19 @@ class MethodChannelAmplify extends AmplifyClass { MethodChannelAmplify() : super.protected(); @override - Future _configurePlatforms(String version, String configuration) { - return _channel.invokeMethod( + Future _configurePlatforms( + String version, String configuration) async { + final configured = await _channel.invokeMethod( 'configure', { 'version': version, 'configuration': configuration, }, ); + if (configured ?? false) { + await Future.wait( + AnalyticsCategory.plugins.map((plugin) => plugin.onConfigure())); + } + return configured; } } From 8db30da94c6dc5938711dc72a4d4bc1ef86b1eb9 Mon Sep 17 00:00:00 2001 From: Dillon Nys Date: Thu, 29 Jul 2021 17:19:13 -0700 Subject: [PATCH 2/5] Add iOS no-op --- .../ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift | 3 +++ .../lib/method_channel_amplify.dart | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift b/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift index 29a8d18daa..43a73ef28a 100644 --- a/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift +++ b/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift @@ -42,6 +42,9 @@ public class SwiftAmplifyAnalyticsPinpointPlugin: NSObject, FlutterPlugin { switch method{ case "addPlugin": FlutterAnalytics.addPlugin(result: result) + case "sessionStart": + // No-op + result(nil) case "recordEvent": FlutterAnalytics.record(arguments: callArgs, result: result, bridge: bridge) case "flushEvents": diff --git a/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart b/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart index b6c5b1cb18..5a9dadae9e 100644 --- a/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart +++ b/packages/amplify_analytics_pinpoint/lib/method_channel_amplify.dart @@ -46,9 +46,7 @@ class AmplifyAnalyticsPinpointMethodChannel extends AmplifyAnalyticsPinpoint { @override Future onConfigure() async { try { - if (Platform.isAndroid) { - await _channel.invokeMethod('startSession'); - } + await _channel.invokeMethod('startSession'); } on Exception { // TODO: log, but should not happen } From ee45c7327cb83a3158ab2fd2ffa77e41254bdd0b Mon Sep 17 00:00:00 2001 From: Dillon Nys Date: Thu, 29 Jul 2021 17:45:09 -0700 Subject: [PATCH 3/5] Update comment --- .../AmplifyAnalyticsPinpointPlugin.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt b/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt index 82a26f990d..c4cda6606b 100644 --- a/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt +++ b/packages/amplify_analytics_pinpoint/android/src/main/kotlin/com/amazonaws/amplify/amplify_analytics_pinpoint/AmplifyAnalyticsPinpointPlugin.kt @@ -56,7 +56,9 @@ class AmplifyAnalyticsPinpointPlugin : FlutterPlugin, ActivityAware, MethodCallH "addPlugin" -> AmplifyAnalyticsBridge.addPlugin(result, context) "startSession" -> { - // Hack: The AutoSessionTracker in the Pinpoint plugin listens for lifecycle changes and + // TODO: Update AutoSessionTracker logic to support Flutter. + // + // The AutoSessionTracker in the Pinpoint plugin listens for lifecycle changes and // starts and stops session tracking accordingly. It is registered during the call // to Amplify.configure. In native Android apps, this call is made before launching // the main activity and thus receives the initial onResume event, kicking off session From bad985c9a1827c5112ee75e238be5b6a86708ba4 Mon Sep 17 00:00:00 2001 From: Dillon Nys Date: Thu, 29 Jul 2021 17:45:17 -0700 Subject: [PATCH 4/5] Mark internal method protected --- .../lib/amplify_analytics_pinpoint.dart | 2 -- .../lib/amplify_analytics_plugin_interface.dart | 4 ++-- packages/amplify_flutter/lib/method_channel_amplify.dart | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart b/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart index 46dae7a04e..c18aff92c8 100644 --- a/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart +++ b/packages/amplify_analytics_pinpoint/lib/amplify_analytics_pinpoint.dart @@ -78,8 +78,6 @@ class AmplifyAnalyticsPinpoint extends AnalyticsPluginInterface { return _instance.identifyUser(userId: userId, userProfile: userProfile); } - // Internal - @override Future onConfigure() { return _instance.onConfigure(); diff --git a/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart b/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart index 3403d5579e..645da5e0dd 100644 --- a/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart +++ b/packages/amplify_analytics_plugin_interface/lib/amplify_analytics_plugin_interface.dart @@ -18,6 +18,7 @@ library amplify_analytics_plugin_interface; import 'dart:async'; import 'package:amplify_core/types/index.dart'; +import 'package:meta/meta.dart'; import 'src/types.dart'; export 'src/types.dart'; @@ -64,7 +65,6 @@ abstract class AnalyticsPluginInterface extends AmplifyPluginInterface { throw UnimplementedError('identifyUser() has not been implemented.'); } - // Internal - + @protected Future onConfigure() async {} } diff --git a/packages/amplify_flutter/lib/method_channel_amplify.dart b/packages/amplify_flutter/lib/method_channel_amplify.dart index 0b28bd45d0..c4fe626ea7 100644 --- a/packages/amplify_flutter/lib/method_channel_amplify.dart +++ b/packages/amplify_flutter/lib/method_channel_amplify.dart @@ -33,6 +33,7 @@ class MethodChannelAmplify extends AmplifyClass { ); if (configured ?? false) { await Future.wait( + //ignore:invalid_use_of_protected_member AnalyticsCategory.plugins.map((plugin) => plugin.onConfigure())); } return configured; From 5e7c34f8375b0ad25161f559142deebe27adf102 Mon Sep 17 00:00:00 2001 From: Dillon Nys Date: Thu, 29 Jul 2021 18:52:13 -0700 Subject: [PATCH 5/5] Fix iOS method name --- .../ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift b/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift index 43a73ef28a..13b0a4c45a 100644 --- a/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift +++ b/packages/amplify_analytics_pinpoint/ios/Classes/SwiftAmplifyAnalyticsPinpointPlugin.swift @@ -42,7 +42,7 @@ public class SwiftAmplifyAnalyticsPinpointPlugin: NSObject, FlutterPlugin { switch method{ case "addPlugin": FlutterAnalytics.addPlugin(result: result) - case "sessionStart": + case "startSession": // No-op result(nil) case "recordEvent": @@ -60,7 +60,7 @@ public class SwiftAmplifyAnalyticsPinpointPlugin: NSObject, FlutterPlugin { case "identifyUser": FlutterAnalytics.identifyUser(arguments: callArgs, result: result, bridge: bridge) default : - print("unknown event") + result(FlutterMethodNotImplemented) } }