Handling interactive notifications from APNS with expo-notifications

  1. SDK Version: 49
  2. Platforms(Android/iOS/web/all): iOS

My nodeJS backend sends push notifications for Android through Expo/FCM, but for iOS the notifications go directly through APNS, because I need custom sounds.

This said, the notifications arrive correclty on both clients, and my question is specifically on how to handle the notification coming from APNS and trigger an interactive notification. I added “category”:“interactiveCategory” to my payload, and it’s present in my notification.request.content.

I also declared the category with the various actions:

const category = {
identifier: ‘interactiveCategory’,
actions: [
{
identifier: ‘action1’,
title: ‘Action 1’,
options: {
opensAppToForeground: true,
},
},
{
identifier: ‘action2’,
title: ‘Action 2’,
options: {
opensAppToForeground: true,
},
},
],
options: {
allowAnnouncement: false,
allowInCarPlay: false,
customDismissAction: true,
showSubtitle: true,
showTitle: true,
},
};

… and registered the categories:

Notifications.setNotificationCategoryAsync(‘interactiveCategory’, [category]);

I set up the listeners :

useEffect(() => {
registerForPushNotificationsAsync().then((token) => {
setExpoPushToken(token);
});

notificationListener.current =
  Notifications.addNotificationReceivedListener((notification) => {
    setNotification(notification);
    console.log('Received notification:', notification);

    if (
      notification &&
      notification.request &&
      notification.request.content
    ) {
      // Check the categoryIdentifier to determine which actions to handle
      const categoryIdentifier =
        notification.request.content.categoryIdentifier; // should be 'interactiveCategory'

      if (categoryIdentifier === 'interactiveCategory') {
        // Extract the actionIdentifier from the notification
        const actionIdentifier =
          notification.request.content.actionIdentifier;
        console.log('Interactive Action Handler:', actionIdentifier);

        if (actionIdentifier === 'action1') {
          // Handle Action 1
          console.log('Action 1 pressed');
          // Add your code here for Action 1
        } else if (actionIdentifier === 'action2') {
          // Handle Action 2
          console.log('Action 2 pressed');
          // Add your code here for Action 2
        } else if (actionIdentifier === 'action3') {
          // Handle Action 3
          console.log('Action 3 pressed');
          // Add your code here for Action 3
        }
      } else if (categoryIdentifier === 'defaultCategory') {
        // Handle actions for the 'defaultCategory' if needed
        const { actionIdentifier } = notification.request.content;

        if (actionIdentifier === 'defaultAction') {
          // Handle opening the app and navigating to 'nightscout'.
          // Add your code here.
        } else if (actionIdentifier === 'snoozeAction') {
          // Handle the snooze action (dismiss the notification).
          Notifications.dismissNotificationAsync(
            notification.request.identifier
          );
          // Add your code here if needed.
        }
      }
    }
    console.log('YAY!', notification);
  });

responseListener.current =
  Notifications.addNotificationResponseReceivedListener((response) => {
    console.log('NEW: Notification response:', response);
  });

return () => {
  Notifications.removeNotificationSubscription(
    notificationListener.current
  );
  Notifications.removeNotificationSubscription(responseListener.current);
};

}, );

… and the response:

const lastNotificationResponse = Notifications.useLastNotificationResponse();

useEffect(() => {
if (lastNotificationResponse) {
// Check if the notification was triggered by an action from the ‘interactiveCategory’
if (
lastNotificationResponse.notification.request.content
.categoryIdentifier === ‘interactiveCategory’
) {
const actionIdentifier =
lastNotificationResponse.notification.request.content
.categoryIdentifier;
console.log(‘NEW: Action Identifier:’, actionIdentifier);

    // Handle the specific actions from 'interactiveCategory' here
    if (actionIdentifier === 'action1') {
      // Handle Action 1
      console.log('Action 1 pressed');
      // Add your code here for Action 1
    } else if (actionIdentifier === 'action2') {
      // Handle Action 2
      console.log('Action 2 pressed');
      // Add your code here for Action 2
    } else if (actionIdentifier === 'action3') {
      // Handle Action 3
      console.log('Action 3 pressed');
      // Add your code here for Action 3
    }
  } else {
    // Handle the default action or other cases if needed
    navigate('myView');
  }
}

}, [lastNotificationResponse]);

I tried so many things and I am stuck. I get “standard”, non-interactive push notifications. Tapping them opens my app and navigates to ‘myView’ as expected, but why on flat Earth am I doing wrong ?

Any help appreciated. :slight_smile:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.