A Flutter plugin to use Azure Notification Hubs
Microsoft Azure Notification Hubs is a scalable push notification engine for quickly sending millions of messages to any mobile platform. You can visit the developer center to learn more.
Before you can integrate Microsoft Azure Notification Hubs in your Flutter project, you need to already have one created in the Azure portal. If you haven't already done this, you can follow the quick start guide provided in the developer center. Also make sure you configure on the Azure portal any platforms to which you intend to send notifications by following the respective guides.
Note
Although you are using Azure Notification Hubs to send your messages, behind the sceenes that uses Firebase Cloud Messaging to deliver the messages to devices. That's why you need to have a configured app in your Firebase console as well.
-
Open the Firebase console and create a project for your Flutter app.
-
Add an Android app and provide all the details the Firebase console asks for the app
-
Download the
google-services.json
file and place it in theandroid/app
folder of your Flutter app.If you already have an Android app registered with Firebase, then you can download the
google-services.json
by going to the settings of the app on the Firebase console -
Add the Google Services plugin to the
android/settings.graddle
file of your Flutter app and
//....
plugins {
//....
id "com.google.gms.google-services" version "4.3.15" apply false
}
include ":app"
- Apply the Google Services plugin to the
android/app/build.gradle
file of your Flutter app
plugins {
//.....
id "com.google.gms.google-services"
}
- Add the notification hub name and connection string to the
android/app/src/main/AndroidManifest.xml
file of your Flutter app (you can obtain the values from the Azure portal)
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="...."
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
....>
<!-- ... -->
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="NotificationHubName"
android:value="....." />
<meta-data
android:name="NotificationHubConnectionString"
android:value="Endpoint=sb://...." />
</application>
<!-- ... -->
</manifest>
- Add the following code to the
application
method in your Flutter app'sios/Runner/AppDelegate.swift
orios/Runner/AppDelegate.m
file
// Swift
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
}
// Objective-C
if (@available(iOS 10.0, *)) {
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
}
- In the
ios/Info.plist
file of your Flutter app add values for the notification hub name and connection string
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- .... -->
<key>NotificationHubConnectionString</key>
<string>Endpoint=sb://....</string>
<key>NotificationHubName</key>
<string>....</string>
<!-- .... -->
</dict>
</plist>
-
Open your Flutter app in XCode and for the
Runner
project, underSigning & Capabilities
add thePush Notifications
capability.If you also want to handle push notifications while your app is in the background, also add the
Background Modes
capability and tick theRemote notifications
mode.
In order to register the device with the Azure Notification Hub and start receiving messages you need to call the start()
method. This has to be done as early as possible (preferably in the main()
method of your Flutter app after Flutter's bindings are initialized) and needs to be awaited before trying to call any other plugin methods. This will also ask for user permission to receive push notifications.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AzureNotificationHub.instance.start();
runApp(const MyApp());
}
The plugin exposes an onMessage
stream on which you can listen. You can have more than one listener in different places of your app, just remember to cancel the subscription once your widget is disposed.
You will receive the push notification as a Map<String, dynamic>
that has title
& body
properties of the notification as well as data
which is another Map<String, dynamic>
of all custom properties sent with the notification.
Note
On both platforms foreground notifications are silent and are not shown to the user.
Unlike foreground, notifications in the background are handled by a callback since on Android it needs to be executed in an isolate. Because of this you also can not update any UI/widget state in this callback, but you should have access to save the data in files/settings/etc.
The callback needs to be globally available and decorated with @pragma('vm:entry-point')
to prevent Dart's tree shacking from removing it. The adding of the callback needs to happen even before calling start.
@pragma('vm:entry-point')
Future<void> _onBackgroundMessageReceived(Map<String, dynamic> message) async {
print('onBackgrounMessage: $message');
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
AzureNotificationHub.instance.registerBackgroundMessageHandler(_onBackgroundMessageReceived);
await AzureNotificationHub.instance.start();
runApp(const MyApp());
}
For iOS in order background notifications to work, you need to have enabled the Background Mode for the app with the Remote notification ticked. Also you need to have "content-available": 1
set in your aps
JSON payload for the notification:
{
"aps": {
"content-available": 1
},
"acme1": "bar",
"acme2": 42
}
For more details you can check the official Apple documentation for notification's payload.
The plugin exposes an onMessageOpenedApp
stream on which you can listen to get the tapped notification which caused your app to open. Similar to foreground messages you can have multiple listeners. And you will receive a similar object as for a foreground message.
Important
The way Android notifications work, when the user taps on the message the title
and body
properties are not sent to the native code. If you need to access those properties when the user taps the message, you can also send them in the data
payload of the notification.
You can easily manage tags by calling the plugin's getTags()
, addTags(...)
, removeTags(...)
and clearTags()
methods.
The plugin currently supports setting a single template with the name hardcoded in the plugin as FANH DEFAULT TEMPLATE
.
To easily receive cross platform notifications without worrying in your backend about the platform specific payload, it is best you define the template body based on the platform you are currently running on. Then Azure Notification Hubs will handle sending the correct payload for each platform. For example:
import 'package:flutter/foundation.dart';
import 'package:az_notification_hub/az_notification_hub.dart';
final _platformTemplates = {
TargetPlatform.android.name: {
'message': {
'notification': {
'title': '\$(title)',
'body': '\$(body)',
},
'data': {
'title': '\$(title)',
'body': '\$(body)',
'extra': '\$(extra)',
},
},
},
TargetPlatform.iOS.name: {
'aps': {
'alert': {
'title': '\$(title)',
'body': '\$(body)',
},
"sound": "default",
"content-available": 1,
},
'title': '\$(title)',
'body': '\$(body)',
'extra': '\$(extra)',
},
};
Future<bool> _setTemplate() {
return AzureNotificationHub.instance.setTemplate(
json.encode(_platformTemplates[defaultTargetPlatform.name]),
);
}
And the JSON payload that needs to be submitted to Azure Notification Hub is:
{
"title": "Great News1",
"body": "Notifications actually work",
"extra": "123"
}
For more info about template expressions you check the official Microsoft documentation.