Using Amazon SNS to send push notifications on Rails Projects

Some months ago, I was working on a project that sends a lot of push notifications to ours users, and we were sending theses pushes through a gem named apn_on_rails, for iOS notifications, and rpush, for android notifications. This situation let us to some problems:

  • First of all, the apn_on_rails gem was a outdated gem, that has no updates anymore, and I had already cloned and did some changes on my own to be able to use this with the last version of rails;
  • Second, the push notifications were being sent by the same servers that our application uses, and we wanted to send the pushes without increase ours application servers load;

When I was talking to a friend and explain this situation to him, he advises me to use Amazon SNS to manage all of ours push notifications. So, let's see what I had to do to use SNS to send ours push notifications.

To start, Amazon has a great gem(aws-sdk) to let us integrate rails projects to all of its services. In this post I will just show how easy is to configure and send a simple push notification, but SNS has a lot of docs and tools that can help you to do a lot more.

After installs the aws-sdk gem, you have to setting up your aws credentials. I recommend you to do this is using environment variables, named AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. I also configured my aws region using env variables, if you want to do this, just set the variable AWS_REGION, and will be easier for you when need to do some integration with amazon services.

So, we are almost ready to start coding, but before we need to configure some applications in amazon SNS web page(you can do this using the aws-sdk gem too, but it is easy to use the SNS web page and in my case, I had to do this only one time, and never more, so would not be smart to code something that would only be done one time). Just log in to your amazon account and open the SNS console. Then click in the Create Platform Application button.

It will open a popup where you can choose the application name and the platform that you want to send the push notifications. In my case, I create a platform application for GCM and APNS.

So, let's focus on code now. First, we need to be able to create endpoints of our users to platform applications that we create on Amazon SNS console, like the code samples below.

Android:

iOS:

I was able to call the Aws::SNS::Cliente.new method without params because I configured all AWS credentials and the AWS region in env variables, but if you did not do that, you will need to pass those credentials and region here.

The apps ARN is what was generated on SNS after you created the platform application, you can see the ARN of your platform apps on SNS console, just click in Applications link on the left of the page.

The iOS device token has to be send to amazon sns with no empty spaces. In my case, the API was receiving the device token with empty spaces, so I need to clean the token before create a SNS endpoint.

The attributes key is optional, I like to use it to store in SNS my users' id, so it is easier to identify my users when I am looking to SNS console. But be careful with this, because if you use this to store some information of your user, and then you try to create another endpoint with same token and different attributes, amazon SNS will throw Aws::SNS::Errors::InvalidParameter, and you will have to handle with this exception. If you let this optional key blank, it will not happen, because when you try to create a new endpoint with some token that another endpoint is using, and this endpoint has attributes blank and you are passing attributes as blank too, SNS will handle this without throw an exception.

After you create an endpoint, SNS will return an ARN code to your endpoint, and you need to store this ARN code in your database to use it to send push notification to your users after.

With the endpoint created and the ARN stored in the database, to send the notification, you just need to run the code below.

Android:

iOS:

In both cases, SNS can throw some exceptions, and it is good if your code can handle with those exceptions, like Aws::SNS::Errors::EndpointDisabled, Aws::SNS::Errors::InvalidParameter and Aws::SNS::Errors::PlatformApplicationDisabled. You can see more about it in aws-sdk documentation. So, just add the code to handle the exceptions you think that can be throw in your case, and it is done.