Android Parse Empurre o registro de dispositivos de notificação apenas uma vez em um dispositivo

? Mayur Raval @ | Original: StackOverFlow
---

Cada um que eu estou usando o serviço de análise para notificação de envio em meu aplicativo . mas cadastre-se todos os tempos quando eu re- instalar o aplicativo em um problema device.Then é que, um dispositivo de receber várias notificações em cada um. Tenho feito algumas código de registo que é mostrado abaixo . por favor me ajude, obrigado antecipadamente.

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 para se inscrever:

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

Na tag aplicação :

    <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 cada vez que quando estou a instalar, ele mostrará erro que é mostrado abaixo.

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)

Quero me cadastrar apenas uma vez para no dispositivo . não deve haver um problema se app instalado tempo múltipla em device.please me ajudar, obrigado antecipadamente.

No meu caso Samsung Tab 3 registros duas vezes com o mesmo UniqueId . É UniqueId está marcado como coluna exclusiva em parse db ? Ou devemos fazê-lo original ? se sim, como ?

---

Top 5 Responder

1Eran @

PushService.subscribe Parece cache a assinatura no armazenamento local, para evitar a re- inscrição, quando você iniciar o aplicativo várias vezes.

Isto é o que o primeiro parâmetro desse método é utilizado para:

contexto - Isso é usado para acessar o armazenamento local para armazenar em cache o   assinatura, por isso deve atualmente             ser um contexto viável .

( citação de http://parse.com/docs/android/api/com/parse/PushService.html ) .

No entanto, quando você desinstalar o aplicativo, armazenamento local para esse app é limpo a partir do seu dispositivo, assim que a nova instalação vai causar PushService.subscribe para registrar-se novamente ao Google Cloud Messaging . Se o novo registro retorna um novo ID de registro, Parse teria dois IDs de registro que podem ser usados ​​para enviar notificações push para o seu app, e ambos seriam ligados ao mesmo nome de usuário que você forneceu para subscribe . Portanto enviar uma notificação para esse nome de usuário vai enviá-lo para ambos os IDs de registro, fazendo-a chegar duas vezes.

Quando Parse enviar as notificações para você, eles devem começar a partir de Google uma resposta com canonical_registration_id, que vai deixá-los saber um dos IDs de registro associados com o seu aplicativo em seu dispositivo é velho, e não deve ser mais utilizado . Portanto (assumindo Parse ter uma implementação decente de GCM) da próxima vez que você enviar uma notificação para o seu dispositivo, você deve recebê-lo apenas uma vez.

2Mayur Raval @

Eu tenho que após a atualização da tabela com o envio de identificação única do 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();

Ele irá atualizar a matéria, mas não re- registrar o dispositivo .

3Sheraz Ahmad Khilji @

Eu também estava enfrentando esse problema . Eu meio que resolveu chamando o método a seguir na minha atividade de 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);
                }
            });

    }

Mesmo que ele não resolveu completamente o meu problema, mas agora o meu app não travar e não mais da ANR devido a esta implementação Parse . Se eu voltar a instala um aplicativo e executá-lo agora, em seguida, o aplicativo cria um novo registro de instalação e remover é o último . O único problema é que o channel_name não está inscrito neste prazo, mas na próxima corrida do canal está inscrito com sucesso.

4user1201239 @

Acho Mukul forneceu grande código de cloud para esse 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();
});
});

Observe que o proprietário é o nome de usuário ou a chave primária que você acha que u pode usar .

aqui está o link do mesmo com uma melhor explicação por mukul  https://www.parse.com/questions/check-for-duplicate-installations-of-same-user-on-re-installation-of-app

5Albert Vila @

O que funcionou para mim para se livrar dessa exceção estava usando saveEventually() em vez de saveInBackground() .

Aqui você tem http://stackoverflow.com/a/27151459/4034572 para a minha resposta a uma pergunta semelhante .

Eu acho que saveEventually() é a melhor opção porque assegura que a instalação será sempre salvo, independentemente da disponibilidade netwwork . Em contraste, com saveInBackground() há uma chance de que o teste falhar devido à falta de conectividade de rede. Também com saveEventually() você não precisa fazer qualquer verificação de erros, o que você deve fazer em um SaveCallback() com saveInBackground() .

Em relação as notificações duplicadas, isso não deve ocorrer se você estiver usando o SDK mais recente Parse ( que não aconteça a mim com 1.7.1) . Houve um erro que foi resolvido agora. Veja http://stackoverflow.com/q/24590804/4034572 e https://developers.facebook.com/bugs/1520221558200050/ .

Note-se que primeira vez que o usuário recebe uma notificação depois de reinstalar o aplicativo, esta notificação pode ser entregue duas vezes. Aconteceu- me, mas só acontece pela primeira notificação. (Veja o link FB para mais detalhes. ) Depois que a notificação duplicada, a instalação antigo será removido automaticamente por Parse . Esta é a minha experiência.

Se você está tentando evitar o envio de notificações duplicadas através da implementação de uma lógica na CloudCode (usando um beforeSave que dispara ao salvar uma nova instalação, verifique se o aplicativo já havia sido instalado no dispositivo e apagar a antiga instalação), não faça isso! Não há necessidade . Analise vai fazer isso por você : ele irá apagar a instalação antiga :)