Сообщение Firebase с высоким приоритетом не бодрствующее устройство от Doze android 6+

Я перенес свой проект из GCM в Firebase. Push-уведомление приходит нормально, когда устройство не спит или недавно спит, но если я оставляю устройство, скажем, на час, push-уведомление не отправляется, пока я не активирую устройство.

Документы Android говорят, что если вам нужно разбудить устройство для доставки сообщения, используйте FireBase с высоким приоритетом. В нем также говорится, что на приложения администратора устройства не распространяются ограничения Doze, мое приложение является приложением администратора устройства.

Я подумал, что упомяну, что когда я перенес проект из GCM в FCM, я указал только имя пакета в консоли Firebase, а не fingerprint.

Что я пробовал

  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, FCM игнорирует его после сентября 2016 года.

  2. Приложения для администрирования устройства не подлежат Doze, мое приложение является приложением для администрирования устройства, но я также явно добавил приложение в белый список Doze, который можно найти в разделе "Настройка" → "Аккумулятор" → "Оптимизация". Это было сделано вручную через приложение настроек, а НЕ программно в коде.

Я оставил свое устройство, чтобы ложиться спать в течение 3 часов, и никакого толчка не прошло. Я также использовал ADB, чтобы поместить устройство в Doze. Когда adb переводит устройство в режим Doze, push не принимается, а когда adb выводит устройство из Doze, push проходит.

дальнейших мыслей я не пробовал.

Мои толчки - это сообщения с данными. Это потому, что я не хочу, чтобы нажатие приходило на панель уведомлений на устройстве и чтобы пользователь щелкнул ее, чтобы выполнить функцию. Пользователь не взаимодействует с приложением администратора устройства. Таким образом, сообщение с данными обрабатывается

onMessageReceived(RemoteMessage remoteMessage)

Я верю, что уведомления вызывают пробуждение устройства, а это то, что мне нужно, но я хочу, чтобы приложение обрабатывало толчок, а не пользователя. Могу ли я иметь сообщения, которые являются одновременно уведомлением и данными, но onMessageRecievied обрабатывают эту функциональность?

Кто-нибудь испытывал что-то подобное или есть какие-то решения для этого?

[EDIT1] Ниже я обнаружил следующую ссылку, в которой говорится, что вы можете отправить сообщение, содержащее как уведомление, так и данные, но если приложение находится в фоновом режиме, уведомление отображается, но данные выполняются только тогда, когда пользователь щелкает уведомление. Это не то, что я хочу, так как я хотел бы, чтобы данные выполнялись в onMessageRecived сразу.

уведомление с данными

[EDIT2] Я добавил следующий код и разрешение для приложения. Теперь приложение просит пользователя внести в белый список приложение для Doze, поэтому я нажал "да". Я тогда через 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]

Я провел дополнительное тестирование, чтобы попытаться изолировать проблему и вывести код моего веб-приложения из уравнения. Я помещаю устройство в Doze через adb и используемую консоль FireBase для отправки push. Push- код прошел правильно. Это говорит о том, что существует проблема с кодом моего веб-приложения, который отправляет всю push-информацию в конечную точку fcm. Я получу код сегодня вечером и опубликую позже.

[EDIT4] Я только что провел еще несколько испытаний. Я поместил устройство в дрему, а затем использовал консоль FireBase для отправки сообщения с двумя парами ключ-значение. Когда устройство находится в режиме 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)
            {



            }

         }//

Спасибо

Ответ 1

Вы ничего не можете сделать.

Это известная проблема, вызванная оптимизацией батареи, реализованной некоторыми OEM-производителями (например, Meizu или Asus). Когда приложение переключается в приложение-переключателе, приложение обрабатывается так, как если бы оно было принудительно остановлено, что не является поведением Android по умолчанию. Несчастливый побочный эффект этого заключается в том, что это может привести к тому, что служба FCM для вашего приложения перестанет работать. Подобный эффект может быть вызван сообщениями с высоким приоритетом в режиме доз.

Команда Firebase работает над улучшением этого поведения с их конца, но фактическое исправление должно исходить от OEM-стороны.

Один из способов проверить, влияет ли ваше приложение на любую функцию управления аккумуляторами OEM, выглядит следующим образом:

1) Прикрепите OEM-устройство к adb

2) Запустите приложение на устройстве

3) Проведите приложение от последнего экрана на устройстве

4) Команда запуска: пакет adb shell dumpsys MY-PACKAGE | grep остановлен

Если он показывает stop = true, можно с уверенностью предположить, что у OEM есть такой механизм и что на ваше приложение влияет то же самое.

Ответ 2

После борьбы с подобной проблемой мне удалось заставить это работать.

Я посылаю следующие данные 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

Во время работы над приложением я тоже застрял. Затем я нашел вопрос об этом на Github, который решил мою проблему. То есть

На устройствах под управлением Android 6.0+ режим Doze завершает весь фон когда телефон простаивает и не заряжается, в том числе фоновое соединение с Pushy.

Как только устройство перемещается или пробуждается пользователем, фон восстанавливаются соединения, и любые ожидающие уведомления будут в течение нескольких секунд, если они еще не истекли.

Чтобы отправлять уведомления на устройства в режиме "Доза", ваше приложение может объявить разрешение REQUEST_IGNORE_BATTERY_OPTIMIZATIONS в его AndroidManifest.xml и отобразите системный диалог, в котором пользователи настройте свое приложение с помощью оптимизации аккумулятора, не выходя из приложения.

Это будет эффективно поддерживать фоновое соединение с Pushy active и устройства смогут получать уведомления даже в режиме "Доза".

Вы можете проверить эту проблему здесь https://github.com/ToothlessGear/node-gcm/issues/231

Надеюсь, это поможет вам!

Ответ 4

Похоже, что невозможно сделать высокий приоритет при отправке только поля данных без уведомления. Вот цитата из документации:

Сообщения с высоким приоритетом обычно должны приводить к взаимодействию пользователя с вашим приложением или его уведомлениями. Если FCM обнаруживает шаблон, в котором они этого не делают, ваши сообщения могут быть расставлены по приоритетам.

Ответ 5

Установка time_to_live в 0 решила проблему для меня.

Я думаю, потому что очень маленький time_to_live скажет FCM, что это сообщение стоит только прямо сейчас. Таким образом, в попытке доставить его как можно скорее, он будет игнорировать оптимизацию батареи, как Android P "корзины ожидания приложений". Будьте осторожны, так как установка небольшого time_to_live может означать, что в некоторых случаях уведомление вообще не доставляется. Я не думаю, что вы должны применять его ко всем видам push-уведомлений.

Подробнее о time_to_live: https://firebase.google.com/docs/cloud-messaging/concept-options#setting-the-priority-of-a-message

Ответ 6

Вместо использования "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"  
}