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.
val permissionUtil by permissionUtil()
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")
How to implement Push Notifications in Kotlin Multiplatform was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.
[Read on Medium]