martes, 25 de noviembre de 2014

Servidor Push con GCM

Para poder realizar el envío de notificaciones a los dispositivos es necesario enviar una solicitud al servidor de Google Cloud Messaging.
Para ello se pueden emplear distintas alternativas de comunicación con el mismo, en este caso se va a utilizar una comunicación vía HTTP empleando formato JSON. Se creará un servicio web que cumple una doble función, por un lado el mencionado envío de notificaciones, y por otro la recepción de los ids de los dispositivos que se registran en el sistema, los cuales hay que especificar al enviar una notificación obligatoriamente para que el servicio GCM sepa cuáles son los destinatarios del envío (mínimo un dispositivo, máximo 1000).

Lo mínimo necesario

Una clase para el envío de peticiones al servidor GCM:
public class GcmClient {

    private static final String PROP_URL =
"https://android.googleapis.com/gcm/send";
   
    //Clave obtenida con Google Developers API
    private static final String PROP_KEY = "key";

    /**
     * Enviar un mensaje simple
     * @param ids ids separados por comas
     * @param data datos
     * @return respuesta
     * @throws IOException error al enviar
     */
    public String send(String ids, String data) throws IOException{
        //Datos
        String input = "{\"registration_ids\": [" + ids + "]" +
                        ",\"data\": {" +
                            ",\"data\": \"" + data + "\"}}";
       
        return send(input);
    }
   
    /**
     * Enviar un mensaje
     * @param input mensaje
     * @return respuesta
     * @throws IOException error al enviar
     */
    private String send(String input) throws IOException {
        String res = null;
        HttpURLConnection conn = null;
        BufferedReader br = null;
        try {
            URL url = new URL(PROP_URL);
            conn = (HttpURLConnection) url.openConnection();
           
            //Establecer propiedades
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Authorization", "key=" + PROP_KEY);

            //Enviar
            OutputStream os = conn.getOutputStream();
            os.write(input.getBytes("UTF-8"));
            os.flush();
           
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK){
                br = new BufferedReader(
new InputStreamReader((conn.getInputStream())));

                res = "";
                String linea;
                while ((linea = br.readLine()) != null) {
                    res += linea;
                }
            }
        } finally {
            // cerramos las conexiones
            if (br != null) {
          br.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
       
        return res;
    }
}

Un Servlet para gestionar tanto el envío como la recepción de ids de dispositivo:
@WebServlet(name = "GcmWS", urlPatterns = {"/GcmWS"})
public class GcmWS extends HttpServlet {

    private static final String PARAM_OP = "op";
    private static final String PARAM_ID = "id";
    private static final String OP_SEND = "send";
    private static final String OP_SAVE = "save";
   
    private List<String> ids;

    @Override
    public void init() throws ServletException {
        super.init();
        //Inicializar la lista de dispòsitivos
        //El método init solamente se llama una vez al desplegar el Servlet
        ids = new ArrayList<String>();
    }   
   
    @Override
    protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
        //Habilitado en desarrollo para poder probar con el navegador
        this.doPost(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = response.getWriter();
       
        try{
            //Obtener la operación que requiere el usuario
            String op = request.getParameter(PARAM_OP);
               
            //Responder en función de la operación solicitada
            if (op.equals(OP_SEND)) {
                send(request, out);
            }else if (op.equals(OP_SAVE)) {
                save(request, out);
            }
        } catch (Exception ex) {
            out.println(ex);
        } finally {
            out.close();
        }

    }
   
    /**
     * Enviar un push a todos los recipientes
     * @param request
     * @param out
     * @throws Exception
     */
    private void send(HttpServletRequest request, PrintWriter out)
throws Exception {
        //Datos para la prueba
        //Se puede pasar al cliente cualquier dato serializado o en JSON
        //Lo recibirá como parámetros del Intent
        String data = "12";
       
        //Enviar y devolver resultado
        GcmClient client = new GcmClient();               
        out.println(client.send(getIds(), data));       
    }
   
    /**
     * Obtener los ids destino, separados por comas
     * @return
     */
    private String getIds(){
        String res = "";
        for (String s: ids){
            res += "\"" + s + "\",";
        }
        //Quitar la última coma
        if (res.length() > 0){
            res = res.substring(0, res.length() - 1);
        }
        return res;
    }
   
    /**
     * Almacenar un id
     * @param request
     * @param out
     * @throws Exception
     */
    private void save(HttpServletRequest request, PrintWriter out)
throws Exception {
        String id = request.getParameter(PARAM_ID);
       
        if (id == null || id.length() == 0){
            out.println("ID incorrecto");
        }else{
            ids.add(id);
            out.println("OK");
        }
    }

}

Referencias

https://developer.android.com/google/gcm/http.html

No hay comentarios:

Publicar un comentario