Push Messages⚓︎
This section describes how to set up Firebase Cloud Messaging (FCM) for your Android apps and Apple Push Notification Service (APNS) for your iOS apps. These services are required to receive push notifications from the server (e.g. push login, logout, account removal). We will also describe a fallback method to pull any outstanding push notifications directly from the server. The Mobile SDK will take care of deduplication of push messages in case it receives a particular message multiple times.
Important
Setting up push messages for your app also requires a setup at the message center. Follow the steps described here to set up push messaging from the server side.
Info
Messages that are sent over FCM/APNS (or those that are pulled directly by the app) are encrypted during transmission to and from your app. The Mobile SDK takes care of the decryption and processing of these encrypted messages.
Receive Push Messages⚓︎
Android⚓︎
On Android, you will need to add a google-services.json file to your app. You can generate one of these in the Firebase Console under Settings > General > Your Apps. Make sure that it has an entry for the application id(s) of your app (e.g. com.nextauth.authenticator), including all build flavours (e.g. com.nextauth.authenticator.beta).
When starting the app, register the FCM token. You can do this by adding the following code to the onCreate() method of MyApplication.
FirebaseMessaging.getInstance().getToken().addOnSuccessListener(FCMToken -> {
NextAuth.getNextAuth().updatePushToken(FCMToken);
});
Next, create a service that extends the FireBaseMessagingService to receive the FCM messages and handle updates of the FCM token. Here you should also handle notifications to be shown to the user.
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import com.nextauth.android.NextAuth;
import com.nextauth.android.PushMessage;
public class MyPushMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage message) {
Map<String, String> data = message.getData();
// pass the encrypted push message to the Mobile SDK
PushMessage decryptedPushMessage = NextAuth.getNextAuth().decryptPushMessage(data);
// TODO implement notifications based on decryptedPushMessage
}
@Override
public void onNewToken(@NonNull String token) {
// update the FCM push token
NextAuth.getNextAuth().updatePushToken(token);
}
}
Decrypting LOGIN push messages does not start a login flow automatically. To start the login flow, you must manually call the processPushMessage() method from the last received LOGIN push message, if any.
NextAuth.getNextAuth().processPushMessage();
processPushMessage() method in two places:
- inside your notification handling code, after checking that your app is in the foreground; and
- at the app level code, which runs when your app returns to the foreground.
Optionally, create a receiver that extends BroadcastReceiver to start the application immediately after the device has booted.
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
NextAuth.getNextAuth().retrieveMessages();
}
}
}
Finally, add the following to your project’s build.gradle:
buildscript {
dependencies {
...
classpath 'com.google.gms:google-services:4.4.4'
}
}
to your app’s build.gradle:
dependencies {
...
// Play services
implementation 'com.google.android.gms:play-services-base:18.10.0'
// FCM
implementation 'com.google.firebase:firebase-messaging:25.0.1'
}
apply plugin: 'com.google.gms.google-services'
and AndroidManifest:
<!--optional-->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
...
<service
android:name="MyPushMessagingService"
android:exported="false"
android:stopWithTask="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!--optional-->
<receiver
android:name="BootReceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
iOS⚓︎
Notification Service Extension⚓︎
Apple enables updating a notification’s content before it is displayed to the user, even when the device is in its locked state. For this reason, you will need to create a new Notification Service app extension. Additionally, the extension and your app need to be members of an App Group so that they can share data.
First, navigate to Apple’s Developer portal to create an App Group and an App ID for the app extension. The App Group’s identifier will typically have the form group.com.nextauth.Authenticator. Once it has been created, don’t forget to grant the app’s Bundle ID the capability to access this group. Next, create a new App ID for the Notification Service extension. We recommend setting it to com.nextauth.Authenticator.NSExtension, but you are of course free to choose another value. Ensure that you also grant this ID the App Group entitlements with the relevant group.
Once you have completed these steps, open Xcode and choose File > New > Target and choose Notification Service Extension in the dialog. Fill out the following screen as required by your setup, where we typically set the target’s name to AuthenticatorNSExtension.
Handling Push Notifications⚓︎
In contrast to Android, iOS will invoke a couple of different methods of your app’s AppDelegate class when you receive push notifications. You should therefore ensure that it conforms to both UIApplicationDelegate and UNUserNotificationCenterDelegate. Furthermore, don’t forget to request authorisation from the user to send push notifications (e.g. immediately when the app is started for the first time or during an onboarding flow).
Once a device push token has been requested from and granted by iOS, it will call application(_ :didRegisterForRemoteNotificationsWithDeviceToken:). The generated token should simply be passed to the nextAuth Mobile SDK, which will take care of registering it with the Message Center.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
// MARK: - UIApplicationDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().getNotificationSettings() { settings in
guard settings.authorizationStatus == .authorized else {
return
}
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NextAuth.default.updatePushToken(deviceToken)
}
}
Finally, push notifications can be received by the app in a number of ways. In order to ensure proper handling of both silent and presented notifications when the app can be in the foreground or background, you should also add the following methods to your AppDelegate. Each of them will process the received notification(s) and pass then to the Mobile SDK by calling the dedicated NextAuth.default.start(notification:) method.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
// MARK: - UIApplicationDelegate
func applicationWillEnterForeground(_ application: UIApplication) {
UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
for notification in notifications {
NextAuth.default.start(notification: notification)
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notification.request.identifier])
}
}
// MARK: - UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
NextAuth.default.start(notification: response.notification)
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
NextAuth.default.start(notification: notification)
completionHandler([])
}
}
Message Retrieval⚓︎
In addition to pushing notification through FCM and APNs, the Message Center also supports message retrieval using a pull-based mechanism. On Android systems, we recommend regularly polling this to improve reliability or as a fallback if the user has not authorised push notifications.
On iOS, it is possible that the user has silenced notifications. If this is the case, then the pull-based mechanism will only work when the application is in the foreground. On iOS, we have generally found APNs to be quite reliable, and we advise against relying on the pull-based fallback mechanism on this system because doing so may impact the energy usage of your app.
NextAuth.getNextAuth().retrieveMessages()
NextAuth.default.retrieveMessages()
Note that the retrieveMessages() method on both platforms does not have any return values. If the Message Center returns any messages, they will be processed immediately by the Mobile SDK and the relevant callbacks will be issued. Furthermore, both push and pull mechanisms can be used simultaneously, as the Mobile SDK will deduplicate any incoming messages.