El cliente de un
servicio GCM podrá recibir notificaciones Push y procesarlas mediante algún
mecanismo. Cabe destacar que una notificación Push despierta a un servicio de
la app pasándole información proveniente del servidor, dicha información puede
ser directamente un dato necesario en la app, un identificador de algún
registro de la base de datos, o simplemente la llamada que le indique a la app
que los datos deben ser actualizados con información del servidor. Una vez
obtenida esta alerta, la app puede indicar mediante una notificación del
sistema operativo algún mensaje al usuario.
El proceso completo
para poder recibir notificaciones es el siguiente:
- La app se registra en GCM, empleando el id de la aplicación correspondiente
- La app envía a un servidor propio el id de registro, necesario para poder enviarle notificaciones
- El servidor ya podrá enviar notificaciones a la app, indicando su id de registro y la información necesaria para la comunicación
Lo mínimo necesario
Configurar el manifest del proyecto de aplicación. En este
caso hay dos Activity definidas, la principal que realiza el registro, y una
Activity para mostrar cuando se recibe una alerta. El resto de elementos son
requeridos para poder recibir las notificaciones push.
La aplicación debe referenciar la librería Google Play
Services para poder funcionar correctamente:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="es.hubiqus.gcmclient"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
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="es.hubiqus.gcmclient.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission
android:name="es.hubiqus.gcmclient.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"
/>
<activity
android:name="es.hubiqus.gcmclient.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>
<activity
android:name="es.hubiqus.gcmclient.AlertaActivity"
android:label="@string/app_name"/>
<receiver
android:name="es.hubiqus.gcmclient.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND"
>
<intent-filter>
<action
android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="es.hubiqus.gcmclient"
/>
</intent-filter>
</receiver>
<service android:name="es.hubiqus.gcmclient.GcmIntentService"
/>
</application>
</manifest>
|
Cabe destacar del Manifest anterior que en los permisos de
tipo C2D_MESSAGE debe incluirse el
nombre de paquete de la app, así como en la etiqueta category del receiver.
Una Activity principal que realiza el registro con el
servidor GCM. Una vez registrado envía el id recibido al servidor propio.
Es necesario que esta clase chequee si se encuentra
habilitado el APK de Google Play Services en el dispositivo, en caso contrario
lanza una ventana de descarga del mismo, y cierra la app:
public class
MainActivity extends Activity {
private static final String
PROP_REGID = "regId";
private static final String
PROP_VERSION = "appVersion";
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
private GoogleCloudMessaging gcm;
//Id del proyecto, se obtiene en la Google API Console
private String SENDER_ID = "ID";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Comprobar que existen los servicios de Google Play,
//en tal caso registrar el dispositivo
if (checkPlayServices()) {
gcm = GoogleCloudMessaging.getInstance(this);
String regid = getRegId();
//Registrar si no estaba registrado
if (regid.length() == 0) {
registrar();
}
}
}
@Override
protected void onResume() {
super.onResume();
//Chequear Play Services
checkPlayServices();
}
/**
* Chequear
la APK Google Play Services APK
* Si no, lanza diálogo para la descarga
*/
private boolean checkPlayServices() {
int resultCode =
GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode !=
ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode))
{
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
finish();
}
return false;
}
return true;
}
/**
* Obtener el ID de registro si
ya existía
* Si devuelve cadena vacía es necesario
registro con el servidor
*
* @return regID, o cadena vacía si no está registrado
*/
private String getRegId() {
SharedPreferences prefs =
getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE);
String registrationId = prefs.getString(PROP_REGID, "");
if (registrationId.length() == 0) {
return "";
}
//Si la app fue actualizada se obtiene nuevo ID
int registeredVersion =
prefs.getInt(PROP_VERSION,
Integer.MIN_VALUE);
int currentVersion =
getAppVersion();
if (registeredVersion !=
currentVersion) {
return "";
}
return registrationId;
}
/**
* Guardar
regId y versión
* @param regId registration ID
*/
private void setRegId(String regId) {
SharedPreferences prefs =
getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE);
int appVersion =
getAppVersion();
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROP_REGID,
regId);
editor.putInt(PROP_VERSION, appVersion);
editor.commit();
}
/**
* Obtener la versión de la app
* @return número de versión
*/
private int getAppVersion() {
try {
PackageInfo packageInfo = getPackageManager().
getPackageInfo(getPackageName(), 0);
return packageInfo.versionCode;
} catch (NameNotFoundException e) {
return 0;
}
}
/**
* Registrar con el servidor
*/
private void registrar(){
TareaRegistro tarea = new TareaRegistro();
tarea.execute();
}
/**
* Enviar el regId al servidor para
que lo incluya en los push
*/
private void enviar(String regId){
TareaEnvio tarea = new TareaEnvio();
tarea.execute(regId);
}
private class TareaRegistro extends AsyncTask<Void, Void, String> {
@Override
protected String
doInBackground(Void... args) {
String regid = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.
getInstance(MainActivity.this);
}
regid = gcm.register(SENDER_ID);
//Enviar al servidor
enviar(regid);
} catch (IOException ex) {
regid = "Error :" + ex.getMessage();
}
return regid;
}
}
private class TareaEnvio extends AsyncTask<String, Void, String> {
@Override
protected String
doInBackground(String... args) {
String
res = args[0];
try {
EnviarHttp
client =
new
EnviarHttp(MainActivity.this);
res
= client.callService(res);
}
catch (Exception ex) {
ex.printStackTrace();
res
= null;
}
return res;
}
@Override
protected void onPostExecute(String result) {
if (result != null){
//Guardar el regId
setRegId(result);
}
}
}
}
|
Una clase para el envío de id de registro al servidor:
public class
EnviarHttp {
//Codificación empleada
public static final String
ENCODING = "UTF-8";
private static final String
PARAM_OP = "op";
private static final String
PARAM_ID = "id";
private static final String
OP_SAVE = "save";
private static final int TIMEOUT_CONN = 5000;
private static final int TIMEOUT_SOCK = 15000;
private Context context;
public EnviarHttp(Context
context){
this.context = context;
}
/**
* Envío de solicitud HTTP
* @return
* @throws Exception
*/
public String callService(String
id) throws Exception {
String
res = null;
InputStream
is = null;
HttpParams
httpParameters = new
BasicHttpParams();
//Timeout para conectar, por defecto 0 (no hay timeout)
HttpConnectionParams.setConnectionTimeout(httpParameters,
TIMEOUT_CONN);
//Timeout para obtener datos
HttpConnectionParams.setSoTimeout(httpParameters,
TIMEOUT_SOCK);
HttpClient
client = new
DefaultHttpClient(httpParameters);
try {
//La solicitud será a la URL que determine el parámetro
HttpPost post =
new HttpPost(context.getString(R.string.ws_url));
//Parámetros de envío
List<NameValuePair>
params =
new
ArrayList<NameValuePair>();
params.add(new BasicNameValuePair(PARAM_OP, OP_SAVE));
params.add(new BasicNameValuePair(PARAM_ID, id));
post.setEntity(new
UrlEncodedFormEntity(params));
//Lanzar petición
HttpResponse
response = client.execute(post);
// Procesar la información
is =
response.getEntity().getContent();
res
= this.procesar(is);
}
finally {
// cerrar las conexiones
if (is != null) {
is.close();
}
}
return res;
}
/**
* Método para obtener la respuesta
* @param is stream de entrada con los datos a procesar
* @return objeto procesado
* @throws IOException error en la conexión
*/
public String procesar(InputStream
is) throws IOException{
String
res = null;
BufferedReader
br =
new BufferedReader(new InputStreamReader(is, ENCODING));
String
linea;
if ((linea = br.readLine()) !=
null){
res = linea;
}
return res;
}
}
|
Un receiver que se encarga de obtener la notificación Push y
ceder el control al servicio de notificaciones:
public class
GcmBroadcastReceiver extends
WakefulBroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//Servicio que gestionará el push
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
//Lanzar el servicio
startWakefulService(context,
(intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
|
Un servicio de notificaciones que se encargará de realizar
el procesamiento en función del mensaje recibido, y de notificar en la barra
del sistema:
public class
GcmIntentService extends
IntentService {
public GcmIntentService() {
super("GcmIntentService");
}
@Override
protected void onHandleIntent(Intent intent) {
try {
int id = Integer.parseInt(intent.getExtras().getString("data"));
GoogleCloudMessaging gcm =
GoogleCloudMessaging.getInstance(this);
String messageType =
gcm.getMessageType(intent);
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.
equals(messageType)) {
//Realizar el procesamiento
this.notificarBarra(getApplicationContext(),
id);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//Liberar el bloqueo lanzado por el
WakefulBroadcastReceiver
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
}
/**
* Notificar alerta, pasando datos
a la activity correspondiente
* @param
context
* @param id
*/
private void notificarBarra(Context context, int id) {
//Gestor
de notificaciones
NotificationManager
mNotificationManager =
(NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
//Información
de la notificación
CharSequence contentTitle =
context.getString(R.string.app_name);
CharSequence contentText =
context.getString(R.string.msg_alerta);
//Construir
alerta
NotificationCompat.Builder
builder =
new
NotificationCompat.Builder(context)
.setContentTitle(contentTitle)
.setContentText(contentText)
.setWhen(when)
.setSmallIcon(icon)
.setAutoCancel(true);
builder.setDefaults(Notification.DEFAULT_ALL);
//Intent que se lanzará cuando el usuario pulse en
la alerta
Intent
notificationIntent =
new Intent(context,
AlertaActivity.class);
Bundle args = new Bundle();
args.putInt(AlertaActivity.PARAM_ID, id);
notificationIntent.putExtras(args);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent =
PendingIntent.getActivity(context, id, notificationIntent, 0);
builder.setContentIntent(contentIntent);
//Notificar
mNotificationManager.notify(id,
builder.build());
}
}
|
No hay comentarios:
Publicar un comentario