How do I prompt for Push Notification permissions on Android?

I’ve got push notifications working on iOS but on Android it doesn’t prompt for permission. I see the following comment in the code sample in the Push Notification documentation:

// Android remote notification permissions are granted during the app
// install, so this will only ask on iOS

But I don’t see any mention of how to actually configure Android so that the permission prompt happens. Do I need to add something to app.json?

Having you tried sending a test notification to the Android device? IIUC it should Just Work as long as you granted permissions during installation.

That’s the whole problem, I don’t know how to make it prompt for the permission during install. I don’t see anything in the Expo documentation for how to tell Android that the app requires push notification permission. Is there something I’m supposed to put in app.json?

AFAIK this is handled for you during our build process. Have you confirmed that you’re unable to receive push notifications on the device with your APK installed?

How am I supposed to do that? It never promoted for permission so I never got a device token so I don’t have anything to send to.

Does your code call https://docs.expo.io/versions/latest/sdk/notifications.html#exponotificationsgetexpopushtokenasync ?

Yes, I literally copied and pasted from here: https://docs.expo.io/versions/v19.0.0/guides/push-notifications.html

OK, cool. How far does the example code make it before you hit a problem?

Immediately? I’m sorry I feel like I’m not being clear. I used the code from the documentation as is and when I install my app on an android phone it never asks for push notification permissions so I never get a device token. Is this code supposed to work? Like, from a completely brand new app, if you include that code, should it work out of the box? Or is there something else that needs to be done so android knows to prompt for permission on install?

Can you take a look at this snack I made with the code from the docs and let me know how what you’re doing differs?

My code is almost exactly the same except I make the call to Permissions.getAsync(Permissions.NOTIFICATIONS) in my root component’s componentDidMount function (and via a Redux action) rather than the constructor. Here is the exact code from my Redux action:


export function registerDevice(){
    return async (dispatch, getState) => {
        const { session } = getState();
        if(session && session.authToken){

            const userId = session.user.id;

            dispatch(registerDeviceRequest(userId));

            Log.info('requesting notification permissions', userId);

            const { existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
            let finalStatus = existingStatus;

            Log.info(existingStatus);

            // only ask if permissions have not already been determined, because
            // iOS won't necessarily prompt the user a second time.
            if (existingStatus !== 'granted') {
                // Android remote notification permissions are granted during the app install, so this will only ask on iOS
                const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
                finalStatus = status;
            }

            // Stop here if the user did not grant permissions
            if (finalStatus !== 'granted') {
                return;
            }

            // Get the token that uniquely identifies this device
            let token = await Notifications.getExpoPushTokenAsync();

            // POST the token to our backend so we can use it to send pushes from there
            Log.info(finalStatus, token);

            return new NotificationActionHandler(session.authToken)
            .registerDevice(session.user.id, token)
            .then(response => {
                Log.debug('success');
                dispatch(registerDeviceSuccess(userId));
            })
            .catch(error => {
                Log.debug('catching error', error.message || error);
                dispatch(registerDeviceError(userId, error.message || 'Could not register device.'));
            });

        }
    };

}

@dikaiosune I’ve tried the snack and experienced what I can best describe as the red flash of an error before seeing my device’s expo push token (tested on a Samsung Galaxy S6). Why is there no “NOTIFICATIONS” permissions for android available for the app.json config?

@dikaiosune How does the Expo build process determine that I’m calling Notifications.getExpoPushTokenAsync? Does it do some sort of grep to find that code? Or do I need to be calling it at a more root level than where I have it (in a Redux action, behind some other conditions)?

@ryanvanderpol on Android, we ask for permission at installation (EDIT: I’ll need to check with our Android dev about why this isn’t listed: unless you exclude it using app.json), on iOS it’s a runtime permissions request.

@dikaiosune so, you’re saying it’s hard-coded to ask for push notification permission for every single Android app? Cause I can guarantee you my app did NOT ask for it when I installed it (on multiple devices, including a Galaxy S6 and a Galaxy S7).

Hm, interesting. @jesse do you know what’s up here? (note that Jesse is out of the office for a couple of days, reply might be delayed)

Here is a screenshot of the install screen on an S7:

@dikaiosune @jesse Any update here? We’re trying to release this app next week and I need this to work.

Sorry for the delay here – our Android lead is out of the office at the moment, but he’ll be back early next week.

I’m still unclear about what actual behavior you’re seeing with failing to retrieve the push notification token. Maybe you could record a video demonstrating how it’s failing? Or paste the error message you’re getting?

I’m sorry, I’m really not sure how to make this more clear. You said specifically that the android build process is hard coded to request push notification permission for every app that is built with exp build:android. I just posted a screenshot that shows that my app does NOT request that permission when installed. My iOS app works fine, but my android app never asked for push notification permission, so there’s no way to get the token. I’m really not sure how to be more clear.