programacion - Android Parse: registra el registro del dispositivo de notificación solo una vez en un dispositivo
notificaciones push android php mysql (7)
PushService.subscribe
parece almacenar en caché la suscripción en el almacenamiento local, para evitar volver a suscribirse cuando inicie la aplicación varias veces.
Para esto se usa el primer parámetro de ese método:
contexto: se usa para acceder al almacenamiento local para almacenar en caché la suscripción, por lo que debe ser un contexto viable en la actualidad.
(cita de aquí ).
Sin embargo, cuando desinstala la aplicación, el almacenamiento local de esa aplicación se elimina de su dispositivo, por lo que la nueva instalación provocará que PushService.subscribe
se PushService.subscribe
nuevamente en Google Cloud Messaging. Si el nuevo registro devuelve un nuevo ID de registro, Parse tendrá dos ID de registro que pueden usarse para enviar notificaciones automáticas a su aplicación, y ambos estarán vinculados al mismo nombre de usuario que usted suministró para subscribe
. Por lo tanto, el envío de una notificación a ese nombre de usuario lo enviará a ambos ID de registro, haciendo que llegue dos veces.
Cuando Parse envíe las notificaciones por usted, deben obtener de Google una respuesta con canonical_registration_id
, que les informará que uno de los ID de registro asociados con su aplicación en su dispositivo es antiguo y no debe volver a utilizarse. Por lo tanto (suponiendo que Parse tenga una implementación decente de GCM) la próxima vez que envíe una notificación a su dispositivo, debe recibirla solo una vez.
Todos estoy usando el servicio de análisis para notificaciones automáticas en mi aplicación. pero se registra todo el tiempo cuando reinstalo la aplicación en un dispositivo. Luego el problema es que un dispositivo recibe múltiples notificaciones en cada uno. He hecho un código para el registro que se muestra a continuación. por favor, ayúdenme, gracias de antemano.
Parse.initialize(this, PARSE_APP_ID, PARSE_CLIENT_KEY);
ParseACL defaultACL = new ParseACL();
defaultACL.setPublicReadAccess(true);
ParseACL.setDefaultACL(defaultACL, true);
PushService.setDefaultPushCallback(this, MainActivity.class);
ParseInstallation.getCurrentInstallation().getInstallationId();
ParseInstallation.getCurrentInstallation().saveInBackground();
Y para suscribirse:
PushService.subscribe(this, userName, Detail.class);
En Manifiesto
Encima
<permission
android:name="com.example.app.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.example.app.permission.C2D_MESSAGE" />
En la etiqueta de la aplicación:
<receiver android:name="com.parse.ParseBroadcastReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.USER_PRESENT" />
<action android:name="act" />
</intent-filter>
</receiver>
<receiver android:name="com.app.example.PushReceiver" >
<intent-filter>
<action android:name="act" />
</action>
</intent-filter>
</receiver>
<receiver
android:name="com.parse.GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<action android:name="act" />
<category android:name="com.example.app" />
</intent-filter>
</receiver>
Y cada vez que instalo, muestra el error que se muestra a continuación.
03-10 12:18:48.555: E/ParseCommandCache(12709): Failed to run command.
03-10 12:18:48.555: E/ParseCommandCache(12709): com.parse.ParseException: at least one ID field (installationId,deviceToken) must be specified in this operation
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.ParseCommand$3.then(ParseCommand.java:348)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$10.run(Task.java:452)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$1.execute(Task.java:68)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.completeImmediately(Task.java:448)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.continueWith(Task.java:322)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.continueWith(Task.java:333)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$8.then(Task.java:385)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$8.then(Task.java:1)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$11.run(Task.java:485)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$1.execute(Task.java:68)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.completeAfterTask(Task.java:481)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.access$9(Task.java:477)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$7.then(Task.java:350)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$7.then(Task.java:1)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.runContinuations(Task.java:514)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.access$5(Task.java:510)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:569)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$TaskCompletionSource.setResult(Task.java:603)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$11$1.then(Task.java:497)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$11$1.then(Task.java:1)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$10.run(Task.java:452)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$1.execute(Task.java:68)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.completeImmediately(Task.java:448)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.access$8(Task.java:444)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$6.then(Task.java:315)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$6.then(Task.java:1)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.runContinuations(Task.java:514)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.access$5(Task.java:510)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:569)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$TaskCompletionSource.setResult(Task.java:603)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$11$1.then(Task.java:497)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$11$1.then(Task.java:1)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$10.run(Task.java:452)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$1.execute(Task.java:68)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.completeImmediately(Task.java:448)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.continueWith(Task.java:322)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.continueWith(Task.java:333)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$11.run(Task.java:489)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$1.execute(Task.java:68)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.completeAfterTask(Task.java:481)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.access$9(Task.java:477)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$7.then(Task.java:350)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$7.then(Task.java:1)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.runContinuations(Task.java:514)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task.access$5(Task.java:510)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$TaskCompletionSource.trySetResult(Task.java:569)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$TaskCompletionSource.setResult(Task.java:603)
03-10 12:18:48.555: E/ParseCommandCache(12709): at com.parse.Task$3.run(Task.java:228)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.util.concurrent.FutureTask.run(FutureTask.java:237)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:152)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:265)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
03-10 12:18:48.555: E/ParseCommandCache(12709): at java.lang.Thread.run(Thread.java:841)
Deseo registrarme solo una vez para el dispositivo. no debería haber un problema si la aplicación se instaló varias veces en el dispositivo. Por favor ayúdenme, gracias de antemano.
En mi caso, Samsung tab 3 registra dos veces con el mismo UniqueId. ¿UniqueId está marcado como columna única en parse db? O deberíamos hacerlo único? si es así, ¿cómo?
Yo también estaba enfrentando este problema. De alguna manera lo resolví llamando al método de abajo en mi Actividad onCreate()
/**
* Initialize Push Messaging Service and subscribe to all-users channel
*/
private void initParsePushMessaging() {
ParseInstallation parseInstallation = ParseInstallation
.getCurrentInstallation();
//You might skip this if
if (ParseUser.getCurrentUser() != null) {
parseInstallation.put("user",
ParseUser.getCurrentUser());
}
if (parseInstallation.getObjectId() != null)
parseInstallation.saveInBackground(new SaveCallback() {
@Override
public void done(ParseException e) {
PushService.subscribe(getApplicationContext(),"channel_name",
MainHomeActivity.class);
}
});
}
Aunque no resolvió completamente mi problema, ahora mi aplicación no se bloquea y no hay más ANR debido a esta implementación de Parse. Si vuelvo a instalar una aplicación y la ejecuto ahora, la aplicación crea un nuevo registro de instalación y elimina el último. El único problema es que channel_name no está suscrito en esta ejecución, pero en la siguiente ejecución el canal se suscribió con éxito .
Creo que Mukul ha proporcionado un excelente código de nube para este problema
aquí está
Parse.Cloud.beforeSave(Parse.Installation, function(request, response) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.Installation);
query.equalTo("owner", request.user);
query.equalTo("uniqueID", request.object.get("uniqueID"));
query.first().then(function(duplicate) {
if (typeof duplicate === "undefined") {
console.log("Duplicate does not exist,New installation");
response.success();
} else {
console.log("Duplicate exist..Trying to delete " + duplicate.id);
duplicate.destroy().then(function(duplicate) {
console.log("Successfully deleted duplicate");
response.success();
}, function() {
console.log(error.code + " " + error.message);
response.success();
});
}
}, function(error) {
console.warn(error.code + error.message);
response.success();
});
});
Tenga en cuenta que el propietario es el nombre de usuario o la clave principal que cree que puede usar.
aquí está el enlace de la misma con una mejor explicación por mukul https://www.parse.com/questions/check-for-duplicate-installations-of-same-user-on-re-installation-of-app
Lo obtuve después de actualizar la tabla con el envío de la identificación única del dispositivo Android.
String android_id = Secure.getString(getApplicationContext().getContentResolver(),Secure.ANDROID_ID);
Log.e("LOG","android id >>" + android_id);
PushService.setDefaultPushCallback(this, MainActivity.class);
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("installationId",android_id);
installation.saveInBackground();
Actualizará la versión en bruto, pero no vuelve a registrar el dispositivo.
Crea una nueva clase y amplíala con la aplicación. escribe el código de esta manera
public class BBApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Parse.initialize(this, "app key", "client key");
ParseInstallation.getCurrentInstallation().saveInBackground();
ParsePush.subscribeInBackground("", new SaveCallback() {
@Override
public void done(com.parse.ParseException arg0) {
// TODO Auto-generated method stub
if (arg0 == null) {
Log.d("com.parse.push", "successfully subscribed to the broadcast channel.");
} else {
Log.e("com.parse.push", "failed to subscribe for push", arg0);
}
}
});
ParseUser.enableAutomaticUser();
ParseACL defaultACL = new ParseACL();
// Optionally enable public read access.
// defaultACL.setPublicReadAccess(true);
ParseACL.setDefaultACL(defaultACL, true);
}
}
Agregar entrada en el archivo de manifest
<application android:label="@string/app_name"
android:name="org.cocos2dx.cpp.BBApplication"
android:icon="@drawable/icon">
Encontré trabajo que volverá a registrar las instalaciones eliminadas en Parse nuevamente.
public void clearApplicationData() {
File cache = getCacheDir();
File appDir = new File(cache.getParent());
if (appDir.exists()) {
String[] children = appDir.list();
for (String s : children) {
if (s.equals("app_Parse")) {
deleteDir(new File(appDir, s));
System.out.println( "**************** File /data/data/APP_PACKAGE/" + s + " DELETED *******************");
}
}
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
Y al inicializar Parse solo
Parse.initialize(this, Constants.PARSE_APP_ID, Constants.PARSE_CLIENT_ID);
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
//Trying to update the current installation with a custom key and this will trigger the ParseException if this installation is not found in Installations Table in Parse Server
String value= "Value";
if(installation.get("customKey") != null){
value= installation.get("customKey").toString();
}
installation.put("customKey", value);
//Now lets see what call back brings in
installation.saveInBackground(new SaveCallback() {
@Override
public void done(ParseException e) {
System.out.println("Done");
if (e == null) {
System.out.println("Succesfull Registration.....");
} else {
System.out.println("Cleare cache");
//By clearing the cache the next time user will close and re open the app it will be installed in installations again
clearApplicationData();
}
}
});
Lo que funcionó para mí para deshacerme de esta excepción fue usar saveEventually()
lugar de saveInBackground()
.
Aquí tienes un enlace a mi respuesta a una pregunta similar.
Creo que saveEventually()
es una mejor opción porque asegura que la instalación siempre se guardará, independientemente de la disponibilidad de red. Por el contrario, con saveInBackground()
existe la posibilidad de que el guardado falle debido a la falta de conectividad de red. También con saveEventually()
no necesita hacer ninguna comprobación de errores, lo que debe hacer en SaveCallback()
con saveInBackground()
.
En cuanto a las notificaciones duplicadas , esto no debería ocurrir si está utilizando el último SDK de Parse (no me pasa con 1.7.1). Hubo un error que se ha resuelto ahora. Vea esta pregunta AS y este error FB .
Tenga en cuenta que la primera vez que el usuario recibe una notificación después de volver a instalar la aplicación, esta notificación se puede enviar dos veces. Me ha pasado a mí, pero solo ocurre en la primera notificación. (Consulte el enlace de FB para más detalles.) Después de esa notificación duplicada, Parse eliminará automáticamente la instalación anterior. Esta es mi experiencia.
Si intenta evitar el envío de notificaciones duplicadas implementando alguna lógica en el CloudCode (utilizando un beforeSave que se activa al guardar una instalación nueva, compruebe si la aplicación ya se había instalado en el dispositivo y eliminando la instalación anterior), no haga ¡ese! No hay necesidad Parse lo hará por usted: eliminará la instalación anterior :)