A step-by-step guide on how to setup Apple Push Notifications (APN) on Meteor and React Native

Heyse Li
4 min readMay 26, 2016

--

Meteor is mainly for the web, but what how can we stay up to date when we step away from our desktops and laptops? Having a mobile app version of your webapp can let people get updates through push notifications.

If you’ve never used React Native and Meteor before, you should check out the great tutorials by Spencer Carli on the subject.

Here’s a high level overview of what this guide is going to cover:

  1. Get certificate and key from Apple
  2. Convert certificate and key to .pem format
  3. Test the certificate and key .pem files
  4. Meteor server: Save .pem files
  5. React Native: Link the PushNotificationsIOS library manually
  6. React Native: Update AppDelegate
  7. React Native: Setup react-native-push-notifications
  8. React Native: Send device token to server
  9. Meteor server: Set device token
  10. Meteor server: Setup apnagent
  11. Meteor server: Send a push notification
  12. Some random issues you might have when trying this

Get certificate and key from Apple

We’re going to follow the Parse guide to get the .cer (certificate), .p12 (key) from Apple. Do Step 1 (Creating the SSL certificate) and Step 2 (Creating the Development Provisioning Profile) in the Parse guide.

Convert certificate and key to .pem format

I had issues getting the .p12 file working, so we are going to convert them to .pem. Follow the following commands to get the .pem files. cert.cer is probably named by default as aps_development.cer.

$ openssl x509 -in cert.cer -inform DER -outform PEM -out cert.pem
$ openssl pkcs12 -in key.p12 -out key.pem -nodes

https://github.com/argon/node-apn/wiki/Preparing-Certificates

Test the certificate and key .pem files

Next, let’s test our .pem files to see if they are working. Follow the appropriate step for development and production certificates and keys.

For Development (sandbox) certificate and key

$ openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert cert.pem -key key.pem

For Production certificate and key

$ openssl s_client -connect gateway.push.apple.com:2195 -cert cert.pem -key key.pem

You can tell if your .pem files are good if the the terminal doesn’t let you input commands. Also, you can check the return code. A return code of 0 is success. All the return codes are documented by Apple here. Here’s a StackOverflow discussion on their different meanings.

Meteor server: Save .pem files

The server is going to need the certificate and keys in order to send push notifications. So let’s save them in somewhere private. The Meteor docs say:

All files inside a top-level directory called private/ are only accessible from server code and can be loaded via the Assets API. This can be used for private data files and any files that are in your project directory that you don’t want to be accessible from the outside.

That sounds like a good place to put them. Let’s save our certificate and key .pem files in /private/cert.pem and /private/key.pem.

React Native: Link the PushNotificationsIOS library manually

Follow the Facebook React Native guide on how to link libraries manually. Make sure to add the following to Header Search Paths:

$(SRCROOT)/../node_modules/react-native/Libraries/PushNotificationIOS

React Native: Update AppDelegate

Follow the Facebook React Native guide on how to update your AppDelegate to enable push notifications.

React Native: Setup react-native-push-notifications

We’re going to be using the npm package react-native-push-notifications to handle the receipt of push notifications on our React Native app. What’s nice about this package is that it can also handle Google Cloud Messaging (GCM), but we won’t be covering that in this tutorial.

react-native-push-notifications handles setting up iOS notification listeners for you. You don’t need to request permissions manually either.

Just need to install the package:

npm install --save react-native-push-notifications

React Native: Send device token to server

On registration, we’ll receive some data in the method onRegister. It looks like this:

data = {
token // the device-specific token
os // 'ios' or 'android'
}

We will be sending the data object to our Meteor server by calling the Meteor method notifications.set.pushToken.

Meteor server: Set device token

The following code is assumes that you’ve set up some kind of log in system for your users and associates each device with a user. It also assumes that each user can have multiple devices.

Meteor server: Setup apnagent

We’re going to use apnagent to help us communicate with Apple and send push notifications.

Put this following code somewhere on the server. I’ve put mine in /server/apnagent.js. I’m also using the development certificate and key so I need to enable the sandbox mode. You don’t need that if you are using the production ones.

apnagent setup

Meteor server: Send a push notification

Sending extra data down

From the apnagent docs:

Set extra key values that will be incuded as part of the payload. aps is reserved by Apple and enc is reserved by apnagent.

Notifications while app is in background

If you want to get notifications to popup when the app is in the background, make sure to use .alert(someString).

With that, you should be able to send APN messages from the server and receive them on a React Native app.

Let me know if this has been helpful or if you found anything confusing!

Random Issues

“Unable to resolve some modules” when trying to run Meteor app

I ran into this problem when I was trying to run my Meteor app.

Unable to resolve some modules:“./lib-cov/apnagent” in/myapp/node_modules/apnagent/index.js(os.osx.x86_64)"./lib-cov/inherits” in/myapp/node_modules/tea-inherits/index.js(os.osx.x86_64)
...

I didn’t list them all here, but there’s more modules that can’t be resolved, and they’re all related to apnagent’s imports. However, it seems like if you just wait a bit longer, it’s able to resolve all the required modules. So just sit and wait. Not a very insightful solution, I know. If someone has another solution to this I’d love to hear it.

--

--