Skip to content

Commit

Permalink
Receiving Data payload Notification type is implemented (#5)
Browse files Browse the repository at this point in the history
*Push Notification Data Payload handling
*Updating sample code
*Updating documentation
  • Loading branch information
mirzemehdi authored Dec 25, 2023
1 parent 0715729 commit 65b698d
Show file tree
Hide file tree
Showing 21 changed files with 237 additions and 17 deletions.
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,43 @@ NotifierManager.addListener(object : NotifierManager.Listener {
})
```



#### Receive data payload
```kotlin
NotifierManager.addListener(object : NotifierManager.Listener {
override fun onPayloadData(data: PayloadData) {
println("Push Notification payloadData: $data") //PayloadData is just typeAlias for Map<String,*>.
}
})
```
And you need to call below platform-specific functions in order to receive payload data properly.
##### Android
Call `NotifierManager.onCreateOrOnNewIntent(intent)` on launcher Activity's `onCreate` and `onNewIntent` methods.
```kotlin
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
NotifierManager.onCreateOrOnNewIntent(intent)
...
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
NotifierManager.onCreateOrOnNewIntent(intent)
}

```
##### iOS
Call `NotifierManager.onApplicationDidReceiveRemoteNotification(userInfo: userInfo)` on application's `didReceiveRemoteNotification` method.

```
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
NotifierManager.shared.onApplicationDidReceiveRemoteNotification(userInfo: userInfo)
return UIBackgroundFetchResult.newData
}
```

#### Other functions
```kotlin
NotifierManager.getPushNotifier().getToken() //Get current user push notification token
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ plugins {

allprojects {
group = "io.github.mirzemehdi"
version = "0.1.9"
version = "0.2.0"
val sonatypeUsername = gradleLocalProperties(rootDir).getProperty("sonatypeUsername")
val sonatypePassword = gradleLocalProperties(rootDir).getProperty("sonatypePassword")
val gpgKeySecret = gradleLocalProperties(rootDir).getProperty("gpgKeySecret")
Expand Down
1 change: 1 addition & 0 deletions iosApp/iosApp/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
</dict>
<key>UIBackgroundModes</key>
<array>
<string>processing</string>
<string>remote-notification</string>
</array>
<key>UILaunchScreen</key>
Expand Down
8 changes: 7 additions & 1 deletion iosApp/iosApp/iOSApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
NotifierManager.shared.initialize(configuration: NotificationPlatformConfigurationIos.shared)
AppInitializer.shared.onApplicationStart()

return true
}
Expand All @@ -17,6 +17,12 @@ class AppDelegate: NSObject, UIApplicationDelegate {
Messaging.messaging().apnsToken = deviceToken
}


func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
NotifierManager.shared.onApplicationDidReceiveRemoteNotification(userInfo: userInfo)
return UIBackgroundFetchResult.newData
}

}

@main
Expand Down
10 changes: 10 additions & 0 deletions kmpnotifier/api/kmpnotifier.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
public final class com/mmk/kmpnotifier/extensions/NotifierManagerExtKt {
public static final fun onCreateOrOnNewIntent (Lcom/mmk/kmpnotifier/notification/NotifierManager;Landroid/content/Intent;)V
}

public abstract interface class com/mmk/kmpnotifier/notification/Notifier {
public abstract fun notify (Ljava/lang/String;Ljava/lang/String;)V
}
Expand All @@ -12,6 +16,12 @@ public final class com/mmk/kmpnotifier/notification/NotifierManager {

public abstract interface class com/mmk/kmpnotifier/notification/NotifierManager$Listener {
public abstract fun onNewToken (Ljava/lang/String;)V
public abstract fun onPayloadData (Ljava/util/Map;)V
}

public final class com/mmk/kmpnotifier/notification/NotifierManager$Listener$DefaultImpls {
public static fun onNewToken (Lcom/mmk/kmpnotifier/notification/NotifierManager$Listener;Ljava/lang/String;)V
public static fun onPayloadData (Lcom/mmk/kmpnotifier/notification/NotifierManager$Listener;Ljava/util/Map;)V
}

public abstract interface class com/mmk/kmpnotifier/notification/PushNotifier {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.mmk.kmpnotifier.extensions

import android.content.Intent
import androidx.core.os.bundleOf
import com.mmk.kmpnotifier.notification.NotifierManager
import com.mmk.kmpnotifier.notification.NotifierManagerImpl


/***
* In order to receive notification data payload this functions needs to be called in
* Android side in launcher Activity #onCreate and #onNewIntent methods.
*
* Example:
*
* ```
* class MainActivity : ComponentActivity() {
* override fun onCreate(savedInstanceState: Bundle?) {
* super.onCreate(savedInstanceState)
* NotifierManager.onCreateOrOnNewIntent(intent)
* setContent {
* App()
* }
* }
*
* override fun onNewIntent(intent: Intent?) {
* super.onNewIntent(intent)
* NotifierManager.onCreateOrOnNewIntent(intent)
* }
*
* }
*
* ```
*/
public fun NotifierManager.onCreateOrOnNewIntent(intent: Intent?) {
if (intent == null) return
val extras = intent.extras ?: bundleOf()
val payloadData = mutableMapOf<String, Any>()
extras.keySet().forEach { key ->
val value = extras.get(key)
value?.let { payloadData[key] = value }
}
if (extras.containsKey("google.sent_time")) NotifierManagerImpl.onPushPayloadData(payloadData)
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ internal class MyFirebaseMessagingService : FirebaseMessagingService() {
message.notification?.let {
notifier.notify(it.title ?: "", it.body ?: "")
}
if (message.data.isNotEmpty()){
notifierFactory.onPushPayloadData(message.data)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ public object NotifierManager {
* Called when push notification token is updated, or initialized first time
* @param token Push Notification token
*/
public fun onNewToken(token: String)
public fun onNewToken(token: String){}

/**
* Called when push notification data is available
* @param data Push Notification Payload Data
*/
public fun onPayloadData(data:PayloadData) {}
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ internal object NotifierManagerImpl : KMPKoinComponent() {
listeners.forEach { it.onNewToken(token) }
}

fun onPushPayloadData(data: PayloadData) {
println("Received Push Notification payload data")
if (listeners.size == 0) println("There is no listener to notify onPushPayloadData")
listeners.forEach { it.onPayloadData(data) }
}

private fun requireInitialization() {
if (LibDependencyInitializer.isInitialized().not()) throw IllegalStateException(
"NotifierFactory is not initialized. " +
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.mmk.kmpnotifier.notification

public typealias PayloadData = Map<String, *>

/**
* Class represents push notification such as Firebase Push Notification
*/
public interface PushNotifier {


/**
* @return current push notification token
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.mmk.kmpnotifier.extensions

import com.mmk.kmpnotifier.notification.NotifierManager
import com.mmk.kmpnotifier.notification.NotifierManagerImpl

/***
* In order to receive notification data payload this functions needs to be called in
* ios Swift side application didReceiveRemoteNotification function
*
* Example:
*
* ```
* func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
* NotifierManager.shared.onApplicationDidReceiveRemoteNotification(userInfo: userInfo)
* return UIBackgroundFetchResult.newData
* }
* ```
*/
public fun NotifierManager.onApplicationDidReceiveRemoteNotification(userInfo:Map<Any?, *>){
val payloadData = userInfo.keys
.filterNotNull()
.filterIsInstance<String>()
.associateWith { key -> userInfo[key] }

if (payloadData.containsKey("gcm.message_id")) NotifierManagerImpl.onPushPayloadData(payloadData)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mmk.kmpnotifier.notification

import com.mmk.kmpnotifier.extensions.onApplicationDidReceiveRemoteNotification
import com.mmk.kmpnotifier.permission.IosPermissionUtil
import platform.UserNotifications.UNMutableNotificationContent
import platform.UserNotifications.UNNotification
Expand Down Expand Up @@ -47,6 +48,8 @@ internal class IosNotifier(
// FIRMessaging.messaging()
// .appDidReceiveMessage(didReceiveNotificationResponse.notification.request.content.userInfo)

val userInfo = didReceiveNotificationResponse.notification.request.content.userInfo
NotifierManager.onApplicationDidReceiveRemoteNotification(userInfo)
withCompletionHandler()
}

Expand All @@ -57,6 +60,8 @@ internal class IosNotifier(
) {
// FIRMessaging.messaging()
// .appDidReceiveMessage(didReceiveNotificationResponse.notification.request.content.userInfo)
val userInfo =willPresentNotification.request.content.userInfo
NotifierManager.onApplicationDidReceiveRemoteNotification(userInfo)
withCompletionHandler(IosPermissionUtil.NOTIFICATION_PERMISSIONS)
}
}
Expand Down
16 changes: 16 additions & 0 deletions sample/api/sample.api
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
public final class com/mmk/kmpnotifier/sample/AppInitializer {
public static final field $stable I
public static final field INSTANCE Lcom/mmk/kmpnotifier/sample/AppInitializer;
public final fun onApplicationStart ()V
}

public final class com/mmk/kmpnotifier/sample/AppKt {
public static final fun App (Landroidx/compose/runtime/Composer;I)V
}
Expand Down Expand Up @@ -25,3 +31,13 @@ public final class com/mmk/kmpnotifier/sample/MainActivityKt {
public static final fun AppAndroidPreview (Landroidx/compose/runtime/Composer;I)V
}

public final class com/mmk/kmpnotifier/sample/MainApplication : android/app/Application {
public static final field $stable I
public fun <init> ()V
public fun onCreate ()V
}

public final class com/mmk/kmpnotifier/sample/Platform_androidKt {
public static final fun onApplicationStartPlatformSpecific ()V
}

1 change: 1 addition & 0 deletions sample/src/androidMain/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<application
android:allowBackup="true"
android:name=".MainApplication"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
package com.mmk.kmpnotifier.sample

import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.mmk.kmpnotifier.extensions.onCreateOrOnNewIntent
import com.mmk.kmpnotifier.notification.NotifierManager
import com.mmk.kmpnotifier.notification.configuration.NotificationPlatformConfiguration
import com.mmk.kmpnotifier.permission.AndroidPermissionUtil
import com.mmk.kmpnotifier.permission.permissionUtil

class MainActivity : ComponentActivity() {
private val permissionUtil: AndroidPermissionUtil by permissionUtil()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val permissionUtil by permissionUtil()
permissionUtil.askNotificationPermission()
NotifierManager.initialize(
configuration = NotificationPlatformConfiguration.Android(
notificationIconResId = R.drawable.ic_launcher_foreground,
)
)
NotifierManager.onCreateOrOnNewIntent(intent)
setContent {
App()
}
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
NotifierManager.onCreateOrOnNewIntent(intent)
}

}

@Preview
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.mmk.kmpnotifier.sample

import android.app.Application
import com.mmk.kmpnotifier.notification.NotifierManager
import com.mmk.kmpnotifier.notification.PayloadData
import com.mmk.kmpnotifier.notification.configuration.NotificationPlatformConfiguration

class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
AppInitializer.onApplicationStart()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mmk.kmpnotifier.sample

import com.mmk.kmpnotifier.notification.NotifierManager
import com.mmk.kmpnotifier.notification.configuration.NotificationPlatformConfiguration

actual fun onApplicationStartPlatformSpecific() {
NotifierManager.initialize(
configuration = NotificationPlatformConfiguration.Android(
notificationIconResId = R.drawable.ic_launcher_foreground,
)
)
}
12 changes: 6 additions & 6 deletions sample/src/commonMain/kotlin/com/mmk/kmpnotifier/sample/App.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.mmk.kmpnotifier.sample

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
Expand All @@ -13,19 +12,17 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.mmk.kmpnotifier.notification.NotifierManager
import kotlinx.coroutines.launch
import com.mmk.kmpnotifier.notification.PayloadData

@Composable
fun App() {
var myPushNotificationToken by remember { mutableStateOf("") }

LaunchedEffect(true) {
NotifierManager.addListener(object : NotifierManager.Listener {
override fun onNewToken(token: String) {
Expand All @@ -37,9 +34,12 @@ fun App() {
}



MaterialTheme {
Column (Modifier.fillMaxSize().padding(20.dp), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
Column(
Modifier.fillMaxSize().padding(20.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(onClick = {
val notifier = NotifierManager.getLocalNotifier()
notifier.notify("Title", "bodyMessage")
Expand Down
Loading

0 comments on commit 65b698d

Please sign in to comment.