Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[firebase_messaging] Add support for handling messages in background #1900

Closed
wants to merge 16 commits into from
Closed
74 changes: 73 additions & 1 deletion packages/firebase_messaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,79 @@ Note: When you are debugging on Android, use a device or AVD with Google Play se
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
```

#### Optionally handle background messages

By default background messaging is not enabled. To handle messages in the background:

1. Add an Application.java class to your app

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where in the App we should put this Java class, with the MainActivity or inside io.flutter.plugins?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JillyTaboga You should add it alongside your MainActivity.java file.


```
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. Set name property of application in `AndroidManifest.xml`
collinjackson marked this conversation as resolved.
Show resolved Hide resolved
```
<application android:name=".Application" ...>
```
1. Define a top level Dart method to handle background messages
```
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
if (message.containsKey('data')) {
// Handle data message
dynamic data = message['data'];
}

if (message.containsKey('notification')) {
// Handle notification message
dynamic notification = message['notification'];
}

// Or do work with other plugins, eg: write to RTDB.
FirebaseDatabase.instance.reference().child('foo').set('bar');
return Future<void>.value();
}
```
Note: the protocol of `data` and `notification` are in line with the
fields defined by a [RemoteMessage](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/RemoteMessage).
1. Set `onBackgroundMessage` handler when calling `configure`
kroikie marked this conversation as resolved.
Show resolved Hide resolved
```
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print("onMessage: $message");
_showItemDialog(message);
},
onBackgroundMessage: myBackgroundMessageHandler,
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
_navigateToItemDetail(message);
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
_navigateToItemDetail(message);
},
);
```
Note: `configure` should be called early in the lifecycle of your application
so that it can be ready to receive messages as early as possible. See the
example app for a demonstration.

### iOS Integration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ 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/android_fcm_background");
kroikie marked this conversation as resolved.
Show resolved Hide resolved
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) {
Expand Down Expand Up @@ -99,7 +104,40 @@ private Map<String, Object> parseRemoteMessage(RemoteMessage message) {

@Override
public void onMethodCall(final MethodCall call, final Result result) {
if ("configure".equals(call.method)) {
/* 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` 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;
long backgroundMessageHandle = 0;
try {
Map<String, Long> callbacks = ((Map<String, Long>) call.arguments);
setupCallbackHandle = callbacks.get("setupHandle");
backgroundMessageHandle = callbacks.get("backgroundHandle");
} catch (Exception e) {
Log.e(TAG, "There was an exception when getting callback handle from Dart side");
e.printStackTrace();
}
FlutterFirebaseMessagingService.setBackgroundSetupHandle(
kroikie marked this conversation as resolved.
Show resolved Hide resolved
this.registrar.context(), setupCallbackHandle);
FlutterFirebaseMessagingService.startBackgroundIsolate(
this.registrar.context(), setupCallbackHandle);
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()
.addOnCompleteListener(
Expand Down
Loading