Расширенный Android в Kotlin 01.2: облачный обмен сообщениями Android Firebase

Эта кодовая лаборатория является частью курса Advanced Android in Kotlin. Вы получите максимальную отдачу от этого курса, если будете последовательно работать с лабораториями кода, но это не обязательно. Все кодовые лаборатории курса перечислены на целевой странице Advanced Android in Kotlin codelabs .

Введение

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

Что такое push-уведомление?

Push-уведомления — это уведомления, которые сервер «отправляет» на мобильные устройства. Они могут быть доставлены на устройство независимо от того, запущено ваше приложение или нет.

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

В push-уведомлениях используется шаблон публикации/подписки , который позволяет серверным приложениям отправлять соответствующий контент заинтересованным клиентам. Без модели публикации/подписки пользователям вашего приложения пришлось бы периодически проверять наличие обновлений в вашем приложении. Этот процесс утомителен и ненадежен для пользователей. Кроме того, по мере роста числа клиентов эти периодические проверки будут создавать слишком большую нагрузку на сетевые и вычислительные ресурсы как для сервера вашего приложения, так и для пользовательского устройства.

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

Что такое облачный обмен сообщениями Firebase?

Firebase Cloud Messaging является частью платформы Firebase для разработки мобильных приложений. Обычно вам нужно настроить сервер с нуля, который может связываться с мобильными устройствами для запуска уведомлений. С помощью Firebase Cloud Messaging вы можете отправлять уведомления всем пользователям вашего установленного приложения или их части без настройки сервера. Например, вы можете отправить пользователям напоминание или предложить им специальную акцию, например бесплатный подарок. Вы можете удаленно отправить уведомление на одно или несколько устройств.

Вы также можете использовать Firebase Cloud Messages для передачи данных из вашего серверного приложения или из проекта Firebase вашим пользователям.

В этой лаборатории кода вы узнаете, как использовать Firebase Cloud Messaging для отправки push-уведомлений для вашего приложения Android, а также для отправки данных.

Если вы столкнетесь с какими-либо проблемами (ошибки в коде, грамматические ошибки, нечеткие формулировки и т. д.) при работе с этой лабораторией кода, сообщите о проблеме по ссылке Сообщить об ошибке в левом нижнем углу лаборатории кода.

Что вы уже должны знать

Вы должны быть знакомы с:

  • Как создавать приложения для Android на Kotlin. В частности, работа с Android SDK.
  • Как разработать приложение с использованием компонентов архитектуры и привязки данных.
  • Общее представление о широковещательных приемниках.
  • Базовое понимание AlarmManager.
  • Как создавать и отправлять уведомления с помощью NotificationManager.

Что вы узнаете

  • Как отправлять сообщения пользователю через Firebase Cloud Messaging.
  • Как отправлять данные из серверной части в ваше приложение с помощью сообщений с данными, которые являются частью Firebase Cloud Messaging.

Что ты будешь делать

  • Добавьте push-уведомления в стартовое приложение.
  • Обрабатывайте Firebase Cloud Messaging во время работы вашего приложения.
  • Передавайте данные с помощью Firebase Cloud Messaging.

В этой лаборатории кода вы будете работать с кодом из предыдущей лаборатории кода Использование уведомлений в приложениях Android . В предыдущей кодовой лаборатории вы создали приложение таймера для яиц, которое отправляет уведомления, когда таймер приготовления истекает. В этой лаборатории кода вы добавите Firebase Cloud Messaging для отправки push-уведомлений пользователям вашего приложения, чтобы напомнить им есть яйца.

Чтобы получить пример приложения, вы можете:

Клонируем репозиторий с GitHub и переключаемся на стартовую ветку:

$  git clone https://github.com/googlecodelabs/android-kotlin-notifications-fcm


Кроме того, вы можете загрузить репозиторий в виде Zip-файла, разархивировать его и открыть в Android Studio.

Скачать ZIP

Шаг 1. Создайте проект Firebase.

Прежде чем вы сможете добавить Firebase в свое Android-приложение, вам необходимо создать проект Firebase для подключения к вашему Android-приложению.

  1. Войдите в консоль Firebase .
  2. Нажмите « Добавить проект» , затем выберите или введите имя проекта . Назовите свой проект fcm-codelab .
  3. Нажмите Продолжить .
  4. Вы можете пропустить настройку Google Analytics, отключив кнопку Включить Google Analytics для этого проекта .
  5. Нажмите «Создать проект» , чтобы завершить настройку проекта Firebase.

Шаг 2. Зарегистрируйте свое приложение в Firebase

Теперь, когда у вас есть проект Firebase, вы можете добавить в него свое Android-приложение.

  1. В центре страницы обзора проекта консоли Firebase щелкните значок Android , чтобы запустить рабочий процесс установки.

  1. В поле имени пакета Android введите com.example.android.eggtimernotifications .
  2. Щелкните Зарегистрировать приложение .

Важно! Убедитесь, что вы ввели правильный идентификатор своего приложения, потому что вы не сможете добавить или изменить это значение после того, как зарегистрируете свое приложение в своем проекте Firebase.

Шаг 3. Добавьте файл конфигурации Firebase в свой проект.

Добавьте файл конфигурации Firebase Android в свое приложение.

  1. Нажмите Загрузить google-services.json , чтобы получить файл конфигурации Firebase Android ( google-services.json ). Убедитесь, что файл конфигурации не дополнен дополнительными символами и имеет точное имя google-services.json .
  2. Переместите файл конфигурации в каталог модуля (уровня приложения) вашего приложения.

Шаг 4. Настройте проект Android для включения продуктов Firebase.

Чтобы включить продукты Firebase в своем приложении, вы должны добавить плагин google-services в свои файлы Gradle.

  1. В вашем корневом (проектном) файле Gradle ( build.gradle ) убедитесь, что у вас есть репозиторий Google Maven.
  2. Затем добавьте правила, чтобы включить подключаемый модуль Google Services.

build.gradle

buildscript {

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
  }

  dependencies {
    // ...

    // Add the following line:
    classpath 'com.google.gms:google-services:4.3.2'  // Google Services plugin
  }
}

allprojects {
  // ...

  repositories {
    // Check that you have the following line (if not, add it):
    google()  // Google's Maven repository
    // ...
  }
}
  1. В вашем файле Gradle модуля (уровня приложения) (обычно app/build.gradle ) добавьте строку для применения плагина в нижней части файла.

приложение/build.gradle

apply plugin: 'com.android.application'

android {
  // ...
}

// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services'  // Google Play services Gradle plugin

В этой задаче вы добавите Firebase Cloud Messaging (FCM) в свой проект, чтобы использовать push-уведомления.

Код службы Android для FCM этой кодовой лаборатории приведен в MyFirebaseMessagingService.kt . На следующих шагах вы добавите код в свое приложение для Android.

Вы будете использовать компоновщик уведомлений для тестирования своей реализации. Композитор уведомлений — это инструмент, который помогает вам создавать и отправлять сообщения с веб-сайта консоли Firebase.

  1. Откройте MyFirebaseMessagingService.kt
  2. Проверьте файл и, в частности, следующие функции:
  • onNewToken() — вызывается автоматически, если ваша служба зарегистрирована в манифесте Android. Эта функция вызывается при первом запуске приложения и каждый раз, когда Firebase выдает новый токен для вашего приложения. Токен — это ключ доступа к вашему серверному проекту Firebase. Он создается для вашего конкретного клиентского устройства. С помощью этого токена Firebase знает, какому клиенту серверная часть должна отправлять сообщения. Firebase также знает, действителен ли этот клиент и имеет ли он доступ к этому проекту Firebase.
  • onMessageReceived — вызывается, когда ваше приложение запущено и Firebase отправляет сообщение вашему приложению. Эта функция получает объект RemoteMessage , который может нести полезную нагрузку уведомления или сообщения данных. Вы узнаете больше о различиях между уведомлениями и полезными данными сообщений позже в этой лаборатории кода.

Шаг 1. Отправка уведомлений FCM на одно устройство

Консоль уведомлений позволяет протестировать отправку уведомления. Чтобы отправить сообщение на конкретное устройство с помощью консоли, вам необходимо знать токен регистрации этого устройства.

Когда серверная часть Firebase генерирует новый или обновленный токен, будет вызываться функция onNewToken() , при этом новый токен передается в качестве аргумента. Если вы хотите настроить таргетинг на одно устройство или создать группу устройств, на которые вы хотите отправить широковещательное сообщение, вам потребуется получить доступ к этому токену, расширив FirebaseMessagingService и переопределив onNewToken() .

  1. Откройте AndroidManifest.xml и раскомментируйте следующий код, чтобы включить MyFirebaseMessagingService для приложения таймера для яиц. Метаданные службы в манифесте Android регистрируют MyFirebaseMessagingService как службу и добавляют фильтр намерений, чтобы эта служба получала сообщения, отправленные из FCM. Последняя часть метаданных объявляет breakfast_notification_channel_id как default_notification_channel_id для Firebase. Вы будете использовать этот идентификатор на следующем шаге.
<!-- AndroidManifest.xml -->
<!-- TODO: Step 3.0 uncomment to start the service  -->

        <service
                android:name=".MyFirebaseMessagingService"
                android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>
        <!-- [START fcm_default_icon] -->
        <!--
 Set custom default icon. This is used when no icon is set for incoming notification messages.
             See README(https://goo.gl/l4GJaQ) for more.
        -->
        <meta-data
                android:name="com.google.firebase.messaging.default_notification_icon"
                android:resource="@drawable/common_google_signin_btn_icon_dark"/>
        <!--
 Set color used with incoming notification messages. This is used when no color is set for the incoming
             notification message. See README(https://goo.gl/6BKBk7) for more.
        -->
        <meta-data
                android:name="com.google.firebase.messaging.default_notification_color"
                android:resource="@color/colorAccent"/> <!-- [END fcm_default_icon] -->
        <!-- [START fcm_default_channel] -->
        <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="@string/breakfast_notification_channel_id" />
        <!-- [END fcm_default_channel] -->

Рекомендуется создать новый канал уведомлений для FCM, так как ваши пользователи могут захотеть включить/отключить таймер для яиц или push-уведомления FCM отдельно.

  1. Откройте ui/EggTimerFragment.kt . В onCreateView() добавьте следующий код создания канала.
// EggTimerFragment.kt

   // TODO: Step 3.1 create a new channel for FCM
    createChannel(
        getString(R.string.breakfast_notification_channel_id),
        getString(R.string.breakfast_notification_channel_name)
    )
  1. Откройте MyFirebaseMessagingService.kt и раскомментируйте onNewToken() . Эта функция будет вызываться при создании нового токена.
// MyFirebaseMessagingService.kt

   // TODO: Step 3.2 log registration token
    // [START on_new_token]
    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the     
     * InstanceID token is initially generated so this is where you would retrieve     
     * the token.
     */
    override fun onNewToken(token: String?) {
        Log.d(TAG, "Refreshed token: $token")

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // Instance ID token to your app server.
        sendRegistrationToServer(token)
    }
    // [END on_new_token]
  1. Запустите приложение таймера яиц.
  2. Наблюдайте за logcat ( View > Tool Windows > Logcat ). Вы должны увидеть строку журнала, показывающую ваш токен, аналогичную приведенной ниже. Это токен, который вам нужен для отправки сообщения на это устройство. Эта функция вызывается только при создании нового токена.
2019-07-23 13:09:15.243 2312-2459/com.example.android.eggtimernotifications D/MyFirebaseMsgService: Refreshed token: f2esflBoQbI:APA91bFMzNNFaIskjr6KIV4zKjnPA4hxekmrtbrtba2aDbh593WQnm11ed54Mv6MZ9Yeerver7pzgwfKx7R9BHFffLBItLEgPvrtF0TtX9ToCrXZ5y7Hd-m

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

Теперь вы можете протестировать, отправив уведомление. Чтобы отправить уведомление, вы будете использовать компоновщик уведомлений .

  1. Откройте консоль Firebase и выберите свой проект.
  2. Затем выберите Cloud Messaging из навигации слева.
  3. Нажмите Отправить первое сообщение .

  1. Введите Time for Breakfast! как заголовок уведомления и Don't forget to eat eggs! в качестве текста уведомления и выберите Отправить тестовое сообщение . Появится всплывающее диалоговое окно « Проверить на устройстве », в котором вас попросят предоставить токен регистрации FCM.

  1. Скопируйте токен приложения из logcat.

  1. Вставьте этот токен в поле « Добавить токен регистрации FCM » во всплывающем окне, затем нажмите кнопку « Добавить » рядом с токеном.
  2. В появившемся списке флажков выберите токен. Кнопка « Тест» должна стать активной.

  1. На вашем устройстве установите приложение Egg Timer в фоновом режиме.
  2. Во всплывающем окне нажмите « Тест» .
  1. После нажатия кнопки « Тест » целевое клиентское устройство, на котором ваше приложение работает в фоновом режиме, должно получить уведомление на панели уведомлений системы. (Вы увидите больше о том, как обрабатывать сообщения FCM, когда ваше приложение будет на переднем плане позже.)

Задача: Отправка уведомлений FCM в тему

Тематические сообщения FCM основаны на модели публикации/подписки.

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

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

Чтобы подписаться на тему, клиентское приложение вызывает функцию subscribeToTopic( ) Firebase Cloud Messaging с названием темы breakfast . Этот вызов может иметь два исхода. Если вызывающая сторона преуспеет, обратный вызов OnCompleteListener будет вызван с подписанным сообщением. Если клиент не может подписаться, обратный вызов вместо этого получит сообщение об ошибке.

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

  1. Откройте EggTimerFragment.kt и найдите пустую функцию subscribeTopic() .
  2. Получите экземпляр FirebaseMessaging и вызовите subscibeToTopic() с названием темы.
  3. Добавьте addOnCompleteListener , чтобы получать уведомления от FCM об успешной или неудачной подписке.
// EggTimerFragment.kt

   // TODO: Step 3.3 subscribe to breakfast topic
    private fun subscribeTopic() {
        // [START subscribe_topics]
        FirebaseMessaging.getInstance().subscribeToTopic(TOPIC)
            .addOnCompleteListener { task ->
                var msg = getString(R.string.message_subscribed)
                if (!task.isSuccessful) {
                    msg = getString(R.string.message_subscribe_failed)
                }
                Toast.makeText(context, msg, Toast.LENGTH_SHORT).show()
            }
        // [END subscribe_topics]
    }
  1. Вызовите функцию subscribeTopic() , чтобы подписаться на тему при запуске приложения. Прокрутите вверх до onCreateView() и добавьте вызов subscribeTopic() .
// EggTimerFragment.kt

   // TODO: Step 3.4 call subscribe topics on start
    subscribeTopic()

    return binding.root
  1. Чтобы подписаться на тему завтрака, снова запустите приложение. Вы должны увидеть всплывающее сообщение с надписью «Подписан на тему».

Теперь вы можете протестировать отправку сообщений в тему:

  1. Откройте компоновщик уведомлений и выберите « Создать уведомление» .
  2. Установите заголовок уведомления и текст уведомления , как и раньше.
  3. На этот раз вместо отправки сообщения на одно устройство нажмите « Тема » в разделе « Цель » и введите breakfast в качестве темы сообщения.

  1. Выберите сейчас для планирования.

  1. Убедитесь, что ваше приложение работает в фоновом режиме на тестовом устройстве.
  1. Щелкните Обзор , а затем щелкните Опубликовать . Если вы можете запустить приложение более чем на одном устройстве, вы можете проверить и убедиться, что уведомление получено на всех устройствах, подписанных на эту тему.

Теперь в приложении есть следующие каналы для уведомлений: « Яйцо и завтрак ». На клиентском устройстве нажмите и удерживайте значок приложения, выберите « Информация» и нажмите « Уведомления ». Вы должны увидеть каналы уведомлений о яйцах и завтраках , как показано на следующем снимке экрана. Если вы отмените выбор канала « Завтрак », ваше приложение не будет получать уведомления, отправленные по этому каналу.

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

Шаг 1: Сообщения данных

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

Чтобы обрабатывать сообщения данных, вам необходимо обрабатывать полезную нагрузку данных в функции onMessageReceived() службы MyFirebaseMessagingService . Полезная нагрузка хранится в свойстве data объекта remoteMessage . И объект remoteMessage , и свойство data могут иметь значение null .

  1. Откройте MyFirebaseMessagingService.
  2. Проверьте, имеет ли свойство data объекта remoteMessage какое-либо значение, и распечатайте данные в журнале.
// MyFirebaseMessagingService.kt

    // [START receive_message]
    override fun onMessageReceived(remoteMessage: RemoteMessage?) {
        // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
        Log.d(TAG, "From: ${remoteMessage?.from}")
        
       // TODO: Step 3.5 check messages for data
        // Check if the message contains a data payload.
        remoteMessage?.data?.let {
            Log.d(TAG, "Message data payload: " + remoteMessage.data)
        }

    }
    // [END receive_message]

Чтобы протестировать свой код, вы можете снова использовать компоновщик уведомлений .

  1. Откройте компоновщик уведомлений, создайте новое сообщение, установив его цель на тему «завтрак».
  2. На этот раз, когда вы перейдете к шагу 4, Дополнительные параметры , установите свойства ключа и значения пользовательских данных следующим образом:
  1. Ключ: eggs
  2. Стоимость: 3

  1. Убедитесь, что ваше приложение работает на переднем плане. Если ваше приложение находится в фоновом режиме, сообщение FCM вызовет автоматическое уведомление, а onMessageReceived() получит только объект remoteMessage когда пользователь щелкнет уведомление.
  2. Отправьте сообщение из компоновщика уведомлений и просмотрите журнал сообщений данных, который появляется в logcat.

Шаг 2. Обработка сообщений на переднем и заднем плане

Когда клиентское устройство, на котором запущено ваше приложение, получает сообщение, содержащее как уведомления, так и полезные данные, поведение приложения зависит от того, находится ли ваше приложение в фоновом или переднем плане на этом устройстве:

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

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

Когда вы отправляете сообщение FCM на устройства, на которых установлено приложение таймера для яиц, уведомление будет отображаться автоматически, если приложение не запущено или находится в фоновом режиме. Однако, если приложение запущено на переднем плане, уведомление не отображается автоматически; вместо этого код приложения решает, что делать с сообщением. Если приложение находится на переднем плане, когда оно получает сообщение FCM, onMessageReceived() будет автоматически запущена с сообщением FCM. Здесь ваше приложение может автоматически обрабатывать уведомления и полезные данные или инициировать уведомление.

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

  1. Снова откройте функцию onMessageReceived() в MyFirebaseMessagingService .
  2. Сразу после кода, который вы недавно добавили для проверки сообщения с данными, добавьте следующий код, который отправляет уведомление с помощью платформы уведомлений.
// MyFirebaseMessagingService.kt

    // TODO: Step 3.6 check messages for notification and call sendNotification
    // Check if the message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
        sendNotification(it.body as String)
    }
  1. Если вы снова запустите приложение и отправите уведомление с помощью компоновщика уведомлений, вы должны увидеть уведомление, точно такое же, как вы видели в первой части кода, независимо от того, находится ли приложение на переднем плане или в фоновом режиме.

Код решения находится в основной ветке вашего загруженного кода .

  • Реализуйте FCM BroadcastReceiver, расширив FirebaseMessagingService .
  • Настройте проект Firebase Cloud Messaging (FCM) и добавьте FCM в свое приложение для Android.
  • Протестируйте свое приложение, отправив push-уведомления из компоновщика уведомлений.
  • Подпишитесь на темы FCM, вызвав функцию subscribeToTopic() класса FirebaseMessaging .
  • Отправьте полезные данные с помощью объекта RemoteMessage .
  • Обрабатывать данные в функции onMessageReceived() .
  • Добавьте логику для обработки FCM, когда приложение находится на переднем плане и когда оно находится в фоновом режиме.

Удасити курс:

Документация Firebase:

Ссылки на другие лаборатории кода в этом курсе см. на целевой странице Advanced Android in Kotlin codelabs .