User Notifications

With user notifications, 3rd-party app servers can send a single message to multiple instance of an app running on devices owned by a single user. This feature is called user notifications. User notifications make it possible for every app instance that a user owns to reflect the latest messaging state. For example:

  • If a message has been handled on one device, the GCM message on the other devices are dismissed. For example, if a user has handled a calendar notification on one device, the notification will go away on the user's other devices.
  • If a message has not been delivered yet to a device and but it has been handled, the GCM server removes it from the unsent queue for the other devices.
  • Likewise, a device can send messages to the notification_key, which is the token that GCM uses to fan out notifications to all devices whose registration IDs are associated with the key.

The way this works is that during registration, the 3rd-party server requests a notification_key. The notification_key maps a particular user to all of the user's associated registration IDs (a regID represents a particular Android application running on a particular device). Then instead of sending one message to one regID at a time, the 3rd-party server can send a message to to the notification_key, which then sends the message to all of the user's regIDs.

Note: A notification dismissal message is like any other upstream message, meaning that it will be delivered to the other devices that belong to the specified notification_key. You should design your app to handle cases where the app receives a dismissal message, but has not yet displayed the notification that is being dismissed. You can solve this by caching the dismissal and then reconciling it with the corresponding notification.

You can use this feature with either the XMPP (CCS) or HTTP connection server.

You can generate notification keys in two different ways: on the server, and on the client, if the user has a Google account. All of the associated registration IDs can be mapped to a single user.

The examples below show you how to perform generate/add/remove operations, and how to send upstream messages. For generate/add/remove operations, the message body is JSON.

Generate a Notification Key on the Server

To generate a notification key on the server, you create a new notification_key and map it to a notification_key_name.

This example shows how to create a new notification_key for a notification_key_name called appUser-Chris. The notification_key_name is a name or identifier (it can be a username for a 3rd-party app) that is unique to a given user. It is used by third parties to group together registration IDs for a single user. Note that notification_key_name and notification_key are unique to a group of registration IDs. It is also important that notification_key_name be uniquely named per app in case you have multiple apps for the same project ID. This ensures that notifications only go to the intended target app.

A create operation returns a token (notification_key). Third parties must save this token (as well as its mapping to the notification_key_name) to use in subsequent operations:

request:
{ 
   "operation": "create",
   "notification_key_name": "appUser-Chris",
   "registration_ids": ["4", "8", "15", "16", "23", "42"]
}

Request format

To send a message in cases where your notification key is generated on the server, the application server issues a POST request to https://android.googleapis.com/gcm/notification.

Here is the HTTP request header you should use for all server side create/add/remove operations:

content-type: "application/json"
Header : "project_id": <projectID>
Header: "Authorization", "key=API_KEY"

Generate a Notification Key on the Client

Generating a notification key on the client is useful for cases where a server is unavailable. To generate a notification key on the client, the device must have at least one Google account. Note that the process for generating a notification key on the client is significantly different from the server process described above.

To generate a notification key on the client:

  1. Open your project in the Google Developers Console.
  2. Click APIS & AUTH > Credentials.
  3. Under OAuth, click Create new Client ID.
  4. In the Create Client ID dialog, select Web Application as the application type, and click Create Client ID.
  5. Copy the value from Client ID for web application > Client ID. This client ID represents a Google account "scope" that you will use to generate an id_token.

Once you've followed the above steps and gotten a client ID from Google Developers Console, you're ready to add this feature to your app. First check the device for the presence of a Google account. For example:

// This snippet takes the simple approach of using the first returned Google account,
// but you can pick any Google account on the device.
public String getAccount() {
    Account[] accounts = AccountManager.get(getActivity()).
        getAccountsByType("com.google");
    if (accounts.length == 0) {
        return null;
    }
    return accounts[0].name;
}

Next, get an authentication token (id_token) by using the GoogleAuthUtil class. For example:

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 id_token = null;
try {
    id_token = GoogleAuthUtil.getToken(context, accountName, scope);
} catch (Exception e) {
    log("exception while getting id_token: " + e);
}
...

Now use id_token to authenticate your request. This add operation returns a notification_key. Third parties must save this notification_key (as well as its mapping to the notification_key_name) to use in subsequent operations. Note that a client request only takes a single regID. The only operations supported on the client side are add/remove.

request:
{
   "operation": "add",
   "notification_key_name": "appUser-Chris",
   "registration_ids": ["4"]
   "id_token": "id_token"
}

Request format

To send a message in cases where your notification key is generated on the client, the application server issues a POST request to https://android.googleapis.com/gcm/googlenotification.

Here is the HTTP request header you should use for all add/remove operations. The client side doesn't support the create operation; the add operation has the effect of creating the notification key if it doesn't already exist:

content-type: "application/json"
Header : "project_id": <projectID>

Note that the authentication token is passed in the JSON body as shown above, not the header. This is different from the server case.

Add Registration IDs

This example shows how to add registration IDs for a given notification key. The maximum number of members allowed for a notification_key is 20.

Note that the notification_key_name is not strictly required for adding/removing regIDs. But including it protects you against accidentally using the incorrect notification_key.

request:
{ 
   "operation": "add",
   "notification_key_name": "appUser-Chris",
   "notification_key": "aUniqueKey"
   "registration_ids": ["4", "8", "15", "16", "23", "42"]
}

Remove Registration IDs

This example shows how to remove registration IDs for a given notification key:

request:
{ 
   "operation": "remove",
   "notification_key_name": "appUser-Chris",
   "notification_key": "aUniqueKey"
   "registration_ids": ["4", "8", "15", "16", "23", "42"]
}

Send Upstream Messages

To send an upstream (device-to-cloud) message, you must use the GoogleCloudMessaging API. Specifying a notification_key as the target for an upstream message allows a user on one device to send a message to other devices in the notification group—for example, to dismiss a notification. Here is an example that shows targeting a notification_key:

GoogleCloudMessaging gcm = GoogleCloudMessaging.get(context);
String to = 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);

This call generates the necessary XMPP stanza for sending the message. The Bundle data consists of a key-value pair.

For a complete example, see Implementing GCM Client.

Response Formats

This section shows examples of the responses that can be returned for notification key operations.

Create/add/remove operations

When you make a request to create a notification_key or to add/remove its regIDs, a successful response always returns the notification_key. Use the returned notification_key for sending messages:

HTTP status: 200
{ 
    "notification_key": "aUniqueKey",   // to be used for sending
}

Send operations

For a send operation that has a notification_key as its target, the possible responses are success, partial success, and failure.

Here is an example of "success"—the notification_key has 2 regIDs associated with it, and the message was successfully sent to both of them:

{
  "success": 2,
  "failure": 0
}

Here is an example of "partial success"—the notification_key has 3 regIDs associated with it. The message was successfully send to 1 of the regIDs, but not to the other 2. The response message lists the regIDs that failed to receive the message:

{
  "success":1,
  "failure":2,
  "failed_registration_ids":[
     "regId1",
     "regId2"
  ]
}

In the case of failure, the response has HTTP code 503 and no JSON. When a message fails to be delivered to one or more of the regIDs associated with a notification_key, the 3rd-party server should retry.