Push Tokens

Requesting Permission and Getting a Push Token

Since Android 13, notifications need the runtime permission POST_NOTIFICATIONS, and Android shows the prompt only once the app has a channel. Ask at a moment the user understands: after two refusals, only Settings helps.

src/notify/setup.ts: permission first, then a token (excerpt)TypeScript
export async function registerForPush() {
  // Android 13+: create a channel first, or the permission prompt never appears
  await Notifications.setNotificationChannelAsync('new-arrivals', {
    name: 'New arrivals', importance: Notifications.AndroidImportance.HIGH,
  });
  let { status } = await Notifications.getPermissionsAsync();
  if (status !== 'granted') ({ status } = await Notifications.requestPermissionsAsync());
  console.log('notification permission:', status, '| real device:', Device.isDevice);
  if (status !== 'granted') return null;
  try {
    const projectId = Constants.expoConfig?.extra?.eas?.projectId;   // set by `eas init`
    const { data } = await Notifications.getExpoPushTokenAsync({ projectId });
    return data;                                   // ExponentPushToken[...]
    // ...catch: log 'no push token:' and return null

The first launch showed the prompt (New Arrival Alerts's figure); after Allow, logcat read:

Output of 205
'notification permission:', 'granted', '| real device:', false
'no push token:', 'Unable to get Firebase Messaging instance. Did you configure
  `googleServicesFile` path in
app config? ... Default FirebaseApp is not initialized in this process com.anonymous.booknest.
  ...'

An Expo 6,418 push token wraps the platform's device token, and on Android that comes from Firebase 1 , which needs a Firebase project and its google-services.json (next section). This emulator image has Google Play 1 services, so with those files it could receive pushes; Device.isDevice lets you skip the attempt elsewhere.