简体   繁体   English

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

[英]Firebase message with high priority not waking device from Doze android 6+

I have migrated my project from using GCM to use Firebase.我已将我的项目从使用 GCM 迁移到使用 Firebase。 Push notification comes through ok when the device is awake or been asleep recently but if I leave the device for say an hour, no push is sent until I wakeup the device.当设备最近处于唤醒状态或睡眠状态时,推送通知可以正常发送,但如果我离开设备一个小时,则在我唤醒设备之前不会发送推送。

The Android docs say that if you need to wake a device to deliver a message, then use FireBase with priority set to high. Android 文档说,如果您需要唤醒设备以传递消息,请使用优先级设置为高的 FireBase。 It also says that device Admin apps are not subject to Doze restrictions, my app is a device admin app.它还说设备管理应用程序不受打盹限制,我的应用程序是设备管理应用程序。

I thought I would mention that when I migrated the project from GCM to FCM, I only specified the package name in the firebase console and not the fingerprint.我想我会提到,当我将项目从 GCM 迁移到 FCM 时,我只在 firebase 控制台中指定了包名称,而不是指纹。

What I have tried.我尝试过的。

  1. Set priority to high将优先级设置为高

    { "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........" ] }

    Time to live is set so the message will come through eventually.生存时间是设定的,因此信息最终会通过。 delay_while_idle is set to false, this is ignored by FCM after sept 2016. delay_while_idle 设置为 false,这在 2016 年 9 月之后被 FCM 忽略。

  2. Device admin apps are not subject to Doze, mine is a device admin app but I have also explicitly added the app to the Doze whitelist found in Setting -> Battery -> Optimization.设备管理应用程序不受 Doze 的影响,我的是一个设备管理应用程序,但我也明确地将该应用程序添加到设置 -> 电池 -> 优化中的 Doze 白名单中。 This was done manually through the settings app and NOT programmatically in code.这是通过设置应用程序手动完成的,而不是在代码中以编程方式完成。

I have left my device to go to sleep for 3 hours and no push come through.我已经让我的设备进入睡眠状态 3 个小时,但没有推送通过。 I have also used adb to put the device into Doze.我还使用 adb 将设备放入 Doze。 When adb puts the device in Doze no push is received, when adb takes the device out of Doze, the push comes through.当 adb 将设备置于 Doze 时不会收到推送,当 adb 将设备从 Doze 中取出时,推送会通过。

further thoughts I haven't tried.进一步的想法我还没有尝试过。

My pushes are data messages.我的推送是数据消息。 This is because I don't want the push to come to the notification bar on the device and have the user click it to execute the functionality.这是因为我不希望推送到达设备上的通知栏并让用户单击它来执行功能。 The user has no interaction with the device admin app.用户与设备管理应用程序没有交互。 So a data message is handled by因此,数据消息由

onMessageReceived(RemoteMessage remoteMessage)

I believe notification messages do wake up the device, which is what I need but I want the app to handle the push, not the user.我相信通知消息确实会唤醒设备,这正是我所需要的,但我希望应用程序来处理推送,而不是用户。 Could I have messages that are both notification and data but have onMessageRecievied handle the functionality?我可以让消息既是通知又是数据,但让 onMessageRecievied 处理该功能吗?

Has anybody experienced anything similar or have any solutions to this?有没有人遇到过类似的事情或对此有任何解决方案?

[EDIT1] I have found the following link below that says you can send a message which is both notification and data, but if the app is in the background, the notification is displayed but the data is only executed when the user clicks the notification. [EDIT1] 我发现下面的链接说你可以发送一条消息,它既是通知又是数据,但如果应用程序在后台,则显示通知但数据仅在用户单击通知时执行。 This is not what I want as I would like the data to execute in onMessageRecived straight away.这不是我想要的,因为我希望数据立即在 onMessageRecived 中执行。

notification with data 数据通知

[EDIT2] I have added the following code and permission to the app. [EDIT2] 我已向该应用程序添加了以下代码和权限。 The app now asks the user to whitelist the app for Doze, so I clicked yes.该应用程序现在要求用户将该应用程序列入 Doze 白名单,因此我单击了“是”。 I then via adb put the device in Doze and sent a push.然后我通过 adb 将设备放入 Doze 并发送推送。 Nothing came through until I took the device back out of doze mode.在我将设备从打瞌睡模式中取出之前,什么都没有发生。 So, unfortunately, this does not work.所以,不幸的是,这行不通。

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

[EDIT3] [编辑3]

I have done further testing to try to isolate the problem and take my web application code out of the equation.我已经做了进一步的测试,试图找出问题并将我的 Web 应用程序代码排除在外。 I put the device into Doze via adb and the used FireBase console to send the push instead.我通过 adb 将设备放入 Doze 并使用 FireBase 控制台发送推送。 The push came through correctly This tells me there is a problem with my web application code that sends all the push info to the fcm endpoint.推送正确通过这告诉我我的 Web 应用程序代码存在问题,该代码将所有推送信息发送到 fcm 端点。 I will get the code tonight and post later.我今晚会得到代码,稍后发布。

[EDIT4] i have just done some more testing. [EDIT4] 我刚刚做了一些更多的测试。 I placed the device into doze then used FireBase console to send a data message with 2 key-value pairs.我将设备置于休眠状态,然后使用 FireBase 控制台发送带有 2 个键值对的数据消息。 When the device is in Doze and the app is in the foreground (on the screen), the push comes through and onMessageReceived executes.当设备处于 Doze 并且应用程序处于前台(在屏幕上)时,推送通过并执行 onMessageReceived。 This is great.这很棒。 However, if the app is in the BG then only a notification is displayed.但是,如果应用程序在 BG 中,则仅显示通知。 I understand that from the docs, the data messages are dispatched to the launcher activity via an Intent, but my launcher app does not handle the pushes.The class that handles the pushes is called MyAndroidFirebaseMsgService and extends FirebaseMessagingService.我从文档中了解到,数据消息通过 Intent 分派到启动器活动,但我的启动器应用程序不处理推送。处理推送的类称为 MyAndroidFirebaseMsgService 并扩展 FirebaseMessagingService。

Do i have to route the intent to this class in case the app is in the BG?如果应用程序在 BG 中,我是否必须将意图路由到此类? Seems a bit starnge to have to do this.必须这样做似乎有点奇怪。 It was never the case in GCM.在 GCM 中从来没有这种情况。

Also, i do not want the app launching from a push as this is very invasive as the device user could be using a different app.此外,我不希望通过推送启动应用程序,因为这是非常具有侵入性的,因为设备用户可能正在使用不同的应用程序。 My app is also a device admin app, so 99% of the time there is no user interaction, it is just a client that executes policies on the device.我的应用程序也是一个设备管理应用程序,所以 99% 的时间没有用户交互,它只是一个在设备上执行策略的客户端。

[edit5] [编辑5]

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



            }

         }//

thanks谢谢

After struggling with a similar issue I managed to get it to work.在遇到类似问题后,我设法让它发挥作用。

I send following json data through postman:我通过邮递员发送以下json数据:

{
  "data": {
    "body": "Test body from curl"
  },
  "registration_ids": ["Token"],
  "webpush": {
    "headers": {
      "Urgency": "high"
    }
  },
  "android": {
    "priority": "high"
  },
  "priority": 10
}

It seems like the last "priority":10 is what's fixing it for me.似乎最后一个"priority":10是为我解决的问题。

I could not find any reference to this in the Firebase documentation, but in the deprecated GCM documentation it's used.我在 Firebase 文档中找不到对此的任何参考,但在已弃用的 GCM 文档中使用了它。 https://developers.google.com/cloud-messaging/concept-options https://developers.google.com/cloud-messaging/concept-options

There is nothing you can do.你无能为力。

This is a known issue that is caused by a battery optimization implemented by some OEMs (like Meizu or Asus).这是一个已知问题,由某些 OEM(如魅族或华硕)实施的电池优化引起。 When an app is swiped away in the app switcher, the application is treated as if it were Force stopped, which is not the default Android behavoir.当应用程序在应用程序切换器中被刷掉时,应用程序被视为强制停止,这不是默认的 Android 行为。 The unfortunate side effect of this is that it can cause the FCM service for your app to stop running.不幸的副作用是它可能导致您的应用程序的 FCM 服务停止运行。 Similar effect can be caused on high priority messages in doze mode.在瞌睡模式下对高优先级消息可能会产生类似的影响。

Firebase team is working to improve this behavior from their end but the actual fix has to come from OEM side. Firebase 团队正在努力从他们的最终改善这种行为,但实际的修复必须来自 OEM 方面。

One way to check if your app is affected by any OEM's battery management feature, is as below:检查您的应用是否受任何 OEM 电池管理功能影响的一种方法如下:

1) Attach the OEM device to adb 1) 将 OEM 设备附加到 adb

2) Run your app on the device 2) 在设备上运行您的应用

3) Swipe the app away from recent screen on the device 3) 将应用从设备上的最近屏幕上滑开

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

If it shows stopped=true, it's safe to assume that the OEM has such a mechanism and that your app is affected by the same.如果它显示stopped=true,则可以安全地假设OEM 具有这样的机制并且您的应用程序受到相同的影响。

TL;DR - make sure to set the notification priority correctly based on the JSON payload structure for FCM's legacy HTTP protocol vs its HTTP v1 protocol. TL;DR - 确保根据 FCM 的旧 HTTP 协议与其 HTTP v1 协议的 JSON 有效负载结构正确设置通知优先级。

There may already be sufficient answers from posts above based on your circumstance or implementation, but I wanted to provide an answer with more context based on the distinction between the legacy HTTP and HTTP v1 protocols that FCM provides in their documentation, but there is a subtle difference between the two protocol APIs when setting notification priority.根据您的情况或实现,上面的帖子可能已经有足够的答案,但我想根据 FCM 在其文档中提供的旧 HTTP 和 HTTP v1 协议之间的区别提供更多上下文的答案,但有一个微妙的设置通知优先级时两个协议 API 的区别。

Our team experienced the same problem of not receiving push notifications on Android 6+ devices that have Doze enabled even though our server was seemingly setting the priority correctly in the FCM API payload that similar to the payload provided in the original question.我们的团队遇到了同样的问题,即在启用了 Doze 的 Android 6+ 设备上无法接收推送通知,即使我们的服务器似乎在 FCM API 负载中正确设置了与原始问题中提供的负载类似的优先级。 We rely on Amazon SNS to forward payloads to FCM, and the payload sent from our server to Amazon SNS would set the priority based on the AndroidConfig JSON object:我们依靠 Amazon SNS 将负载转发到 FCM,从我们的服务器发送到 Amazon SNS 的负载将根据AndroidConfig JSON 对象设置优先级:

{
    "android": {
        "priority": "high"
    }
}

However, this is only correct according to the HTTP v1 protocol .但是,这仅根据HTTP v1 协议是正确的。 What we didn't realize is that Amazon SNS is likely still using the legacy HTTP protocol where the priority has to be set at the top-level of the JSON payload:我们没有意识到的是,Amazon SNS 可能仍在使用旧的 HTTP 协议,其中优先级必须设置在 JSON 负载的顶层:

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

Thus, the notification priority would only take effect and enable push notifications to be received while in Doze when the legacy HTTP priority parameter was set to "high" or 10.因此,只有当旧的 HTTP 优先级参数设置为“高”或 10 时,通知优先级才会生效并允许在 Doze 中接收推送通知。

For context, these are the API endpoints for each protocol when sending messages to FCM:对于上下文,这些是向 FCM 发送消息时每个协议的 API 端点:

While working on an application, I am also stuck at this point.在处理应用程序时,我也卡在了这一点上。 Then I found a issue about it on Github, which solved my problem.然后我在 Github 上发现了一个关于它的问题,解决了我的问题。 That is,也就是说,

On devices running Android 6.0+, Doze mode terminates all background connections when the phone is idle and not being charged, including the background connection to Pushy.在运行 Android 6.0+ 的设备上,Doze 模式会在手机空闲且未充电时终止所有后台连接,包括与 Pushy 的后台连接。

As soon as the device is moved or awoken by the user, background connections are restored and any pending notifications will be delivered within seconds, providing they have not expired yet.一旦设备被用户移动或唤醒,后台连接就会恢复,任何挂起的通知都将在几秒钟内发送,前提是它们尚未过期。

To send notifications to devices in Doze mode, your app can declare the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission in its AndroidManifest.xml and display a system dialog that asks users to whitelist your app from battery optimizations without leaving the app.要在 Doze 模式下向设备发送通知,您的应用可以在其AndroidManifest.xml声明REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,并显示一个系统对话框,要求用户在不离开应用的情况下将您的应用列入电池优化白名单。

This will effectively keep the background connection to Pushy active and devices will be able to receive notifications even in Doze mode.这将有效地保持与 Pushy 的后台连接处于活动状态,即使在打盹模式下,设备也能够接收通知。

You can check this issue here https://github.com/ToothlessGear/node-gcm/issues/231您可以在此处查看此问题https://github.com/ToothlessGear/node-gcm/issues/231

Hope it helps you!希望对你有帮助!

It looks like it is not possible to make high priority while sending only data field without notification.看起来不可能在没有通知的情况下仅发送数据字段时设置高优先级。 Here is the quote from documentation :这是文档中的引用:

High priority messages generally should result in user interaction with your app or its notifications.高优先级消息通常会导致用户与您的应用或其通知进行交互。 If FCM detects a pattern in which they don't, your messages may be de-prioritized.如果 FCM 检测到他们没有检测到的模式,您的消息可能会被取消优先级。

Setting a time_to_live of 0 solved the problem for me.time_to_live设置为 0 为我解决了这个问题。

I think it's because a very small time_to_live will tell FCM that this message is only worth delivering right this instant.我认为这是因为一个非常小的time_to_live会告诉 FCM 这个消息只值得在这个瞬间传递。 So in an attempt to deliver it ASAP, it will ignore battery optimizations like the Android P's "app standby buckets".因此,为了尽快交付它,它将忽略电池优化,例如 Android P 的“应用待机存储桶”。 Be careful though, as setting a small time_to_live might mean not delivering the notification at all in some cases.不过要小心,因为设置一个小的 time_to_live 可能意味着在某些情况下根本不发送通知。 I don't think you should be applying it to all kinds of push notifications.我认为您不应该将其应用于所有类型的推送通知。

For more details about time_to_live: https://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message有关 time_to_live 的更多详细信息: https ://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message

Instead of using "android":{"priority":"high"}, use like this而不是使用“android”:{“priority”:“high”},像这样使用

    {
      "time_to_live": 300000,
      "delay_while_idle": false,
      "data": {
               "message": "PING_DEVICE",
               "time": "21/01/2018 16:20:28",
               "pushguid": "10062"
               },
      "priority": "high"  
}

Thanks for the replies everyone.谢谢大家的回复。 we finally sorted it.我们终于整理好了。

We logged into the firebase console and realized due to the age of the code we did not use a settings/config file that is generated in the console.我们登录了 firebase 控制台并意识到由于代码的年龄,我们没有使用在控制台中生成的设置/配置文件。 sorry i've forgotten the name of it.抱歉我忘记了它的名字。 this file has settings etc which are used when pushes are sent to google.这个文件有设置等,当推送被发送到谷歌时使用。 once we used the file in our requests, my application can wake up a phone in doze.一旦我们在请求中使用了该文件,我的应用程序就可以唤醒处于瞌睡状态的手机。

thanks谢谢

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 即使使用高优先级消息,Android 应用程序也不会从打盹模式中唤醒 - Android app not waking up from doze mode even with High priority Message android 6.0.1(Galaxy Note 5)通过FCM推送通知,优先级高,不从打盹模式唤醒 - android 6.0.1 (Galaxy Note 5) Push notification via FCM, priority high, not waking up from doze mode 为什么 Android 不退出打盹模式,尽管 FCM 中消息的优先级很高? - Why Android does not exit DOZE mode, despite the high priority of the message in FCM? Ble beacon Android Oreo和P无法从打ze模式唤醒应用程序 - Ble beacon Android Oreo and P not waking app from doze mode FCM 正常优先级消息可以将设备从打盹模式中唤醒吗? - Can FCM normal priority message wake up device from doze mode? Android DOZE模式GCM优先级 - Android DOZE mode GCM Priority android:唤醒设备 - android: waking up the device Android中具有PHP的高优先级GCM消息? - High priority GCM message in Android with PHP? Doze期间的后台操作,Android 6+上的睡眠模式 - Background operations during Doze, Sleeping mode on Android 6+ 收到消息后,GCM没有唤醒设备 - GCM not waking up device when message received
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM