40

I'm working an application and I need to use push notification. I know that push notification are a normal permission so I can't ask it at run time. But I would insert in the permission when the user downloads and installs the application, and the notice that the application should send a push notification.

How can I do it? Do I have to insert something in the manifest?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Paul
  • 511
  • 1
  • 5
  • 7
  • Possible duplicate : https://stackoverflow.com/questions/37294076/push-notifications-gcm-permission-at-runtime – Haresh Chhelana Jun 01 '17 at 10:37
  • You can replicate runtime behaviour by showing your own dialog and maintaining a `SharedPreference` to see if it granted or not.. – Veneet Reddy Jun 01 '17 at 10:40
  • Pushes and notifications 2 entirely different things on Android. It's unclear what you're asking about. – Agent_L Apr 05 '18 at 08:01

8 Answers8

57

UPDATE 2022

The way we request permissions on Android has changed drastically with Android 13. Please see other answers below that mention the same.


As answered here, you don't need permissions for push notifications.

Actually the push notification permission lie in the normal category permission like Internet permission, not in dangerous category permission.

You don't have to ask for push notification permissions.

While Contacts/Locations are the dangerous permissions because you are accessing user data. So it is always needed to ask the user to allow it.

https://developer.android.com/guide/topics/security/permissions.html

Kunal Chawla
  • 1,236
  • 2
  • 11
  • 24
  • 21
    It has changed. So now you must ask permission for notifications on Android 13+. There is a new API for that: https://developer.android.com/about/versions/13/changes/notification-permission – Agna JirKon Rx Jul 15 '22 at 17:21
  • 1
    You can install the app without permission, but if you don't ask for permission, by default, notifications will not be displayed. – Azhagthott Jan 12 '23 at 07:16
  • For android 12L and lower, what if one turns off the Post Notification permission, is it possible for the App to ask to re-enable it? – Elye Aug 23 '23 at 14:30
35

Here's the answer to new update: In API 33 we need runtime permission for push notification: Full documentation is available here but you can simply use like below :

in app level:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> 

you can trigger the prompt using this:

pushNotificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)

handle notification result:

private val pushNotificationPermissionLauncher = registerForActivityResult(RequestPermission()) { granted ->
            viewModel.inputs.onTurnOnNotificationsClicked(granted)
        }
0llie
  • 8,758
  • 2
  • 24
  • 13
Rax
  • 1,347
  • 3
  • 20
  • 27
  • Can I customize the text of this permission in the pop up dialogue? – IgorGanapolsky Sep 28 '22 at 18:17
  • As answered below, you do not need this permission at all for normal "background service" push notifications (ones for when the app is running on the device). You only POST_NOTIFICATIONS if attempting to send a notification while the app is not running. – Alan Nelson Apr 28 '23 at 14:47
23

Here is the complete example of how can you ask run time permission for notifications in Android 13 (Tiramisu)

First, add the below permission in your manifest file

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

Use the below code to ask for run time permission

package com.example.myapplication

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.BitmapFactory
import android.graphics.Color
import android.net.Uri
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import android.widget.Button
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.NotificationCompat
import com.google.android.material.dialog.MaterialAlertDialogBuilder

class MainActivity : AppCompatActivity() {

    private val notificationPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
            hasNotificationPermissionGranted = isGranted
            if (!isGranted) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (Build.VERSION.SDK_INT >= 33) {
                        if (shouldShowRequestPermissionRationale(android.Manifest.permission.POST_NOTIFICATIONS)) {
                            showNotificationPermissionRationale()
                        } else {
                            showSettingDialog()
                        }
                    }
                }
            } else {
                Toast.makeText(applicationContext, "notification permission granted", Toast.LENGTH_SHORT)
                    .show()
            }
        }

    private fun showSettingDialog() {
        MaterialAlertDialogBuilder(this, com.google.android.material.R.style.MaterialAlertDialog_Material3)
            .setTitle("Notification Permission")
            .setMessage("Notification permission is required, Please allow notification permission from setting")
            .setPositiveButton("Ok") { _, _ ->
                val intent = Intent(ACTION_APPLICATION_DETAILS_SETTINGS)
                intent.data = Uri.parse("package:$packageName")
                startActivity(intent)
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    private fun showNotificationPermissionRationale() {

        MaterialAlertDialogBuilder(this, com.google.android.material.R.style.MaterialAlertDialog_Material3)
            .setTitle("Alert")
            .setMessage("Notification permission is required, to show notification")
            .setPositiveButton("Ok") { _, _ ->
                if (Build.VERSION.SDK_INT >= 33) {
                    notificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
                }
            }
            .setNegativeButton("Cancel", null)
            .show()
    }

    var hasNotificationPermissionGranted = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<Button>(R.id.btnRequestPermission).setOnClickListener {
            if (Build.VERSION.SDK_INT >= 33) {
                notificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
            } else {
                hasNotificationPermissionGranted = true
            }
        }
        findViewById<Button>(R.id.btnShowNotification).setOnClickListener {
            if (checkSelfPermission(android.Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
                showNotification()
            }
        }
    }

    private fun showNotification() {

        val channelId = "12345"
        val description = "Test Notification"

        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val notificationChannel =
                NotificationChannel(channelId, description, NotificationManager.IMPORTANCE_HIGH)
            notificationChannel.lightColor = Color.BLUE

            notificationChannel.enableVibration(true)
            notificationManager.createNotificationChannel(notificationChannel)

        }

        val  builder = NotificationCompat.Builder(this, channelId)
            .setContentTitle("Hello World")
            .setContentText("Test Notification")
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setLargeIcon(
                BitmapFactory.decodeResource(
                    this.resources, R.drawable
                        .ic_launcher_background
                )
            )
        notificationManager.notify(12345, builder.build())
    }
}

If you using jetpack compose then user below code

class MainActivity : ComponentActivity() {

  @RequiresApi(VERSION_CODES.M)
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContent {
      JetpackComposeNotifcationPermissionTheme {
        val context = LocalContext.current
        val permissionOpenDialog = remember { mutableStateOf(false) }
        val rationalPermissionOpenDialog = remember { mutableStateOf(false) }

        if (permissionOpenDialog.value) {
          ShowSettingDialog(openDialog = permissionOpenDialog)
        }

        var hasNotificationPermission by remember {
          if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            mutableStateOf(
              ContextCompat.checkSelfPermission(
                context,
                Manifest.permission.POST_NOTIFICATIONS
              ) == PackageManager.PERMISSION_GRANTED
            )
          } else mutableStateOf(true)
        }

        val launcher = rememberLauncherForActivityResult(
          contract = ActivityResultContracts.RequestPermission(),
          onResult = { isGranted ->
            if (!isGranted) {
              if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
                rationalPermissionOpenDialog.value = true
              } else {
                permissionOpenDialog.value = true
              }
            } else {
              hasNotificationPermission = isGranted
            }
          }
        )
        if (rationalPermissionOpenDialog.value) {
          ShowRationalPermissionDialog(openDialog = rationalPermissionOpenDialog) {
            rationalPermissionOpenDialog.value = false
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
              launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
            }
          }
        }


        Column(
          modifier = Modifier.fillMaxSize(),
          verticalArrangement = Arrangement.Center,
          horizontalAlignment = Alignment.CenterHorizontally
        ) {
          Button(onClick = {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
              launcher.launch(Manifest.permission.POST_NOTIFICATIONS)
            }
          }) {
            Text(text = "Request permission")
          }
          Button(onClick = {
            if (hasNotificationPermission) {
              showNotification()
            }
          }) {
            Text(text = "Show notification")
          }
        }
      }
    }
  }

  private fun showNotification() {
    val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val channelId = "12345"
    val description = "Test Notification"

    if (VERSION.SDK_INT >= VERSION_CODES.O) {
      val notificationChannel =
        NotificationChannel(channelId, description, NotificationManager.IMPORTANCE_HIGH)
      notificationChannel.lightColor = Color.BLUE

      notificationChannel.enableVibration(true)
      notificationManager.createNotificationChannel(notificationChannel)
    }
    val notification = NotificationCompat.Builder(applicationContext, channelId)
      .setSmallIcon(R.drawable.ic_launcher_foreground)
      .setContentTitle("Hello Nilesh")
      .setContentText("Test Notification")
      .build()
    notificationManager.notify(1, notification)
  }

  @Composable
  fun ShowSettingDialog(openDialog: MutableState<Boolean>) {
    if (openDialog.value) {
      AlertDialog(
        onDismissRequest = {
          openDialog.value = false
        },
        title = {
          Text(text = "Notification Permission")
        },
        text = {
          Text("Notification permission is required, Please allow notification permission from setting")
        },

        buttons = {
          Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.End,
            verticalAlignment = Alignment.CenterVertically,
          ) {
            TextButton(
              onClick = {
                openDialog.value = false
              }
            ) {
              Text("Cancel")
            }
            Spacer(modifier = Modifier.width(20.dp))
            TextButton(
              onClick = {
                openDialog.value = false
                val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                intent.data = Uri.parse("package:$packageName")
                startActivity(intent)
              },
            ) {
              Text("Ok")
            }
          }

        },
      )
    }
  }

  @Composable
  fun ShowRationalPermissionDialog(openDialog: MutableState<Boolean>, onclick: () -> Unit) {
    if (openDialog.value) {
      AlertDialog(
        onDismissRequest = {
          openDialog.value = false
        },
        title = {
          Text(text = "Alert")
        },
        text = {
          Text("Notification permission is required, to show notification")
        },

        buttons = {
          Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.End,
            verticalAlignment = Alignment.CenterVertically,
          ) {
            TextButton(
              onClick = {
                openDialog.value = false
              }
            ) {
              Text("Cancel")
            }
            Spacer(modifier = Modifier.width(20.dp))
            TextButton(
              onClick = onclick,
            ) {
              Text("Ok")
            }
          }

        },
      )
    }
  }
}
NickUnuchek
  • 11,794
  • 12
  • 98
  • 138
AskNilesh
  • 67,701
  • 16
  • 123
  • 163
  • Android 13 permission push notification dialog is popping up itself without asking any permission in menifest. Do we still need to request runtime permission. – waheed shah Jan 16 '23 at 07:09
  • @waheedshah If targetSdk 33 you have to integrate run time permission and if targetSdk 32 or lower automatically app will ask for the permission. – Abhishek kumar Jan 18 '23 at 06:09
  • What should happen if the user clicks "Skip" in the sample screens : https://developer.android.com/develop/ui/views/notifications/notification-permission#wait-to-show-prompt ? Will shouldShowRequestPermissionRationale return next time true again and the user will see this rationale page again? – Saftpresse99 Jan 25 '23 at 08:43
  • 1
    Thank you for this. I have been trying to come up with a way to cleanly ask for this based on the official docs but been having a lot of issues with compose and trying to figure out if I needed to launch a whole new composable screen, or what. This was extremely helpful!!! – Neglected Sanity May 25 '23 at 18:18
14

If your app targets Android 13 (Tiramisu) or higher, you must declare the POST_NOTIFICATIONS permission as follows:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

For more details, see the Notification runtime permission page in the Android Developers documentation.

Adil Hussain
  • 30,049
  • 21
  • 112
  • 147
Ercan Akkök
  • 458
  • 5
  • 7
3
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>// add this to menifest file

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        if (ActivityCompat.checkSelfPermission(this,Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
        
            requestPermissions(new String[] {Manifest.permission.POST_NOTIFICATIONS}, 1);

    } 
    else {
      // repeat the permission or open app details
     }
    }
1

Two line solution

 int permissionState = ContextCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS);
    // If the permission is not granted, request it.
    if (permissionState == PackageManager.PERMISSION_DENIED) {
        ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.POST_NOTIFICATIONS}, 1);
    }
0

I use https://github.com/zoontek/react-native-permissions

import {requestNotifications} from 'react-native-permissions';

await requestNotifications(['alert', 'badge', 'sound']);

and add

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> 

to androidManifest.xml

-4

Try this:

In your Activity class, add the below code:

private static final int NOTIFICATION_PERMISSION_CODE = 123;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_activity);

    requestNotificationPermission();

    // Some code
}

 private void requestNotificationPermission() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NOTIFICATION_POLICY) == PackageManager.PERMISSION_GRANTED)
        return;

    if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_NOTIFICATION_POLICY)) {

    }

    ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_NOTIFICATION_POLICY}, NOTIFICATION_PERMISSION_CODE );
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    // Checking the request code of our request
    if (requestCode == NOTIFICATION_PERMISSION_CODE ) {

        // If permission is granted
        if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            // Displaying a toast
            Toast.makeText(this, "Permission granted now you can read the storage", Toast.LENGTH_LONG).show();
        } else {
            // Displaying another toast if permission is not granted
            Toast.makeText(this, "Oops you just denied the permission", Toast.LENGTH_LONG).show();
        }
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Fakhriddin Abdullaev
  • 4,169
  • 2
  • 35
  • 37