Skip to content

iOS: Quick actions not working when app is killed due to onBackgroundEvent() not triggering #1084

@stephanie-bassey

Description

@stephanie-bassey

Hi. I am having an issue with quick actions on iOS only. I have two quick actions on a push notification, one opens the app in the foreground, the other does not. When clicking the quick action that launches the app, from an app killed state, the press event is lost and the background nor foreground event handlers are ever triggered. This is an issue because our app relies on a mutation firing off based on the quick action selected, but as of now, the app just launches and never reaches the logic in notifee.onBackgroundEvent or notifee.onForegroundEvent().

Quick actions work fine when the app is open or simply backgrounded (i.e., not force quit from the app switcher) because the notifee.onForegroundEvent() handler gets called.

Our project is an Expo managed app, with the following dependencies:

"expo": "~50.0.17",
"@notifee/react-native": "^7.8.2",
"@react-native-firebase/app": "19.0.1",
"@react-native-firebase/messaging": "19.0.1"

Implementation
index.js

import "@expo/metro-runtime";

import notifee, { EventType } from "@notifee/react-native";
import messaging from "@react-native-firebase/messaging";
import { App } from "expo-router/build/qualified-entry";
import { renderRootComponent } from "expo-router/build/renderRootComponent";

messaging().onMessage(onMessageReceived);
messaging().setBackgroundMessageHandler(onMessageReceived);
 
notifee.onBackgroundEvent(async ({ type, detail }) => {
  if (type === EventType.PRESS) {
    console.log("Regular pressed");
  } else if (type === EventType.ACTION_PRESS) {
    console.log("Action pressed");
  }
  notifee.cancelDisplayedNotifications();
});

renderRootComponent(App);

_layout.tsx (located at project-name/app/_layout.tsx)

import notifee, { EventType } from "@notifee/react-native";
import * as SplashScreen from "expo-splash-screen";
import React, { ReactElement, useCallback, useState } from "react";
import { useOnMount, useOnUpdate } from "@/util/hooks";

const SPLASH_SCREEN_TIMEOUT = 2000;

SplashScreen.preventAutoHideAsync();

export type AppLayoutType = object;

const RootView = styled.View`
  height: 100%;
  width: 100%;
`;

const AppLayout: React.FC<AppLayoutType> = (): ReactElement | null => {
  const [appIsReady, setAppIsReady] = useState<boolean>(false);

  useOnMount(async () => {
    try {
      await new Promise((resolve) =>
        setTimeout(resolve, SPLASH_SCREEN_TIMEOUT),
      );
    } catch (error) {
      console.error(error);
    }

    setAppIsReady(true);

    return notifee.onForegroundEvent(async ({ type, detail }) => {
      const { notification } = detail;

      if (type === EventType.PRESS) {
        console.log("Regular press");
      } else if (type === EventType.ACTION_PRESS) {
        console.log("Action press");
      }
    });
  });

  const onLayoutRootView = useCallback(async () => {
    if (appIsReady) {
      await SplashScreen.hideAsync();
    }
  }, [appIsReady]);

  if (!appIsReady) {
    return null;
  }

  return (
    <SafeAreaProvider>
      ...other providers
         <RootView onLayout={onLayoutRootView}>
             <Stack />
         </RootView>
    </SafeAreaProvider>
  );
};

export default AppLayout;

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions