DEV Community

Cover image for React Native: Locally Test Push Notifications on iOS
Azim Ahmed
Azim Ahmed

Posted on

React Native: Locally Test Push Notifications on iOS

Recently, I had an opportunity to solve push notification testing locally on iOS in a React Native app.

Problem

Testing push notifications is a bit tricky when you are using an iOS simulator. It doesn’t work the same as an Android emulator, where we can test push notifications like we would on a real device. On the iOS simulator, we have to rely on the CLI utility to trigger push notifications manually.

xcrun simctl push <device> <bundle-identifier> <path-to-apns-file>
Enter fullscreen mode Exit fullscreen mode

This doesn’t help to test the back-end logic of programmatically triggering the push notification. Also, we want to be able to check if the notification was sent to the correct devices.

Solution

We used the CLI utility to trigger the iOS notification programmatically with the help of shelljs. Furthermore, we listened to incoming notifications on React Native side to check if the notification was meant for the user in question.

Step 1: Use shelljs to trigger a push notification programmatically

Make sure your project has shelljs as a dependency in order to use the following code.

The message object is what the APNS payload looks like with tokens additional data.

const shell = require('shelljs');
const message = {
  aps: {
    alert: {
      title: 'Test',
      body: 'Test',
    },
    tokens: ['FCM_TOKEN_OF_USERS_QUESTION'],
  }
}
shell.exec(`echo '${JSON.stringify(message)}' | xcrun simctl push booted com.example.pushnotification -`);
Enter fullscreen mode Exit fullscreen mode

Step 2: Register a listener to check if the notification was meant for the user in question

In our React Native app, we added the following code to listen to the local notification clicks. The CLI utility triggers local notifications since there is no concept of remote notifications on the simulator.

import PushNotificationIOS, {
  PushNotification,
} from '@react-native-community/push-notification-ios';
interface IIOSLocationNotification {
  aps: {
    alert: {
      title: string;
      body: string;
    };
    tokens: string[];
  };
}
useEffect(() => {
  if (Platform.OS !== 'ios' && !__DEV__) {
    return;
  }
  PushNotificationIOS.addEventListener(
    'localNotification',
    onRemoteNotification,
  );
  return () => {
    PushNotificationIOS.removeEventListener('localNotification');
  };
}, []);
const onRemoteNotification = (notification: PushNotification) => {
  const token = 'FCM_TOKEN_OF_USERS_QUESTION';
  const data = notification.getData() as IIOSLocationNotification;
  if (!token || !data.aps.tokens.length) {
    return;
  }
  Alert.alert(
    data.aps.tokens.includes(token)
      ? 'Yes, this notification is for you'
      : 'No, this notification is not for you',
  );
};
Enter fullscreen mode Exit fullscreen mode

Sample App

I have put together a sample app to showcase this solution in more detail. The project has a very simple express backend and React Native app nested in its own folder.

1_9luCXbO7r6zP4-Fs0gU4bg

Try out the sample app and feel free to share your thoughts in the comments section.

Github

Discussion (0)