Skip to content

Commit

Permalink
Merge pull request flutter#38 from collinjackson/flutter#1900
Browse files Browse the repository at this point in the history
[firebase_messaging] Add Android support for handling messages in background
  • Loading branch information
kroikie authored Sep 5, 2019
2 parents 9cd0e07 + e762755 commit bfc666d
Show file tree
Hide file tree
Showing 7 changed files with 501 additions and 7 deletions.
4 changes: 4 additions & 0 deletions packages/firebase_messaging/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 5.1.5

* Enable background message handling on Android.

## 5.1.4

* Update documentation to reflect new repository location.
Expand Down
77 changes: 76 additions & 1 deletion packages/firebase_messaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,82 @@ 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

>Background message handling is intended to be performed quickly. Do not perform
long running tasks as they may not be allowed to finish by the Android system.
See [Background Execution Limits](https://developer.android.com/about/versions/oreo/background)
for more.

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

1. Add an Application.java class to your app

```
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`
```
<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
final dynamic data = message['data'];
}

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

// Or do other work.
}
```
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`
```
_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,15 @@ 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) {
Expand Down Expand Up @@ -99,7 +105,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(
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

0 comments on commit bfc666d

Please sign in to comment.