Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 8 commits into from
Sep 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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