Android Parse Spingere registrazione dispositivo di notifica solo una volta su un dispositivo

? Mayur Raval @ | Original: StackOverFlow

Ognuno Sto usando il servizio di analisi per la notifica push nella mia app . ma registrare tutti i tempi quando ho ri - installare l'applicazione in un problema device.Then è che, un dispositivo riceve più notifiche su ogni . Ho fatto qualche codice di registrazione che riportiamo di seguito . please help me, grazie in anticipo .

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();

E per iscriversi :

PushService.subscribe(this, userName, Detail.class);

In Manifest

Above

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

  <uses-permission android:name="com.example.app.permission.C2D_MESSAGE" />

In tag applicazione :

    <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>

E ogni volta che mi installare, esso esposizione errore che riportiamo di seguito .

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)

Vorrei iscrivermi solo una volta per il dispositivo . Non ci dovrebbe essere un problema se un'applicazione installata tempo più in device.please mi aiuti, grazie in anticipo .

Nel mio caso scheda di Samsung 3 registri due volte con lo stesso UniqueId . È UniqueId è contrassegnato come colonna unica parse db ? O dovremmo renderlo unico ? Se sì, come ?



Top 5 Respuesta

1Eran @

PushService.subscribe Sembra mettere in cache la sottoscrizione in memoria locale, per evitare una nuova sottoscrizione quando si avvia l'applicazione più volte .

Questo è ciò che il primo parametro di tale metodo è utilizzato per :

contesto - Questo è usato per accedere allo storage locale per memorizzare nella cache il   sottoscrizione, quindi deve attualmente             essere un contesto vitale.

( citazione da http://parse.com/docs/android/api/com/parse/PushService.html ) .

Tuttavia, quando si disinstalla l'applicazione, memorizzazione locale per tale applicazione è cancellato dal dispositivo, in modo che il nuovo impianto farà PushService.subscribe a ri - registrarsi per Google Cloud Messaging . Se la nuova registrazione restituisce un nuovo ID di registrazione, Parse avrebbe due ID di registrazione che possono essere utilizzati per inviare notifiche push per la vostra applicazione, ed entrambi sarebbero legati al lo stesso nome utente che hai fornito a subscribe . Pertanto l'invio di una notifica a tale nome utente invierà ad entrambi gli ID di registrazione, facendolo arrivare due volte .

Quando Parse inviare le notifiche per voi, essi dovrebbero ottenere da Google una risposta con canonical_registration_id, che permetterà loro di conoscere uno degli ID di registrazione associati con la tua applicazione sul dispositivo è vecchio, e non dovrebbe essere usato più. Pertanto ( supponendo Parse hanno una implementazione decente di GCM ) la prossima volta che si invia una notifica al dispositivo, si dovrebbe ricevere una sola volta .



2Mayur Raval @

Ho capito dopo l'aggiornamento della tabella con l'invio di unico id 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("UniqueId",android_id);

    installation.saveInBackground();

Si aggiornerà il grezzo, ma non registrare nuovamente il dispositivo .

3Sheraz Ahmad Khilji @

Mi è stato anche di fronte a questo problema . I sorta di risolto chiamando il metodo seguito nella mia attività di 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);
                }
            });

    }

Anche se non ha risolto completamente il mio problema, ma ora il mio app non si blocca e non più di ANR a causa di questa implementazione Parse . Se i ri installare un app e corro subito quindi l'applicazione crea un nuovo record di installazione e rimuovere è l'ultimo . L'unico problema è che il nome_canale non è sottoscritto in questo periodo, ma sulla prossima corsa del canale sono sottoscritto con successo .

4user1201239 @

Penso Mukul ha fornito grande codice nuvola di questo problema

here it is

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();
});
});

Si noti che il proprietario è il nome utente o la chiave primaria che si pensa u possibile utilizzare .

ecco il link dello stesso con una migliore spiegazione mukul  https://www.parse.com/questions/check-for-duplicate-installations-of-same-user-on-re-installation-of-app

5Albert Vila @

Che cosa ha funzionato per me per sbarazzarsi di questa eccezione è stata con saveEventually() invece di saveInBackground() .

Qui avete http://stackoverflow.com/a/27151459/4034572 alla mia risposta a una domanda simile .

Penso che saveEventually() è una scelta migliore, perché assicura che sarà sempre salvato l'installazione, a prescindere dalla disponibilità netwwork . Al contrario, con saveInBackground() c'è una possibilità che il salvataggio fallisce a causa di connettività di rete . Anche con saveEventually() non c'è bisogno di fare alcun controllo degli errori, che si dovrebbe fare in un SaveCallback() con saveInBackground() .

Per quanto riguarda le notifiche duplicati, questo non dovrebbe accadere se si utilizza l'ultimo SDK Parse ( non capita a me con 1.7.1 ) . C'è stato un errore che ora è stato risolto . Vedere http://stackoverflow.com/q/24590804/4034572 e https://developers.facebook.com/bugs/1520221558200050/ .

Si noti che la prima volta che l'utente riceve una notifica dopo la reinstallazione l'applicazione, la notifica può essere consegnato due volte . E ' successo a me, ma succede solo per la prima notifica. ( Vedi il link FB per maggiori dettagli ). Dopo tale notifica duplicato, il vecchio impianto verrà eliminato automaticamente da Parse . Questa è la mia esperienza .

Se si sta cercando di evitare l'invio di notifiche duplicate mediante l'attuazione di una logica al CloudCode ( utilizzando un BeforeSave che si innesca quando il salvataggio di una nuova installazione, controllare se l'applicazione era già stata installata nel dispositivo e di eliminare il vecchio impianto ), non fare che ! Non vi è bisogno . Analizza lo farà per voi : si eliminerà il vecchio impianto :)