iOS Push Notification problems: "APNS token has not been set" on second run. SDK v31
See original GitHub issueEnvironment
Expo CLI 2.6.0 environment info:
System:
OS: macOS 10.14
Shell: 5.5.1 - /usr/local/bin/zsh
Binaries:
Node: 8.11.3 - /usr/local/bin/node
Yarn: 1.10.1 - /usr/local/bin/yarn
npm: 5.6.0 - /usr/local/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
IDEs:
Xcode: 10.1/10B61 - /usr/bin/xcodebuild
npmPackages:
expo: ^31.0.2 => 31.0.6
react: 16.5.0 => 16.5.0
react-native: https://github.com/expo/react-native/archive/sdk-31.0.0.tar.gz => 0.57.1
npmGlobalPackages:
expo-cli: 2.6.0
iOS 12, ejected ExpoKit app. Tested on iPhone 6S, 6 Plus, 7 Plus and XR.
Steps to Reproduce
I apologize that this is a bit tedious to reproduce, mostly because you need to setup all the necessary push notification certificates and provisioning profiles with Apple for your associated bundle id. Here’s a guide. Once that is done, these are the necessary steps to reproduce it.
-
initialize a new project with
expo init
, then runexpo eject
and choose the expokit option. Enter your bundle id that you used when configuring push notifications with Apple. -
Run the usual
pod update && pod install
. -
Replace app.js with the following:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { Permissions, Notifications } from 'expo';
async function registerForPushNotificationsAsync() {
const { status: existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
let finalStatus = 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.getDevicePushTokenAsync();
return token;
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
token: { status: 'no token' },
};
}
componentDidMount() {
this.getToken();
}
async getToken() {
const token = await registerForPushNotificationsAsync();
this.setState({ token });
}
render() {
return (
<View style={styles.container}>
<Text>Token: {JSON.stringify(this.state.token)}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
-
Open the xcode workspace, enable push notifications under entitlements, uncheck
Debug executable
inproduct > scheme
and run the project on an iOS device. -
Give push notification permissions when asked, and verify that your token is printed on the screen.
-
Close the app (don’t just background it, you need to actually close it).
-
Reopen the app, and notice the warning:
APNS token has not been set
, even though status isgranted
. Notifications are not received within the app at this point. They still work if the app is backgrounded or closed.
Expected Behavior
Token is returned from registerForPushNotificationsAsync
on subsequent runs.
Actual Behavior
Unhandled Promise Rejection: Error: APNS token has not been set. No token is returned.
Reproducible Demo
See reproduction steps.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:13 (5 by maintainers)
For anyone else who stumbles here from google, I was able to get the actual APNS token by adding
[application registerForRemoteNotifications]
to my AppDelegate.m(Of note, I do not have the code that PushNotificationIOS tells you to add to the AppDelegate.m - I was having conflicts with ExpoKit and AppDelegate.m both trying to declare handlers for notifications.
then in my JS code, I can call:
that returns
{ "type": "apns", "data": "<32 byte apns token>" }
I’m then able to handle notifications with:
Notifications.addListener(this._handleNotification)
And, additionally, the notification sent to APNS has to be of a certain form because ExpoKit does some validation of the notification. I believe this is a private API, so things may change in the future, but it is necessary for now:
I’m using the RPush gem and the
alert
key of the notification object is the actual text displayed - I’m not sure what that corresponds to in “pure” APNS, but hopefully this helps someone along the way.Sorry if this is a bit garbled, it’s the result of about 20 hours fighting with APNS and ExpoKit in a detached Expo app (:
Looks like the workaround has been found, so I’m closing this issue as ExpoKit is also no longer supported. Recently we’ve rewritten Notifications API from scratch so you can give them a try if you’re still hitting this.