Push Notification in Kotlin Multiplatform
In this blog post I will share with you how to implement push notifications using Firebase in Kotlin Multiplatform (targeting iOS and Android platforms).
Push notifications play a crucial role in keeping users engaged and informed about important updates in your Kotlin Multiplatform (KMP) applications. While Firebase provides a robust platform for handling push notifications, integrating it seamlessly across both Android and iOS platforms in a KMP project can be a challenging task since Firebase doesn’t yet support Kotlin Multiplatform. For this purpose we will use the KMPNotifier library. I developed this push notification library to serve as the bridge between your Kotlin Multiplatform codebase and the implementation of push notifications. Whether you’re aiming to send local notifications or push notifications, KMPNotifier provides a clean and efficient API for managing the entire notification lifecycle. With KMPNotifier you can listen for token changes, subscribe or unsubscribe to topics, get current user token, or just send local notifications for any events.
Zeroth Step — Basic setup using Firebase official guideline
Before starting you need to setup basic things using the Firebase official guidelines (like initializing project in Firebase, adding google-services.json
to Android, and GoogleService-Info.plist
to iOS).
Firebase setup for iOS — https://firebase.google.com/docs/ios/setup
Firebase setup for Android— https://firebase.google.com/docs/android/setup
Gradle Setup
KMPNotifier is available on Maven Central. In your root project build.gradle.kts
file (or settings.gradle
file) add mavenCentral()
to repositories, and google-services
plugin to plugins.
plugins { id("com.android.application") version "8.1.3" apply false id("org.jetbrains.kotlin.multiplatform") version "1.9.20" apply false id("com.google.gms.google-services") version "4.4.0" apply false } repositories { mavenCentral() }
Then in your shared module you add dependency with latest version in commonMain
. Latest version(https://github.com/mirzemehdi/KMPNotifier/releases):
In iOS framework part you need to export this library as well.
sourceSets { commonMain.dependencies { api("io.github.mirzemehdi:kmpnotifier:<version>") // in iOS export this library } } listOf( iosX64(), iosArm64(), iosSimulatorArm64() ).forEach { iosTarget -> iosTarget.binaries.framework { export(project("io.github.mirzemehdi:kmpnotifier:<version>")) baseName = "shared" isStatic = true } }
And in androidApp build.gradle.kts
file you apply google-services
plugin
plugins { id("com.android.application") id("com.google.gms.google-services") }
Platform Setup
In both platforms on Application Start you need to initialize library using initialize method :
NotifierManager.initialize(NotificationPlatformConfiguration) //passing android or ios configuration depending on the platform
Android Setup
class MyApplication : Application() { override fun onCreate() { super.onCreate() NotifierManager.initialize( configuration = NotificationPlatformConfiguration.Android( notificationIconResId = R.drawable.ic_launcher_foreground, ) ) } }
Also starting from Android 13(API Level 33) you need to ask runtime POST_NOTIFICATIONS
in activity. I created a utility function that you can use in the activity.
permissionUtil.askNotificationPermission() //this will ask permission in Android 13(API Level 33) or above, otherwise permission will be granted.
iOS Setup
First, you just need to include FirebaseMessaging library to your iOS app from Xcode. Then on application start you need to call both FirebaseApp initialization and NotifierManager initialization methods, and setting apnsToken as below. Don’t forget to add Push Notifications and Background Modes (Remote Notifications) signing capability in Xcode.
import SwiftUI import shared import FirebaseCore import FirebaseMessaging class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FirebaseApp.configure() //important NotifierManager.shared.initialize(configuration: NotificationPlatformConfigurationIos.shared) return true } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken } } @main struct iOSApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate var body: some Scene { WindowGroup { ContentView() } } }
Usage
You can send either local or push notification.
Local Notification
val notifier = NotifierManager.getLocalNotifier() notifier.notify("Title", "Body") //Sends local notification
Push Notification
Listen for push notification token changes -> In this callback method you can send notification token to the server.
NotifierManager.addListener(object : NotifierManager.Listener { override fun onNewToken(token: String) { println("onNewToken: $token") //Update user token in the server if needed } })
Other useful functions
NotifierManager.getPushNotifier().getToken() //Get current user push notification token NotifierManager.getPushNotifier().deleteMyToken() //Delete user's token for example when user logs out NotifierManager.getPushNotifier().subscribeToTopic("new_users") NotifierManager.getPushNotifier().unSubscribeFromTopic("new_users")
This article was previously published on proandroiddev.com