Firebase в android: Push Notifications или как реализовать рассылку уведомлений пользователям вашего мобильного приложения

Это очередное видео из серии “Инструменты андроид-разработчика”, в котором мы начинаем разбираться с таким замечательным инструментом от Google, как Firebase. Вернее, это целый набор инструментов и сервисов для реализации в приложениях таких вещей, как аутентификация пользователей, облачное хранение данных и файлов, сообщения и уведомления, облачное тестирование, аналитика, отчеты о сбоях, реклама и т.д. Firebase встроили в среду разработки с последним обновлением до версии Android Studio 2.2, о котором я рассказывал в предыдущем видео. Кто не смотрел, можете найти его по ссылке в описании.

А сейчас я покажу вам, как просто можно реализовать рассылку целевых уведомлений для пользователей вашего приложения через сервис Firebase Notifications.

Чтобы на практике реализовать рассылку уведомлений с помощью FCM, записывайтесь на продвинутый курс по разработке приложения «Чат-мессенжер»

Для этого я создал новый проект в Android Studio, все параметры я оставил по умолчанию.
Сервис Firebase доступен в меню Tools. Открываем и видим все инструменты, доступные для добавления в наше приложение. Сейчас нас интересует Notifications, остальные будем рассматривать в последующих выпусках.
Выбираем его в списке. Открылось меню со списком шагов по внедрению сервиса в проект.

2016-10-04_19-51-22

В первом шаге нужно установить связь приложения с Firebase. Нажимаем кнопку. Откроется окно браузера, где нужно выбрать аккаунт Google, через который произойдет ваша регистрация в сервисе Firebase. Нужно подтвердить согласие с предоставлением доступа к вашему аккаунту. В случае успеха в Android Studio видим сообщение “Connected”.
Следующий шаг: добавление библиотек Notifications в приложение. Нажатие кнопки добавляет необходимые зависимости в файлы сборки проекта и приложения.
В третьем шаге указано, что приложение уже настроено для получения уведомлений в фоновом режиме. Для проверки нужно перейти в консоль Firebase и отправить уведомление. Но прежде нужно запустить приложение на устройстве. Запускаем и сворачиваем приложение, поскольку на данном этапе уведомление будет получено, только если приложение не активно в настоящий момент. Теперь переходим по ссылке в консоль Firebase, видим наше приложение. Выбираем в меню слева вкладку Notifications.

2016-10-04_19-54-36

Здесь можно создать новое сообщение. Вводим его текст. Можно ввести заголовок, но это необязательно – он не будет показан на устройстве.

2016-10-04_19-56-52

Указываем дату доставки сообщения – можно отправить сейчас или запланировать на срок до одного месяца. Указываем таргетинг – можно отправить уведомление на все устройства с установленным приложением или только на определенные, на основании токена.
Мы отправляем на все, ниже выбираем имя пакета приложения. Можно обрабатывать события конверсий, например, отправлено, прочитано, или добавлять свои события для оценки эффективности оповещений. В расширенных настройках можно указать заголовок оповещения, который будет отображаться на устройстве, а также добавить пары “ключ-значение”, которые будут включены в оповещение. Также можно установить приоритет оповещения, срок его действия и включить звуковое уведомление, которое по умолчанию отключено. Нажимаем кнопку отправки сообщения, и попадаем в список оповещений, где можно посмотреть их состояние, дату доставки и статистику прочитанных сообщений. Статистика обновляется с задержкой, поэтому сейчас ничего не будет видно. Тем не менее, уведомление получено устройством, его можно прочитать и перейти в приложение при нажатии на уведомление.

device-2016-10-04-200138
Как я уже говорил, уведомление приходит только когда приложение не активно. Это происходит потому, что когда приложение находится в бэкграунде, то уведомление отправляется сразу в Notification center андроид-устройства. Если открыть приложение, то уведомление не будет получено устройством, хотя на сервере оно отмечается как отправленное. Чтобы получать уведомления, когда приложение открыто, нужно создать сервис в приложении, который будет слушать оповещения и реагировать на них. Создайте в приложении такой класс сервиса, унаследованный от класса FirebaseMessagingService.

package info.fandroid.firebasetest;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        sendNotification(remoteMessage.getNotification().getBody());

    }
    private void sendNotification(String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_launcher))
                .setContentTitle(this.getString(R.string.app_name))
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0, notificationBuilder.build());
    }
}

Метод onMessageReceived выполняется при получении сообщения с сервера и получает на вход объект класса RemoteMessage, который хранит в себе всю информацию о собщении, доступную через геттеры. Вот все поля, которые имеются в этом классе. В данном случае нас интересует только метод внутреннего класса Notification getBody, который содержит текст уведомления. Мы его будем передавать методу sendNotification, в котором мы создаем уведомление для отображения на устройстве. Здесь создаем интент, который будет выполняться при нажатии на уведомление. В данном случае у нас будет открываться главное активити, но можно прописать здесь открытие любого другого активити, или другое действие, переход по внешней ссылке, например. Созданием уведомления занимается notificationBuilder, он устанавливает маленькую иконку, которая отображается в панели уведомлений, большую иконку для открытого уведомления, заголовок уведомления, текст уведомления – его мы передаем в методе onMesageReceived, далее методом setAutoCancel устанавливаем уничтожение уведомления при касании, а методом setSound задаем сигнал для уведомления. Его мы получаем здесь из класса RingtoneManager с флагом, указывающим тим сигнала. Это может быть NOTIFICATION – сигнал уведомления, ALARM – сигнал будильника, RINGTON – сигнал звонка. Но лучше не злоупотреблять терпением пользователей и оставить по умолчанию звук уведомления, или вообще без звука. Уведомление построили, теперь для его отправки используем NotificationManager — это системный сервис Android, который управляет всеми уведомлениями. Экземпляр NotificationManager создается при помощи вызова метода getSystemService(), а затем, когда надо показать уведомление пользователю, вызывается метод notify(), которому мы передаем идентификатор (в данном случае не используется и равен 0) и созданное уведомление.
Перед тем, как проверить работу сервиса, его нужно прописать в манифесте вот таким образом.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.fandroid.firebasetest">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

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

    </application>

</manifest>

Теперь запускаем приложение на устройстве и идем в консоль Firebase для создания и отправки тестового уведомления. Уведомление приходит на устройство и тогда, когда приложение активно.

device-2016-10-04-200403
Предвижу ваш вопрос: как поменять иконку уведомления, когда приложение работает в бэкграунде? Дело в том, что когда приложение находится в бэкграунде, то иконка в уведомлении не будет отображаться поскольку уведомление отправляется сразу в Notification center, и метод onMessageReceived не срабатывает. Чтобы использовать свои иконки уведомлений, вам нужно посылать сообщение не через Firebase, а через ваше собственное API. Но эта тема выходит за рамки нашего урока, возможно рассмотрим ее в следующий раз, на уроке о сервисе Firebase Cloud Messages.

<<<Предыдущий урок      Следующий урок>>>

Коментарі: 4
  1. lex

    Почему-то, при открытии уведомления, открывается исключительно главное активити.
    Даже если задать любое другое.
    Пытался так же повесить внешнюю ссылку по Intent.ACTION_VIEW, Uri.parse(“http”); так же не отрабатывает.

    1. тебе просто нужно отправлять data сообщение с командной строки как с сервера при помощи небольшого скрипта на питоне. Но перед этим настрой json c firebase/ как это делается тут https://firebase.google.com/docs/admin/setup далее скчиваешь и сохраняешь где-нибудь готовый json/ далее создаешь скрипт на питоне на той же папке, для удобства и прописываем ему туда вот это:
      import firebase_admin
      from firebase_admin import credentials, messaging

      cred = credentials.Certificate("C:\\Users\\admin\\pythonProjects\\testapp-firebase-adminsdk.json")
      firebase_admin.initialize_app(cred)

      # This registration token comes from the client FCM SDKs.
      # registration_token = 'YOUR_REGISTRATION_TOKEN'

      # See documentation on defining a message payload.
      message = messaging.Message(

      data={
      'text': 'Вышла новая версия !',
      'version': '2.0',
      },

      topic="updates"
      )

      # Send a message to the device corresponding to the provided
      # registration token.
      response = messaging.send(message, dry_run=False) #если здесь True, то нотиф не отправится. ок
      # Response is a message ID string.
      print('Successfully sent message:', response)

      Далее в файле класса MyFirebaseMessagingService в методе onMessageReceived подправляем код
      // TODO(developer): Handle FCM messages here.
      // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
      Log.d(TAG, "From: " + remoteMessage.getFrom());

      // Check if message contains a data payload.
      Map data = remoteMessage.getData();
      if (data.size() > 0) {
      Log.d(TAG, "Message data payload: " + data);
      String message="";
      if (data.containsKey("text")) {
      message+=data.get("text") +" ";
      }
      if (data.containsKey("version")) {
      message+=data.get("version");
      }
      if (/* Check if data needs to be processed by long running job */ true) {
      // For long-running tasks (10 seconds or more) use Firebase Job Dispatcher.
      scheduleJob();
      } else {
      // Handle message within 10 seconds
      handleNow();
      }

      sendNotification(message);
      }

      вроде готово, осталось запустить вышесозданный скрипт на питоне через терминал. Придет уведомление с перенаправление на приложение в плей маркет будь приложение запущено или не запущено. Но что б направилось на плей маркет или куда нибудь надо прописать ссылку как ты выше делал по Intent.ACTION_VIEW, Uri.parse(«http»). вроде все

  2. Alla

    Очень интересно и полезно как всегда. Спасибо за Ваши уроки!

Додати коментар