Monday, August 19, 2013

Push Notification for iOS and Android with RESTlet Framework


Introduction :

Push notifications let your application notify a user of new messages or events even when the user is not actively using your application. On Android devices, when a device receives a push notification, your application's icon and a message appear in the status bar. When the user taps the notification, they are sent to your application. At iOS devices, it will appear as an alert box with buttons and header text and custom message.

Below are some prerequisites for Google Cloud Messaging (GCM) and Apple Push Notification Service (APNS).

1. GCM :
- Google Account.
- Register your application on GCM from Google APIs Console.
- Android API Key
- Android Device Push String (Android 2.2+)

2. iOS :
- iOS developer account
- Register your application on iOS developer account
- Download Push Notification P12 Certificate
- Add Device Profile on iOS developer account
- iOS device



Now, lets move to coding portion, I've used Eclipse IDE, RESTlet Framework for Web Services and JSON datatype for request & response.

Project Structure :






Project Coding :

Web.xml


  PushRnD
  
    RestletServlet
    org.restlet.ext.servlet.ServerServlet
    
      org.restlet.application
      com.test.pushmsg.application.PushApplication
    
  
  
    RestletServlet
    /service/*
  
  
    
    PushApplication
    PushApplication
    com.test.pushmsg.application.PushApplication
  
  
    PushApplication
    /PushApplication
  


Push Application :

package com.test.pushmsg.application;

import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;

import com.test.pushmsg.resource.TestPushMessageService;

public class PushApplication extends Application{
 public synchronized Restlet createInboundRoot() {
  //Create a router Restlet that routes each call to a new resource.
  Router router = new Router(getContext());
  router.attach("/TestPushMessage/{type}/{push_string}",TestPushMessageService.class); // Test Push Notification Message Is working on both devices or not.
  return router;
 }
}

TestPushMessageService.java

package com.test.pushmsg.resource;

import org.restlet.data.MediaType;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

import com.test.pushmsg.manager.TestPushMessage;

public class TestPushMessageService extends ServerResource{
 
 @Get("json")
 public Representation getJson() {
     String jsonString="";
     try{
      String devicetype = (String)this.getRequestAttributes().get("type");
      String PushString = (String)this.getRequestAttributes().get("push_string");
      TestPushMessage tpm = new TestPushMessage();
      jsonString = tpm.sendPushNotification(devicetype,PushString);
     }catch(Exception ex){
      System.out.println("Error while get records.."+ex.toString());
     }
     return new StringRepresentation(jsonString,MediaType.APPLICATION_JSON);
    }
 
}

TestPushMessage.java

package com.test.pushmsg.manager;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class TestPushMessage {

 public String sendPushNotification(String devicetype,String pushString){
  String retString = "";
  ResponseParseFactory parseFactory = new ResponseParseFactory();
  try{
   if("android".equalsIgnoreCase(devicetype)){
    
    String gcmsend = "";
    PushManager gcm = PushManagerFactory.getInstance("Android");
    Map<string tring=""> pushParam = new HashMap<string string="">();
    pushParam.put("Message", "This is test Message");
    gcmsend = gcm.sentMessage(pushString,"TestPushMessage","Android","View",pushParam);
    if("true".equalsIgnoreCase(gcmsend)){
     retString = parseFactory.getSuccessJsonString("Push Message Send For Android Device");
    }else{
     retString = parseFactory.getSuccessJsonString("Push Message Not Send For Android Device");
    }
    
   }else if("iphone".equalsIgnoreCase(devicetype)){
    
    PushManager apns = PushManagerFactory.getInstance("Iphone");
    Map<string string=""> param = new HashMap<string string="">(); 
    String apnssend = "";
    param.put("Message", "This is test Message");
    apnssend = apns.sentMessage(pushString, "TestPushMessage", "iOS", "View", param);
    
    if("true".equalsIgnoreCase(apnssend)){
     retString = parseFactory.getSuccessJsonString("Push Message Send For Apple Device");
    }else{
     retString = parseFactory.getSuccessJsonString("Push Message Not Send For Apple Device");
    }
   }
  }catch(Exception ex){
   System.out.println("Error While Sending Push Notification..."+ex.toString());
   retString = parseFactory.ServerErrorFound();
  }
  return retString;
 }
 
 public static String RandomStringGenerator(int totchar){
  String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    Random rnd = new Random();
    StringBuilder sb = new StringBuilder( totchar );
    for( int i = 0; i &lt; totchar; i++ ) 
     sb.append( AB.charAt( rnd.nextInt(AB.length()) ) );
    return sb.toString();
 }
 
}

Push Manager :

import java.util.Map;

/**
 * this interface define the template for the push managers . 
 *
 */
public interface PushManager {
 /**
  * for configure the push notification accounts instance or to register the services over the push notification services like APNS OR GCM
  * 
  * @param confString
  * @param password
  * @return String
  */
 public String configureAccount(String confString, String password);
 /**
  *  This method actually sent the message to the device and return the status of the notification to the caller resources.
  *  
  * @param pushString
  * @param message
  * @param deviceName
  * @return String
  */
 public String sentMessage(String pushString , String message,String deviceName,String screen,Map<string string=""> param);
 
}

PushManagerFactory.java

package com.test.pushmsg.manager;

import org.apache.log4j.Logger;

public class PushManagerFactory {
 static Logger logger = Logger.getLogger(PushManagerFactory.class);
 private static ApplePushManager apmInstance = null;
 private static AndroidGcmManager andInstance = null;
 
 /**
  * return the instance of the manager class according to device type if the instance is null already then it will create a new instance of the manager class
  * @param type
  */
 public static PushManager getInstance(String type){
  
  if("Iphone".equalsIgnoreCase(type)){
   apmInstance = new ApplePushManager();
   apmInstance.configureAccount("/test/Test_Certificates.p12", "");
   return apmInstance;
  }else if("Android".equalsIgnoreCase(type)){
   andInstance = new AndroidGcmManager();
   andInstance.configureAccount("abcdefghijklmnopqrstu-abcdefghijklmnopq",null);
   return andInstance;
  }
  return null;
 }
}

Android GCM Manager :

package com.test.pushmsg.manager;

import java.io.IOException;
import java.util.Map;

import org.apache.log4j.Logger;

import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Message.Builder;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;

public class AndroidGcmManager implements PushManager {
 static Logger logger = Logger.getLogger(AndroidGcmManager.class);
 Sender sender;

 /**
  * configure android GSM account for the sending push notification to the
  * android device.
  */
 @Override
 public String configureAccount(String apiKey, String password) {
  String responseString = "true";
  sender = new Sender(apiKey);
  return responseString;
 }

 /**
  * this method send the notification to the device and return the status of
  * the notification.
  */
 @Override
 public String sentMessage(String pushString, String message,
   String deviceName, String screen, Map<string string=""> param) {
  String responseString = "true";
  if (sender != null) {
   try {
    Builder builder = new Message.Builder();
    for (String key : param.keySet()) {
     builder.addData(key, param.get(key));
    }
    builder.addData("data.payload", message);
    builder.collapseKey(TestPushMessage.RandomStringGenerator(9));
    Message gcmMessage = builder.build();
    Result result = sender.send(gcmMessage, pushString, 5);
    if (result != null) {
     if (result.getMessageId() != null) {
      String canonicalRegId = result
        .getCanonicalRegistrationId();
      if (canonicalRegId != null) {
       logger.info("Canonical Registration: " + canonicalRegId);
      }
     } else {
      String error = result.getErrorCodeName();
      if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
       logger.info("Error Code Name: " + result.getErrorCodeName());
       // application has been removed from device -
       // unregister database
      }
     }
    }
   } catch (IOException e) {
    logger.info(e.toString());
    responseString = "false";
   }
  } else
   responseString = "false";
  return responseString;
 }
}

Apple Push Manager :

package com.test.pushmsg.manager;

import java.util.ArrayList;
import java.util.Map;

import javapns.back.FeedbackServiceManager;
import javapns.back.PushNotificationManager;
import javapns.back.SSLConnectionHelper;
import javapns.data.Device;
import javapns.data.PayLoad;
import javapns.data.PayLoadCustomAlert;

import org.apache.log4j.Logger;

/**
 * This is the applePushManager class implement the functionality of the push Manager.
 */
public class ApplePushManager implements PushManager{
 
 static Logger logger = Logger.getLogger(ApplePushManager.class);
 private static final String HOST = "gateway.sandbox.push.apple.com";//"gateway.push.apple.com";
    private static final int PORT = 2195;
    PushNotificationManager pushManager = PushNotificationManager.getInstance();
    FeedbackServiceManager feedbackManager = FeedbackServiceManager.getInstance();

    public ApplePushManager() {
 }
    
    /**
     * configure apple account for the sending push notification to the iphone device.
     */
 @Override
 public String configureAccount(String confString, String password) {
  try{
   pushManager.initializeConnection( HOST, PORT, confString, password, SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
            logger.info( "Connection initialized..." );
            logger.info( "done" );
  }catch(Exception e){
   logger.info(e.toString());
   return "false";
  }
  return "true";
 }

 /**
  * this method send the notification to the device and return the status of the notification. 
  */
 @SuppressWarnings({"unchecked","rawtypes"})
 @Override
 public String sentMessage(String pushString, String message,String DeviceName,String screen,Map<string string=""> param) {
  String retString = "false";
  PayLoad aPayload = new PayLoad();
        PayLoadCustomAlert customAlert = new PayLoadCustomAlert();
        try{
         if(!"".equals(screen)){
       customAlert.addActionLocKey(screen);
      }
         customAlert.addLocKey(message);
          
         ArrayList parameters = new ArrayList();
         parameters.add("JAVA");
         parameters.add("apns");
         parameters.add(2);
            
         aPayload.addCustomAlert(customAlert);
         aPayload.addSound("default");
         if((param != null) &amp;&amp; (!(param.isEmpty()))){
          for(String key : param.keySet()){
           aPayload.addCustomDictionary(key, param.get(key));
          }
         }else{
          aPayload.addCustomDictionary("screen", screen);
         }
         try {
             pushManager.removeDevice(DeviceName);//Eclipse
   } catch (Exception e) {
    logger.info("Device Not Found..");
   }
         pushManager.addDevice(DeviceName, pushString);
         Device client = pushManager.getDevice( DeviceName );
         if(client!=null){
          pushManager.sendNotification( client, aPayload );
          retString ="true";
         }else{
          retString = "false";
         }
            pushManager.stopConnection();
            try {
             pushManager.removeDevice(DeviceName);//Eclipse
   } catch (Exception e) {
    logger.info("Device Not Found..");
   }
        }catch(Exception e){
         logger.info(e.toString());  
         retString ="false";
        }
  return retString;
 }
}

ResponseParseFactory.java

package com.test.pushmsg.manager;

import java.util.LinkedHashMap;

import org.json.simple.JSONValue;

public class ResponseParseFactory {
 
 /**
  * Class Constructor creates Logger class objects.
  */
 public ResponseParseFactory(){
 }
 
 /**
  * This method will used to return success JSON string.
  * @param String It contains the string message to send in response
  * @return String It contains the JSON string for success message
  */
 @SuppressWarnings({ "rawtypes", "unchecked" })
 public String getSuccessJsonString(String msg){
  String jsonString = "";
  LinkedHashMap list = new LinkedHashMap();
  list.put("response", msg);
  jsonString = JSONValue.toJSONString(list);
  return jsonString;
 }
 
 /**
  * This method will used to return Server Error JSON string in response with it's code.
  * @return String It contains Server Error message in JSON String
  */
 @SuppressWarnings({ "rawtypes"})
 public String ServerErrorFound(){
  String jsonString = "";
  LinkedHashMap list = new LinkedHashMap();
  jsonString = JSONValue.toJSONString(list);
  return jsonString;
 }
}

you can check web service with any REST Client.




Thanks :)

References :
Eclipse
Google GCM
iOS Push Notification
RESTlet Framework



Share:

4 comments:

  1. Hi thank you for this wonderful tutorial. I want to use push notification for mobile app developed in unity3D. Could you please say how to implement this service on my client side.

    ReplyDelete
    Replies
    1. Hello Vignesh,

      I had not work with Unity team but i think below URL will do best for your requirement.

      http://forum.unity3d.com/threads/easy-cross-platform-notifications-available-now.185452/

      Sorry for late reply.

      Delete