You are on page 1of 48

Google Cloud Messaging

Overview
• Free service that enables developers to send
messages between servers and client apps:
– Downstream messages from servers to client apps;
– Upstream messages from client apps to servers.

2
Components
• Google Connection Servers accept downstream messages
from your app server and send them to a client app;

• Your App Server implements the HTTP and/or XMPP protocol to


communicate with the Google connection server(s). App servers
send downstream messages to a GCM connection server; the
connection server enqueues and stores the message, and then
sends it to the client app;

• Client App receives and sends messages, by registering with


Google to get an unique ID and registration token.
3
Connection Server Protocol
• Upstream/Downstream messages:
– HTTP: Downstream only, cloud-to-device up to 4KB of data;
– XMPP: Upstream and downstream (device-to-cloud, cloud-to-device), up to
4 KB of data.
• Messaging (synchronous or asynchronous):
– HTTP: Synchronous. App servers send messages as HTTP POST requests
and wait for a response. This mechanism is synchronous and blocks the
sender from sending another message until the response is received;
– XMPP: Asynchronous. App servers send/receive messages to/from all their
devices at full line speed over persistent XMPP connections. The XMPP
connection server sends acknowledgment or failure notifications (in the form
of special ACK and NACK JSON-encoded XMPP messages)
asynchronously.
4
Connection Server Protocol Format
• JSON:
– HTTP: JSON messages sent as HTTP POST;
– XMPP: JSON messages encapsulated in XMPP messages.
• Plain Text:
– HTTP: Plain Text messages sent as HTTP POST.
– XMPP: Not supported.
• Multicast downstream send to multiple registration tokens:
– HTTP: Supported in JSON message format.
– XMPP: Not supported.

5
Credentials
• Sender ID: a unique numerical value created when you configure
your API project given as project number in the Google
Developers Console. The sender ID is used in the registration
process to identify an app server that is permitted to send
messages to the client app;

• API Key: a key saved on the app server that gives the app
server authorized access to Google services. In HTTP, the API
key is included in the header of POST requests that send
messages. In XMPP, the API key is used in the SASL PLAIN
authentication request as a password to authenticate the
connection. You obtain the API key when you configure your API
6
Credentials (II)
• Application ID: the client app that is registering to receive
messages, implemented as platform-dependent:
– Android: based on the package name from the app manifest;
– iOS: based on the app's bundle identifier;
– Chrome: based on the Chrome extension name;

• Registration Token: an ID issued by the GCM connection


servers to the client app that allows it to receive messages.

7
Lifecycle Flow
• Register to enable GCM: a client app registers to receive
messages;
• Send downstream messages: the app server sends messages to
the client app:
– The app server sends a message to GCM connection servers;
– The GCM connection server enqueues and stores the message if the device is
offline;
– When the device is online, the GCM connection server sends the message to the
device;
– On the device, the client app receives the message according to the platform-
specific implementation.
• Receive downstream messages: A client app receives a message
from a GCM connection server; 8
Lifecycle Flow (II)
• Send upstream messages: this feature is only available with XMPP:
– On the device, the client app sends messages to the XMPP connection server;
– The XMPP connection server enqueues and stores the message if the server is
disconnected;
– When the app server is re-connected, the XMPP connection server sends the
message to the app server.
• Receive upstream messages: an app server receives a message
from the XMPP connection server and then does the following:
– Parses the message header to verify client app sender information;
– Sends "ack" to the XMPP connection server to acknowledge receiving the
message;
– Optionally parses the message payload, as defined by the client app.
9
Components of a Message
• Target: when your app server sends a message, it must specify a
target that identifies the destination of the message using the field to:
– Single registration token;
– Topic;
– Notification key (for sending to a device group).
• Options: the app server can set various options when sending a
downstream message to a client app, such as whether that message
should be replaced by a subsequent one;
• Payload: downstream messaging provides two types of payload:
– Notification with a 2KB limit and a predefined set of user-visible keys;
– Data up to 4KB of custom key/value pairs. Notification messages can contain an
optional data payload which is delivered when users click on the notification.
10
Notification Messages
• To send notifications,  {
    "to" :
set notification with the "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
    "notification" : {
necessary predefined       "body" : "great match!",
      "title" : "Portugal vs. Denmark",
set of key options for       "icon" : "myicon"
the user-visible part of   }
 }
the notification message:
• Notifications are delivered to the notification tray when the app is
inactive. For an active iOS app, notifications are instead passed to
didReceiveRemoteNotification. For an active Android app, notification
payloads are passed to onMessageReceived() under the notification
key in the data bundle.
11
Data Messages
{
• Set data with your    "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
custom key/value pairs    "data" : {
     "Nick" : "Mario",
to send a data payload      "body" : "great match!",
     "Room" : "PortugalVSDenmark"
to the client app,    },
maximum 4KB payload:  }
• On Android, a client app receives data messages in
onMessageReceived() and can handle the key/value pairs
accordingly. On iOS, GCM stores the message and delivers it only
when the app is in the foreground and has established a GCM
connection.

12
Hybride Messages
{
• Contains both notification     "to" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
and data;     "notification" : {
      "body" : "great match!",
• App behavior when receiving       "title" : "Portugal vs. Denmark",
messages that include both       "icon" : "myicon"
    },
notification and data payloads     "data" : {
depends on whether the app is       "Nick" : "Mario",
in the background, or the       "Room" : "PortugalVSDenmark"
  }
foreground:  }
– When in the background, apps receive the notification payload in the notification
tray, and only handle the data payload when the user taps on the notification;
– When in the foreground, your app receives a bundle with both payloads
available.
13
Checking the validity of an API key
• If you receive authentication errors when sending messages,
check the validity of your API key:
api_key=YOUR_API_KEY
curl --header "Authorization: key=$api_key“ \
--header Content-Type:"application/json" \
https://gcm-http.googleapis.com/gcm/send \ -d "{\"registration_ids\":[\"ABC\"]}"

• If you receive a 401 HTTP status code, your API key is not valid,
otherwise you should see something like this:
{"multicast_id":6782339717028231855,
"success":0,"failure":1, "canonical_ids":0,
"results":[{"error":"InvalidRegistration"}]}

14
Authentication with an HTTP Connection Server
• The HTTP request must contain the following headers:
– Authorization: key=YOUR_API_KEY;
– Content-Type: application/json for JSON; application/x-www-form-
urlencoded;charset=UTF-8 for plain text. If Content-Type is omitted, the
format is assumed to be plain text.

Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

{ "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...", "data" : { ... }, }

15
Authentication with an XMPP Connection Server
• Client: <stream:stream to="gcm.googleapis.com" version="1.0" xmlns="jabber:client“
xmlns:stream="http://etherx.jabber.org/streams">

• Server: <str:features xmlns:str="http://etherx.jabber.org/streams">


<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>X-OAUTH2</mechanism>
<mechanism>X-GOOGLE-TOKEN</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
</str:features>

<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">


• Client: MTI2MjAwMzQ3OTMzQHByb2plY3RzLmdjbS5hb mFTeUIzcmNaTmt…==
</auth>

• Server: <success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>


16
Request Format for HTTP Server
• Message with payload — notification message:
{ "notification": {
    "title": "Portugal vs. Denmark",
    "text": "5 to 1"
  },
  "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
}
• Message with payload — data message:
{ "data": {
    "score": "5x1",
    "time": "15:10"
  },
  "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
}
17
Response Format for HTTP Server
• There are two possible outcomes when trying to send a message:
– The message is processed successfully. The HTTP response has a 200 status,
and the body contains more information about the status of the message;
– The server rejects the request. The HTTP response contains a non-200 status
code (such as 400, 401 or 5xx).
• When a JSON request is successful (HTTP status code 200), the
JSON object returned contains the Downstream HTTP message
response body: { "multicast_id": 108,
  "success": 1,
  "failure": 0,
  "canonical_ids": 0,
  "results": [ { "message_id": "1:08" } ]
}
18
Request Format for XMPP Server
• Regular: <gcm xmlns:google:mobile:data> JSON payload </gcm>

• ACK: <message id="">


<gcm xmlns="google:mobile:data">
{ "from":"REGID", "message_id":"m-1366082849205" "message_type":"ack" }
</gcm>
</message>

• NACK: <message>
<gcm xmlns="google:mobile:data">
{ "message_type":"nack", "message_id":"msgId1", "from":"SomeInvalidRegistrationId",
"error":"BAD_REGISTRATION",
"error_description":"Invalid token on 'to' field: SomeInvalidRegistrationId" }
</gcm>
</message>
19
Request Format for XMPP Server (II)
• Control message:
– Periodically, the server needs to close down a connection to perform load
balancing. Before it closes the connection, CCS sends a
CONNECTION_DRAINING message to indicate that the connection is being
drained and will be closed soon. When you receive a
CONNECTION_DRAINING message, you should immediately begin
sending messages to another CCS connection, opening a new connection if
necessary.

<message>
<data:gcm xmlns:data="google:mobile:data">
{ "message_type":"control" "control_type":"CONNECTION_DRAINING" }
</data:gcm>
</message>

20
Response Flow for XMPP Server
• Every message sent to CCS
receives either an ACK or a
NACK response. Messages
that haven't received one of
these responses are
considered pending. If the
pending message count
reaches 100, the app server
should stop sending new
messages and wait for CCS to
acknowledge some of the
existing pending messages
21
Downstream Messaging
• Sending downstream messages to the server:

https://gcm-http.googleapis.com/gcm/send <message id="">


Content-Type:application/json   <gcm xmlns="google:mobile:data">
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA     { "data": {
      "score": "5x1",
{ "data": {       "time": "15:10"
    "score": "5x1",     },
    "time": "15:10"     "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1..."
  },  }
  "to" :   </gcm>
"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1 </message>
..."
}

22
Receiving Messages on Android Client App
• To receive simple downstream
messages, use a service that @Override
public void onMessageReceived(String from, Bundle data) {
extends GcmListenerService     String message = data.getString("message");
to handle messages captured     Log.d(TAG, "From: " + from);
    Log.d(TAG, "Message: " + message);
by GcmReceiver, which
extends     if (from.startsWith("/topics/")) {
        // message received from some topic.
WakefulBroadcastReceiver,     } else {
guaranteeing that the CPU is         // normal downstream message.
  }
awake so that your listener
service can complete its task.     // ...
}

23
Receiving Messages on Android Client App (II)
• Handle messages with notification in the payload:
– When your app is in the background, Android directs messages with notification
to the system tray. A user click on a notification opens the app launcher by
default;
– If you want to open your app and perform a specific action, set click_action in the
notification payload and map it to an intent filter in the Activity you want to launch:

<intent-filter>
<action android:name="OPEN_ACTIVITY_1" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>

24
Upstream Messaging
• If your app server implements the XMPP Connection Server protocol,
it can receive upstream messages from a user's device to the cloud.
To initiate an upstream message, the client app sends a request
containing the following:
– The address of the receiving app server, in the format
SENDER_ID@gcm.googleapis.com;
– A message ID that should be unique per sender ID;
– The message data comprising the key/value pairs of the message's payload.

25
Send Upstream Message
from Android Client App
• Your Android app can send an upstream             @Override
message using the             protected String doInBackground(Void... params) {
                String msg = "";
GoogleCloudMessaging API to call                 try {
gcm.send:                     Bundle data = new Bundle();
                    data.putString("my_message", "Hello World");
                    data.putString("my_action","SAY_HELLO");
public void onClick(final View view) {                     String id = Integer.toString(msgId.incrementAndGet());
    if (view == findViewById(R.id.send)) {                     gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
                    msg = "Sent message";
        new AsyncTask() {                 } catch (IOException ex) {
                           msg = "Error :" + ex.getMessage();
        }
                return msg;
        }.execute(null, null, null);       }
    } else if (view == findViewById(R.id.clear)) {             @Override
        mDisplay.setText("");             protected void onPostExecute(String msg) {
  }                 mDisplay.append(msg + "\n");
}       }
    

26
Sending Messages to Topics
• GCM topic messaging allows your app server to send a message to
multiple devices that have opted in to a particular topic;
• Based on the publish/subscribe model, topic messaging supports
unlimited subscriptions per app;
• The app server sends messages with payloads up to 2KB to the
topic, and GCM handles the message routing and delivers the
message reliably to the right devices.

27
Managing Topic Subscriptions on the Server
• You can take advantage of Instance ID APIs to perform basic topic
management tasks from the server side. Given the registration
token(s) of client app instances, you can:
– Find out details about a client app instance’s subscriptions, including each topic
name and subscribe date;
– Subscribe or unsubscribe an app instance to a topic;
– Subscribe or unsubscribe multiple app instances to a topic;
• In addition to these server-side methods, you can enable client app
instances to subscribe to topics from the client side.

28
Receiving Topic Messages on Android Client App
• Each client app needs to obtain a registration token and subscribe to
the topic using that token. Note that, for topic messaging it's not
required to send the registration token to your app server; however, if
you do send it, your server can verify the validity of the token and get
more information about the app that created it;
• Subscribe to a topic:
private void subscribeTopics(String token) throws IOException {
    GcmPubSub pubSub = GcmPubSub.getInstance(this);
    for (String topic : TOPICS) {
        pubSub.subscribe(token, "/topics/" + topic, null);
  }
}

29
Receiving Topic Messages on Android Client App (II)
• Receive and handle
topic messages: topic @Override
messages are delivered public void onMessageReceived(String from, Bundle data) {
    String message = data.getString("message");
the same way as other     Log.d(TAG, "From: " + from);
GCM messages. On     Log.d(TAG, "Message: " + message);

Android, the from field     if (from.startsWith("/topics/")) {


identifies if the message         // message received from some topic.
    } else {
is a topic message and         // normal downstream message.
contains the specific   }

topic name.     // ...


}

30
Device Group Messaging
• With device group messaging, app servers can send a single
message to multiple instance of an app running on devices belonging
to a group;
• Typically, "group" refers a set of different devices that belong to a
single user;
• However, a group could also represent a set of devices where the
app instance functions in a highly correlated manner, such as a
phone with a temperature control app installed, a smart thermostat,
and an automatic window opener;
• All devices in a group share a common notification key, which is the
token that GCM uses to fan out messages to all devices in the group.
31
Device Group Messaging (II)
• Device group messaging makes it possible for every app instance in
a group to reflect the latest messaging state;
• In addition to sending messages downstream to a notification key,
you can enable devices to send upstream messages to a device
group;
• You can use device group messaging with either the XMPP or HTTP
connection server;
• The limit on data payload is 2KB when sending to iOS devices, and
4KB for other platforms.

32
Managing Device Groups
• Before sending messages to a device group, you must:
– Obtain registration tokens for each device in the group;
– Create the notification_key, which identifies the device group by mapping a
particular group (typically a user) to all of the group’s associated registration
tokens. You can create notification keys on the app server.
• With a notification_key, instead of sending one message to one
registration token at a time, the app server can send one message to
the notification_key, and GCM then sends the message to all of the
group’s registration tokens;
• The maximum number of members allowed for a notification_key is
20.

33
Creating a Device Group
https://android.googleapis.com/gcm/notification
• To create a device group, send a Content-Type:application/json
POST request that provides a Authorization:key=API_KEY
name for the group, and a list of project_id:SENDER_ID
registration tokens for the {
devices. GCM returns a new    "operation": "create",
notification_key that    "notification_key_name": "appUser-Chris",
   "registration_ids": ["4", "8", "15", "16", "23", "42"]
represents the device group; }
• A successful request returns a
notification_key like the
following: {
   "notification_key": "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ"
}
34
Adding and Removing Devices from a Device Group
• To add or remove devices from an existing group, send a POST
request with the operation parameter set to add or remove, and
provide the registration tokens for addition or removal;
{
   "operation": "add",
   "notification_key_name": "appUser-Chris",
   "notification_key": "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ",
   "registration_ids": ["51"]
}
• A successful request returns a notification_key like the following:
{
   "notification_key": "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ"
}
35
Sending Downstream Messages to Device Groups
• Sending messages to a device group is very similar to sending
messages to an individual device. Set the to parameter to the
unique notification key for the device group.
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json {
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA   "success":1,
  "failure":2,
{   "failed_registration_ids":[
  "to": "aUniqueKey",      "regId1",
  "data": {      "regId2"
    "hello": "This is a GCM Device Group Message!",  ]
   } }
}

36
Sending Upstream Messages to Device Groups
• Client apps can send messages upstream to device groups by
targeting messages to the appropriate notification key in the to field.

GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);


String to = aUniqueKey; // the notification key
AtomicInteger msgId = new AtomicInteger();
String id = Integer.toString(msgId.incrementAndGet());
Bundle data = new Bundle();
data.putString("hello", "world");

gcm.send(to, id, data);

37
Managing Device Groups on Android Client Apps
• Obtain a Client ID in the Google Developers Console;
• Validate the Google account on the device;
• Get an authentication token:
String accountName = getAccount();

// Initialize the scope using the client ID you got from the Console.
final String scope = "audience:server:client_id:"
        + "1262xxx48712-9qs6n32447mcj9dirtnkyrejt82saa52.apps.googleusercontent.com";
String idToken = null;
try {
    idToken = GoogleAuthUtil.getToken(context, accountName, scope);
} catch (Exception e) {
    log("exception while getting idToken: " + e);
}

38
Adding a Group
public String addtNotificationKey(
        String senderId, String userEmail, String registrationId, String idToken)
        throws IOException, JSONException {     con.setRequestProperty("project_id", senderId);
    URL url = new URL("https://android.googleapis.com/gcm/googlenotification");     con.setRequestProperty("Content-Type", "application/json");
    HttpURLConnection con = (HttpURLConnection) url.openConnection();     con.setRequestProperty("Accept", "application/json");
    con.setDoOutput(true);     con.setRequestMethod("POST");
    // HTTP request header     con.connect();
    // HTTP request
    OutputStream os = con.getOutputStream();     JSONObject data = new JSONObject();
    os.write(data.toString().getBytes("UTF-8"));     data.put("operation", "add");
    os.close();     data.put("notification_key_name", userEmail);
    data.put("registration_ids", new JSONArray(Arrays.asList(registrationId)));
    // Read the response into a string     data.put("id_token", idToken);
    InputStream is = con.getInputStream();
    String responseString = new Scanner(is, "UTF-8").useDelimiter("\\A").next();
    is.close();

    // Parse the JSON string and return the notification key


    JSONObject response = new JSONObject(responseString);
    return response.getString("notification_key");

39
Removing from a Group
• A remove operation requires the following keys: operation set to
remove, id_token set to the idToken obtained above,
notification_key_name and registration_ids:

// HTTP request
JSONObject data = new JSONObject();
data.put("operation", "remove");
data.put("notification_key_name", userEmail);
data.put("registration_ids", new JSONArray(Arrays.asList(registrationId)));
data.put("id_token", idToken);

40
Implementing GCM Network Manager on Android
• GcmNetworkManager enables client apps to register services that perform
network-oriented tasks based on specified criteria such as:
– Schedule one-off vs. periodic tasks. Register one-off or repeating tasks using a simple API call;
– Automatic back-off and failure retry. Return appropriate results from the service’s execution logic, and GCM
Network Manager handles the necessary back-off and retry.
– Awareness of network activity. The Network Manager's scheduler service leverages many GCM signals and
other clients' task execution to determine the optimal time to schedule and execute the task.
– Awareness of device charging state. Certain tasks do not need to be run immediately, and can be executed
when the device is charging in order to minimize battery consumption. For such tasks, you can specify that
your app should wait to run until the device is charging.
– Persistence of tasks across boot. The GCM Network Manager persists task states across boot and app
restarts.
– Ease of implementation/refactoring of existing code. Developers familiar with sync adapters can easily
subclass a client service and override one function to add Network Manager to existing apps.

41
Implementing GCM Network Manager on Android (II)
• Edit your application’s manifest:
– Implement GcmTaskService, and add the service to the manifest;
– Declare SERVICE_PERMISSION to ensure that other apps cannot start your service;
– Add all applicable intent filters.

<service
    android:name=".MyTaskService"
    android:exported="true"
    android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
    <intent-filter>
        <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
    </intent-filter>
</service>

42
Implementing GCM Network Manager on Android (III)
• Get an instance of GcmNetworkManager to schedule tasks:

mGcmNetworkManager = GcmNetworkManager.getInstance(this);

• Schedule a one-off task when network is connected:


OneoffTask task = new OneoffTask.Builder()
        .setService(MyTaskService.class)
        .setTag(TASK_TAG_WIFI)
        .setExecutionWindow(0L, 3600L)
        .setRequiredNetwork(Task.NETWORK_STATE_UNMETERED)
        .build();

mGcmNetworkManager.schedule(task);

43
Implementing GCM Network Manager on Android (IV)
• Schedule a periodic task:
PeriodicTask task = new PeriodicTask.Builder()
        .setService(MyTaskService.class)
        .setTag(TASK_TAG_PERIODIC)
        .setPeriod(5L)
        .build();

mGcmNetworkManager.schedule(task);

• Schedule a persistent task:


– If you would like your task to be persisted and rescheduled across reboots, call the
Task.Builder#setPersisted method when building your task;
– Note that in order for task persistence to work, your app must hold the
RECEIVE_BOOT_COMPLETED permission.

44
Implementing GCM Network Manager on Android (V)
• Run tasks:
– When the scheduler starts your service, a new thread is created and the system
invokes onRunTask(). Implement the logic for your tasks by overriding onRunTask();
its return value specifies exactly what GCM Network Manager should do with this
task. See the GCM Network Manager constants RESULT_RESCHEDULE,
RESULT_SUCCESS, and RESULT_FAILURE for more information;
– Keep in mind that RESULT_SUCCESS and RESULT_FAILURE are not different
behaviorally. The distinction between them exists mainly to avoid returning
RESULT_SUCCESS if in fact you have determined that your task has failed. Also, it
helps in debugging issues locally when you run commands like the following, as you
will see the successes/failures for your endpoint listed.

adb shell dumpsys activity service GcmService --endpoints YOUR_ENDPOINT

45
Android Demo App
• This is a demo app used to demonstrate demonstrates various
aspects of interacting with GCM on Android:
– Registering a client app;
– Sending downstream, upstream and notification messages;
– Subscribing to topics.
– Creating notification groups;
– Using the network manager to schedule tasks.

46
Android Demo App (II)

47
Thank you!

48

You might also like