Google Cloud Messaging, ASP.NET Web Api and Android client

Pushing message from the server to client so that client doesn’t have to send the request to the server periodically is not a new concept anymore. Earlier when then client wants to check if the server wants to send something to him, he has to send dummy request to server repeatedly to ask for notifications. Although the server has nothing new, he is still overloaded because of handling these kinds of requests. Actively pushing message from the server to client will save him from unnecessary requests of clients. In this concept, the client will connect to the server through a channel and wait there for a new message. When the server wants to notify a client, he just uses the current active channel between him and client, then sends a message through it. The client receives notification and handles it. Server and client don’t have to send ping-pong message to communicate, all they have to do is building up an active channel between them and communicating through that channel.

 

1. Instructions

In this small blog post, I would like to illustrate how we can combine Google Cloud Messaging (GCM) and ASP.NET Web server to build such a system for pushing messages actively from server to client.
“Google Cloud Messaging for Android (GCM) is a service that allows you to send data from your server to your users’ Android-powered device. This could be a lightweight message telling your app there is new data to be fetched from the server (for instance, a movie uploaded by a friend), or it could be a message containing up to 4kb of payload data (so apps like instant messaging can consume the message directly)”. (From Google). You can read more about Google Cloud Messaging at following link http://developer.android.com/google/gcm/index.html or follow the steps below to prepare your development environment.

1. First of all, you need to register a Google account so that you can use Google API Console (https://code.google.com/apis/console/). Log in to Google API Console and create a new project.

Google Api Console

 

Project ID

When creating a project, you need to write down the number on the popup dialog. That’s called sender id, we need it for calling Google Cloud Messaging service from Android client.

2. In the panel of Google API Console, https://console.developers.google.com/apis/ , search for “Google Cloud Messaging” and activate it.

Google Cloud Messaging for Android

 

Enable Google Cloud Messaging

3. In the panel of Google API Console, on the left, go to Credentials –> API Key. Write down the API key, you need it for calling Google Cloud Messaging from your server.

Server API key
Server key

4. We have registered to use GCM. You have 2 important values so far:
– #project value is the send id which will be used in Android client to “authorize” client with GCM.
– API key value will be used in your server to “authorize” server with GCM.

5. Before continuing, I would like to explain how the system works so that you can understand the code easier.

GCM Workflow

The image above describes shortly how all the steps works. At the beginning, the client has to register himself with GCM by calling register function of GCMRegistar

public static void register(android.content.Context context, java.lang.String... senderIds)

when registration is successful. The client will receive a unique registration id for him and the event (or callback) onRegistered will be fired on the client.Handling this event, you’ll know that GCM has already accepted the device. However to manage the devices, you have to register the device with your server too. Registration id is mandatory, you have to store it on your server so that you can send a message to the device later. Besides registration id, you can store some other metadata like name, email in my sample application.

After registering the device with server and GCM, the device is ready to be pushed message from the server. Anytime when you want to send a message to a device, just go to your server and send a message to it. But how the server looks like, you can find it in next step.

4. So now let’s build up a server to manage clients and send a message to them. I already make a sample server at

http://restwebserviceforandroid.apphb.com/devicemanager

Device manager web interface

You need, of course,a user interface like my sample to manage registered devices. My user interface is pretty simple, he enumerates all devices with a text box and a button. When I want to send a message to a device, just enter a message in text box and click on button Send. A ajax call will be made to SendMessage function

[HttpPost]
public void SendMessage(string message, string deviceId)
{
	Device device = ViewModel.Devices.Where(x => x.Id == Convert.ToInt32(deviceId)).FirstOrDefault();
	PushBroker pushBroker = new PushBroker();
	pushBroker.RegisterGcmService(new GcmPushChannelSettings("YOURAPIKEYINSTEP3"));
	pushBroker.QueueNotification(new GcmNotification().ForDeviceRegistrationId(device.RegistrationId)
		.WithJson(@"{""message"":""" + message + @"""}"));
	pushBroker.StopAllServices();
	
}

In SendMessage function, I use https://github.com/Redth/PushSharp (with Nuget) to queue notifications to the device in GCM. When the device is not online, the message will be queued and pushed to the device if the device gets an active channel to GCM again.

In listing above, we need API key to “authorize” our server with GCM and registration id of the device so that we can send a message to it. You don’t have to use PushSharp to queue message in GCM, read the specification for sending a message at http://developer.android.com/google/gcm/gcm.html#send-msg and with standard HttpWebRequest you can queue your message to GCM too.

6. In Android client, we have only two activities. One for receiving a message and one for registering a device with GCM.

Main activity

Register activity

7. First of all, you need to declare and use a custom permission so only your application can receive GCM messages:

 <permission android:name="com.hintdesk.Google_Cloud_Messaging.permission.C2D_MESSAGE" android:protectionLevel="signature">
    <uses-permission android:name="com.hintdesk.Google_Cloud_Messaging.permission.C2D_MESSAGE"/>

8. Add the following permissions

<!-- App receives GCM messages. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- GCM connects to Google Services. -->
<uses-permission android:name="android.permission.INTERNET" /> 
<!-- GCM requires a Google account. -->
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<!-- Keeps the processor from sleeping when a message is received. -->
<uses-permission android:name="android.permission.WAKE_LOCK" />

9. Remember to add a Google account to your phone or your emulator. In the emulator, you can find it under Settings -> Accounts –> Add account. GCM needs a Google account to make it work.

Android Emulator Google Account

10. Add the following broadcast receiver

<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" >
	<intent-filter>
		<action android:name="com.google.android.c2dm.intent.RECEIVE" />
		<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
		<category android:name="com.hintdesk.Google_Cloud_Messaging" />
	</intent-filter>
</receiver>

This broadcast receiver is responsible for handling the 2 intents that can be sent by GCM (com.google.android.c2dm.intent.RECEIVE and com.google.android.c2dm.intent.REGISTRATION) and should be defined in the manifest (rather than programmatically) so that these intents can be received even if the application is not running. By setting the com.google.android.c2dm.permission.SEND permission, you are ensuring that only intents sent by the GCM system framework are sent to the receiver (a regular application cannot issue intents with that permission). (From Google)

11. Add the following intent service

<service android:name=".GCMIntentService" />

This intent service will be called by the GCMBroadcastReceiver (which is provided by the GCM library), as shown in the next step. It must be a subclass of com.google.android.gcm.GCMBaseIntentService, must contain a public constructor, and should be named my_app_package.GCMIntentService (unless you use a subclass of GCMBroadcastReceiver that overrides the method used to name the service).

The intent service must also define its sender ID(s). It does this as follows:
– If the value is static, the service’s default constructor should call super(senderIds).
– If the value is dynamic, the service should override the getSenderIds() method. (From Google). The sender id is the #project value that we took at step 2.

12. A sample source code of GCMIntentService looks like following

public class GCMIntentService extends GCMBaseIntentService {
    private ServerUtil serverUtil;

    public GCMIntentService() {
        super(Constants.SENDER_ID);
        serverUtil = new ServerUtil();

    }

    @Override
    protected void onMessage(Context context, Intent intent) {
        String message = intent.getExtras().getString("message");
        AppUtil.notifyMessage(getApplicationContext(), message);
    }

    @Override
    protected void onError(Context context, String s) {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    protected void onRegistered(Context context, String registrationId) {
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
        String name = sharedPreferences.getString(Constants.PREFERENCE_NAME, "");
        String email = sharedPreferences.getString(Constants.PREFERENCE_EMAIL, "");
        if (!registrationId.equals(""))
            serverUtil.register(context, new Device(name, email, registrationId));
        else
            AppUtil.notifyMessage(getApplicationContext(), "GCMRegistrar can't register your device");
    }


    @Override
    protected void onUnregistered(Context context, String registrationId) {
        String name = Thread.currentThread().getName();
        serverUtil.unRegister(context, registrationId);
    }
}

it extends GCMBaseIntentService and overrides 4 events to handle cases when the device is registered, unregistered with GCM, receives a message or any error happens during communicating.

In my sample app, in the case of registering/unregistering, I just add/remove the device from my server with mandatory field (registration id) and two metadata (name, email).

Handling message is a little more complex, when a message comes, I need to notify my application by sending a broadcast message

public class AppUtil {
    public static void notifyMessage(Context context,String message)
    {
        Intent intent = new Intent(Constants.DISPLAY_MESSAGE_ACTION);
        intent.putExtra(Constants.EXTRA_MESSAGE,message);
        context.sendBroadcast(intent);
    }
}

And for handling this broadcast message, I will need a broadcast receiver. Please note that this is my custom receiver internal my application. It’s not the broadcast receiver for receiving intent from GCM. When my custom receiver has the signal, he will wake up the phone and show a message on the phone screen.

private final BroadcastReceiver gcmBroadCastReceiver = new BroadcastReceiver() {
	@Override
	public void onReceive(Context context, Intent intent) {
		String message = intent.getExtras().getString(Constants.EXTRA_MESSAGE);
		synchronized (LOCK) {
			if (wakeLock == null) {
				PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
				wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "GCMWAKELOCK");
			}
			wakeLock.acquire();
		}
		textViewMessage.append(Constants.ENVIRONMENT_NEWLINE + message);
		Toast.makeText(getApplicationContext(), "New message: " + message, Toast.LENGTH_LONG).show();
		wakeLock.release();
	}
};

2. Source code

The source code is pretty simple if you understand how the system works. There are of course many other classes in Android client, but I think you can read and understand yourself.
Server: https://bitbucket.org/hintdesk/dotnet-rest-web-service-for-android/
Android client: https://bitbucket.org/hintdesk/android-google-cloud-messaging-asp-net-web-api-and-android

36 thoughts on “Google Cloud Messaging, ASP.NET Web Api and Android client”

  1. Hi, is the source code of server available to download? Thanks, it’s seems pretty easy but I’m new on push notifications.

    🙂

  2. @Selene: The source code of my server contains sensitive data. I can’t post it right now. Maybe later after removing sensitive data.

  3. @ali: The server code is for reference only because the connection to database is not available. Read my comments above to understand more.

  4. thanks sir , for this nice detail if i success to run your code then it is very very helpful for me sir thanks

  5. can you provide the asp code in c# without use of MVC and suppoerted for vs 2010?? otherwise it is very nice easy runnable source code so thank you very much and send the c# server code for us if that’s possible.
    and also i saw that you give the response very soon as possible that is the big think of this blog sir…
    thanks….

  6. can we manage the notification if the application is closed if yes then pls show the when the changes made….thanks

  7. in this application I am not able to get the message when the app is close so it is not good so hope you change this very soon thanks,if possible then please showing the notification when the app is close thank you…….

  8. @bapu: The source code of server is already written in post above. The SendMessage() function is all the code of server. You can port yourself the code to ASP.NET application.
    @saun sefferd: When the app is killed, you have no chance to receive the notification. Use has to start app again or let it run in background to receive notification.

  9. thank you very much for your response ……..
    i done all think i also generate the notification when the app is closed .
    so thanks sir…..

  10. can we chat from asp.net to android ?? if yes then pls help us and send the source code sir pls

  11. if possible then psl send the asp.net code which is run in 2008 and without nugets……
    it is possible to chat from asp.net to android and both side ……….
    i waiting for your response

  12. @saun, bapu: Notification system is not a chat system. You can extend the server to make a chat system as you want.
    Moreover there is no code to send. All sources are available in post.

  13. i have some problem to run server code given by you. I also read your commented data then also i doesn’t get any ideas pls help us….. I get msg as not connected.

  14. i did not actually understand what happened when i installed its apk on my device… how did it link my phone with the server?

  15. what version of Visual studio do we need. Pliz give the requirements for running the server side code. Thank you.

  16. I have visual studio 2013. the solution has opened well. Though I am getting errors with Nuget when I try to build the Solution. How do I overcome the errors as a result of NUget and what is its relevancy to the solution.

  17. A whole host of files in packages.config are bringing errors. It appears as though most of them are under references already. What could be the cause of the errors.

  18. Hey,

    From your demo panel i am not receiving any message . Your demo panel is not working. Can you please guide.

  19. Hi

    Thanks for article, since there has been alot of change in google, it would be appreciated if you could update the screen shots and article based on new UI. (Personally I could follow the instructions)

  20. hello i changed the refence of the database to my locale database to manage my own data what url should i put on the AndroidApplication (Canstant class ) (i’m using the local host for the moment for my asp.NET webApplication)

  21. @Kilwwa: Then just use your localhost URL. Replace root URL with your localhost. However you have to config your emulator to be able to connect to your localhost.

Leave a Reply

Your email address will not be published. Required fields are marked *