Google Cloud Messaging for Android (GCM) is a push-notification-like service freely provided by Google. Simply, it allows you to send data from one-end “we will call it a GCM server” to GCM clients e.g. Android app.
This service can be used to send notifications or messages containing up to 4Kb of payload data. The GCM service takes care of messages queueing and delivery to the target application. GCM is completely free no matter how big your messaging needs are, and there are “so far” no quotas.
Objective:
Building a complete example showing how to enable GCM service, how to build GCM client “Android app” and how to build GCM server.
Environment & Tools:
- Eclipse ADT
- Emulator AVD, target: Google APIs – API Level 19
Library:
- Jackson library to convert Java object to JSON
About the tutorial:
This tutorial is trying to cover all the needed steps to build a complete working example. As shown in the picture above we need to go over 4 steps:
- Go to Google Developers Console
- Build GCM Client “Android App”
- Build GCM Server “Java App”
- Run & Test
- a. Register the Android app with GCM to receive Registration Id “RegId“
- b. Share “RegId” with the server
- c. Send a message from server to GCM using HTTP POST request
( 1 ) Go to Google Developers Console
Google Developers Console is a place where you enable “activate” Google services that you want to integrate in your application. In this console you need to do the following:
- 1.1 Create a Project
- 1.2 Get Project Number
- 1.3 Enable Google Cloud Messaging for Android
- 1.4 Create Server API Key
1.1 Create a Project
If this is the first time you visit Google Developer Console, you need to create a Project “A project consists of a set of applications, along with activated APIs, Google Cloud resources, and the team and billing information associated with those resources.”
- Go to Developer Console home page
- Click “CREATE PROJECT” button
- Fill Project name “HMKCODE GCM” & Project ID “hmkcode-gcm-project“
1.2 Get Project Number
- Go to Developer Console home page
- Click on the project name “HMKCODE GCM“
- At the top of the page yo will see Project Number
- We we will need this number in Android app
1.3 Enable Google Cloud Messaging for Android
- Under the same project “HMKCODE GCM”
- Click on API & auth >> API
- Enable Google Cloud Messaginf for Android
1.4 Create Serve API Key
- Go to API & auth >> Credentials
- Under Public API access click CREATE NEW KEYSelect Server Key
- Click Create “leave the text box empty if you don’t have a specific IP address”
- The Server API Key will be created
- We will need this key in GCM Server
( 2 ) Build GCM Client “Android App”
- 2.1 Create a new Android Project
- 2.2 Create a Layout for MainActivity
- 2.3 MainActivity.java
- 2.4 GcmBroadcastReceiver.java
- 2.5 GcmMessagerHandler.java
- 2.6 AndroidManifest.xml
2.1 Create a new Android Project
- Application Name: Android GCM
- Project Name: android-gcm-client
- Package Name: com.hmkcode.android.gcm
2.2 Create Layout for MainActivity
The layout is so simple for this example. One Button to request registration ID and oneEditText to display the registration ID “RegID”
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" android:orientation="vertical" > <Button android:id="@+id/btnGetRegId" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Get RegId"/> <EditText android:id="@+id/etRegId" android:layout_width="match_parent" android:layout_height="250dp" /> </LinearLayout>
2.3 MainActivity.java
- /src/com/hmkcode/android/gcm/MainActivity.java
This class has three functions
- onCreate() : Loads the layout and get reference to Button and EditText
- getRegId(): AsyncTask will register the app with GCM, receive registration id “RegID” & display it on EditText. Here you need to use the Project Number when communicating with GCM
- onClick(): Listens to Button click event and call getRegId()
package com.hmkcode.android.gcm; import java.io.IOException; import com.google.android.gms.gcm.GoogleCloudMessaging; import android.os.AsyncTask; import android.os.Bundle; import android.app.Activity; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class MainActivity extends Activity implements OnClickListener { Button btnRegId; EditText etRegId; GoogleCloudMessaging gcm; String regid; String PROJECT_NUMBER = "102488860000"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnRegId = (Button) findViewById(R.id.btnGetRegId); etRegId = (EditText) findViewById(R.id.etRegId); btnRegId.setOnClickListener(this); } public void getRegId(){ new AsyncTask<Void, Void, String>() { @Override protected String doInBackground(Void... params) { String msg = ""; try { if (gcm == null) { gcm = GoogleCloudMessaging.getInstance(getApplicationContext()); } regid = gcm.register(PROJECT_NUMBER); msg = "Device registered, registration ID=" + regid; Log.i("GCM", msg); } catch (IOException ex) { msg = "Error :" + ex.getMessage(); } return msg; } @Override protected void onPostExecute(String msg) { etRegId.setText(msg + "\n"); } }.execute(null, null, null); } @Override public void onClick(View v) { getRegId(); } }
2.4 GcmBroadcastReceiver.java
- /src/com/hmkcode/android/gcm/GcmBroadcastReceiver.java
This is class will receive the GCM message & pass it to the GcmMessageHandler.
package com.hmkcode.android.gcm; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.support.v4.content.WakefulBroadcastReceiver; public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Explicitly specify that GcmMessageHandler will handle the intent. ComponentName comp = new ComponentName(context.getPackageName(), GcmMessageHandler.class.getName()); // Start the service, keeping the device awake while it is launching. startWakefulService(context, (intent.setComponent(comp))); setResultCode(Activity.RESULT_OK); } }
2.5 GcmMessageHandler.java
- /src/com/hmkcode/android/gcm/GcmMessageHandler.java
This class defines what to do with the received message. The received message will contain in its data part “as we will see later in GCM server step” two attributes title & message, we will extract “title” value from the intent extras & display it on a Toast.
{ "data": { "title": "Test Title", "message": "Test Message" }, ..... }
package com.hmkcode.android.gcm; import com.google.android.gms.gcm.GoogleCloudMessaging; import android.app.IntentService; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.widget.Toast; public class GcmMessageHandler extends IntentService { String mes; private Handler handler; public GcmMessageHandler() { super("GcmMessageHandler"); } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); handler = new Handler(); } @Override protected void onHandleIntent(Intent intent) { Bundle extras = intent.getExtras(); GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); // The getMessageType() intent parameter must be the intent you received // in your BroadcastReceiver. String messageType = gcm.getMessageType(intent); mes = extras.getString("title"); showToast(); Log.i("GCM", "Received : (" +messageType+") "+extras.getString("title")); GcmBroadcastReceiver.completeWakefulIntent(intent); } public void showToast(){ handler.post(new Runnable() { public void run() { Toast.makeText(getApplicationContext(),mes , Toast.LENGTH_LONG).show(); } }); } }
2.6 AndroidManifest.xml
You need to add five permissions, a receiver and service tags.
- Permission
com.google.android.c2dm.permission.RECEIVE
.- Permission
android.permission.INTERNET
- Permission
android.permission.GET_ACCOUNTS
- Permission
android.permission.WAKE_LOCK
- Permission
applicationPackage + ".permission.C2D_MESSAGE"
- Receiver name=com.hmkcode.android.gcm.GcmBroadcastReceiver
- Service name=com.hmkcode.android.gcm.GcmMessageHandler
- Meta-data for Google Play service version
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.hmkcode.android.gcm" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> <permission android:name="com.hmkcode.android.gcm.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="com.hmkcode.android.gcm.permission.C2D_MESSAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.hmkcode.android.gcm.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".GcmBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> <category android:name="com.hmkcode.android.gcm" /> </intent-filter> </receiver> <service android:name=".GcmMessageHandler" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> </application> </manifest>
( 3 ) Build GCM Server “Java App”
GCM server can be an app “web, desktop or even mobile app”, or scheduled scripts that can establish HTTP connection with GCM and then send POST request instructing GCM to send a message to one or more registered GCM clients “mobile apps”.
The HTTP POST request should include two headers:
Authorization
: key=SERVER API KEYContent-Type
:application/json
for JSON;application/x-www-form-urlencoded;charset=UTF-8
for plain text.
HTTP POST body can be in JSON or plain text format. In this example we will use JSONformat. Below is an example of what we will send in body of the request.
{ "data": { "title": "Test Title", "message": "Test Message" }, "registration_ids": ["RegId", "another RegId if needed"] }
- 3.1 Create a new Java Project
- 3.2 Content.java
- 3.3 POST2GCM.java
- 3.4 App.java
3.1 Create a new Java Project
3.2 com/hmkcode/vo/Contnet.java
This is a simple POJO to hold POST body content “will be converted to JSON when sending the request”. Here we need to pass the following:
- RegIds: One or more RegId can be added
- title & message: Two strings which will form the data part of the content.
package com.hmkcode.vo; import java.io.Serializable; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; public class Content implements Serializable { private List<String> registration_ids; private Map<String,String> data; public void addRegId(String regId){ if(registration_ids == null) registration_ids = new LinkedList<String>(); registration_ids.add(regId); } public void createData(String title, String message){ if(data == null) data = new HashMap<String,String>(); data.put("title", title); data.put("message", message); }
3.3 com/hmkcode/POST2GCM.java
This class will send the POST request. Here we need to pass the following:
- Server API Key: this key will be added to POST headers.
- Content object which will be converted in JSON format using Jackson library
package com.hmkcode; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import com.fasterxml.jackson.databind.ObjectMapper; import com.hmkcode.vo.Content; public class POST2GCM { public static void post(String apiKey, Content content){ try{ // 1. URL URL url = new URL("https://android.googleapis.com/gcm/send"); // 2. Open connection HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // 3. Specify POST method conn.setRequestMethod("POST"); // 4. Set the headers conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Authorization", "key="+apiKey); conn.setDoOutput(true); // 5. Add JSON data into POST request body //`5.1 Use Jackson object mapper to convert Contnet object into JSON ObjectMapper mapper = new ObjectMapper(); // 5.2 Get connection output stream DataOutputStream wr = new DataOutputStream(conn.getOutputStream()); // 5.3 Copy Content "JSON" into mapper.writeValue(wr, content); // 5.4 Send the request wr.flush(); // 5.5 close wr.close(); // 6. Get the response int responseCode = conn.getResponseCode(); System.out.println("\nSending 'POST' request to URL : " + url); System.out.println("Response Code : " + responseCode); BufferedReader in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); // 7. Print result System.out.println(response.toString()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
3.4 com/hmkcode/App.java
Here we run the server and pass the needed parameters Server API Key, RegId & data (title & message)
package com.hmkcode; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import com.fasterxml.jackson.databind.ObjectMapper; import com.hmkcode.vo.Content; public class App { public static void main( String[] args ) { System.out.println( "Sending POST to GCM" ); String apiKey = "AIzaSyB8azikXJKi_NjpWcVNJVO0d........"; Content content = createContent(); POST2GCM.post(apiKey, content); } public static Content createContent(){ Content c = new Content(); c.addRegId("APA91bFqnQzp0z5IpXWdth1lagGQZw1PTbdBAD13c-UQ0T76BBYVsFrY96MA4SFduBW9RzDguLaad-7l4QWluQcP6zSoX1HSUaAzQYSmI93...."); c.createData("Test Title", "Test Message"); return c; } }
( 4 ) Run & Test
Note: If you are using an emulator to run the Android app make sure the target is Google APIs.
a. Register the Android app with GCM to receive Registration Id “RegId“
- Run the Android app “built in step 2″
- Click Get RegId
- RegId will be displayed in EditText & also in LogCat
- Copy the RegId so we can use it in Server app.
b. Share “RegId” with the server
Server needs to know client(s) RegId(s) to whom the message will be sent to. Here for thesake of simplicity, our app will share RegId by manually copying it from the client and then “hard-coding” it in the server code “copy and paste”. However, in a real world, your app needs to share its RegId with GCM server by for example “sending it using HTTP POST request”.
So just copy the RegId from LogCat window and paste it in the server App.java class
//App.java class c.addRegId("APA91bFqnQzp0z5IpXWdth1lagGQZw1PT..........");
c. Send a message from server to GCM using HTTP POST request
Now, run App.java class to send the POST request to GCM which will boradcast it to registered clients.
댓글 없음:
댓글 쓰기