Android Push Notification ( Parte 1 – Cliente )

Las Notificaciones push son por hoy una de los mejores features (Opino yo) que han tenido los móviles, ya que le da al developer la opción de poder interactuar de la manera que quiera con el usuario final y poder así brindarle un buen producto de calidad y una buena experiencia.

Desde enviarle una notificación de un chat o mail hasta hacer que su celular se comporte de forma que el developer quiera (Evil inside).

Hoy dia hay varias alternativas para poder implementar las notificaciones push desde proveedores terceros hasta el mismo google con GCM (Google cloud message) y el que estaremos usando para este tutoriral.

Ahora mismo un poco de la interacciones que suceden para poder llevar acabo esto.

Flow Interation

 

 Detalles de las interacciones

Paso 1 & 2:

Desde el móvil la aplicación se conecta al CGM y solicita un identificador.

Paso 3:

Desde la aplicación buscamos la manera de almacenar ese identificador retornado por GCM. Digo la manera por que el hecho es que el identificador se genero y depende de nosotros guardarlo.

Paso 4:

Desde nuestro servidor de aplicación enviamos las peticiones al GCM para que este luego procesa a enviar los push al dispositivo especifico.

 

Antes de comenzar a coder debemos primero realizar los siguientes pasos.

1.Antes de comenzar debemos crear un projecto en el Google console Developer.

Google_Developers_Console

2.Luego debemos agregarle la api de Google Cloud Message a nuestro Projecto

Google_Developers_Console_api

3.Generar una key para nuestro projecto.

Google_Developers_Console_server_keyGoogle_Developers_Console_ip_key

 

 

Una vez hecho todo Esto, Mano en el codigo.

Crear un projecto Android Simple.

Incluirle el google-play-service-lib

Agregar estos permisos a nuestra applicacion.

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <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" />

Dentro del tag de application agregar esto, sino les dara un error.

    <meta-data
            android:name="com.google.android.gms.version"
               android:value="@integer/google_play_services_version" />

Luego agregar este permiso especial, y cambiar “com.example.projecto” por el propio.

    <permission
        android:name="com.example.projecto.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />

Luego debemos crear un Servicio android que extienda de IntentService, el servicio estara encargado de generar una notificacion una vez reciba un push notificacion de GCM.

public class GCMService extends IntentService{

    private NotificationManager mNotificationManager;

    private int NOTIFICATION_ID = 1234;

	public GCMService() {
		super("Listener-Service");
	}

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();

        sendNotification("Received: " + extras.toString());

        GCMBroadCastReceiver.completeWakefulIntent(intent);
    }

    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, MainActivity.class), 0);

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
        											.setSmallIcon(R.drawable.ic_launcher)
											        .setContentTitle("Developer")
											        .setStyle(new NotificationCompat.BigTextStyle()
											        .bigText(msg))
											        .setContentText(msg);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
}

Agregar el servicio que acabamos de crear a nuestro manifest.xml.

<service android:name="com.example.deveoper.GCMService" />

Ahora necesitamos crear un receiver para poder recibir las notificaciones.

public class GCMBroadCastReceiver extends WakefulBroadcastReceiver{

	private String TAG = "Broadcast receiver";

	@Override
	public void onReceive(Context context, Intent intent) {
		ComponentName comp = new ComponentName(context.getPackageName(),GCMService.class.getName());

        startWakefulService(context, (intent.setComponent(comp)));

        setResultCode(Activity.RESULT_OK);

        Log.i(TAG,"Notification receive");
	}
}

Agregar el receiver que acabamos de crear en nuestro archivo manifest.xml

        <receiver
            android:name="com.example.developer.GCMBroadCastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

                <category android:name="com.example.developer" />
            </intent-filter>
        </receiver>

Una vez esten creado nuestro servicio y nuestro receiver procedemos a trabajar sobre la actividad donde estaremos solicitando nuestro “client-id”.

En este ejemplo usare el main activity pueden usar cualquier actividad. Nuestra mainActivity estaria quedando de esta forma.

public class MainActivity extends Activity {

	private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

	private GoogleCloudMessaging gcm = null;

	private String SENDER_ID = "tu-project-id";
	private String regid;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		if( checkPlayServices(this) == true ){
			getReigstrationId(this);
		}
	}

	public void getReigstrationId(final Context context){
		new AsyncTask<Void, Void, Void>(){

			private String msg;

			@Override
			protected Void doInBackground(Void... arg0) {

				if (gcm == null) {
	                gcm = GoogleCloudMessaging.getInstance(context);
	            }

	            try {
	            	Log.i("Sender",SENDER_ID);

					regid = gcm.register(SENDER_ID);

					msg = "Movil registrado, registration ID=" + regid;

				} catch (IOException e) {
					e.printStackTrace();
				}

				return null;
			}

			@Override
			protected void onPostExecute(Void result) {

				Log.i("Developer",msg);
				Toast.makeText(context, msg, Toast.LENGTH_LONG).show();
			}
		}.execute();
	}

	public static boolean checkPlayServices(Context context) {
	    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
	    if (resultCode != ConnectionResult.SUCCESS) {
	        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
	            GooglePlayServicesUtil.getErrorDialog(resultCode, (Activity) context,PLAY_SERVICES_RESOLUTION_REQUEST).show();
	        } else {
	            Log.i("Developer", "This device is not supported.");
	        }
	        return false;
	    }
	    return true;
	}
}

Si todos los pasos le salieron bien, tendrían como resultado un Toast con su “registratio-id” el cual es el que se usa para enviar las notificaciones.

Hasta aqui la primera parte de este tutorial.

Repositorio con el ejemplo completo

Google Cloud Meesage

Share on Google+Share on LinkedInShare on RedditShare on TumblrTweet about this on TwitterShare on Facebook
  • Luis Alberto Romero Calderon

    Primero 🙂

  • Pingback: Android Push Notification ( Parte 1 - Cliente )...()

  • Hola, necesito ayuda con esto, tienes dos buenos post pero son la mitad de lo que quiero hacer.

    Necesito saber la manera de mandar notificaciones a todos los que usen mi app. Por el momento desconozco Python así que necesito una alternativa, probé plugins en wordpress pero todos son pagando, intenté buscar pero todo lo que me sale son notificaciones que se dan a través de un toque a un botón en la misma app, y en otras vi servicios que te ofrecían el servicio push pero si no eran pagas entonces habían caducado (Parse.com).

    Necesito saber como hacerlo sin necesidad de un servicio externo, GCM es un poquito complicado para mi pero igual ese es solo la mitad.

    Por favor si me puedes ayudar te lo agradecería.

    Gracias de antemano.
    Saludos!

    • Luis Alberto Romero Calderon

      Existen muchas alternativas para implementar notificaciones push en android (alternativas a parse tambien) https://batch.com/ podria ser de utilidad para ti.

      Aqui hay una lista de posibles alternativas a parse.com, yo tu y le tiro un ojo en caso de que batch no cumpla con tus espectativas o satisfaga tus necesidades. https://github.com/relatedcode/ParseAlternatives#push-notification-providers

      Saludos,
      Gracias por comentar. 🙂

      • Muchísimas gracias, probaré a ver que tal ese batch y si no bueno veré los otros que me mandaste.

        Cualquier duda regreso, jeje.

        Saludos!

      • Estoy viendo que que ese Batch también tienes sus limitaciones para una cuenta gratuita, pero mi inglés no está muy bien del todo.

        No entiendo si es que dan 500 notificaciones push por minuto por app, o es de otra forma? Si es como pienso entonces en dos minutos podría mandar 1.000 notificaciones en una app?

        Lo otro que no comprendo del todo aun es si el servicio es como el de Parse, ya que vi que ese se podían mandar las notificaciones en JSON, eso me es util porque yo mandaría un titulo, y texto para describir la notificación y una url para que con el Intent habrá un WebView mostrando la url.

        Te agradezco me disipes la duda.
        Gracias de antemano.
        Saludos!

        • Luis Alberto Romero Calderon

          El primer punto es cierto ellos te limitan a 500 que es bastante bien, solo tendrias que separar en porciones de 500 usuarios tus notificaciones en caso de.

          Con respecto a lo de la libreria, estan colicionando las mismas librerias, parece estas usando un projeco como libreria, lo que debes de hacer es actualizar dicho projecto con una neuva version de android-support o en el area de build-path no incluir una de las dos.

          • Creo que ya lo logré pero como te dije en el anterior comentario, quiero poder decidir que activity abrir de mi app y que parámetros mandar, además de que no sé como recibirlos.

            Disculpa por preguntar tanto pero es que mi inglés es malisimo.
            Gracias por responder.

          • Luis Alberto Romero Calderon

            Para recibir las notificaciones, necesitas crear el broadcast receiver y un service, luego crear crear una notificación y abrir la actividad que quieras cuando se pulse esa actividad. Aquí pdras ver un tutorial de como crear notificaciones y eso http://nightdeveloper.net/notificaciones-android/

          • Una pregunta: sabes para que son los deeplinks? Me dicen que con eso haré lo de lanzar una actividad especifica de mi app.

          • Luis Alberto Romero Calderon

            Eso en si es un filtro que le creas a una actividad en particular, con eso puedes lograr simplemente presionando un link en el movil android o incluso cualquier tipo de documento. https://developer.android.com/training/app-indexing/deep-linking.html

          • Eso quiere decir entonces que eso no me funcionará, entonces estoy mal, porque el crear el broadcast receiver y un service no me funciona, creo el intent y le digo que abrir pero sigue abriendo el MainActivity de mi app, yo quiero abir otra activity cuando el usuario toque la notificación pero ya no sé que hacer, nada me funciona o no sé si lo estoy haciendo mal.

          • Luis Alberto Romero Calderon

            Puedo ver la forma es como estas creando esa notificacion?

          • Uuuhh… cambiaste la apariencia de la página, jejeje…

            Si, intenté modificar algo y si me sale pero con errores. Yo estoy usando los códigos que dan en la documentación de Batch. Mira este link primero https://batch.com/doc/android/advanced/intercepting-notifications.html.

            Este es mi código:

            public class PushService extends IntentService {

            public PushService() {
            super(“MyPushService”);
            }

            @Override
            protected void onHandleIntent(Intent intent)
            {
            try
            {
            if( Batch.Push.shouldDisplayPush(this, intent) ) {
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
            builder.setSmallIcon(R.drawable.icono_app)
            .setContentTitle(“App”)
            .setContentText(“Descripción”);

            Intent launchIntent = new Intent(this, Activity_Lista_Noticias.class);
            Batch.Push.appendBatchData(intent, launchIntent);

            PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
            builder.setContentIntent(contentIntent);

            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);

            int id = (int) (Math.random() * Integer.MAX_VALUE);
            notificationManager.notify(id, builder.build());

            // Call Batch to keep track of that notification
            Batch.Push.onNotificationDisplayed(this, intent);
            }
            }
            finally
            {
            PushReceiver.completeWakefulIntent(intent);
            }
            }
            }

          • Luis Alberto Romero Calderon

            Ese codigo te deberia de funcionar la verdad, pero intentar solucionarlo con esto http://stackoverflow.com/a/21250686/1056852

          • Pienso lo mismo, es más, no sé si sea error de ellos o que pero cuando elimino el if que tienen al principio me funciona en parte, ya que me salen dos notifiaciones: la que yo modifique con todo y el intent bien y la que mando a través de la página de Batch.