Breaking News
Loading...
August 1, 2015

Android Device to Device Messaging using Google Cloud Messaging (GCM) via Http

7:01 PM
This Android tutorial will help to learn Android device to device messaging using Google Cloud Messaging (GCM) via a GCM Http server. This is just an improvisation of downstream messaging using GCM server. Communication flow originates from an Android device and the message to be communicated will be sent to GCM application server. From that server the message will be relayed to the Google Cloud Messaging server with the RegId of the device to send the notification. Then this message will be sent to the another Android device by the Google Cloud Messaging server as a notification.
Tutorial for upstream communication from an Android device using Google Cloud Connection Server (XMPP), will be posted soon. When we say device to device messaging immediate chat application comes to our mind. If you are thinking about a chat application or similar cases then XMPP will be the best way to go. If you are looking for simple notifications between Android devices then continue with this Android tutorial. You may even upgrade the example app provided in this tutorial to a chat application.
If you are just starting with Google Cloud Messaging (GCM), I recommend you to go through the earlier tutorial Google Cloud Messaging GCM for Android and Push Notifications. It gives you more detailed step by step instruction to get started with Google Cloud Messaging. In this tutorial, I am just directly going to jump into the application and code. For the prerequisite like setting up your development environment, getting a Google API server key and all those preliminary steps you need to refer the above linked tutorial.

Device to Device Messaging Flow

Before start of exchanging messages, Android devices should register itself with the Google Cloud Messaging server and get a RegId. Then the Android device will share that regid with the GCM application server. Along with RegId, an identifier name will also be passed. The GCM app server will persist the name and RegId pair. Similarly all the devices that are going to participate should register themselves.
GCM server application which will act as a relay between the Android devices. Device one will send a message to GCM server by invoking a callback URL provided by the server. In the parameter it will send the recipient name. Using the recipient name GCM app sever will pick the respective RegId from its store and send the message along with RegId to the Google Cloud Messaging server. Subsequently Google Cloud messaging server will pass that message as a notification to the corresponding device.

Google Cloud Messaging Client App

RegisterActivity.java
package com.javapapers.android.gcm.devicetodevice;

import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.google.android.gms.gcm.GoogleCloudMessaging;

public class RegisterActivity extends Activity {

 Button btnGCMRegister;
 Button btnAppShare;
 GoogleCloudMessaging gcm;
 Context context;
 String regId;
 EditText userName;

 public static final String REG_ID = "regId";
 private static final String APP_VERSION = "appVersion";

 static final String TAG = "Register Activity";

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_register);

  context = getApplicationContext();

  // to register with Google GCM Server
  btnGCMRegister = (Button) findViewById(R.id.btnGCMRegister);
  btnGCMRegister.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View arg0) {
    if (TextUtils.isEmpty(regId)) {
     regId = registerGCM();
     Log.d("RegisterActivity", "GCM RegId: " + regId);
    } else {
     Toast.makeText(getApplicationContext(),
       "Already Registered with GCM Server!",
       Toast.LENGTH_LONG).show();
    }
   }
  });

  // to share regid to our custom GCM application server
  btnAppShare = (Button) findViewById(R.id.btnAppShare);
  btnAppShare.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View arg0) {

    userName = (EditText) findViewById(R.id.userName);
    String name = userName.getText().toString();

    if (TextUtils.isEmpty(regId)) {
     Toast.makeText(getApplicationContext(), "RegId is empty!",
       Toast.LENGTH_LONG).show();
    } else if (TextUtils.isEmpty(name)) {
     Toast.makeText(getApplicationContext(), "Name is empty!",
       Toast.LENGTH_LONG).show();
    } else {
     Intent i = new Intent(getApplicationContext(),
       MainActivity.class);
     i.putExtra(Config.REGISTER_NAME, name);
     i.putExtra("regId", regId);
     Log.d("RegisterActivity",
       "onClick of Share: Before starting main activity.");
     startActivity(i);
     finish();
     Log.d("RegisterActivity", "onClick of Share: After finish.");
    }
   }
  });
 }

 public String registerGCM() {

  gcm = GoogleCloudMessaging.getInstance(this);
  regId = getRegistrationId(context);
  if (TextUtils.isEmpty(regId)) {
   registerInBackground();
   Log.d("RegisterActivity",
     "registerGCM - successfully registered with GCM server - regId: "
       + regId);
  } else {
   Toast.makeText(getApplicationContext(),
     "RegId already available. RegId: " + regId,
     Toast.LENGTH_LONG).show();
  }
  return regId;
 }

 private String getRegistrationId(Context context) {
  final SharedPreferences prefs = getSharedPreferences(
    MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
  String registrationId = prefs.getString(REG_ID, "");
  if (registrationId.isEmpty()) {
   Log.i(TAG, "Registration not found.");
   return "";
  }
  int registeredVersion = prefs.getInt(APP_VERSION, Integer.MIN_VALUE);
  int currentVersion = getAppVersion(context);
  if (registeredVersion != currentVersion) {
   Log.i(TAG, "App version changed.");
   return "";
  }
  return registrationId;
 }

 private static int getAppVersion(Context context) {
  try {
   PackageInfo packageInfo = context.getPackageManager()
     .getPackageInfo(context.getPackageName(), 0);
   return packageInfo.versionCode;
  } catch (NameNotFoundException e) {
   Log.d("RegisterActivity",
     "I never expected this! Going down, going down!" + e);
   throw new RuntimeException(e);
  }
 }

 private void registerInBackground() {
  new AsyncTask() {
   @Override
   protected String doInBackground(Void... params) {
    String msg = "";
    try {
     if (gcm == null) {
      gcm = GoogleCloudMessaging.getInstance(context);
     }
     regId = gcm.register(Config.GOOGLE_PROJECT_ID);
     Log.d("RegisterActivity", "registerInBackground - regId: "
       + regId);
     msg = "Device registered, registration ID=" + regId;

     storeRegistrationId(context, regId);
    } catch (IOException ex) {
     msg = "Error :" + ex.getMessage();
     Log.d("RegisterActivity", "Error: " + msg);
    }
    Log.d("RegisterActivity", "AsyncTask completed: " + msg);
    return msg;
   }

   @Override
   protected void onPostExecute(String msg) {
    Toast.makeText(getApplicationContext(),
      "Registered with GCM Server." + msg, Toast.LENGTH_LONG)
      .show();
   }
  }.execute(null, null, null);
 }

 private void storeRegistrationId(Context context, String regId) {
  final SharedPreferences prefs = getSharedPreferences(
    MainActivity.class.getSimpleName(), Context.MODE_PRIVATE);
  int appVersion = getAppVersion(context);
  Log.i(TAG, "Saving regId on app version " + appVersion);
  SharedPreferences.Editor editor = prefs.edit();
  editor.putString(REG_ID, regId);
  editor.putInt(APP_VERSION, appVersion);
  editor.commit();
 }
}
activity_register.xml


    

    
MainActivity.java
package com.javapapers.android.gcm.devicetodevice;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class MainActivity extends Activity {

 ShareExternalServer appUtil;
 String regId;
 String userName;
 AsyncTask shareRegidTask;

 EditText toUser;
 EditText message;
 Button btnSendMessage;

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  appUtil = new ShareExternalServer();

  regId = getIntent().getStringExtra("regId");
  Log.d("MainActivity", "regId: " + regId);

  userName = getIntent().getStringExtra(Config.REGISTER_NAME);
  Log.d("MainActivity", "userName: " + userName);

  shareRegidTask = new AsyncTask() {
   @Override
   protected String doInBackground(Void... params) {
    String result = appUtil
      .shareRegIdWithAppServer(regId, userName);
    return result;
   }

   @Override
   protected void onPostExecute(String result) {
    shareRegidTask = null;
    Toast.makeText(getApplicationContext(), result,
      Toast.LENGTH_LONG).show();
   }

  };

  // to send message to another device via Google GCM
  btnSendMessage = (Button) findViewById(R.id.sendMessage);
  btnSendMessage.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View arg0) {

    toUser = (EditText) findViewById(R.id.toUser);
    String toUserName = toUser.getText().toString();

    message = (EditText) findViewById(R.id.message);
    String messageToSend = message.getText().toString();

    if (TextUtils.isEmpty(toUserName)) {
     Toast.makeText(getApplicationContext(),
       "To User is empty!", Toast.LENGTH_LONG).show();
    } else if (TextUtils.isEmpty(messageToSend)) {
     Toast.makeText(getApplicationContext(),
       "Message is empty!", Toast.LENGTH_LONG).show();
    } else {
     Log.d("MainActivity", "Sending message to user: "
       + toUserName);
     sendMessageToGCMAppServer(toUserName, messageToSend);

    }
   }
  });

  shareRegidTask.execute(null, null, null);
 }

 private void sendMessageToGCMAppServer(final String toUserName,
   final String messageToSend) {
  new AsyncTask() {
   @Override
   protected String doInBackground(Void... params) {

    String result = appUtil.sendMessage(userName, toUserName,
      messageToSend);
    Log.d("MainActivity", "Result: " + result);
    return result;
   }

   @Override
   protected void onPostExecute(String msg) {
    Log.d("MainActivity", "Result: " + msg);
    Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG)
      .show();
   }
  }.execute(null, null, null);
 }
}
activity_main.xml


    

    

    

        
    

    

    

    
ShareExternalServer.java
package com.javapapers.android.gcm.devicetodevice;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import android.util.Log;

public class ShareExternalServer {

 public String shareRegIdWithAppServer(final String regId,
   final String userName) {
  String result = "";
  Map paramsMap = new HashMap();
  paramsMap.put("action", "shareRegId");
  paramsMap.put("regId", regId);
  paramsMap.put(Config.REGISTER_NAME, userName);
  result = request(paramsMap);
  if ("success".equalsIgnoreCase(result)) {
   result = "RegId shared with GCM application server successfully. Regid: "
     + regId + ". Username: " + userName;
  }
  Log.d("ShareExternalServer", "Result: " + result);
  return result;
 }

 public String sendMessage(final String fromUserName,
   final String toUserName, final String messageToSend) {

  String result = "";
  Map paramsMap = new HashMap();
  paramsMap.put("action", "sendMessage");
  paramsMap.put(Config.REGISTER_NAME, fromUserName);
  paramsMap.put(Config.TO_NAME, toUserName);
  paramsMap.put(Config.MESSAGE_KEY, messageToSend);
  result = request(paramsMap);
  if ("success".equalsIgnoreCase(result)) {
   result = "Message " + messageToSend + " sent to user " + toUserName
     + " successfully.";
  }
  Log.d("ShareExternalServer", "Result: " + result);
  return result;
 }

 public String request(Map paramsMap) {
  String result = "";
  URL serverUrl = null;
  OutputStream out = null;
  HttpURLConnection httpCon = null;
  try {
   serverUrl = new URL(Config.APP_SERVER_URL);
   StringBuilder postBody = new StringBuilder();
   Iterator> iterator = paramsMap.entrySet()
     .iterator();
   while (iterator.hasNext()) {
    Entry param = iterator.next();
    postBody.append(param.getKey()).append('=')
      .append(param.getValue());
    if (iterator.hasNext()) {
     postBody.append('&');
    }
   }
   String body = postBody.toString();
   byte[] bytes = body.getBytes();
   httpCon = (HttpURLConnection) serverUrl.openConnection();
   httpCon.setDoOutput(true);
   httpCon.setUseCaches(false);
   httpCon.setFixedLengthStreamingMode(bytes.length);
   httpCon.setRequestMethod("POST");
   httpCon.setRequestProperty("Content-Type",
     "application/x-www-form-urlencoded;charset=UTF-8");
   Log.d("ShareExternalServer", "Just before getting output stream.");
   out = httpCon.getOutputStream();
   out.write(bytes);
   int status = httpCon.getResponseCode();
   Log.d("ShareExternalServer", "HTTP Connection Status: " + status);
   if (status == 200) {
    result = "success";
   } else {
    result = "Post Failure." + " Status: " + status;
   }

  } catch (MalformedURLException e) {
   Log.e("ShareExternalServer", "Unable to Connect. Invalid URL: "
     + Config.APP_SERVER_URL, e);
   result = "Invalid URL: " + Config.APP_SERVER_URL;
  } catch (IOException e) {
   Log.e("ShareExternalServer",
     "Unable to Connect. Communication Error: " + e);
   result = "Unable to Connect GCM App Server.";
  } finally {
   if (httpCon != null) {
    httpCon.disconnect();
   }
   if (out != null) {
    try {
     out.close();
    } catch (IOException e) {
     // do nothing
    }
   }
  }
  return result;
 }

}
I have not displayed the source of GCMNotificationIntentService.java, GcmBroadcastReceiver.java, Config.java and AndroidManifest.xml files. As they are same as given the previous tutorial. Either you may refer the previous tutorial or you can download the project below to get the complete files. Source URL:http://javapapers.com/android/android-device-to-device-messaging-using-google-cloud-messaging-gcm-via-http/

0 comments:

Post a Comment

 
Toggle Footer