错误广播意图回调:result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=com.flagg327.guicomaipu (has extras) }。

41

我从Android Studio的Android Monitor中收到了这个错误。当我通过GCM在真实设备上发送推送通知时,如果应用程序尚未启动或已被强制停止,则会出现此错误。昨天一切正常,今天完全不起作用(仅在应用程序在后台或前台运行时才有效)。

我认为这可能是AndroidManifest的错误,但我已经厌倦了寻找问题并且找不到任何东西。

清单

<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

“tokens” 的注册每天都会更新。这是因为每个使用 GCM 的 Android 应用程序都必须有一个 InstanceIDListenerService 来管理这些更新。

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会自动显示推送通知,但前提是相关应用必须有一个GCMListenerService。

public class NotificacionsListenerService extends GcmListenerService {

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

        // Do something

    }
}

RegistrationService.java

GCM使用注册卡(“令牌”)来识别Android设备。我的应用程序应该能够从安装了该应用的每个Android设备上进行注册。

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

错误

当我通过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) }

昨天在工作... 有什么想法吗?感谢您的时间。


根据这个帖子,当设备上的接收应用程序处于停止状态(例如通过从设置中使用强制停止)时,就会出现此问题。只有在手动启动后,它才会重新开始接收消息。您还可以查看这个相关的SO帖子 - abielita
已解决,请查看此链接..https://dev59.com/3qPia4cB1Zd3GeqPsQvr#45810771 - Rahul Devanavar
这里有一些步骤可以帮助你。 - IgniteCoders
10个回答

27

由于没有提供官方链接,我决定询问Firebase团队,并从他们那里得到了官方答案。

看起来当您的应用程序被强制停止或关闭时,出现了问题。实际上,这是按照预期工作的。Android框架建议已停止的应用程序(即从“设置”中杀死/强制停止)不应在没有明确用户交互的情况下启动。FCM遵循此建议,因此其服务也不会启动。这还意味着当应用程序处于“已停止”状态时,将无法接收消息(FirebaseMessagingService不会被调用)。以下是一些有用的链接,以便您更好地理解此主题: https://developer.android.com/about/versions/android-3.1#launchcontrols https://github.com/firebase/quickstart-android/issues/368#issuecomment-343567506

总之:

  • 被用户杀死(从设置/强制停止)的应用程序将被标记为一个标志,无法自动触发包括Firebase消息服务在内的任何服务。这与应用程序被系统杀死或从最近的应用程序中滑动不同。
  • 然而,在一些来自VIVO或ONEPLUS的ROM中,向右滑动功能(点击最近应用程序按钮/向右滑动)被错误地实现为类似于设置/强制停止。这导致Firebase消息服务无法启动。
  • 此问题已在此处和许多其他地方提出。FCM团队已经意识到该问题并正在解决。
  • 注意:即使问题涉及GCM,但FCM在问题标题中也会报 exact 相同的错误。


    5
    不过,我猜他们还没有任何解决方案。 - Amin Pinjari
    Pixel 3出现问题 - emanuel sanga

    20

    我收到了相同的错误提示

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

    在杀死应用程序之后。

    经过一些研究,我意识到这只是一个“调试问题”。即使应用程序已关闭,“签名的APK”也可以正确处理广播。

    希望对你有所帮助!


    1
    请为您的资源提供链接来源。 - natanavra
    @natanavra 你是什么意思?完整的源代码已经在原始问题中了,不是吗? - niggeulimann
    @niggeulimann 我是指你的研究。请添加一个链接到支持你发现的文档... - natanavra
    4
    无效。如果我强制停止一个应用,将无法接收消息。 - Stony
    1
    这个答案是正确的。在许多手机上进行了测试,行为始终相同。即使您杀死应用程序,签名应用程序仍会接收推送。 - IgniteCoders
    @niggeulimann,你能分享一下你在哪些Android版本和设备型号上看到了这个修复的问题吗?这似乎不是标准的Android ASOP行为,可能与ROM有关。 - jkasten

    17

    经过调查,发现这种情况出现的原因是在Android Studio中杀掉了该应用程序。

    如果您从启动器中打开该应用程序并将其划掉,您的应用程序仍将接收通知。

    (在配备FCM而不是GCM的OnePlus One上进行了测试)


    1
    这个对我很有帮助。谢谢。 - gorkem
    你能否请稍微解释一下? - Amin Pinjari
    @amin 确定,点击 Android Studio 中的“停止”按钮会完全终止应用程序并彻底删除其后台服务(例如类似于“强制停止”)。 - natanavra

    7

    所以...我解决了这个问题。问题就是设备没有注册接收GCM(Google Cloud Messaging)如果应用程序被强行关闭或设备启动后从未打开过该应用程序。解决方案很简单,在手机启动时注册设备。为此,我实现了一个BroadcastReceiver并在其内部启动了一个注册进程。

    修改内容:

    添加到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);
        }
    }
    

    因此,在启动时,该设备将向GCM服务器注册,并能够从我的服务器接收任何推送通知。希望这对你有用。

    谢谢@flagg327,我也遇到了同样的问题,并通过您的答案解决了它。 - Krunal Patel
    问题也会出现在休眠模式中。 - Farhan
    如果您的应用程序针对电池使用进行了优化,这将无法正常工作。 - Praveen
    我希望 https://dev59.com/HlkS5IYBdhLWcg3ww5Bd#58162451 能够解决你的问题。 - Amin Pinjari
    你好,能否分享注册服务的代码? - Tarun

    5

    我在模拟器上安装应用程序时也遇到了这个问题。我只使用FCM数据消息,因为我需要自己处理消息(包括静默推送)。

    但是当我测试后台接收时,什么都没有发生。我也观察到了你的错误。

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

    我对此进行了大量阅读,因为我不相信当应用程序被杀死时 FCM 无法工作,这将破坏推送通知的整个目的。

    我还观察到一些情况下,即使应用程序已被杀死,我的消息也被接收到,但我不知道为什么有时会发生这种情况。

    在浏览了 GitHub 上的 Firebase 问题后,我停留在一个非常显著的答案:

    经过一些测试,看起来 stopped=true 只在我使用 Android Studio 启动应用程序时才会出现。如果我手动启动应用程序或使用 adb shell am start -n,然后杀死它(从最近的任务中滑动关闭),那么状态就是 stopped=false,并且推送通知可以正常工作!

    https://github.com/firebase/quickstart-android/issues/822#issuecomment-611567389

    所以,如果您仍然面临此问题,请尝试以下操作:

    1. 通过 Android Studio 安装应用程序
    2. 关闭并杀死应用程序(之后不会收到任何消息,观察到错误发生)
    3. 重新启动应用程序
    4. 再次杀死(现在可以接收到消息,一切正常工作)

    太好了,谢谢! - undefined

    2
    为了解决这个问题,目前没有官方的解决方案,但是你可以使用下面的解决方法。
    你需要管理两件事:自动启动和电池优化,然后你的问题会得到解决。
    1. 自动启动 你需要请求自动启动权限,以便在用户关闭应用后在后台重新启动。
    你可以使用以下意图进行操作。
     private void enableAutoStart() {
        if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
          new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
            .content(
              "Please allow QuickAlert to always run in the background,else our services can't be accessed when you are in distress")
            .theme(Theme.LIGHT)
            .positiveText("ALLOW")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
              @Override
              public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
    
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.miui.securitycenter",
                  "com.miui.permcenter.autostart.AutoStartManagementActivity"));
                startActivity(intent);
              }
            })
            .show();
        } else if (Build.BRAND.equalsIgnoreCase("Letv")) {
          new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
            .content(
              "Please allow QuickAlert to always run in the background,else our services can't be accessed when you are in distress")
            .theme(Theme.LIGHT)
            .positiveText("ALLOW")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
              @Override
              public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
    
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.letv.android.letvsafe",
                  "com.letv.android.letvsafe.AutobootManageActivity"));
                startActivity(intent);
              }
            })
            .show();
        } else if (Build.BRAND.equalsIgnoreCase("Honor")) {
          new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
            .content(
              "Please allow QuickAlert to always run in the background,else our services can't be accessed when you are in distress")
            .theme(Theme.LIGHT)
            .positiveText("ALLOW")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
              @Override
              public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.huawei.systemmanager",
                  "com.huawei.systemmanager.optimize.process.ProtectActivity"));
                startActivity(intent);
              }
            })
            .show();
        } else if (Build.MANUFACTURER.equalsIgnoreCase("oppo")) {
          new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
            .content(
              "Please allow QuickAlert to always run in the background,else our services can't be accessed when you are in distress")
            .theme(Theme.LIGHT)
            .positiveText("ALLOW")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
              @Override
              public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                try {
                  Intent intent = new Intent();
                  intent.setClassName("com.coloros.safecenter",
                    "com.coloros.safecenter.permission.startup.StartupAppListActivity");
                  startActivity(intent);
                } catch (Exception e) {
                  try {
                    Intent intent = new Intent();
                    intent.setClassName("com.oppo.safe",
                      "com.oppo.safe.permission.startup.StartupAppListActivity");
                    startActivity(intent);
                  } catch (Exception ex) {
                    try {
                      Intent intent = new Intent();
                      intent.setClassName("com.coloros.safecenter",
                        "com.coloros.safecenter.startupapp.StartupAppListActivity");
                      startActivity(intent);
                    } catch (Exception exx) {
    
                    }
                  }
                }
              }
            })
            .show();
        } else if (Build.MANUFACTURER.contains("vivo")) {
          new MaterialDialog.Builder(MainActivity.this).title("Enable AutoStart")
            .content(
              "Please allow QuickAlert to always run in the background.Our app runs in background to detect when you are in distress.")
            .theme(Theme.LIGHT)
            .positiveText("ALLOW")
            .onPositive(new MaterialDialog.SingleButtonCallback() {
              @Override
              public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
                try {
                  Intent intent = new Intent();
                  intent.setComponent(new ComponentName("com.iqoo.secure",
                    "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity"));
                  startActivity(intent);
                } catch (Exception e) {
                  try {
                    Intent intent = new Intent();
                    intent.setComponent(new ComponentName("com.vivo.permissionmanager",
                      "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
                    startActivity(intent);
                  } catch (Exception ex) {
                    try {
                      Intent intent = new Intent();
                      intent.setClassName("com.iqoo.secure",
                        "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager");
                      startActivity(intent);
                    } catch (Exception exx) {
                      ex.printStackTrace();
                    }
                  }
                }
              }
            })
            .show();
        }
      }
    
      public boolean checkServiceRunning() {
        ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(
          Integer.MAX_VALUE)) {
          if ("com.sac.speechdemo.MyService".equals(service.service.getClassName())) {
            return true;
          }
        }
        return false;
      }
    
    1. Battery Optimization/Background Free/ DOZE Mode

      to manage battery optimization use below code with permission, it will work on Stock Android

      private void askIgnoreOptimization() {

      if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
          Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
          intent.setData(Uri.parse("package:" + getPackageName()));
          startActivityForResult(intent, IGNORE_BATTERY_OPTIMIZATION_REQUEST);
      } else {
          openNextActivity();
      }
      

      }

    对于自定义操作系统,您需要像下面的意图一样重定向用户以获取电池优化权限,例如OPPO设备

    intent.setClassName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerConsumptionActivity"); startActivity(intent);
    

    调用以上意图,它将重定向您到电池选项,“在\"节能器 -> 您的APP”中禁用后台冻结、异常应用程序优化和Doze。

    注意:一旦调用上述意图,您可能会获得不同的选项来关闭省电选项。此电池优化选项可以在设备设置中的电池选项中找到,根据ROM的不同而异。


    1
    java.lang.SecurityException: 权限拒绝即使在清单文件中添加了权限: - Mohsin Falak
    @Mohsin Falak 我也遇到了同样的问题 - undefined

    1

    对我来说,我的应用程序提供了AutoStart功能。转到设置,选择已安装的应用程序并启用AutoStart。这将解决问题。


    1
    我也遇到了这个问题。当我从堆栈中移除应用程序时,推送通知无法接收。经过大量的谷歌搜索,我发现一些手机有电池优化功能,这会禁用应用程序的后台运行。当我启用它时,我的应用程序也可以在后台运行。推送通知正常工作。只有像WhatsApp等少数应用程序才能具有默认启用功能。您可以查看下面的URL。

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


    1
    这是因为您的应用已经针对电池使用进行了优化,要禁用此功能并在应用程序不在后台运行时接收通知,请添加此权限到清单中。请保留HTML标签。

    这是因为您的应用已经针对电池使用进行了优化,要禁用此功能并在应用程序不在后台运行时接收通知,请添加此权限到清单中。

    将此权限添加到清单中

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

    在您的应用首次启动时,请求用户允许忽略此应用的电池优化。
     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);
                }
            }
    

    它无法在OPPO、Realme等设备上运行,这些设备需要自启动权限。 - Amin Pinjari

    0

    即使我的应用程序已经打开,我仍然遇到了这个错误。最终我发现我的清单文件中缺少了一个com.google.android.c2dm.intent.RECEIVE接收器。

    在我的情况下,这是由于通过清单合并意外删除了FirebaseInstanceIdReceiver引起的:

      <receiver
                android:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"
                tools:node="remove" />
    

    删除此元素后,接收器在清单合并期间被正确添加(通过检查最终apk的清单进行验证)。

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接