GCM for iOS and Android at the same time

Google have decreed that GCM be replaced with Firebase, so the advice below is now out of date (as of 2017).

This guide is for complete beginners, so I will try to explain everything very simply.

Google Cloud Messaging (GCM) enables you to send remote push notifications to a mobile app you have written, using the same server-side code for both Android and iOS. Therefore, it is wonderful! Sadly the documentation isn't wonderful; it makes assumptions about what you already know, and what technologies you will use. It talks only about CocoaPods, Swift, Objective C, Xcode...failing to recognise you might not use any of these.

I was building my apps with Phonegap Build, adding GCM capability with a plugin, and using ASP.NET on the server-side to make the GCM calls. You may wish to use something else on the server-side. Anything that can read a database and send HTTP calls will do. Anything that can talk to the GCM API/SDK on the client-side will do.

Another niggle is that any documentation mentioning iOS always assumes you are a Mac user. What if you aren't? My employer causes me to be limited to Windows and PCs. What if you don't own an iPhone or iPad to test on? I will try to address these issues as well.

Definitions

When I talk about a 'notification' I mean the message boxes that pop up on your phone or tablet to tell you something, when the app being talked about isn't actually running in the foreground. These are called 'push' notifications, and sometimes 'remote' notifications, because a remote server pushes the message to the client app. The text might say "You have a new message" and you can tap it to visit the relevant app. There are also 'local' notifications, which look the same on screen, but were created by the app (not pushed from a server), and an example might be "Please play Angry Birds more often". We're not looking at local notifications here.

Note that your app might be in various different states. Maybe it has never been opened for the first time, or maybe it has been opened in the past and is now terminated (note that starting it now would be called a 'cold start'). Maybe your app is running in the foreground (i.e. a person is actually using your app right now) or maybe it is running in the background (phone is in someone's pocket, or they are using a different app).

GCM is Google's free offering to control notifications for you, whether for Android apps or iOS apps. Apple have their own system for handling notifications, but it only covers iOS apps. Using Google seems a sane choice - two operating systems supported when you only write one chunk of server-side code - but note that the way Google sends an iOS notification is to contact the Apple service on your behalf. So you still end up using Apple's services, but indirectly. Hence you have to obey Apple's certification rules, which are umpteen times more complicated than Google's.

The Apple service is called APNS (Apple Push Notification Service) sometimes referred to as APN and it only talks to iOS apps.

When testing, I say I am working in a 'Development' situation, also called debug/test/local/dev. When going live to the app stores, I used to call it a 'Production' environment, but Apple call it 'Distribution' so I will use that term here.

Later on in this document I give definitions and examples for the various terminology Apple/Google use when talking about the numeric/string/Hex values that get passed around.

I will talk about Android apps in the Google Play store, but I believe there are no changes necessary to the code required for Kindle apps in the Amazon store (these run on Android too).

What I will not talk about

I have not had any experience of making apps for Windows Mobile. I have never written any native code for iOS or Android.

I have not properly looked into Amazon SNS (though it appears more difficult than GCM) and haven't even glanced at UrbanAirship or PushWhoosh (there must be others too).

You will always find great answers on StackOverflow if this guide has not covered what you need.

Money

There is no cost to get notifications working for Android apps. You have to pay a price (currently 99USD or 79GBP per year) to develop an iOS app, although this is not specifically for notifications, this is just for app creation in general. The GCM service and APNS service are both free, though they may be rate-limited. Getting a certificate from Apple (described below) is also free, unless you have to buy a Mac to do it!

Quickest way to see your own notification

Let's get something happening on screen as fast as possible, and then we'll cover all the other (slower) areas. For this we are going to use the Android version of your app. We have to sign up for GCM manually, get our client-side code talking to Google, then we can write our server-side code to send a test notification. The route to getting iOS working is much longer and we'll do that later.

Signing up for GCM (what a human does before coding)

Google changes the appearance of the pages within its Developer area often. I won't describe which buttons to click as the names will change. You need some sort of account with Google first (e.g. Gmail, Google+, whatever). Use this to log in, or create an account with the Developer Console (if that link breaks, search for "Google APIs"). You may be invited to "create a project" or something like that, in order to register for an API. At present, it seems you can ask for API access in general, without specifying you want it for GCM. To begin with, tell it you have an Android app, if asked. When asked for a project ID this means the name you made up yourself in reverse-domain-name style, say com.mydomainhere.myappname, when developing your app (Google Play demands this same name when you add an app to the store so watch out). You will be told what your project number and API key are, so write them down quick before moving on. Check the section below for terminology and formats, so you can recognise which set of numbers/letters is which, when asked for them in the future.

Terminology

The names given to the various numbers/Hex/strings passed around are confusing and sometimes get muddled in your head. I'm going to stick to the following (in green) and give some example values (in purple). I have used NNN to hide a number, and XXX to hide some letters, just to keep my own details private. I suggest you write down your own details with the terms I'm using here, for future reference. No need to write the full token out though!

This can be seen in iTunesConnect assuming you have set up your app already:

Apple Bundle ID : com.mydomainhere.myappname (Google will ask you for this)

Apple SKU : com.probablythesame.asthelineabove

Apple ID : 966NNN689 (9 digit number)

This can be seen when signing up for GCM:

GCM project name : My Cunning Notifications

GCM project ID : my-app-notifications

GCM project number or sometimes sender ID : 390035NNN459 (12 digit number)

GCM server key or server API key or sometimes API key : AIzaSyNNNfAk5PBUYJpCgSNNNH52VhZNNNC3Hmw (39 char alphanumeric)

Your app will reveal this information to you, which is unique to each device:

GCM token : APA91bGFye4-Vezaa6YaNNNT9qodGsospnflsjyXXXuuZ7XKFWOPOrQ2jNNNdxdKt47AtyPDkDJZG4I8fwLhXXXa14eB5Pq-k2ClnVCcs7r1EgeU83K3DINNNeBV7Q2BNVny4y0qtd6GaAFZALsHhXXXx3m6WAFPOA

(usually a 162 char alphanumeric with hyphens but no other punctuation, and no spaces....however, the documentation suggests the maximum size is 4k and could be much larger in the near future, so make sure your database can cope)

APNS token : 86dXXX8be5c3NNN9817f13cc239ccNNNf20fa7cf3b491ed726750XXX7df38194 sometimes displayed as < 86dXXX8b e5c3NNN9 817f13cc 239ccNNN f20fa7cf 3b491ed7 26750XXX 7df38194 >

(you use this if you are talking to APNS directly yourself; don't try to pass this to GCM as it will give an InvalidRegistration error)

When sending a GCM notification, your server will receive:

GCM multicast_id : 78399NNN36567NNN976 (19 char numeric - sometimes this is not sent to you)

GCM message_id : 0:145NNN9821391315%e0bf69XXX9fd7ecd (zero, then a colon, then 33 alphanumeric chars)

Registering with GCM (what an app does client-side)

The first stage is to get hold of a token for the instance of your app running on a certain device. This is called 'registering'. I use Phonegap Build to write my apps, so I chose a popular Phonegap plugin for GCM and had my app's JavaScript call a few functions. Do this every time your app loads up, at the start. You end up with a long string which you can display on the screen at first. Make sure you can get to this point, seeing the token in your app, before jumping through the next hoops.

Silly analogy: Let's pretend it is a special phone number that only calls a certain phone if it has a certain app on it.

You're probably going to be passing some JSON to the GCM API, and it might look like this:

{ "android": {"senderID": "project number"}, "ios": {"senderID": "project number", "gcmSandbox": true, "alert": "true", "badge": "false", "sound": "true"}, "windows": {} }

Note the value of gcmSandbox should be true when using iOS Development certificates, and false when using a Distribution certificate.

Here's my example code, but you could be doing this in another language, as long as it knows how to call the GCM API/SDK/plugin/doodah...

-------------------------------------title this Phonegap Javascritp, and showt code with config xml too----------------------------

Client-side code talks to your server-side code

My client-side code needs to pass the token value to my server, to be stored. I am going to assume you know how to pass a string from your app to your server using an HTTP call of some sort. You will need to store it in a database or write it to a file somewhere. This step may strike some people as odd, because you have to do it all yourself, unlike the other steps where you talk to GCM and get called back with everything you need.

Silly analogy: Let's pretend this is like a kid verbally telling his mum what his own special phone number is. The kid doesn't ask the telephone company to do this for him.

So let me reiterate: Your app uses the GCM service to get the token but you have to pass it to your own server, and store it in your own database, otherwise that token is stuck on your app, going nowhere, and your server won't have a way to uniquely identify that instance of your app on a particular device.

The one exception might be???? when you only want to send out one message to every app instance at once, and don't need to restrict a message to just one person. The phrases used in this situation are "topic" and "subscribing" - see my comments about further tools from GCM, much further below.

Server-side code talks to Google

Once your server knows what the token value is - eventually you'll have thousands of these in a database - you can write some code to send out a notification. We make a HTTP call to GCM to do this, telling Google what the token value is, and what our server key (or API key) is, along with the message text which is wrapped in some JSON. Below is a Classic ASP example of this, but you could use PHP or Java or Node.js or ASP.NET or Curl or Java or any language that can make a HTTP call. Whilst I keep saying "server side" you don't have to be using a real server to test things out; your laptop will have plenty of ways to fire notifications off for testing purposes in Development. Your choice for Production depends on what situation triggers the need for a notification to be sent.

Silly analogy: This is mummy sending the message "remember to wash your hands" to the telephone company, who will send it on to the kid's phone.

You need to make a POST to the URL https://gcm-http.googleapis.com/gcm/send with the header "Content-Type" set to "application/json", and header "Authorization" set to "key=AIzaSyNNNfAk5PBUYJpCgSNNNH52VhZNNNC3Hmw" which is the server key (API key) you noted down when signing up on Google's website. The key may have a different value for iOS and Android???.

The JSON string - to send a message to one device only - will look a bit like this:

{ "registration_ids": [ "token" ], "data": { "title": "My App Name", "message": "I am notifying you!", "tag": "123" } }

Classic ASP to send notification to one device

<%

Response.Write "Time sent: " & Now() & "<br/><br/>"

Dim sDeviceRegistrationToken, sGoogleURL, oHTTP, sMessageTitle, sTextOfTheMessage, iMessageID

sGoogleURL = "https://gcm-http.googleapis.com/gcm/send"

sDeviceRegistrationToken = "APA91bF7M9P6_MMMXXXMMMGO7yprPCdQQTwgWoMJlsVhp3CN7NNNHwCbsEr81UQC-QAQ"

sTextOfTheMessage = "I am notifying you!"

iMessageID = 123 'your own reference number

sMessageTitle = "My App Name" 'unsupported in iOS so we just use the app name for Android

sMessageTitle = Replace(sMessageTitle, """", "\""")

sTextOfTheMessage = Replace(sTextOfTheMessage, """", "\""")

sJSON = "{ ""registration_ids"": [ """ + sDeviceRegistrationToken + """ ], ""data"": { ""title"": """ & sMessageTitle & """, ""message"": """ & sTextOfTheMessage & """, ""tag"": """ & iMessageID & """" } }"

Response.Write "JSON is " & sJSON & "<br/><br/>"

Set oHTTP = Server.CreateObject("MSXML2.ServerXMLHTTP")

oHTTP.Open "POST", sGoogleURL, False

oHTTP.SetRequestHeader "Content-Type", "application/json"

oHTTP.SetRequestHeader "Authorization", "key=AIzaSyBmGfMMMBUYJpCgS84AXXXZ2ljC3Hmw" 'API key

oHTTP.Send sJSON

Response.Write "HTTP return code is " & oHTTP.Status & "<br/>"

Response.Write oHTTP.ResponseText

Set oHTTP = Nothing

%>

GCM returns a message

In response to your HTTP call, GCM replies to tell you how it went. If all went well you might hear a beep from your phone/tablet, and get a HTTP return code of 200 with this text on your sever:

{"multicast_id":5557NNN1636267NNN36,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:145NNN9821391315%e0bf69XXX9fd7ecd"}]}

The number 1 next to the word success does not mean complete success; it means that your request was received by GCM. GCM might decide not to do anything with this request! See below for how to find out more.

If things went bad straight away, your phone/tablet will stay ominously silent, and your server will see a HTTP 200 returned with this text:

{"multicast_id":64870NNN499959NNN67,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}

The error "InvalidRegistration" is one I saw for many unhappy days, but other error codes will be seen too: see table 9 at this link.

If the value of canonical_ids is greater than zero you will be given some new tokens in the response. Google has realised that your old token values have changed, on one or more devices, and is telling you the new token value(s), which you must use to update your database. This seems to happen often on Android, but not so much on iOS.

If you get the server key (API key) wrong in your header, you see HTTP return code 401 and the word "Unauthorized" returned.

Further tools from GCM

If you have signed up for the Google Play Developer Console then you can link an app to your GCM account, and then the GCM Diagnostics tool is shown to you. You can paste a token value into the box to see the log entries for that app instance. Or you can enter a message_id (the number GCM sends back to you in JSON when a message is actioned - see example above). Do not use a multicast_id here.

Note there is an annoying delay between getting your JSON response from GCM, and actually being able to see details of it in the GCM Diagnostics tool. If you paste something in the box too soon, you will see an error saying "Please enter a valid Registration token or Message ID(s)" which will make you think you pasted the wrong thing. The quickest response I ever got from this tool is six minutes, but it also took an hour at its longest.

Here is a list of possible status values, and a screenshot of the tool:

GCM&#39;s possible status values
GCM Diagnostics screenshot

There are also web services GCM allows you to use, if you code a little bit of ASP/PHP/Java/whatever. To view details for one particular token, your server can fire a GET HTTP request to https://iid.googleapis.com/iid/info/token?details=true with header "Authorization" set to "key=server key" and receive JSON back like this:

{"applicationVersion":"2340","application":"com.mydomainhere.myappname","authorizedEntity":"390NNN978459","platform":"IOS"}

This confirms your app version number and name (which you control and are already aware of!) plus a 12 digit number (???) and it also tells you which platform that particular app instance uses.

Topic notifications

These are a handy way to send one message to a whole group of people all in one go. As long as all the app instances 'subscribe' to a topic (which is just a word you pick) then you can send global messages to all subscribing apps without having to know their tokens.

To have one particular token subscribe to a particular topic, fire a POST HTTP request to https://iid.googleapis.com/iid/v1/token/rel/topics/mytopicname with the "Authorization" header set as usual. You can choose any value for mytopicname but be aware that different parts of GCM require a prefix. See these three examples for a topic called "sailing"...

When an app asks to subscribe to a topic, the value passed is "/topics/sailing".

When your server sends a notification out to all apps who are subscribed, you use a "to" or "registration_ids" value of "/topics/sailing".

For a server to get one app instance subscribed to the topic you use https://iid.googleapis.com/iid/v1/A1B2C34D4E5F6G7H8I9J0K/rel/topics/sailing

If you don't own an Apple device

This can get tricky. Be patient; it can be done!

We are not going to have trouble writing code, the trouble is with obtaining a free certificate file in a way that appeases Apple's rules. You need to prove your identity to Apple, tell them you have an app that wants notifications, digitally sign a certificate, and pair this up with another file called a 'profile'. Compared to what little you did for Android, this feels annoying.

I do not know of any simulator that can work with notifications. This is a common lament for iOS developers.

The only way to get a certificate is with a Mac (iPad might do it if you can create a .CSR file, and convert a .CER into a .P12?????). Most people usually work this out long before they want to send notifications, as you need to create a similar certificate when you first compile an app for iOS and test it. The simplest way is to purchase an item of confectionery or alcohol, and smile nicely at a friend who owns both a Mac and an iPhone/iPad and lives nearby. You need to sit next to them and walk them through the steps. Doing it over the phone/Skype is going to annoy them a lot, unless your friend is a programmer.

?????

Sign up with Apple and get certificates (process for a human to follow)

------------------------------------BLATHER HERE----------------------------

Go to https://developer.apple.com/account/ios/certificate/certificateList.action (or find 'Certificates' via https://developer.apple.com/ if they change the website yet again).

Tell Google that you have an iOS app which needs notifications (a manual process)

I talked about signing up for GCM earlier in this guide, when we mention only Android apps. Now you need to go back to the Developer Console and tell it you have an iOS app. Then Google knows to ask you for extra, iOS-specific, information. Since Google is going to talk to Apple's APNS service on your behalf, you have to let Google in on all your security details.

The .CER file that Apple gave you is your SSL APNS certificate, and you can use this if you want to talk to APNS in order to send notifications. If you want to use GCM then you need to convert this certificate into a .P12 file (in the pkcs12 format) which Google can use.

------------------------------------BLATHER HERE----------------------------

Upload your .P12 certificate to Google, as they will need this so they can talk to Apple's APNS service. I won't walk you through it as their website has changed twice in the past few years. You get to pick an 'app name' when you first register. This could be anything, it is just a label Google will use for display in the developer console. It asks for your iOS bundle ID - see the Terminology section near the top of this guide.

Note that if you upload the wrong certificates, and have to come pack to this page a second time, it may prompt you with a default 'app name', and lead you down the path to create a new sender id and API key which you do not want (especially if you have already set the sender id in your compiled app). Be sure to hit backspace to remove the suggested new app name, and see if the dropdown list then has your old app name recognised. It should remember your iOS bundle ID too.

Make a note of the server API key and the sender ID which Google tells you at the end of this process. Don't ignore the offer of "configuration files" too; this will download to you a PLIST file (it's just XML you can read as text) which contains something called GOOGLE_APP_ID which might be useful one day. I've no idea what for yet.

Sending a notification to an iOS app (server-side code)

Follow the exact same server-side process as for an Android app, to fire off a notification to an iOS app. I talk about making a POST HTTP call, above. Just use the GCM token that your iPhone/iPad sent to your server (probably a 152 char string, not a 64 char APNS token). Your server talks to Google, then Google talks to Apple, then Apple talks to your iOS device. Every step can fail for a multitude of reasons. I wish I could tell you an easy to way to confirm if your setup is correct, sorry.

?????

How to test a APNS token

IF GCM goes wrong and you dont see a token of length 152, you may find yourself with a 64 char length token, and this is an Apple APN(S) token, nothing to do with GCM. If you have access to a Mac, there are free apps in the Mac app store which can send a single notification using this token and your .CER certificate file (this is the one specifically for APNS not the other .CER file which is to do with your app).

Errors with iOS notifications

I was getting these error codes...?????