Введение
Общее описание
Структура приложения
Уроки
Урок 1
Создание приложения, экраны, меню, список, локализация
Урок 2
Просмотр видео (youtube), панель ввода
Урок 3
Карты, PlusMinus, пользовательская обработка экранов
Урок 4
Завершение разработки, закрепление материала
Урок 5
Интро, авторизация, фото
Урок 6
Боковое меню, горизонтальный список, пагинация, раскрывающийся список, баркод-сканер, распознавание речи, поиск, листание страниц
Урок 7
Работа с базами данных SQLite, свайп, componentDateDiapason
Урок 8
Спиннер, календарь, пиккер и события
Урок 9
Работа с пуш сообщениями, BadgeTextView
Урок 10
Анимация, кастомные компоненты
Описание библиотеки
Приложения

Урок 9

На этом уроке мы изучим работу с пуш сообщениями и BadgeTextView

Постановка задачи (задание урока)

Нужно описать экраны на которых используется поддержка пуш сообщений.

Их дизайн приведен на следующих рисунках:

Рис. 1 экран DRAWER
Рис. 1 экран DRAWER
Рис. 2 экран NEWS_EVENTS
Рис. 2 экран NEWS_EVENTS
Рис. 3 экран NEWS_EVENTS
Рис. 3 экран NEWS_EVENTS
Рис. 4 экран NEWS_DETAIL
Рис. 4 экран NEWS_DETAIL

На рисунке 1 изображен экран DRAWER у которого для пункта "Новости, мероприятия" стоит бейджик (метка) с указанием суммарного количества пушей по новостям и мероприятиям. На рисунках 2, 3 изображен экран NEWS_EVENTS в разных состояниях переключен на новости и на мероприятия. Для нерасмотренных вкладок отображается бейджик с указанием соответствующего количества пушей. На рисунке 4 показан экран NEWS_DETAIL.

Описание API

Для всех запросов данного урока авторизация не обязательна

Пуши приходят в формате:
{
    "title" : "title message",
    "body" : "content text message",
    "data" : {
        "push_type" : "news",
        "push_data" : "168",
    }
}
Здесь: push_type - тип пуша (news или events); 
    push_data - данные, которые используются для перехода на экран из списка; 
    title - заголовок сообщения; body - контент сообщения.
Экран NEWS URL "depro/cron/news",ответ:
[
    {
        "newsId":1539,
        "title":"Официально открыта фирма в Грузии — Motion Systems LLC",
        "date":"2019-04-21T17:04:38-0",
        "mainImagePath":"images/IMG-dd209ba862386381e870c31b9f48cd37-V.jpg"
    },
    {
        "newsId":1551,
        "title":"ПУЭТ День карьер",
        "date":"2019-04-24T07:04:33-0",
        "mainImagePath":"images/PUET-foto2.jpg"},
    ....
]
Экран EVENTS URL "depro/cron/events",ответ:
[
    {
        "title":"Турнір зі сквош",
        "imageMid":"depro/aura_fit/111.jpg"
    },
    {
        "title":"Змагання з водного поло!",
        "imageMid":"depro/aura_fit/222.jpg"
    }
    ....
]
Экран NEWS_DETAIL URL depro/cron/news_detail, параметр newsId, ответ:
{
    "newsId":535,
    "title":"Сортировочная линия для мусора ориентировочно будет стоить три с половиной миллиона гривен",
    "text1":"Вчера, 25 октября, на встрече рабочей группы по решению проблемы отходов в Полтаве, ....",
    "text2":" Такая установка может переработать 50 000 тонн твердых бытовых отходов в год .....",
    "mainImagePath":"images/WP_20180709_16_35_24_Pro.jpg",
    "imagePaths":["images/WP_20180709_15_31_38_Pro.jpg","images/WP_20180709_15_31_51_Pro.jpg", .....]
}

Экран DRAWER для пункта меню "Новости, мероприятия" в бейджике (метка) нужно показывать суммарное количество пушей по новостям и мероприятиям. Если это количество = 0, то ничего не показывается. При поступлении нового пуша или программном его удалении обновляется вид бэйджика (изменяется количество).

Экран NEWS_EVENTS во вкладках пейджера показываются новости и мероприятия. Если есть не просмотренные пуши то на соответствующей вкладке показывается бейджик в котором отображается количество пушей.

Экран NEWS_DETAIL ничего особенного нет. Используется только что бы показать переходы при обработке пушей.

Общее описание работы с пушами Имеются пуши типа "news" для новостей и "events" для мероприятий. При поступлении пуша какого нибудь типа сообщение о нем появляется в строке статуса андроида. При поступлении следующего пуша того же типа будет отображаться не текст сообщения, который приходит с сервера, а текст "У вас непрочитанных новостей ХХ" для пуша типа "news" или "У Вас новых мероприятий ХХ" для пуша типа "events". Здесь ХХ количество пушей не просмотренных пользователем. На всех соответствующих бейджиках изменяются отображаемые количества. При клике на сообщение независимо от того какой экран показывается осуществляется переход на нужное место. Это сообщение удаляется из строки статуса. Для каждого типа сообщений в строке статуса показывается отдельный значок. Если будет несколько сообщений одного типа значок будет показан только один на все сообщения. При просмотре экрана для соответствующего типа сообщения в строке статуса удаляется информация о них.

Если приложение будет находиться в фоне, то значок будет показываться для всех типов сообщений один (как в меню для пункта "Фитнес"). И для каждого экземпляра пуша будет показываться новый значок.

При клике на сообщение типа "news" будет вызван экран MAIN, затем в меню (экран DRAWER) будет выбран пункт "Новости, мероприятия" и смоделирован клик на нем. В результате буде осуществлен переход на екран NEWS_EVENTS и установлена вкладка NEWS.

Во вкладке NEWS в списке ищется элемент у которого значение поля "news_id" будет равно значению поля "push_data", которое пришло с пушем. Если такой элемент будет найден, то список позиционируется на нем и моделируется клик по нему.

В результате буде вызван экран NEWS_DETAIL, прекращена обработка пуша, количество непросмотренных пушей типа "news" будет установлено в 0 и изменены все бэйджики связанные с ним.

Аналогично будет обрабатываться клик на сообщении типа "events". За исключением того, что вызов детального описания мероприятий для него не предусмотрен.

В DePro мобильные push-уведомления реализованы на Firebase Cloud Messaging (FCM). Детально работа с ними описана в разделе "Пуш уведомления в DePro"

Поэтому предварительно нужно добавить Firebase в приложение. Процедуру добавления Firebase можно посмотреть а любой статье, но лучше всего использовать Гугловский туториал.

Перечислим основные шаги подключения FCM.

На консоле Firebase:

Далее выполняются следующие действия в Android Studio:

Версии нужно поставить актуальные на момент написания приложения. После внесения изменений в файлы build.gradle не забудьте синхронизировать проект. Иначе студия будет показывать ошибки.

После этого можно приступить к описанию пушей в приложении.

В соответствии с принятыми механизмами обработки пушей в DePro необходимо:

Создать сервис для обработки пушей достаточно просто. Нужно создать java файл:

    public class PushService extends PushFMCService {}

И указать ссылку на него в манифесте:

    <service
        android:name=".PushService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

В файле PushService ничего описывать не нужно. Все необходимые действия выполняет библиотечный класс PushFMCService. Файл PushService нужен лишь для возможности сделать ссылку в мнифесте на сервис.

Описание способов отображения пуш-уведомлений в строке состояний и на панели уведомлений:

Начиная с Android Oreo (API 26) появилась возможность создавать каналы для уведомлений.

В DePro каналы описываются просто. В конце метода declare() класса MyDeclareScreens описываем канал:

    channel("Channel_1", "Новости и мероприятия", IMPORTANCE_HIGH, MainActivity.class,
        notices(notice(PUSH_NEWS)
                .lotPushs("У Вас непрочитанных новостей", true)
                .icon(R.drawable.icon_menu_news, getColor(R.color.accent)),
            notice(PUSH_EVENTS).lotPushs("У Вас новых мероприятий", true)))
        .icon(R.drawable.ic_aura)
        .iconLarge(R.drawable.gift_flag)
        .iconColor(getColor(R.color.green_teal));

Здесь Channel_1 - id канала; "Новости и мероприятия" - имя канала, этот текст будет отображаться в системных настройках приложения в разделе сообщенй; IMPORTANCE_HIGH - важность. Это все стандартные для сообщений параметры и достаточно хорошо описаны в литературе. Параметр notices() описывает отдельные типы пушей, которые имеют одинакое представление в строке статуса. Параметр MainActivity.class указывает класс (java файл), который будет выполнен при клике на сообщения данного канала. В связи с этим в методе declare() класса MyDeclareScreens описание экрана MAIN изменяется следующим образом (синим цветом выделена часть которая изменена):

    activity(MAIN, MainActivity.class)
        .navigator(finishDialog(R.string.attention, R.string.finishOk))
        .drawer(R.id.drawer, R.id.content_frame, R.id.left_drawer, null, DRAWER)
        .pushNavigator(drawer());

Также необходимо создать класс (файл) :

    public class MainActivity extends BaseActivity {
        @Override
        public int getLayoutId() {
            return R.layout.activity_main;
        }
        @Override
        public String getNameScreen() {
            return MyDeclareScreens.MAIN;
        }
    }

Этот класс нужно описать в манифесте и задать атрибут android:launchMode="singleTask" :

    <activity android:name=".MainActivity"
        android:launchMode="singleTask"
        android:screenOrientation="portrait"/>

Количество каналов не ограничено. Каналу заданы его дополнительные свойства:

    .icon(R.drawable.ic_aura)    задает id иконки сообщений канала, если отсутствует, то будет показываться значок андроида.
    .iconColor(getColor(R.color.green_teal)   задает цвет иконки.
    .iconLarge(R.drawable.gift_flag)    большой значок.

Методом notice() задаются отдельные пуши которые привязаны к каналу. Метод имеет один параметр - тип (название) пуша. В нашем случае задается строковыми переменными PUSH_NEWS и PUSH_EVENTS. Сообщениям задаются дополнительные свойства:

    .lotPushs("У Вас непрочитанных новостей", true) - указывает, что в случае если будет 
        много не прочитанных сообщений одного типа нужно выдавать сообщение 
        "У Вас непрочитанных новостей" вместо того что прийдет с пушем. Параметр true указывает на 
        необходимость подсчитывать количество непрочитанных сообщений (заданного типа). 
        При изменении этого количество будет посылаться сообщение.
    .icon(R.drawable.icon_menu_news, getColor(R.color.accent)) задает иконку и ее цвет, если нужно 
        что бы они были отличными от тех которые заданы при описании канала.
Описание действий по обработке пушей.

При клике на сообщение в приложении может потребоваться много действий, что бы перейти на нужный экран. Для этого в DePro предусмотрена мощная система навигации для пушей. Действия указываются на отдельных экранах на которые будет осуществляться переход.

Внесем необходимые изменения (выделены синим цветом) в существующие описания экранов MAIN и DRAWER, а также приведем описание новых экранов:

    activity(MAIN, MainActivity.class)
        .navigator(finishDialog(R.string.attention, R.string.finishOk))
        .drawer(R.id.drawer, R.id.content_frame, R.id.left_drawer, null, DRAWER)
        .pushNavigator(drawer());

    fragment(DRAWER, R.layout.fragment_drawer)
        .navigator(start(R.id.enter, AUTH), exit(R.id.exit))
        .component(TC.PANEL, model(PROFILE),
            view(R.id.panel).noDataView(R.id.no_data))
        .menu(model(menu), view(R.id.recycler))
        .pushNavigator(selectMenu(R.id.recycler, PUSH_NEWS, NEWS_EVENTS, true),
            selectMenu(R.id.recycler, PUSH_EVENTS, NEWS_EVENTS, true));

    fragment(NEWS_EVENTS, R.layout.fragment_news_events)
        .navigator(handler(R.id.back, VH.OPEN_DRAWER))
        .component(TC.PAGER_F, view(R.id.pager, NEWS, EVENT)
            .setTab(R.id.tabs, R.array.news_event))
        .pushNavigator(selectPager(R.id.pager, PUSH_NEWS, NEWS, true),
            selectPager(R.id.pager, PUSH_EVENTS, EVENT, true));

    fragment(NEWS, R.layout.fragment_news)
        .list(model(Api.NEWS),
            view(R.id.recycler, R.layout.item_news),
            navigator(start(NEWS_DETAIL)))
        .pushNavigator(selectRecycler(R.id.recycler, PUSH_NEWS, "news_id", 0,false),
            nullifyCountPush(PUSH_NEWS));

    fragment(EVENT, R.layout.fragment_news)
        .list(model(Api.EVENT),
            view(R.id.recycler, R.layout.item_events))
        .pushNavigator(nullifyCountPush(PUSH_EVENTS));

    activity(NEWS_DETAIL, R.layout.fragment_news_detail).animate(AS.RL)
        .navigator(back(R.id.back))
        .component(TC.PANEL,
            model(Api.NEWS_DETAIL, "news_id"),
            view(R.id.panel));

В нашем случае при клике на все сообщения осуществляется переход на экран MAIN. В нем предусмотрена обработка .pushNavigator(drawer()), которая указывает на передачу всех сообщений в drawer (экран DRAWER).

В описании экрана DRAWER для пуша типа PUSH_NEWS задан обработчик selectMenu(R.id.recycler, PUSH_NEWS, NEWS_EVENTS, true). Здесь R.id.recycler - id представления, которое связано с компонентом menu(); PUSH_NEWS - тип пуша на который реагирует данный обработчик; NEWS_EVENTS - экран на который нужно переключить компонент меню; true - на следующих экранах обработка пуша продолжится. Аналогичный обработчик указан для сообщений типа PUSH_EVENTS.

В результате будет вызван (из меню) экран NEWS_EVENTS, который продолжит обработку пушей.

В описании экрана NEWS_EVENTS для пуша типа PUSH_NEWS задан обработчик selectPager(R.id.pager, PUSH_NEWS, NEWS, true). Здесь R.id.pager - id представления, которое связано с компонентом типа PAGER_F; PUSH_NEWS - тип пуша на который реагирует данный обработчик; NEWS - вкладка пейджера на которую нужно переключить компонент PAGER_F; true - на следующих жкранах обработка пуша продолжится. Аналогичный обработчик указан для сообщений типа PUSH_EVENTS.

В результате на экране NEWS_EVENTS будет установлена вкладка с экраном NEWS или вкладка с экраном EVENT.

В описании экрана NEWS для пуша типа PUSH_NEWS заданы обработчики selectRecycler(R.id.recycler, PUSH_NEWS, "news_id", 0,false) и nullifyCountPush(PUSH_NEWS). Здесь R.id.recycler - id представления, которое связано со списком (компонент типа RECYCLER); PUSH_NEWS - тип пуша на который реагирует данный обработчик; false - на следующих жкранах обработки пуша не будет.

На параметре "news_id" остановимся более подробно. Он указывает имя поля в данных списка (компонент типа list). Обработчик selectRecycler сканирует данные компонента и ищет запись у которой значение поля news_id равняется значению поля push_data пуша, полученного с сервера. Для найденной позиции моделируется клик. В результате будет выполнен навигатор списка. В нашем случае выполнится start(NEWS_DETAIL) - т.е. будет вызван экран NEWS_DETAIL для новости с news_id выбранной позиции.

Обработчик nullifyCountPush(PUSH_NEWS) обнуляет значение счетчика для пушей типа PUSH_NEWS.

На экране EVENT выполняется обработчик nullifyCountPush(PUSH_EVENTS)

При каждом изменении количества непросмотренных пушей (приход нового или обнуление) посылается сообщение на которое реагируют элементы разметки класса BadgeTextView и пункты меню у которых указан дополнительный функционал badge().

Элементу разметки BadgeTextView можно задать атрибут listPushName. В котором через запятую указываются названия пушей на которые он реагирует. В нашем случае для новостей задан атрибут app:listPushName="news". При поступлении сообщения об изменении количества пушей суммарное количество отображается в элементе BadgeTextView. Показано на экране NEWS_EVENTS на вкладках.

Для отображения количества пушей на пункте меню "Новости, мероприятия" добавим бейдж:

    .item(R.drawable.icon_menu_news, R.string.news_events, NEWS_EVENTS).badge("news,events")
Проверка работы пушей

Отправка пушей осуществляется с консоли Firebase. В пункте Notification задаете значения Notification title и Notification text. Не забудьте в пункте Target проверить, что у Вас правильно указано приложение. В пункте Additional options задайте в разделе Custom data ключи и значение сообщения. В частности для мероприятий Key = push_type, а Value = events. Для новостей указывается два параметра: первый Key = push_type, а Value = news, а второй Key = push_data, а Value = 168. Здесь 168 - id новости на которую хочете чтоб был переход. Значение для push_data можете брать любое из имеющихся. Для определения возможных id новостей в приложении перейдите на экран новостей, в студии откройте панель Logсat, в фильтре задайте SMPL, или тот тег, который Вы задали для параметра NAME_LOG_APP в классе MyParams. Вы увидите те данные, которые приходят с сервера. И выбирайте любое значение news_id.

Консоль Firebase отправляет пуши типа notification with data. Поэтому если приложение будет находиться в фоне, то в строке статуса вместо иконки будет показываться белый квадрат. Для того чтобы показывалася иконка нужно в манифесте задать:

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_aura" />

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/green_teal"/>

Если в своих приложениях захотите чтобы пуши обрабатывались и в фоне, то сервер должен отправлять сообщения типа data. Более подробно это описано в разделе "Пуш уведомления".

В некоторых случаях пуши не приходят. Связано это не с библиотекой декларативного программирования DePro, а с: 1) Неправильными настройкам Firebase. Поэтому внимательно проверьте свой проект и порядок отправки пушей в Firebase. 2) допущенными ошибками при описании пушей. Поэтому внимательно проверьте правильность описания всех элементов. 3) ОС андроид "глючит". В этом случае, как правило, помогает выключение и включение (питания) смартфона. 4) В настройках (системных) приложения установлен режим отключения сообщений.

Как подписываться \ отписываться от пушей через сервер описано в следующем разделе.



Лучше пакета DePro может быть только искусственный интеллект
Задать вопрос
Отправить вопрос