6

Due to the recent changes in Notification permissions in the Android 13 SDK, I need to update my app with FCM integration to obey the notifications rule. I have upgraded the compileSdk to 33 and also the targetSdk to 33. I have written code to ask POST_NOTIFICATIONS and the prompt appears. On pressing "Allow" the Notification Permission is enabled. But on sending a push notification the app receives no notification.

I only made changes in asking for the notification permission. Did not change anything in FirebaseMessagingService Class. The app was previously targetSdk 30.

class MyFirebaseMessagingService : FirebaseMessagingService() {
var intent: Intent? = null
var badgecount: Int = 0

override fun onMessageReceived(remoteMessage: RemoteMessage) {

    if (remoteMessage.data.isNotEmpty()) {
        try {
            val json = JSONObject(remoteMessage.data.toString())
            handleDataMessage(json)
        } catch (e: Exception) {
            Log.e("FIREBASEEXCEPTION:", e.message.toString())

        }
    }

    if (remoteMessage.notification != null) {
        sendNotification(remoteMessage.notification!!.body)
        println("Message Notification Body:" + remoteMessage.notification!!.body)

    }
    super.onMessageReceived(remoteMessage)
}
private fun handleDataMessage(json: JSONObject) {
    try {
        val data = json.getJSONObject("body")
        val badge = data.getString("badge")
        val message = data.getString("message")
        Log.e("FIREBASE_MSG:", message)
        badgecount = badge.toInt()
        sendNotification(message)
    } catch (e: JSONException) {
        Log.e("JSONEXCEPTION:", e.message.toString())
    } catch (e: java.lang.Exception) {
    }
}
@SuppressLint("ObsoleteSdkInt")
private fun sendNotification(messageBody: String?) {
    ShortcutBadger.applyCount(this, badgecount)
    intent = Intent(this, HomeActivity::class.java)
    intent!!.action = System.currentTimeMillis().toString()
    intent!!.putExtra("Notification_Recieved", 1)
    val notId = NotificationID.getID()
    val stackBuilder = TaskStackBuilder.create(this)
    stackBuilder.addNextIntentWithParentStack(intent!!)
    val pendingIntent = stackBuilder.getPendingIntent(notId, PendingIntent.FLAG_UPDATE_CURRENT)
    val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
    val notificationBuilder =
        NotificationCompat.Builder(this)
            .setContentTitle(resources.getString(R.string.app_name))
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)
    val notificationManager =
        getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel_id = getString(R.string.app_name) + "_01"
        val name: CharSequence = getString(R.string.app_name)
        val importance = NotificationManager.IMPORTANCE_HIGH
        val mChannel = NotificationChannel(channel_id, name, importance)
        notificationBuilder.setChannelId(mChannel.id)
        mChannel.setShowBadge(true)
        mChannel.canShowBadge()
        mChannel.enableLights(true)
        mChannel.lightColor = resources.getColor(R.color.split_bg)
        mChannel.enableVibration(true)
        mChannel.vibrationPattern = longArrayOf(100, 200, 300, 400, 500)
        notificationManager.createNotificationChannel(mChannel)
    }


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        notificationBuilder.setSmallIcon(R.drawable.notify_small)
        notificationBuilder.color = resources.getColor(R.color.split_bg)
    } else {
        notificationBuilder.setSmallIcon(R.drawable.nas_large)
        notificationBuilder.color = resources.getColor(R.color.split_bg)
    }

    notificationManager.notify(notId, notificationBuilder.build())

}
}

class MyFirebaseInstanceIDService : FirebaseInstanceIdService() {
    var mContext: Context = this
    override fun onTokenRefresh() {

        //val refreshedToken = FirebaseInstanceId.getInstance().token

        val refreshedToken = FirebaseInstanceId.getInstance().token.toString()

        Log.e("FIREBASETOKEN", refreshedToken)
        sendRegistrationToServer(refreshedToken)
        super.onTokenRefresh()
    }

    private fun sendRegistrationToServer(refreshedToken: String) {
        if (refreshedToken != null) {
            PreferenceManager.setFcmID(mContext, refreshedToken)
        }

    }
}

And in manifest

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<service
            android:name=".fcm.MyFirebaseMessagingService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        <service android:name=".fcm.MyFirebaseInstanceIDService"
            android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
Sanju Sabu
  • 61
  • 1
  • 4
  • add some code of manifest , your message handling etc .. – jayesh gurudayalani Feb 08 '23 at 09:31
  • edited in Question, Thank you – Sanju Sabu Feb 08 '23 at 10:27
  • Have you requested the permission programmatically? – Zain Feb 08 '23 at 10:41
  • Yes, I have and the prompt comes up. – Sanju Sabu Feb 08 '23 at 10:47
  • Can you upgrade the firebase messaging dependencies and see – Zain Feb 08 '23 at 11:02
  • This might be helpful: https://stackoverflow.com/questions/61646186/not-receiving-firebase-cloud-push-notifications-in-android-app/61679827#61679827 – MarkWalczak Feb 08 '23 at 12:34
  • Have you updated your implementation based on this [guide](https://firebase.google.com/docs/cloud-messaging/android/first-message#kotlin+ktx)? – Yuji Bry Feb 08 '23 at 15:47
  • @Zain I have upgraded the firebase dependencies. – Sanju Sabu Feb 14 '23 at 06:17
  • @YujiBry We followed the same guide. – Sanju Sabu Feb 14 '23 at 06:18
  • Hey @SanjuSabu, did you use `targetSdk` 33 in your `build.gradle` of the app module? – Vall0n Mar 24 '23 at 10:53
  • @Vall0n Yes, I have upgraded to targetSdk 33. – Sanju Sabu Apr 10 '23 at 06:37
  • @SanjuSabu Just setting the `targetSdk` to 33 alone does not solve your issue. You have to request the permission during runtime by yourself. See [best practices](https://developer.android.com/develop/ui/views/notifications/notification-permission#best-practices) and here for [requesting a permission](https://developer.android.com/training/permissions/requesting#request-permission). Just to test your notification service you can manually allow the notification permission for your app from the app settings. – Vall0n Apr 11 '23 at 17:34
  • How come I don't see any related changes in this article? https://developer.android.com/about/versions/13/behavior-changes-13 – Kimi Chiu Jul 08 '23 at 10:08

2 Answers2

3

With the permission on the Manifest file, you also need to ask for Notification Runtime permissions

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
private val requestPermissionLauncher = registerForActivityResult(
    ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
    if (isGranted) {
        // Can post notifications.
    } else {
        // Inform user that that your app will not show notifications.
    }
}

private fun askNotificationPermission() {
    // This is only necessary for API level >= 33 (TIRAMISU)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) ==
            PackageManager.PERMISSION_GRANTED
        ) {
            // Can post notifications.
        } else if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
            // Display an educational UI explaining to the user the features that will be enabled
            //       by them granting the POST_NOTIFICATION permission. This UI should provide the user
            //       "OK" and "No thanks" buttons. If the user selects "OK," directly request the permission.
            //       If the user selects "No thanks," allow the user to continue without notifications.
        } else {
            // Directly ask for the permission
            requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
        }
    }
}

You can also check if notifications are enabled or not

val notificationManager = getSystemService(NotificationManager::class.java)
val isEnabled = notificationManager.areNotificationsEnabled()

If you faced the problem that is permission Manifest.permission.POST_NOTIFICATIONS not resolved make sure you have this import

import android.Manifest
AmrDeveloper
  • 3,826
  • 1
  • 21
  • 30
1

It depends on the targetSdk in use. So for targeting android 13 (API Level 33) notifications are off by default. See below from the android notification-permission documentation. At least for newly installed apps.

If a user installs your app on a device that runs Android 13 or higher, your app's notifications are off by default. Your app must wait to send notifications until after you request the new permission and the user grants that permission to your app.

The time at which the permissions dialog appears is based on your app's target SDK version:

If your app targets Android 13 or higher, your app has complete control over when the permission dialog is displayed. Use this opportunity to explain to users why the app needs this permission, encouraging them to grant it.

If your app targets 12L (API level 32) or lower, the system shows the permission dialog the first time your app starts an activity after you create a notification channel, or when your app starts an activity and then creates its first notification channel. This is usually on app startup.

Vall0n
  • 1,601
  • 2
  • 14
  • 19