web-dev-qa-db-fra.com

Erreur de rappel d'intention de diffusion: result = CANCELED forIntent {act = com.google.Android.c2dm.intent.RECEIVE pkg = com.flagg327.guicomaipu (comporte des extras)}

Je reçois cette erreur du moniteur Android d'Android Studio. Cette erreur apparaît lorsque j'envoie une notification Push via GCM, dans un périphérique réel, et que l'application n'a pas encore été lancée ou qu'elle a été forcée de s'arrêter. Hier, tout fonctionne bien, aujourd'hui ne fonctionne pas du tout (fonctionne uniquement si l'application est exécutée en arrière-plan ou au premier plan).

Je pense que cela peut être une erreur AndroidManifest, mais j'en ai marre de chercher le problème et je ne trouve rien.

Manifeste

<manifest 
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    package="com.flagg327.guicomaipu">

    ...

    <application
        Android:allowBackup="true"
        Android:icon="@mipmap/ic_launcher"
        Android:label="@string/app_name"
        Android:supportsRtl="true"
        Android:theme="@style/AppTheme">

        ...

        <!--GOOGLE CLOUD MESSAGE-->
        <receiver
            Android:name="com.google.Android.gms.gcm.GcmReceiver"
            Android:exported="true"
            Android:permission="com.google.Android.c2dm.permission.SEND" >
            <intent-filter>
                <action Android:name="Android.intent.action.BOOT_COMPLETED"/>
                <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
                <!-- for Gingerbread GSF backward compat -->
                <action Android:name="com.google.Android.c2dm.intent.REGISTRATION" />
                <category Android:name="com.flagg327.guicomaipu" />
            </intent-filter>
        </receiver>

        <service
            Android:name="com.flagg327.guicomaipu.gcm.RegistrationService"
            Android:exported="false" />

        <service
            Android:name="com.flagg327.guicomaipu.gcm.TokenRefreshListenerService"
        Android:exported="false">
            <intent-filter>
                <action
                    Android:name="com.google.Android.gms.iid.InstanceID" />
            </intent-filter>
        </service>

        <service
            Android:name="com.flagg327.guicomaipu.gcm.NotificacionsListenerService"
        Android:exported="false" >
            <intent-filter>
                <action Android:name="com.google.Android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>

    </aplication>

    <permission 
        Android:name="com.flagg327.guicomaipu.C2D_MESSAGE"
            Android:protectionLevel="signature" />
    <uses-permission Android:name="com.flagg327.guicomaipu.permission.C2D_MESSAGE" />
    <uses-permission Android:name="com.google.Android.c2dm.permission.RECEIVE" />
    <uses-permission Android:name="Android.permission.RECEIVE_BOOT_COMPLETED"/>

TokenRefreshListenerService.Java

Les «jetons d'inscription» sont mis à jour tous les jours. C’est parce que chaque application Android utilisant GCM doit disposer d’un InstanceIDListenerService qui gère ces mises à jour.

public class TokenRefreshListenerService extends InstanceIDListenerService{

    @Override
    public void onTokenRefresh() {
        // Launch the registration process.
        Intent i = new Intent(this, RegistrationService.class);
        startService(i);
    }
}

NotificacionsListenerService.Java

GCM affiche automatiquement les notifications Push, mais uniquement si l'application associée dispose d'un GCMListenerService

public class NotificacionsListenerService extends GcmListenerService {

    @Override
    public void onMessageReceived(String from, Bundle data) {
        Log.d("A", "onMessageReceived()");

        // Do something

    }
}

RegistrationService.Java

GCM identifie les appareils Android à l'aide de cartes d'enregistrement («jetons»). Mon application doit pouvoir être enregistrée à partir de chaque appareil Android sur lequel elle est installée.

public class RegistrationService extends IntentService {

    /**
     * Constructor
     */
    public RegistrationService() {
        super("RegistrationService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        // Generate or download the registration 'token'.
        InstanceID myID = InstanceID.getInstance(this);

        String registrationToken = null;
        try {
            // Get the registration 'token'.
            registrationToken = myID.getToken(
                    getString(R.string.gcm_defaultSenderId),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE,
                    null
            );

            // Subscribe to a topic. The app is able now to receive notifications from this topic.
            GcmPubSub subscription = GcmPubSub.getInstance(this);
            subscription.subscribe(registrationToken, "/topics/guico_maipu_topic", null);
        } catch (IOException e) {
            e.printStackTrace();
        }

        Log.e("Registration Token", registrationToken);
    }
}

Erreur

Cette erreur apparaît lorsque j'envoie une notification Push via python.

09-13 21:21:44.800 1851-1851/? W/GCM-DMM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.Android.c2dm.intent.RECEIVE pkg=com.flagg327.guicomaipu (has extras) }

Hier travaillait ... Une idée? Merci pour votre temps.

18
flagg327

J'ai eu la même erreur

09-13 21:21:44.800 1851-1851/? W/GCM-DMM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.Android.c2dm.intent.RECEIVE pkg=com.XXX.XXX (has extras) }

après avoir tué l'application.

Après quelques recherches, j'ai réalisé qu'il ne s'agissait que d'un "problème de débogage". Un "APK signé" gère correctement la diffusion même si l'application a été fermée. 

J'espère que ça aide!

10
niggeulimann

Alors ... j'ai résolu le problème. Le problème était que le périphérique n'est pas enregistré pour recevoir GCM si l'application est fermée de force ou si l'application n'a jamais été ouverte depuis le démarrage du périphérique. La solution est simple: enregistrez le périphérique au démarrage du téléphone. Pour cela, j'ai implémenté une BroadcastReceiver et commencé un enregistrement de processus à l'intérieur.

Les modifications:

Ajouté à AndroidManifest

    <receiver Android:name="com.flagg327.guicomaipu.gcm.OnBootBroadcastReceiver">
        <intent-filter >
            <action Android:name="Android.intent.action.BOOT_COMPLETED" />

            <category Android:name="Android.intent.category.HOME" />
        </intent-filter>
    </receiver>

OnBootBroadcastReceiver.Java

public class OnBootBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {

        Intent i = new Intent("com.flagg327.guicomaipu.gcm.RegistrationService");
        i.setClass(context, RegistrationService.class);
        context.startService(i);
    }
}

Ainsi, au démarrage, le périphérique s'enregistrera sur le serveur GCM et pourra recevoir toute notification Push de mon serveur. J'espère que cela est utile.

6
flagg327

Après avoir compris pourquoi cela se produit, il semble que cela se produise si vous supprimez l'application depuis Android Studio.

Si vous ouvrez l'application depuis le lanceur et la balayez, votre application recevra toujours des notifications.

(Testé sur OnePlus One avec FCM et non GCM)

4
natanavra

Étant donné qu'aucune des réponses ne fournit de lien officiel, j'ai décidé de demander à l'équipe de Firebase de me donner une réponse officielle. 

Il semble que vous ayez un problème lorsque votre application est arrêtée de force ou tué. En fait, cela fonctionne comme prévu. Le framework Android indique que les applications qui ont été arrêtées (c'est-à-dire qui ont été tuées/arrêtées dans Paramètres) ne doivent pas être démarrées sans un utilisateur explicite interaction. La FCM suit cette recommandation et donc ses services ne commencera pas aussi bien. Cela signifie également que les messages ne seront pas reçu (FirebaseMessagingService ne sera pas appelé) lorsque l'application est en état "tué". Voici quelques liens utiles pour que vous puissiez avoir un meilleure compréhension sur ce sujet: https://developer.Android.com/about/versions/Android-3.1#launchcontrolshttps://github.com/firebase/quickstart-Android/issues/368#issuecomment-343567506

En somme:

  • l'application est tuée par l'utilisateur (à partir des paramètres/arrêt forcé) sera marquée avec un drapeau qui ne sera pas en mesure de déclencher automatiquement tout service inclus le service de messagerie firebase. Ce n'est pas la même chose si l'application est tuée par le système ou par balayage de l'application récente. 
  • Toutefois, sur certaines ROM de VIVO ou ONEPLUS, la fonctionnalité de balayage (cliquez sur le bouton de l'application récente) a été implémentée à tort pour être similaire avec les paramètres/l'arrêt forcé. Cela a causé le service de messagerie firebase ne peut pas démarrer. 
  • La question a été soulevée ici et dans de nombreux endroits. L'équipe de la FCM est consciente du problème et y travaille 

REMARQUE: même la question concerne GCM, mais FCM renvoie exactement la même erreur dans le titre de la question. 

3
thanhbinh84

Je faisais également face au problème. Lorsque je supprime une application de la pile, notification Push non reçue. Après de nombreux travaux sur Google, j'ai constaté que peu de téléphones avaient une fonction d'optimisation de la batterie, ce qui désactivait l'exécution en arrière-plan des applications. Lorsque j'active cette fonctionnalité, mon application peut également s'exécuter en arrière-plan. La notification push fonctionne bien. Seules quelques applications telles que What's application, etc. peuvent uniquement disposer de la fonctionnalité d'activation par défaut. Vous pouvez consulter cette URL ci-dessous.

https://github.com/firebase/quickstart-Android/issues/89

1
ParikshitSinghTomar

En effet, votre application est optimisée pour l'utilisation de la batterie afin de la désactiver et de recevoir une notification même si votre application ne s'exécute pas en arrière-plan.

Ajouter cette autorisation à manifester

<uses-permission 
Android:name="Android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

Lors du premier lancement de votre application, demandez à l'utilisateur l'autorisation d'ignorer cette application pour optimiser la batterie.

 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            Intent intent = new Intent();
            String packageName = getPackageName();
            PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
            if (!pm.isIgnoringBatteryOptimizations(packageName)) {
                intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + packageName));
                startActivity(intent);
            }
        }
1
Praveen