When app is killed clicking expo push notification crashes the app

64 Views Asked by At

I've implemented the push notification like below and it works when app is opened but when the app is killed in ios and the user press the push notification the app opens and then crashes. For android, it's not asking for permission.

Asking for permission doesn't trigger on android somehow.

function useNotificationPermission() {
  const [expoPushToken, setExpoPushToken] = useState('')
  const [notification, setNotification] = useState<Notifications.Notification | null>(null)
  const notificationListener = useRef<Notifications.Subscription | null>(null)
  const responseListener = useRef<Notifications.Subscription | null>(null)

  useEffect(() => {
    Notifications.setNotificationHandler({
      handleNotification: async () => ({
        shouldShowAlert: true,
        shouldPlaySound: false,
        shouldSetBadge: false,
      }),
    })
    async function registerForPushNotificationsAsync() {
      let token

      if (Platform.OS === 'android') {
        Notifications.setNotificationChannelAsync('default', {
          name: 'default',
          importance: Notifications.AndroidImportance.MAX,
          vibrationPattern: [0, 250, 250, 250],
          lightColor: '#FF231F7C',
        })
      }

      if (Device.isDevice) {
        const { status: existingStatus } = await Notifications.getPermissionsAsync()
        let finalStatus = existingStatus
        console.log({ existingStatus })
        if (existingStatus !== 'granted') {
          const { status } = await Notifications.requestPermissionsAsync()
          console.log({ requestStatus: status })
          finalStatus = status
        }
        if (finalStatus !== 'granted') {
          // alert('Failed to get permission for push notification!')
          return
        }
        token = await Notifications.getExpoPushTokenAsync({
          projectId: Constants?.expoConfig?.extra?.eas?.projectId,
        })
      } else {
        // alert('Must use physical device for Push Notifications')
      }

      return token?.data
    }
    registerForPushNotificationsAsync().then((token) => setExpoPushToken(token))

    notificationListener.current = Notifications?.addNotificationReceivedListener(
      (notification) => {
        setNotification(notification)
      }
    )

    responseListener.current = Notifications?.addNotificationResponseReceivedListener(
      (response) => {
        console.log(response)
      }
    )

    return () => {
      if (notificationListener.current) {
        Notifications.removeNotificationSubscription(notificationListener.current)
      }
      if (responseListener.current) {
        Notifications.removeNotificationSubscription(responseListener.current)
      }
    }
  }, [])

  return { expoPushToken, notification }
}

Handling the notification in the app

function useNotificationObserver() {
  useEffect(() => {
    let isMounted = true

    function redirect(notification: Notifications.Notification) {
      const url = notification?.request?.content?.data?.url || '/'

      if (url) {
        router.push(url)
      }
    }

    Notifications.getLastNotificationResponseAsync().then((response) => {
      if (!isMounted || !response?.notification) {
        return
      }
      redirect(response?.notification)
    })

    const subscription = Notifications.addNotificationResponseReceivedListener((response) => {
      redirect(response?.notification)
    })

    return () => {
      isMounted = false
      subscription.remove()
    }
  }, [])
}

Root of the app

export default function Layout (){
   useNotificationObserver()
   useNotificationPermission()
   return (<App/>)
}

When sending the notification in the payload I've added content-available: 1 as well.

0

There are 0 best solutions below