From ef27c934a02b5e248ac073b229b8a9275524d2c8 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 3 Oct 2019 14:10:04 +0100 Subject: [PATCH 01/15] Bump Gradle & AGP to latest versions. --- packages/firebase_messaging/android/build.gradle | 2 +- packages/firebase_messaging/example/android/build.gradle | 2 +- packages/firebase_messaging/example/android/gradle.properties | 1 + .../example/android/gradle/wrapper/gradle-wrapper.properties | 3 ++- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/firebase_messaging/android/build.gradle b/packages/firebase_messaging/android/build.gradle index 7209353c45fd..2664a867266d 100644 --- a/packages/firebase_messaging/android/build.gradle +++ b/packages/firebase_messaging/android/build.gradle @@ -21,7 +21,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.1' } } diff --git a/packages/firebase_messaging/example/android/build.gradle b/packages/firebase_messaging/example/android/build.gradle index 359119307d55..9df1548c6172 100644 --- a/packages/firebase_messaging/example/android/build.gradle +++ b/packages/firebase_messaging/example/android/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.5.1' classpath 'com.google.gms:google-services:4.3.0' } } diff --git a/packages/firebase_messaging/example/android/gradle.properties b/packages/firebase_messaging/example/android/gradle.properties index 8bd86f680510..7be3d8b46841 100644 --- a/packages/firebase_messaging/example/android/gradle.properties +++ b/packages/firebase_messaging/example/android/gradle.properties @@ -1 +1,2 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true diff --git a/packages/firebase_messaging/example/android/gradle/wrapper/gradle-wrapper.properties b/packages/firebase_messaging/example/android/gradle/wrapper/gradle-wrapper.properties index 019065d1d650..384299ed705b 100644 --- a/packages/firebase_messaging/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/firebase_messaging/example/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Oct 03 14:07:08 BST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip From 4b8f8f07416542be3a4952371819cb57b6d7ad4f Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 3 Oct 2019 14:12:22 +0100 Subject: [PATCH 02/15] Bump google-services dependency to 4.3.2 --- packages/firebase_messaging/example/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/firebase_messaging/example/android/build.gradle b/packages/firebase_messaging/example/android/build.gradle index 9df1548c6172..89cd4adf9e45 100644 --- a/packages/firebase_messaging/example/android/build.gradle +++ b/packages/firebase_messaging/example/android/build.gradle @@ -6,7 +6,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.5.1' - classpath 'com.google.gms:google-services:4.3.0' + classpath 'com.google.gms:google-services:4.3.2' } } From 99698d432647962a112ecfe16ffc13ad6aa82f66 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 3 Oct 2019 14:12:51 +0100 Subject: [PATCH 03/15] Update README.md with latest dependency versions --- packages/firebase_messaging/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/firebase_messaging/README.md b/packages/firebase_messaging/README.md index 4e126949b929..e696e544dbc4 100644 --- a/packages/firebase_messaging/README.md +++ b/packages/firebase_messaging/README.md @@ -27,9 +27,9 @@ To integrate your plugin into the Android part of your app, follow these steps: ``` dependencies { // Example existing classpath - classpath 'com.android.tools.build:gradle:3.2.1' + classpath 'com.android.tools.build:gradle:3.5.1' // Add the google services classpath - classpath 'com.google.gms:google-services:4.3.0' + classpath 'com.google.gms:google-services:4.3.2' } ``` 3. Add the apply plugin to the `[project]/android/app/build.gradle` file. From 99c465ba83bebded7a68a4e853abcd22570f893b Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 3 Oct 2019 14:13:03 +0100 Subject: [PATCH 04/15] Bump version, update changelog --- packages/firebase_messaging/CHANGELOG.md | 5 +++++ packages/firebase_messaging/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/firebase_messaging/CHANGELOG.md b/packages/firebase_messaging/CHANGELOG.md index e12b6f5b6495..b020fa5241f3 100644 --- a/packages/firebase_messaging/CHANGELOG.md +++ b/packages/firebase_messaging/CHANGELOG.md @@ -1,3 +1,8 @@ +## 5.1.7 + +* Update Android Gradle plugin dependency to 3.5.1, update documentation and example. +* Update google-services Android gradle plugin to 4.3.2 in documentation and examples. + ## 5.1.6 * Fix warnings when compiling on Android. diff --git a/packages/firebase_messaging/pubspec.yaml b/packages/firebase_messaging/pubspec.yaml index 9612026f3eab..f3aeb9f2789a 100644 --- a/packages/firebase_messaging/pubspec.yaml +++ b/packages/firebase_messaging/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Firebase Cloud Messaging, a cross-platform messaging solution that lets you reliably deliver messages on Android and iOS. author: Flutter Team homepage: https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_messaging -version: 5.1.6 +version: 5.1.7 flutter: plugin: From 762326b978f242d07205b3486d14b024763ea4bc Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 3 Oct 2019 15:58:12 +0100 Subject: [PATCH 05/15] Let FlutterFirebaseMessagingService handle the background channel signals directly (instead of the plugin) --- .../FirebaseMessagingPlugin.java | 9 ------- .../FlutterFirebaseMessagingService.java | 25 +++++++++++++++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java index 653b164768d2..516886b1b6b1 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java @@ -41,15 +41,9 @@ public class FirebaseMessagingPlugin extends BroadcastReceiver public static void registerWith(Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), "plugins.flutter.io/firebase_messaging"); - final MethodChannel backgroundCallbackChannel = - new MethodChannel( - registrar.messenger(), "plugins.flutter.io/firebase_messaging_background"); final FirebaseMessagingPlugin plugin = new FirebaseMessagingPlugin(registrar, channel); registrar.addNewIntentListener(plugin); channel.setMethodCallHandler(plugin); - backgroundCallbackChannel.setMethodCallHandler(plugin); - - FlutterFirebaseMessagingService.setBackgroundChannel(backgroundCallbackChannel); } private FirebaseMessagingPlugin(Registrar registrar, MethodChannel channel) { @@ -136,9 +130,6 @@ public void onMethodCall(final MethodCall call, final Result result) { FlutterFirebaseMessagingService.setBackgroundMessageHandle( this.registrar.context(), backgroundMessageHandle); result.success(true); - } else if ("FcmDartService#initialized".equals(call.method)) { - FlutterFirebaseMessagingService.onInitialized(); - result.success(true); } else if ("configure".equals(call.method)) { FirebaseInstanceId.getInstance() .getInstanceId() diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java index 8c2759770a37..5509684760c5 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java @@ -12,10 +12,16 @@ import android.os.Handler; import android.os.Process; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; +import io.flutter.plugin.common.BinaryMessenger; +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; import io.flutter.view.FlutterCallbackInformation; import io.flutter.view.FlutterMain; @@ -50,6 +56,7 @@ public class FlutterFirebaseMessagingService extends FirebaseMessagingService { /** Background Dart execution context. */ private static FlutterNativeView backgroundFlutterView; + @Nullable private static MethodChannel backgroundChannel; private static Long backgroundMessageHandle; @@ -162,6 +169,24 @@ public static void startBackgroundIsolate(Context context, long callbackHandle) args.libraryPath = flutterCallback.callbackLibraryPath; backgroundFlutterView.runFromBundle(args); pluginRegistrantCallback.registerWith(backgroundFlutterView.getPluginRegistry()); + + BinaryMessenger messenger = backgroundFlutterView.getPluginRegistry() + .registrarFor("io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService") + .messenger(); + final MethodChannel backgroundCallbackChannel = + new MethodChannel(messenger, "plugins.flutter.io/firebase_messaging_background"); + backgroundCallbackChannel.setMethodCallHandler(new MethodCallHandler() { + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { + if ("FcmDartService#initialized".equals(call.method)) { + FlutterFirebaseMessagingService.onInitialized(); + result.success(true); + } else { + result.notImplemented(); + } + } + }); + setBackgroundChannel(backgroundCallbackChannel); } } From eee1993c4be91efc519d8a7a6fce5247d4e57bca Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 3 Oct 2019 22:42:57 +0100 Subject: [PATCH 06/15] Formatting --- .../FlutterFirebaseMessagingService.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java index 5509684760c5..dc0c627589e9 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java @@ -56,8 +56,7 @@ public class FlutterFirebaseMessagingService extends FirebaseMessagingService { /** Background Dart execution context. */ private static FlutterNativeView backgroundFlutterView; - @Nullable - private static MethodChannel backgroundChannel; + @Nullable private static MethodChannel backgroundChannel; private static Long backgroundMessageHandle; @@ -170,22 +169,25 @@ public static void startBackgroundIsolate(Context context, long callbackHandle) backgroundFlutterView.runFromBundle(args); pluginRegistrantCallback.registerWith(backgroundFlutterView.getPluginRegistry()); - BinaryMessenger messenger = backgroundFlutterView.getPluginRegistry() - .registrarFor("io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService") - .messenger(); + BinaryMessenger messenger = + backgroundFlutterView + .getPluginRegistry() + .registrarFor("io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService") + .messenger(); final MethodChannel backgroundCallbackChannel = new MethodChannel(messenger, "plugins.flutter.io/firebase_messaging_background"); - backgroundCallbackChannel.setMethodCallHandler(new MethodCallHandler() { - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { - if ("FcmDartService#initialized".equals(call.method)) { - FlutterFirebaseMessagingService.onInitialized(); - result.success(true); - } else { - result.notImplemented(); - } - } - }); + backgroundCallbackChannel.setMethodCallHandler( + new MethodCallHandler() { + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { + if ("FcmDartService#initialized".equals(call.method)) { + FlutterFirebaseMessagingService.onInitialized(); + result.success(true); + } else { + result.notImplemented(); + } + } + }); setBackgroundChannel(backgroundCallbackChannel); } } From 8e3849f4b77c76e8fef0295fb857b72bab2bc2a7 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Wed, 9 Oct 2019 12:29:58 +0100 Subject: [PATCH 07/15] Unregister from LocalBroadcastReceiver when view is destroyed. --- .../firebasemessaging/FirebaseMessagingPlugin.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java index 516886b1b6b1..52385d6fa5f6 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java @@ -25,6 +25,8 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.NewIntentListener; import io.flutter.plugin.common.PluginRegistry.Registrar; +import io.flutter.plugin.common.PluginRegistry.ViewDestroyListener; +import io.flutter.view.FlutterNativeView; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -44,6 +46,13 @@ public static void registerWith(Registrar registrar) { final FirebaseMessagingPlugin plugin = new FirebaseMessagingPlugin(registrar, channel); registrar.addNewIntentListener(plugin); channel.setMethodCallHandler(plugin); + registrar.addViewDestroyListener(new ViewDestroyListener() { + @Override + public boolean onViewDestroy(FlutterNativeView view) { + plugin.release(); + return false; + } + }); } private FirebaseMessagingPlugin(Registrar registrar, MethodChannel channel) { @@ -58,6 +67,11 @@ private FirebaseMessagingPlugin(Registrar registrar, MethodChannel channel) { manager.registerReceiver(this, intentFilter); } + private void release() { + LocalBroadcastManager manager = LocalBroadcastManager.getInstance(registrar.context()); + manager.unregisterReceiver(this); + } + // BroadcastReceiver implementation. @Override public void onReceive(Context context, Intent intent) { From 97fe5fc8c5691ab8ebca894d3eb1b8184058a901 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 14 Oct 2019 10:29:40 +0100 Subject: [PATCH 08/15] Formatting. --- .../FirebaseMessagingPlugin.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java index 52385d6fa5f6..bf0212378089 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java @@ -46,13 +46,14 @@ public static void registerWith(Registrar registrar) { final FirebaseMessagingPlugin plugin = new FirebaseMessagingPlugin(registrar, channel); registrar.addNewIntentListener(plugin); channel.setMethodCallHandler(plugin); - registrar.addViewDestroyListener(new ViewDestroyListener() { - @Override - public boolean onViewDestroy(FlutterNativeView view) { - plugin.release(); - return false; - } - }); + registrar.addViewDestroyListener( + new ViewDestroyListener() { + @Override + public boolean onViewDestroy(FlutterNativeView view) { + plugin.release(); + return false; + } + }); } private FirebaseMessagingPlugin(Registrar registrar, MethodChannel channel) { From f5c0ced6a73a51ecb53bcda6fd8b9be5aff7329d Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Mon, 14 Oct 2019 13:04:10 +0100 Subject: [PATCH 09/15] Remove a few warnings and ensure to destroy the isolate when the FcmService is done --- .../FlutterFirebaseMessagingService.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java index dc0c627589e9..5086a284390e 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java @@ -84,13 +84,25 @@ public void onCreate() { } } + @Override + public void onDestroy() { + super.onDestroy(); + + if (isIsolateRunning.getAndSet(false)) { + backgroundChannel = null; + + backgroundFlutterView.destroy(); + backgroundFlutterView = null; + } + } + /** * Called when message is received. * * @param remoteMessage Object representing the message received from Firebase Cloud Messaging. */ @Override - public void onMessageReceived(final RemoteMessage remoteMessage) { + public void onMessageReceived(@NonNull final RemoteMessage remoteMessage) { // If application is running in the foreground use local broadcast to handle message. // Otherwise use the background isolate to handle message. if (isApplicationForeground(this)) { @@ -129,7 +141,7 @@ public void run() { * the same as the one retrieved by getInstanceId(). */ @Override - public void onNewToken(String token) { + public void onNewToken(@NonNull String token) { Intent intent = new Intent(ACTION_TOKEN); intent.putExtra(EXTRA_TOKEN, token); LocalBroadcastManager.getInstance(this).sendBroadcast(intent); @@ -215,7 +227,7 @@ public static void onInitialized() { * * @param channel Background method channel. */ - public static void setBackgroundChannel(MethodChannel channel) { + public static void setBackgroundChannel(@NonNull MethodChannel channel) { backgroundChannel = channel; } @@ -300,9 +312,8 @@ private static void executeDartCallbackInBackgroundIsolate( } args.put("handle", backgroundMessageHandle); - if (remoteMessage.getData() != null) { - messageData.put("data", remoteMessage.getData()); - } + messageData.put("data", remoteMessage.getData()); + if (remoteMessage.getNotification() != null) { messageData.put("notification", remoteMessage.getNotification()); } From f31a1cb8c6d99ca1b84989cb546b16a7dee20a8c Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 30 Apr 2020 16:17:11 +0100 Subject: [PATCH 10/15] Refactor the background message handling on Android --- .../android/firebase_messaging.iml | 64 ++++----- .../FirebaseMessagingPlugin.java | 21 +-- .../FlutterFirebaseMessagingService.java | 132 ++++++------------ 3 files changed, 79 insertions(+), 138 deletions(-) diff --git a/packages/firebase_messaging/android/firebase_messaging.iml b/packages/firebase_messaging/android/firebase_messaging.iml index ed181a3905d7..d8ba5979464c 100644 --- a/packages/firebase_messaging/android/firebase_messaging.iml +++ b/packages/firebase_messaging/android/firebase_messaging.iml @@ -4,8 +4,8 @@ @@ -19,16 +19,16 @@ - - + + @@ -80,6 +80,15 @@ + + + + + + + + + @@ -98,15 +107,6 @@ - - - - - - - - - @@ -115,11 +115,11 @@ - - - - - + + + + + @@ -131,27 +131,21 @@ - - + + - - - - - + - - - - + + + - + + - - - + diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java index a4f05da29665..e4b677cb5ef3 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FirebaseMessagingPlugin.java @@ -30,8 +30,6 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.NewIntentListener; import io.flutter.plugin.common.PluginRegistry.Registrar; -import io.flutter.plugin.common.PluginRegistry.ViewDestroyListener; -import io.flutter.view.FlutterNativeView; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -44,7 +42,6 @@ public class FirebaseMessagingPlugin extends BroadcastReceiver private static final String TAG = "FirebaseMessagingPlugin"; private MethodChannel channel; - private Context applicationContext; private Activity mainActivity; public static void registerWith(Registrar registrar) { @@ -55,21 +52,16 @@ public static void registerWith(Registrar registrar) { } private void onAttachedToEngine(Context context, BinaryMessenger binaryMessenger) { - this.applicationContext = context; - FirebaseApp.initializeApp(applicationContext); + FirebaseApp.initializeApp(context); channel = new MethodChannel(binaryMessenger, "plugins.flutter.io/firebase_messaging"); - final MethodChannel backgroundCallbackChannel = - new MethodChannel(binaryMessenger, "plugins.flutter.io/firebase_messaging_background"); channel.setMethodCallHandler(this); - backgroundCallbackChannel.setMethodCallHandler(this); - FlutterFirebaseMessagingService.setBackgroundChannel(backgroundCallbackChannel); // Register broadcast receiver IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(FlutterFirebaseMessagingService.ACTION_TOKEN); intentFilter.addAction(FlutterFirebaseMessagingService.ACTION_REMOTE_MESSAGE); - LocalBroadcastManager manager = LocalBroadcastManager.getInstance(applicationContext); + LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context); manager.registerReceiver(this, intentFilter); } @@ -153,14 +145,10 @@ public void onMethodCall(final MethodCall call, final Result result) { /* Even when the app is not active the `FirebaseMessagingService` extended by * `FlutterFirebaseMessagingService` allows incoming FCM messages to be handled. * - * `FcmDartService#start` and `FcmDartService#initialized` are the two methods used - * to optionally setup handling messages received while the app is not active. + * `FcmDartService#start` is setup to handle messages received while the app is not active. * * `FcmDartService#start` sets up the plumbing that allows messages received while * the app is not active to be handled by a background isolate. - * - * `FcmDartService#initialized` is called by the Dart side when the plumbing for - * background message handling is complete. */ if ("FcmDartService#start".equals(call.method)) { long setupCallbackHandle = 0; @@ -175,9 +163,10 @@ public void onMethodCall(final MethodCall call, final Result result) { e.printStackTrace(); } FlutterFirebaseMessagingService.setBackgroundSetupHandle(mainActivity, setupCallbackHandle); - FlutterFirebaseMessagingService.startBackgroundIsolate(mainActivity, setupCallbackHandle); FlutterFirebaseMessagingService.setBackgroundMessageHandle( mainActivity, backgroundMessageHandle); + mainActivity.startService(new Intent(mainActivity, FlutterFirebaseMessagingService.class)); + result.success(true); } else if ("configure".equals(call.method)) { FirebaseInstanceId.getInstance() diff --git a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java index 5086a284390e..358b38b074a1 100644 --- a/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java +++ b/packages/firebase_messaging/android/src/main/java/io/flutter/plugins/firebasemessaging/FlutterFirebaseMessagingService.java @@ -17,19 +17,17 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; -import io.flutter.plugin.common.BinaryMessenger; +import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.embedding.engine.dart.DartExecutor; +import io.flutter.embedding.engine.dart.DartExecutor.DartCallback; 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; import io.flutter.view.FlutterCallbackInformation; import io.flutter.view.FlutterMain; -import io.flutter.view.FlutterNativeView; -import io.flutter.view.FlutterRunArguments; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -50,49 +48,43 @@ public class FlutterFirebaseMessagingService extends FirebaseMessagingService { private static final String BACKGROUND_MESSAGE_CALLBACK_HANDLE_KEY = "background_message_callback"; - // TODO(kroikie): make isIsolateRunning per-instance, not static. - private static AtomicBoolean isIsolateRunning = new AtomicBoolean(false); - /** Background Dart execution context. */ - private static FlutterNativeView backgroundFlutterView; + @Nullable private FlutterEngine backgroundEngine; - @Nullable private static MethodChannel backgroundChannel; + @Nullable private MethodChannel backgroundChannel; private static Long backgroundMessageHandle; - private static List backgroundMessageQueue = + private AtomicBoolean isIsolateRunning = new AtomicBoolean(false); + private final List backgroundMessageQueue = Collections.synchronizedList(new LinkedList()); - private static PluginRegistry.PluginRegistrantCallback pluginRegistrantCallback; - private static final String TAG = "FlutterFcmService"; - private static Context backgroundContext; - @Override public void onCreate() { super.onCreate(); - backgroundContext = getApplicationContext(); - FlutterMain.ensureInitializationComplete(backgroundContext, null); + FlutterMain.ensureInitializationComplete(this, null); // If background isolate is not running start it. - if (!isIsolateRunning.get()) { - SharedPreferences p = backgroundContext.getSharedPreferences(SHARED_PREFERENCES_KEY, 0); - long callbackHandle = p.getLong(BACKGROUND_SETUP_CALLBACK_HANDLE_KEY, 0); - startBackgroundIsolate(backgroundContext, callbackHandle); - } + SharedPreferences p = getSharedPreferences(SHARED_PREFERENCES_KEY, 0); + long callbackHandle = p.getLong(BACKGROUND_SETUP_CALLBACK_HANDLE_KEY, 0); + startBackgroundIsolate(this, callbackHandle); } @Override public void onDestroy() { super.onDestroy(); - if (isIsolateRunning.getAndSet(false)) { + if (backgroundChannel != null) { + backgroundChannel.setMethodCallHandler(null); backgroundChannel = null; + } - backgroundFlutterView.destroy(); - backgroundFlutterView = null; + if (backgroundEngine != null) { + backgroundEngine.destroy(); + backgroundEngine = null; } } @@ -156,81 +148,57 @@ public void onNewToken(@NonNull String token) { * @param callbackHandle Handle used to retrieve the Dart function that sets up background * handling on the dart side. */ - public static void startBackgroundIsolate(Context context, long callbackHandle) { + public void startBackgroundIsolate(Context context, long callbackHandle) { FlutterMain.ensureInitializationComplete(context, null); String appBundlePath = FlutterMain.findAppBundlePath(); FlutterCallbackInformation flutterCallback = FlutterCallbackInformation.lookupCallbackInformation(callbackHandle); - if (flutterCallback == null) { - Log.e(TAG, "Fatal: failed to find callback"); - return; - } // Note that we're passing `true` as the second argument to our // FlutterNativeView constructor. This specifies the FlutterNativeView // as a background view and does not create a drawing surface. - backgroundFlutterView = new FlutterNativeView(context, true); - if (appBundlePath != null && !isIsolateRunning.get()) { - if (pluginRegistrantCallback == null) { - throw new RuntimeException("PluginRegistrantCallback is not set."); - } - FlutterRunArguments args = new FlutterRunArguments(); - args.bundlePath = appBundlePath; - args.entrypoint = flutterCallback.callbackName; - args.libraryPath = flutterCallback.callbackLibraryPath; - backgroundFlutterView.runFromBundle(args); - pluginRegistrantCallback.registerWith(backgroundFlutterView.getPluginRegistry()); - - BinaryMessenger messenger = - backgroundFlutterView - .getPluginRegistry() - .registrarFor("io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService") - .messenger(); - final MethodChannel backgroundCallbackChannel = - new MethodChannel(messenger, "plugins.flutter.io/firebase_messaging_background"); - backgroundCallbackChannel.setMethodCallHandler( - new MethodCallHandler() { - @Override - public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { - if ("FcmDartService#initialized".equals(call.method)) { - FlutterFirebaseMessagingService.onInitialized(); - result.success(true); - } else { - result.notImplemented(); - } + backgroundEngine = new FlutterEngine(context); + + final DartExecutor executor = backgroundEngine.getDartExecutor(); + + backgroundChannel = + new MethodChannel(executor, "plugins.flutter.io/firebase_messaging_background"); + backgroundChannel.setMethodCallHandler( + new MethodCallHandler() { + @Override + public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) { + if ("FcmDartService#initialized".equals(call.method)) { + onInitialized(); + result.success(true); + } else { + result.notImplemented(); } - }); - setBackgroundChannel(backgroundCallbackChannel); - } + } + }); + + final DartCallback dartCallback = + new DartExecutor.DartCallback(getAssets(), appBundlePath, flutterCallback); + + executor.executeDartCallback(dartCallback); } /** * Acknowledge that background message handling on the Dart side is ready. This is called by the * Dart side once all background initialization is complete via `FcmDartService#initialized`. */ - public static void onInitialized() { + public void onInitialized() { isIsolateRunning.set(true); + synchronized (backgroundMessageQueue) { // Handle all the messages received before the Dart isolate was // initialized, then clear the queue. - Iterator i = backgroundMessageQueue.iterator(); - while (i.hasNext()) { - executeDartCallbackInBackgroundIsolate(backgroundContext, i.next(), null); + for (RemoteMessage remoteMessage : backgroundMessageQueue) { + executeDartCallbackInBackgroundIsolate(this, remoteMessage, null); } backgroundMessageQueue.clear(); } } - /** - * Set the method channel that is used for handling background messages. This method is only - * called when the plugin registers. - * - * @param channel Background method channel. - */ - public static void setBackgroundChannel(@NonNull MethodChannel channel) { - backgroundChannel = channel; - } - /** * Set the background message handle for future use. When background messages need to be handled * on the Dart side the handler must be retrieved in the background isolate to allow processing of @@ -292,7 +260,7 @@ public static Long getBackgroundMessageHandle(Context context) { * @param latch If set will count down when the Dart side message processing is complete. Allowing * any waiting threads to continue. */ - private static void executeDartCallbackInBackgroundIsolate( + private void executeDartCallbackInBackgroundIsolate( Context context, RemoteMessage remoteMessage, final CountDownLatch latch) { if (backgroundChannel == null) { throw new RuntimeException( @@ -323,16 +291,6 @@ private static void executeDartCallbackInBackgroundIsolate( backgroundChannel.invokeMethod("handleBackgroundMessage", args, result); } - /** - * Set the registrant callback. This is called by the app's Application class if background - * message handling is enabled. - * - * @param callback Application class which implements PluginRegistrantCallback. - */ - public static void setPluginRegistrant(PluginRegistry.PluginRegistrantCallback callback) { - pluginRegistrantCallback = callback; - } - /** * Identify if the application is currently in a state where user interaction is possible. This * method is only called by FlutterFirebaseMessagingService when a message is received to From 654b97b8e54a0c28fea4c694584952e59084b7c3 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 30 Apr 2020 16:20:12 +0100 Subject: [PATCH 11/15] Update README --- packages/firebase_messaging/README.md | 51 +-------------------------- 1 file changed, 1 insertion(+), 50 deletions(-) diff --git a/packages/firebase_messaging/README.md b/packages/firebase_messaging/README.md index 538436b8c86a..f0266372d44d 100644 --- a/packages/firebase_messaging/README.md +++ b/packages/firebase_messaging/README.md @@ -61,59 +61,10 @@ for more. By default background messaging is not enabled. To handle messages in the background: -1. Add the `com.google.firebase:firebase-messaging` dependency in your app-level `build.gradle` file that is typically located at `/android/app/build.gradle`. - - ```gradle - dependencies { - // ... - - implementation 'com.google.firebase:firebase-messaging:' - } - ``` - - Note: you can find out what the latest version of the plugin is [here ("Cloud Messaging")](https://firebase.google.com/support/release-notes/android#latest_sdk_versions). - -1. Add an `Application.java` class to your app in the same directory as your `MainActivity.java`. This is typically found in `/android/app/src/main/java//`. - - ```java - package io.flutter.plugins.firebasemessagingexample; - - import io.flutter.app.FlutterApplication; - import io.flutter.plugin.common.PluginRegistry; - import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback; - import io.flutter.plugins.GeneratedPluginRegistrant; - import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService; - - public class Application extends FlutterApplication implements PluginRegistrantCallback { - @Override - public void onCreate() { - super.onCreate(); - FlutterFirebaseMessagingService.setPluginRegistrant(this); - } - - @Override - public void registerWith(PluginRegistry registry) { - GeneratedPluginRegistrant.registerWith(registry); - } - } - ``` - -1. In `Application.java`, make sure to change `package io.flutter.plugins.firebasemessagingexample;` to your package's identifier. Your package's identifier should be something like `com.domain.myapplication`. - - ```java - package com.domain.myapplication; - ``` - -1. Set name property of application in `AndroidManifest.xml`. This is typically found in `/android/app/src/main/`. - - ```xml - - ``` - 1. Define a **TOP-LEVEL** or **STATIC** function to handle background messages ```dart - Future myBackgroundMessageHandler(Map message) { + Future myBackgroundMessageHandler(Map message) async { if (message.containsKey('data')) { // Handle data message final dynamic data = message['data']; From 254e43d18ba0862d9406fa0d872689d1961b3025 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Thu, 30 Apr 2020 16:20:18 +0100 Subject: [PATCH 12/15] Bump version, add changelog --- packages/firebase_messaging/CHANGELOG.md | 6 ++++++ packages/firebase_messaging/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/firebase_messaging/CHANGELOG.md b/packages/firebase_messaging/CHANGELOG.md index 26e6b0acc5f6..0b6b3ca10f09 100644 --- a/packages/firebase_messaging/CHANGELOG.md +++ b/packages/firebase_messaging/CHANGELOG.md @@ -1,3 +1,9 @@ +## 6.1.0 + +* Refactors the Android portion for background messages. It is now using a + `FlutterEngine` internally, which does removes the requirement to manually + register a plugin registrant or include FCM dependencies in the host App. + ## 6.0.14 * Fix for missing UserAgent.h compilation failures. diff --git a/packages/firebase_messaging/pubspec.yaml b/packages/firebase_messaging/pubspec.yaml index 5d13c69a5162..c134ae8aa0a9 100644 --- a/packages/firebase_messaging/pubspec.yaml +++ b/packages/firebase_messaging/pubspec.yaml @@ -2,7 +2,7 @@ name: firebase_messaging description: Flutter plugin for Firebase Cloud Messaging, a cross-platform messaging solution that lets you reliably deliver messages on Android and iOS. homepage: https://github.com/FirebaseExtended/flutterfire/tree/master/packages/firebase_messaging -version: 6.0.14 +version: 6.1.0 flutter: plugin: From 568f372cb8e7ec372cf454dd89f7168ddec4a4f3 Mon Sep 17 00:00:00 2001 From: Sebastian Roth Date: Fri, 15 May 2020 11:03:20 +0100 Subject: [PATCH 13/15] few more refactor tasks and ensure the firebase_messaging example runs on V2 embedding --- .../android/firebase_messaging.iml | 4 +- .../FlutterFirebaseMessagingService.java | 40 +++++++++++++------ .../firebase/messaging/MainActivityTest.java | 1 - .../android/app/src/main/AndroidManifest.xml | 21 +++++----- .../EmbeddingV1Activity.java | 8 +++- .../MainActivity.java | 20 ---------- .../firebase_messaging/example/lib/main.dart | 7 ++++ .../firebase_messaging/example/pubspec.yaml | 2 +- packages/firebase_messaging/pubspec.yaml | 2 +- 9 files changed, 54 insertions(+), 51 deletions(-) delete mode 100644 packages/firebase_messaging/example/android/app/src/main/java/io/flutter/plugins/firebasemessagingexample/MainActivity.java diff --git a/packages/firebase_messaging/android/firebase_messaging.iml b/packages/firebase_messaging/android/firebase_messaging.iml index d8ba5979464c..ae1354c03ed2 100644 --- a/packages/firebase_messaging/android/firebase_messaging.iml +++ b/packages/firebase_messaging/android/firebase_messaging.iml @@ -19,7 +19,7 @@