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

时间:2018-01-25 20:54:41

标签: android firebase-cloud-messaging device-admin

我已将项目从使用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........"
      ]
    }
    

    设置生存时间,以便最终传达消息。 delay_while_idle设置为false,2016年9月后FCM会忽略它。

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

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

    我还没有尝试过进一步的想法。

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

    处理
    onMessageReceived(RemoteMessage remoteMessage)
    

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

    有没有人经历过任何相似或有任何解决方案?

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

    notification with data

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

    [EDIT3]

    我已经做了进一步的测试,试图找出问题并将我的Web应用程序代码排除在外。我通过adb和使用过的FireBase控制台将设备置于Doze中以发送推送。 推送正确 这告诉我,我的网络应用程序代码存在问题,它将所有推送信息发送到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)
                {
    
    
    
                }
    
             }//
    

    感谢

8 个答案:

答案 0 :(得分:6)

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

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

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

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

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

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

因此,当旧的HTTP优先级参数设置为“ high”或10时,通知优先级仅会生效并允许在Doze中接收推送通知。

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

答案 1 :(得分:4)

你无能为力。

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

Firebase团队正在努力改善这种行为,但实际的解决方案必须来自OEM方面。

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

1)将OEM设备连接到adb

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

3)将应用程序从设备上的最近屏幕上移开

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

如果显示stopped = true,则可以安全地假设OEM具有此类机制,并且您的应用程序受此影响。

答案 2 :(得分:4)

在遇到类似问题后,我设法使其正常工作。

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

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

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

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

答案 3 :(得分:2)

在处理应用程序时,我也陷入困境。然后我在Github上找到了一个关于它的问题,这解决了我的问题。也就是说,

  

在运行Android 6.0+的设备上,Doze模式会终止所有后台操作   电话闲置且未充电时的连接,包括   与Pushy的背景联系。

     

用户移动或唤醒设备时,背景   连接已恢复,任何待处理的通知都将被删除   在几秒钟内交付,只要它们尚未过期。

     

要在打盹模式下向设备发送通知,您的应用可以声明   其REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限   AndroidManifest.xml并显示一个询问用户的系统对话框   在不离开应用的情况下,将您的应用从电池优化列入白名单。

     

这将有效地保持与Pushy活动的后台连接   即使在打盹模式下,设备也能够接收通知。

您可以在此https://github.com/ToothlessGear/node-gcm/issues/231

查看此问题

希望它可以帮到你!

答案 4 :(得分:1)

似乎仅发送数据字段而不发出通知时不可能设置高优先级。这是来自documentation的引用:

  

高优先级消息通常应导致用户与您的应用或其通知互动。如果FCM检测到没有这种模式,则您的邮件可能会被取消优先级。

答案 5 :(得分:0)

time_to_live设置为0可以为我解决问题。

我认为这是因为很小的time_to_live会告诉FCM,此消息仅在此刻才值得传递。因此,为了尽快交付它,它将忽略电池优化,例如Android P的“应用程序备用存储桶”。 不过要小心,因为设置一个较小的time_to_live可能意味着在某些情况下根本不传递通知。我认为您不应该将其应用于各种推送通知。

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

答案 6 :(得分:0)

不要使用“ 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"  
}

答案 7 :(得分:0)

感谢大家的答复。我们终于对它进行了排序。

我们登录到Firebase控制台,并意识到由于代码年代久远,我们没有使用控制台中生成的设置/配置文件。对不起,我忘记了它的名字。此文件具有设置等,用于将推送发送给Google时使用。一旦我们在请求中使用了文件,我的应用程序便可以在打ze睡时唤醒手机。

谢谢