diff --git a/README.md b/README.md index 2afdf74..b320a2d 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,12 @@ You can check out [Documentation](https://mirzemehdi.github.io/KMPNotifier) for ## Installation Before starting you need to setup basic setup using Firebase official guideline (like initializing project in Firebase, adding `google-services.json` to android, `GoogleService-Info.plist` to iOS). +## Minimum Requirements + +- **Android:** `minSdkVersion 21` +- **iOS:** `iOS 14.1` + + ### 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 add `google-services` plugin to plugins. diff --git a/build.gradle.kts b/build.gradle.kts index 165699c..91acc0c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ plugins { allprojects { group = "io.github.mirzemehdi" - version = "0.2.0" + version = "0.3.0" val sonatypeUsername = gradleLocalProperties(rootDir).getProperty("sonatypeUsername") val sonatypePassword = gradleLocalProperties(rootDir).getProperty("sonatypePassword") val gpgKeySecret = gradleLocalProperties(rootDir).getProperty("gpgKeySecret") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index bcc95d8..4685863 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ compose = "1.5.4" compose-plugin = "1.5.11" compose-compiler = "1.5.4" agp = "8.1.3" -android-minSdk = "24" +android-minSdk = "21" android-compileSdk = "34" android-targetSdk = "34" androidx-activityCompose = "1.8.0" diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 2ff1300..00ed97f 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -337,7 +337,7 @@ "$(SRCROOT)/../sample/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", ); INFOPLIST_FILE = iosApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -368,7 +368,7 @@ "$(SRCROOT)/../sample/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)", ); INFOPLIST_FILE = iosApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 16.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/kmpnotifier/api/kmpnotifier.api b/kmpnotifier/api/kmpnotifier.api index 2424ee1..7c5d682 100644 --- a/kmpnotifier/api/kmpnotifier.api +++ b/kmpnotifier/api/kmpnotifier.api @@ -3,7 +3,10 @@ public final class com/mmk/kmpnotifier/extensions/NotifierManagerExtKt { } public abstract interface class com/mmk/kmpnotifier/notification/Notifier { - public abstract fun notify (Ljava/lang/String;Ljava/lang/String;)V + public abstract fun notify (ILjava/lang/String;Ljava/lang/String;)V + public abstract fun notify (Ljava/lang/String;Ljava/lang/String;)I + public abstract fun remove (I)V + public abstract fun removeAll ()V } public final class com/mmk/kmpnotifier/notification/NotifierManager { diff --git a/kmpnotifier/build.gradle.kts b/kmpnotifier/build.gradle.kts index f42a208..52f9275 100644 --- a/kmpnotifier/build.gradle.kts +++ b/kmpnotifier/build.gradle.kts @@ -23,7 +23,7 @@ kotlin { cocoapods { - ios.deploymentTarget = "11.0" + ios.deploymentTarget = "14.1" framework { baseName = "KMPNotifier" isStatic = true diff --git a/kmpnotifier/src/androidMain/kotlin/com/mmk/kmpnotifier/notification/AndroidNotifier.kt b/kmpnotifier/src/androidMain/kotlin/com/mmk/kmpnotifier/notification/AndroidNotifier.kt index 89cccbd..fd25aa9 100644 --- a/kmpnotifier/src/androidMain/kotlin/com/mmk/kmpnotifier/notification/AndroidNotifier.kt +++ b/kmpnotifier/src/androidMain/kotlin/com/mmk/kmpnotifier/notification/AndroidNotifier.kt @@ -20,11 +20,19 @@ internal class AndroidNotifier( private val permissionUtil: PermissionUtil, ) : Notifier { - override fun notify(title: String, body: String) { + override fun notify(title: String, body: String): Int { + val notificationID = Random.nextInt(0,Int.MAX_VALUE) + notify(notificationID, title, body) + return notificationID + } + + override fun notify(id: Int, title: String, body: String) { permissionUtil.hasNotificationPermission { if (it.not()) - Log.w("AndroidNotifier", "You need to ask runtime " + - "notification permission (Manifest.permission.POST_NOTIFICATIONS) in your activity") + Log.w( + "AndroidNotifier", "You need to ask runtime " + + "notification permission (Manifest.permission.POST_NOTIFICATIONS) in your activity" + ) } val notificationManager = context.notificationManager ?: return val pendingIntent = getPendingIntent() @@ -44,9 +52,17 @@ internal class AndroidNotifier( } }.build() + notificationManager.notify(id, notification) + } - val notificationID = Random.nextInt() - notificationManager.notify(notificationID, notification) + override fun remove(id: Int) { + val notificationManager = context.notificationManager ?: return + notificationManager.cancel(id) + } + + override fun removeAll() { + val notificationManager = context.notificationManager ?: return + notificationManager.cancelAll() } private fun getPendingIntent(deepLink: String = ""): PendingIntent? { diff --git a/kmpnotifier/src/commonMain/kotlin/com/mmk/kmpnotifier/notification/Notifier.kt b/kmpnotifier/src/commonMain/kotlin/com/mmk/kmpnotifier/notification/Notifier.kt index a94b561..663fd21 100644 --- a/kmpnotifier/src/commonMain/kotlin/com/mmk/kmpnotifier/notification/Notifier.kt +++ b/kmpnotifier/src/commonMain/kotlin/com/mmk/kmpnotifier/notification/Notifier.kt @@ -9,6 +9,29 @@ public interface Notifier { * Sends local notification to device * @param title Title part * @param body Body part + * @return notification id */ - public fun notify(title: String, body: String) + public fun notify(title: String, body: String): Int + + /** + * Sends local notification to device with id + * @param id notification id + * @param title Title part + * @param body Body part + */ + public fun notify(id:Int, title: String, body: String) + + + + /** + * Remove notification by id + * @param id notification id + */ + public fun remove(id:Int) + + /** + * Removes all previously shown notifications + * @see remove(id) for removing specific notification. + */ + public fun removeAll() } \ No newline at end of file diff --git a/kmpnotifier/src/iosMain/kotlin/com/mmk/kmpnotifier/notification/IosNotifier.kt b/kmpnotifier/src/iosMain/kotlin/com/mmk/kmpnotifier/notification/IosNotifier.kt index 2dc4ca7..d271e12 100644 --- a/kmpnotifier/src/iosMain/kotlin/com/mmk/kmpnotifier/notification/IosNotifier.kt +++ b/kmpnotifier/src/iosMain/kotlin/com/mmk/kmpnotifier/notification/IosNotifier.kt @@ -12,13 +12,21 @@ import platform.UserNotifications.UNTimeIntervalNotificationTrigger import platform.UserNotifications.UNUserNotificationCenter import platform.UserNotifications.UNUserNotificationCenterDelegateProtocol import platform.darwin.NSObject +import kotlin.random.Random internal class IosNotifier( private val permissionUtil: IosPermissionUtil, private val notificationCenter: UNUserNotificationCenter, ) : Notifier { - override fun notify(title: String, body: String) { + + override fun notify(title: String, body: String): Int { + val notificationID = Random.nextInt(0, Int.MAX_VALUE) + notify(notificationID, title, body) + return notificationID + } + + override fun notify(id: Int, title: String, body: String) { permissionUtil.askNotificationPermission { val notificationContent = UNMutableNotificationContent().apply { setTitle(title) @@ -27,7 +35,7 @@ internal class IosNotifier( } val trigger = UNTimeIntervalNotificationTrigger.triggerWithTimeInterval(1.0, false) val notificationRequest = UNNotificationRequest.requestWithIdentifier( - identifier = "general-notification-id", + identifier = id.toString(), content = notificationContent, trigger = trigger ) @@ -36,7 +44,14 @@ internal class IosNotifier( error?.let { println("Error showing notification: $error") } } } + } + + override fun remove(id: Int) { + notificationCenter.removeDeliveredNotificationsWithIdentifiers(listOf(id.toString())) + } + override fun removeAll() { + notificationCenter.removeAllDeliveredNotifications() } internal class NotificationDelegate : UNUserNotificationCenterDelegateProtocol, NSObject() { @@ -60,7 +75,7 @@ internal class IosNotifier( ) { // FIRMessaging.messaging() // .appDidReceiveMessage(didReceiveNotificationResponse.notification.request.content.userInfo) - val userInfo =willPresentNotification.request.content.userInfo + val userInfo = willPresentNotification.request.content.userInfo NotifierManager.onApplicationDidReceiveRemoteNotification(userInfo) withCompletionHandler(IosPermissionUtil.NOTIFICATION_PERMISSIONS) } diff --git a/sample/api/sample.api b/sample/api/sample.api index 2d4cb03..3ae303e 100644 --- a/sample/api/sample.api +++ b/sample/api/sample.api @@ -11,8 +11,10 @@ public final class com/mmk/kmpnotifier/sample/AppKt { public final class com/mmk/kmpnotifier/sample/ComposableSingletons$AppKt { public static final field INSTANCE Lcom/mmk/kmpnotifier/sample/ComposableSingletons$AppKt; public static field lambda-1 Lkotlin/jvm/functions/Function3; + public static field lambda-2 Lkotlin/jvm/functions/Function3; public fun ()V public final fun getLambda-1$sample_release ()Lkotlin/jvm/functions/Function3; + public final fun getLambda-2$sample_release ()Lkotlin/jvm/functions/Function3; } public final class com/mmk/kmpnotifier/sample/ComposableSingletons$MainActivityKt { diff --git a/sample/src/commonMain/kotlin/com/mmk/kmpnotifier/sample/App.kt b/sample/src/commonMain/kotlin/com/mmk/kmpnotifier/sample/App.kt index a3979e2..98d6c94 100644 --- a/sample/src/commonMain/kotlin/com/mmk/kmpnotifier/sample/App.kt +++ b/sample/src/commonMain/kotlin/com/mmk/kmpnotifier/sample/App.kt @@ -18,7 +18,6 @@ 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 com.mmk.kmpnotifier.notification.PayloadData @Composable fun App() { @@ -40,13 +39,24 @@ fun App() { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center ) { + val notifier = remember { NotifierManager.getLocalNotifier() } + var notificationId by remember { mutableStateOf(0) } Button(onClick = { - val notifier = NotifierManager.getLocalNotifier() - notifier.notify("Title", "bodyMessage") - + notificationId = notifier.notify("Title", "bodyMessage") }) { Text("Send Local Notification") } + Button(onClick = {notifier.removeAll()}) { + Text("Remove all notifications") + } + + Button(enabled = notificationId != 0, onClick = { + notifier.remove(notificationId) + notificationId = 0 + }) { + Text("Remove NotificationID #$notificationId") + } + Text( modifier = Modifier.padding(20.dp), text = "FirebaseToken: $myPushNotificationToken",