Standalone iOS, Ejected App - Push Notification

I am trying to get the device push token (not expo token) so we can configure push notifications. I saw this PR and when calling

const token = await Notifications.getDevicePushTokenAsync();

The promise is failing.

Error: APNS token has not been set

The app has the push entitlement set, I am actually getting a token in the didRegisterForRemoteNotificationsWithDeviceToken delegate in objc in the same project (if I temporarily disable the Expo inits). Is there something I need to call to register it? It looks like it reads the apns from NSUserDefaults, but I didn’t see where registerForRemoteNotifications was called and then captured and stored that.

Thanks!

That is correct that the device token is read from NSUserDefaults for iOS. You’ll need to request remote notification permissions first Permissions.askAsync(Permissions.REMOTE_NOTIFICATIONS) and then call Notifications.getDevicePushTokenAsync()

Here’s a snippet of what worked for me:

// push-notifications.js
import {
    Permissions,
    Notifications
} from 'expo';

export async function registerForPushNotificationsAsync () {
    const status = await Permissions.askAsync(Permissions.REMOTE_NOTIFICATIONS)
        .then(({ status }) => status);
    if (status === 'granted') {
        const [expoToken, deviceToken] = await Promise.all([
            Notifications.getExponentPushTokenAsync(),
            Notifications.getDevicePushTokenAsync()
        ]);
        return {
            expoToken,
            deviceToken,
        };
    }

    const error = new Error('Permission denied');
    error.status = status;
    throw error;
}

And then elsewhere:

import { registerForPushNotificationsAsync } from '@something/push-notifications';

// ...
const { expoToken, deviceToken } = await registerForPushNotificationsAsync();
const { data: platformToken } = deviceToken;
// Do stuff with your deviceToken
// Also, handle your errors :) 
1 Like

Permissions.askAsync(Permissions.REMOTE_NOTIFICATIONS) sometimes takes forever, meaning the promise won’t resolve and won’t reject, any idea why?

1 Like

@nirpeled What SDK version are you using? I ran into this in the past too - maybe this will help: https://github.com/expo/expo/issues/101

@mglagola Thanks for the response. I am still getting the rejection but I jumped into the objc code some more to debug. In EXRemoteNotificationManager.m , registerForRemoteNotifications

#ifdef EX_DETACHED
//  DDLogWarn(@"Expo Remote Notification services won't work in an ExpoKit app because Expo can not manage your APNS certificates.");
#else
  // don't register, because the detached app may not be built with APNS entitlements,
  // and in that case this method would actually be bad to call. (not just a no-op.)
  [RCTSharedApplication() registerForRemoteNotifications];
#endif

[RCTSharedApplication() registerForRemoteNotifications] (as well as didFail) is never going to be called. I commented out the #def however the didRegisterForRemoteNotificationsWithDeviceToken delegate is never called in ExpoKit.m, which is where the token is set in NSUserDefaults that the js function you wrote is called. Whats interesting is that if I drop didRegisterForRemoteNotificationsWithDeviceToken delegate in the AppDelegate.m in its indeed called, and when commenting that out again, the delegate in ExpoKit.m is not called. I think I am where ExpoKit.m is set as the delegate for didRegisterForRemoteNotificationsWithDeviceToken.

I’m using Expo version 19

@mylescaley I think I am having the same issue as you do, have you found a workaround?

I’m having the same problem on SDK 22. Have anyone found a fix or a workaround?

Running into the same issue on SDK 25. Has anyone found a fix/workaround yet? Halp please!

Also experiencing this issue on SDK 26. I will update with results here.

Same issue here with SDK 31. Has anyone been able to find a solution for this?

You guys are better off using Expo firebase