- Firebase Notifications in Background & Foreground in Android
- Handling Notifications in Foreground
- Using Data
- Conclusion
- The with() operator in Kotlin
- May 18, 2018
- Launching Activities using Kotlin DSL
- May 17, 2018
- Push уведомления в Android. Грабли, костыли и велосипеды
- Push Notification In Flutter in Background as well as in Foreground Using Firebase
- Step I
- Step II
- Step III
- Step IV
- Step V
- Step VI
- Step VII
- Step VIII
- Step IX
- Step X
Firebase Notifications in Background & Foreground in Android
When developers need to integrate push notifications in their Android apps, the first thing comes in mind is Firebase Notifications or Firebase Messaging. But when they integrate, there are few common issues which they stuck into. One of those common issues is that the applications doesn’t get push notifications. There are multiple reasons such as Unregistered device token or app is killed or Android Oreo’s doze mode is on etc.
We will talk about here for one reason of app being in background and foreground and see how it can be solved. Firebase Notifications applies different mechanisms when app is foreground and when app is in background.
Handling Notifications in Foreground
When the app is closed, your notifications are processed by the Google Service process, which take care of displaying your notifications as required, including the default click action (opening the app) and the notification icon.
When the app is in foreground, the received messages are processed by the app, and since there’s no logic to handle it, nothing will happen!
To fix this, we need our own FirebaseMessagingService , let’s create one. Create a new class that extends it and implement the onMessageReceived method. Then get the Notification object from the remoteMessage and create your own Android Notification.
Then add the Service in your AndroidManifest.xml
Now if you try again, you will display notifications while your app is in foreground!
In real life, your onMessageReceived content will be slightly more complex, you will want different smart actions depending on the type of notification, you will want to show a nicer large icon (the one that appears on the notification body) and for sure to change the status bar icon.
The problem you have now is that your onMessageReceived is ONLY called when the app is in foreground, if you app if is background, the Google Services will take care of displaying your message.
The solution? don’t use the “notification” message payload and use “data” instead.
Using Data
The last step to solve this foreground/background problem is to ditch the notification object from your message payload.
Rather than sending:
This way, your notifications will be always handled by the app, by your NotificationService, and not by the Google Service process.
You will need to change your code as well to handle the data payload:
Your whole NotificationService will look like this now:
One more advantage of using data instead of notification object is that you can put anything you want in the “data” object. For example a user ID, a URL to an image… any information that you might want to use to build the notification or to pass to the click action. Note that all will be treated as String s. For example,
This difference is also explained in the Handling Messages section of this document: https://firebase.google.com/docs/cloud-messaging/android/receive
Conclusion
Note that if you keep the “notification” object in your payload, it will behave just like before. You need to get rid of the “notification” and only provide the “data” object.
If you liked this article, you can read my new articles below:
The with() operator in Kotlin
There are times when there’s multiple lines of operations on the same object, and we do it by calling myObject instance everytime we do any operation.
May 18, 2018
Launching Activities using Kotlin DSL
Launching activities in android apps is a common task and different developers use different approaches. Some use the traditional ways of creating Intent bundles and passing them in startActivity() methods along side the Intents.
May 17, 2018
7 years experience. 💻 Creator of various Open Source libraries on Android . 📝 Author of two technical books and 100+ articles on Android. 🎤 A passionate Public Speaker giving talks all over the world.
Источник
Push уведомления в Android. Грабли, костыли и велосипеды
На написание данной статьи меня подтолкнула задача, которая была поставлена передо мной в одном из рабочих проектов: реализовать Push-уведомления в приложении. Казалось, все просто: штудируешь документацию, примеры и вперед. К тому же, опыт работы с уведомлениями уже был. Но не тут то было…
Сервис, в рамках которого реализовано приложение под Android, предъявляет довольно жесткие требования к работе Push-уведомлений. Необходимо в пределах 30-60 секунд оповестить пользователя о некотором действии. При успешном оповещении с устройства пользователя отправляется запрос на сервер с соответствующим статусом. Из документации известно, что сервис GCM (Google Cloud Messaging) не гарантирует доставку PUSH-уведомлений на устройства, поэтому в качестве backdoor варианта, при нарушении этих временных рамок, наш сервис уведомляет пользователя с помощью SMS сообщения. Поскольку стоимость SMS сообщения существенно выше чем PUSH-уведомления, необходимо максимально сократить поток SMS сообщений на клиентские устройства.
Проштудировав документацию и прикрутив пуш-уведомления, мы разослали нескольким клиентам первую сборку приложения для теста и стали ждать. Результаты были примерно следующими:
- при активном Wifi соединении все работает идеально: уведомления доставляются, клиенты рады.
- при активном мобильном интернете началось самое веселье.
Некоторые клиенты писали, что испытывают задержки в доставке пушей, либо получали одновременно и PUSH и SMS, что достаточно не практично. Другие писали, что вовсе не получали уведомлений, а только SMS. У третьих, как и у нас на тестовых устройствах, все было ок. Собрав с недовольных клиентов максимально возможную информацию, стали разбираться в проблеме и вывели следующий список ограничений (этот список позже вылился в полноценный FAQ):
- включенный режим Энергосбережения (например, Stamina на устройствах Sony) влияет на работу Push уведомлений;
- у пользователя обязательно должен быть минимум 1 активный Google аккаунт на устройстве;
- необходимо удостовериться в том, что на устройстве установлена актуальная версия приложения “Сервисы Google Play”;
- проверить, не отключены ли уведомления для приложения (галочка на страничке приложения в настройках телефона);
- проверить, не ограничена ли работа фонового режима для приложения (настройка расположена в меню «Использование данных»);
- в документации к GCM указано, что уведомления рассылаются только по определенным портам, поэтому настройки роутера, файервола и антивируса так же стоит учитывать.
Разослав данную памятку по всем клиентам, мы снова стали ждать результатов. И они оказались снова «не очень». Стали копать дальше.
На данном этапе очень сильно помогла статья, написанная ребятами из Mail.ru. В ней очень подробно описаны тонкости реализации GCM на клиентской стороне, а так же моменты, в связи с которыми отказываются работать Push уведомления в мобильных сетях. В конечном счете было принято решение о том, чтобы держать свое соединение с сервером в связке с GCM.
Перед тем, как приступить к решению, стоить выделить несколько очень важных моментов, которые позволяют сузить круг потенциально «нерабочих» устройств:
- проблема возникает только при подключении к мобильному интернету;
- по данным клиентов, проблема возникает на версии андроида 4 и выше.
И так, перейдем к реализации.
Бывалый разработчик под Android сходу скажет, что решений задачи как минимум 2: использовать Service или AlarmManager. Мы попробовали оба варианта. Рассмотрим первый из них.
Для того, чтобы создать неубиваемый системой сервис, который постоянно будет висеть в фоне и выполнять нашу задачу, мы использовали метод:
- notificationId — некоторый уникальный идентификатор уведомления, который будет выведен в статус баре и в выезжающей шторке;
- notification — само уведомление.
В данном случае обязательным условием является отображение уведомления в статус баре. Такой подход гарантирует то, что сервису будет дан больший приоритет (поскольку он взаимодействует с UI частью системы) в момент нехватки памяти на устройстве и система будет выгружать его одним из последних. Нам это уведомление не нужно, поэтому мы воспользовались следующим велосипедом: достаточно запустить одновременно с первым сервисом второй и для обоих сервисов в качестве notificationID использовать одно и тоже значение. Затем убить второй сервис. При этом уведомление пропадет из статус бара, но функциональные и приоритетные возможности первого сервиса останутся.
Реализовав данный подход, мы отправили сборку на тест. По результатам выяснилось, что система все-таки выгружает сервис, а по логам мы видели, как происходили существенные временные разрывы при запросе данных в фоне с нашего сервера. Поэтому приступили к реализации второго варианта — AlarmManager.
AlarmManager — это класс, который предоставляет работу с, грубо говоря, «будильником». Он позволяет указать время, по достижении которого система отправит широковещательное уведомление, которое позволит пробудить наше приложение и даст ему возможность выполнить необходимые действия. В работе этого метода есть некоторые ограничения, и их необходимо обработать:
- данные о «будильниках» будут стерты после перезагрузки устройства;
- данные о «будильниках» будут стерты после обновления приложения.
Первыми граблями, на которые мы наступили, был метод
который позволяет установить повторяющийся с некоторым интервалом «будильник». Прикрутив данный способ, стали тестировать, и тесты показали обратное — «будильник» не повторялся. Стали разбираться в чем дело, посмотрели документацию. И именно там нашли ответ на вопрос — начиная с 19 API lvl (Kitkat) абсолютно все «будильники» в системе стали разовыми. Вывод — всегда читайте документацию.
Эти грабли не были поводом для расстройства, ведь решение задачи довольно простое — запускать единоразовый «будильник» и после срабатывания переустанавливать его. При реализации этого подхода мы наткнулись на следующие грабли — оказалось, что для разных уровней API необходимо по разному устанавливать будильники, при этом в документации ничего сказано не было. Но данная проблема решилась достаточно просто — методом «тыка» и «гугления». Ниже представлен пример кода, позволяющий правильно устанавливать «будильники»:
Хочу обратить внимание на флаг AlarmManager.RTC_WAKEUP — именно с помощью него система позволит нашему приложению «проснуться» при неактивном экране, когда устройство находится в заблокированном состоянии.
Данный подход с «будильникам» дал нам нужный результат — приложение в фоне корректно опрашивает сервер на наличие новых данных. Сейчас мы дорабатываем алгоритм. На данный момент реализуем и тестируем следующую оптимизацию, которая позволит сузить круг устройств и тем самым уменьшить нагрузку на сервер:
- в сообщении, отправленном средствами GCM на устройство, содержится некоторый уникальный ID;
- получив данные GET запросом в фоновом режиме проверяем, существуют ли уже запись с таким ID на устройстве;
- если локально на устройстве таких данных нет, мы запоминаем этот ID и время его получения T1;
- ждем PUSH с таким же ID, при получении запоминаем время T2 и проверяем разницу между T2 и T1;
- если разница составляет больше некоторого временного критерия (значения), то на устройстве наблюдается проблема с доставкой уведомлений и для корректной работы сервиса необходимо постоянно запрашивать данные в фоновом режиме с сервера (критерий советую выбирать исходя из решаемой задачи. В нашем случае, был выбран критерий равный 5 минутам);
- данную разницу стоит вычислять несколько раз, например 5-10 раз, только после этого делать вывод о том, что устройство действительно содержит проблему с получением Push уведомлений (таким образом исключается ситуация банального разрыва соединения, таймаута и пр.);
- необходимо прогонять данный алгоритм периодически (например, раз в неделю, или после обновления ОС на устройстве).
Всем добра. И поменьше подобных костылей.
Источник
Push Notification In Flutter in Background as well as in Foreground Using Firebase
In application, there comes a point where we need to integrate push notification.Though we integrate it successfully, sometime we got issue or app got crashed while sending push notifications while app in not running or is opened in background.So here we will integrate push notification using firebase in flutter which works in all states:foreground,background and even when app is closed(not running).Moreover, if you want to redirect that notification to the certain page in the application after click on push notification,here is link.
Step I
- Create firebase project for your app and add googleservices.json file in the android/app folder.
- Install firebase_messaging and firebase_core in your flutter project.
- Do the settings for firebase initialization in build.gradle (in both app level and android level) file as usual we did.
- For push notification, add below line under dependencies in app level build.gradle file( sometime we face multidex issue so its better to add multidex inside defaultConfig<>)
Under defaultConfig:
Step II
Create Application.kt file inside android/app/src/main/kotlin ( simply to say where you see MainActivity.kt file create Application.kt file in that folder)and copy and paste the below code:
Step III
Step IV
Add the following lines in the android/app/src/main/res/AndroidManifest.xml
Upto now push notifications done now we are moving to
coding part.
Step V
Add these line in the main function of main.dart file.
Step VI
Create one page and initialize the firebase_messaging and flutter_local_notifications by importing those packages respectively.
Step VII
Here we write code for getting fcm_token in the terminal so that we can use these token under cloud messaging in firebase project that we had created in Step I.
Step VIII
In this step we code for receiving the notifications format and settings.
Step IX
The final code will be :
When you run this code then you will get fcm_token in the console and then copy that token and do the following steps:
Step X
Open firebase project and go to cloud messaging section and write notification title and body like this:
After doing like above picture, hit send text message, you’ll get like this below:
Here paste the fcm_token(what you have copied from terminal in the previous steps) and hit test button.
So after these all steps you will get notification in you mobile either app is in running state or running in background or is closed.If you want to open that notification so here is all the steps.
Finally, push notification works and you can use this feature in future apps.
Thank you 🙂
Follow me here for more updates.
Keep coding and keep learning and then keep earning
Give Feedback
Источник