具有高优先级的Firebase消息不会从Doze android 6+中唤醒设备

tur*_*boy 32 android device-admin firebase-cloud-messaging

我已将项目从使用GCM迁移到使用Firebase.当设备处于唤醒状态或最近处于睡眠状态时,推送通知会通过确认,但如果我离开设备一小时,则在我唤醒设备之前不会发送推送.

Android文档说,如果您需要唤醒设备以传递消息,请使用优先级设置为高的FireBase.它还说设备管理应用程序不受Doze限制,我的应用程序是一个设备管理应用程序.

我想我会提到当我将项目从GCM迁移到FCM时,我只在firebase控制台中指定了包名,而不是指纹.

我试过了什么

  1. 将优先级设置为高

    {
      "time_to_live": 300000,
      "delay_while_idle": false,
      "android": {
        "priority": "high"
      },
      "data": {
        "message": "PING_DEVICE",
        "time": "21/01/2018 16:20:28",
        "pushguid": "10062"
      },
      "registration_ids": [
        "eOMT........"
      ]
    }
    
    Run Code Online (Sandbox Code Playgroud)

    设定生存时间,以便最终传达信息.delay_while_idle设置为false,2016年9月后FCM将忽略此值.

  2. 设备管理员应用程序不受Doze的影响,我的设备管理员应用程序,但我还明确将应用程序添加到设置 - >电池 - >优化中的Doze白名单中.这是通过设置应用程序手动完成的,而不是以编程方式在代码中完成

我已经离开我的设备睡了3个小时,没有推动通过.我还使用adb将设备置于Doze中.当adb将设备置于Doze中时,没有收到推送,当adb将设备从Doze中取出时,推送就会通过.

进一步的想法我没试过.

我的推动是数据消息.这是因为我不希望推送到设备上的通知栏并让用户单击它来执行功能.用户没有与设备管理应用程序的交互.因此,数据消息由处理

onMessageReceived(RemoteMessage remoteMessage)
Run Code Online (Sandbox Code Playgroud)

我相信通知消息会唤醒设备,这是我需要的,但我希望应用程序处理推送,而不是用户.我可以拥有通知和数据但是onMessageRecievied处理功能的消息吗?

有没有人经历过类似的事情或有任何解决方案?

[编辑1]我在下面找到了以下链接,说明您可以发送通知和数据的消息,但如果应用程序在后台,则会显示通知,但只有在用户单击通知时才会执行数据.这不是我想要的,因为我希望数据立即在onMessageRecived中执行.

通知数据

[EDIT2]我已向应用添加了以下代码和权限.该应用程序现在要求用户将应用程序列入白名单,因此我单击是.然后我通过adb将设备放入Doze并发送推送.在我将设备退出打盹模式之前,没有任何事情发生.所以,不幸的是,这不起作用.

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

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Run Code Online (Sandbox Code Playgroud)

[EDIT3]

我已经做了进一步的测试,试图找出问题并将我的Web应用程序代码排除在外.我通过adb和使用过的FireBase控制台将设备置于Doze中以发送推送.推送正确通知这告诉我,我的Web应用程序代码存在问题,它将所有推送信息发送到fcm端点.今晚我会得到代码并稍后发布.

[EDIT4]我刚做了一些测试.我将设备置于打瞌睡状态,然后使用FireBase控制台发送带有2个键值对的数据消息.当设备处于Doze且应用程序位于前台(在屏幕上)时,推送通过并执行onMessageReceived.这很棒.但是,如果应用程序位于BG中,则仅显示通知.我理解,从文档中,数据消息通过Intent被分派到启动器活动,但我的启动器应用程序不处理推送.处理推送的类称为MyAndroidFirebaseMsgService并扩展FirebaseMessagingService.

如果应用程序在BG中,我是否必须将意图路由到此课程?看起来有点像需要这样做.在GCM中从来就不是这样.

此外,我不希望应用程序从推送启动,因为这是非常侵入性的,因为设备用户可能正在使用不同的应用程序.我的应用程序也是一个设备管理员应用程序,所以99%的时间没有用户交互,它只是一个在设备上执行策略的客户端.

[edit5]

internal static void SendNotification (  Dictionary<string, string> nameValues ,  List<string> theregIDs , string sPushName)
         {     
            string stringregIds =  string.Join("\",\"", theregIDs) ;

             JavaScriptSerializer js = new JavaScriptSerializer();
            string keyValueJson = js.Serialize(nameValues);

            string TIME_TO_LIVE = "604800";

            string DELAY_WHILE_IDLE = "false";

            string ENDPOINTADDRESS = @"https://fcm.googleapis.com/fcm/send";


            postData = String.Concat("{\"time_to_live\":", TIME_TO_LIVE,  ",\"delay_while_idle\": ", DELAY_WHILE_IDLE,  ",  \"android\":{\"priority\":\"high\" } ,\"data\": { \"message\" : " + "\"" + sPushName + "\",\"time\": " + "\"" + System.DateTime.Now.ToString() + "\""
                , keyValueJson
               , "},\"registration_ids\":[\"" + stringregIds + "\"]}");


            WebRequest myWebRequest = null;
            WebResponse myWebResponse = null;
            try
            {
                myWebRequest = WebRequest.Create(ENDPOINTADDRESS);                         
                myWebRequest.Method = "post";
                myWebRequest.ContentType = "application/json";
                //  myWebRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
                myWebRequest.Headers.Add("Authorization: key=" + Our_Api_Key);
                myWebRequest.Headers.Add("Sender:id=" + Our_Sender_Id);

                Byte[] BA = Encoding.UTF8.GetBytes(postData);
                myWebRequest.ContentLength = BA.Length;

                using (Stream dataStreamOut = myWebRequest.GetRequestStream())
                {
                    dataStreamOut.Write(BA, 0, BA.Length);

                }

                using (myWebResponse = myWebRequest.GetResponse())
                {
                    using (Stream dataStream = myWebResponse.GetResponseStream())
                    {
                        using (StreamReader tReader = new StreamReader(dataStream))
                        {
                            strServerResponse = tReader.ReadToEnd(); 
                        }

                    }
                }


            }
            catch (WebException ex)
            {



            }

         }//
Run Code Online (Sandbox Code Playgroud)

谢谢

小智 8

TL;DR - 确保根据 FCM 的旧 HTTP 协议与其 HTTP v1 协议的 JSON 有效负载结构正确设置通知优先级。

根据您的情况或实现,上面的帖子可能已经有足够的答案,但我想根据 FCM 在其文档中提供的旧 HTTP 和 HTTP v1 协议之间的区别提供更多上下文的答案,但有一个微妙的设置通知优先级时两个协议 API 的区别。

我们的团队遇到了同样的问题,即在启用了 Doze 的 Android 6+ 设备上无法接收推送通知,即使我们的服务器似乎在 FCM API 负载中正确设置了与原始问题中提供的负载类似的优先级。我们依靠 Amazon SNS 将负载转发到 FCM,从我们的服务器发送到 Amazon SNS 的负载将根据AndroidConfig JSON 对象设置优先级:

{
    "android": {
        "priority": "high"
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这仅根据HTTP v1 协议是正确的。我们没有意识到的是,Amazon SNS 可能仍在使用旧的 HTTP 协议,其中优先级必须设置在 JSON 负载的顶级:

{
    "priority": "high", // legacy HTTP protocol (this can also be set to 10)
    "android": {
        "priority": "high" // HTTP v1 protocol
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,只有当旧的 HTTP 优先级参数设置为“高”或 10 时,通知优先级才会生效并允许在打盹中接收推送通知。

对于上下文,这些是向 FCM 发送消息时每个协议的 API 端点:


小智 7

在遇到类似问题后,我设法使它开始工作。

我通过邮递员发送以下json数据:

{
  "data": {
    "body": "Test body from curl"
  },
  "registration_ids": ["Token"],
  "webpush": {
    "headers": {
      "Urgency": "high"
    }
  },
  "android": {
    "priority": "high"
  },
  "priority": 10
}
Run Code Online (Sandbox Code Playgroud)

似乎最后"priority":10是为我解决的问题。

我在Firebase文档中找不到对此的任何引用,但是在已弃用的GCM文档中使用了它。https://developers.google.com/cloud-messaging/concept-options


Kuv*_*uva 6

您无能为力。

这是由某些OEM(例如魅族或华硕)实施的电池优化引起的已知问题。当在应用程序切换器中将某个应用程序刷掉后,该应用程序将被视为已被强制停止,这不是默认的Android行为。不幸的是,这可能导致您的应用程序的FCM服务停止运行。在打ze模式下,对高优先级消息可能会产生类似的效果。

Firebase团队正在努力从一开始就改善这种行为,但是实际的解决方法必须来自OEM方面。

检查您的应用是否受任何OEM的电池管理功能影响的一种方法如下:

1)将OEM设备连接到adb

2)在设备上运行您的应用

3)将应用程式滑离装置上的最近画面

4)运行命令:adb shell dumpsys package MY-PACKAGE | grep已停止

如果显示Stopped = true,则可以安全地假定OEM具有这种机制,并且您的应用也受此机制影响。


Hei*_*erg 4

在开发应用程序时,我也陷入了这一点。然后我在Github上发现了一个关于它的问题,解决了我的问题。那是,

在运行 Android 6.0+ 的设备上,Doze 模式会在手机空闲且未充电时终止所有后台连接,包括与 Pushy 的后台连接。

一旦用户移动或唤醒设备,后台连接就会恢复,并且任何待处理的通知都将在几秒钟内发送,前提是它们尚未过期。

要向处于打瞌睡模式的设备发送通知,您的应用程序可以REQUEST_IGNORE_BATTERY_OPTIMIZATIONS在其 AndroidManifest.xml并显示一个系统对话框,要求用户将您的应用程序列入电池优化白名单,而无需离开该应用程序。

这将有效地保持与 Pushy 的后台连接处于活动状态,并且即使在打瞌睡模式下,设备也能够接收通知。

您可以在这里检查这个问题https://github.com/ToothlessGear/node-gcm/issues/231

希望对您有帮助!