Домой Android разработкаJava, Kotlin и Android SDK Уведомления в android приложении

Уведомления в android приложении

by dilix
Push уведомления в Android приложении

Уведомления в мобильном приложении бывают разных видов: Push, In-App. Каждый тип сообщения используется для разных целей и несет внутри себя разную информацию. Пуши, например могут приходить когда приложение в фоне. Сообщения внутри приложения привязаны к контексту и привлекают больше внимания.

Push уведомления

Что такое Push уведомления

Push уведомление — это короткое сообщение, которое приходит на устройство пользователя. Обычно оно показывает небольшое всплывающее окно в области уведомлений. Пуши существуют также и на iOS и даже в браузере.

Firebase Cloud Messaging (FCM)

FCM пришел на замену Google Cloud Messaging (GCM). Это облачное решение, которое доставляет сообщения. FCM — стандартное решение для пушей в Android приложении. Система сама обработает пришедшие сообщения когда программа в фоне и покажет уведомление пользователю.

Организовать должным образом Push уведомления в приложении без участия FCM у вас вряд ли получится.

Подключение FCM к проекту

Для начала будет необходимо подключить Firebase к вашему проекту.

Далее добавляем зависимость в gradle:

implementation 'com.google.firebase:firebase-messaging:20.0.1'

После этого вы можете отправлять Push уведомления из вашей Firebase консоли.

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

Обработка Push уведомления когда приложение открыто

Если вы хотите обрабатывать уведомление также, когда приложение открыто, необходимо зарегистрировать свою реализации FirebaseMessagingService:

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

Возможная реализация данного сервиса на Kotlin:

class MyMessagingService : FirebaseMessagingService() {

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        Log.d("MyMessagingService", "Notif: " + remoteMessage.toString())
        Log.d("MyMessagingService", "From: " + remoteMessage.from!!)
        Log.d("MyMessagingService", "Data: " + remoteMessage.data)
        
        // Assume that we have product ID in data.
        val productId = remoteMessage.data["productId"]

        val notification = remoteMessage.notification
        val title = notification?.title
        val message = notification?.body

        if (title != null && message != null) {
            sendNotification(
                title,
                message,
                applicationContext
            )
        }
    }

    private fun sendNotification(
        title: String?,
        message: String?,
        context: Context
    ) {
        val current = GregorianCalendar.getInstance()

        // Channel is a must on android 8+
        val notificationChannel = "chat_notifications"

        val notificationBuilder = NotificationCompat.Builder(context, "notif")
            .setSmallIcon(getNotificationIcon())
            .setContentTitle(title)
            .setContentText(message)
            .setWhen(current.getTimeInMillis())
            .setAutoCancel(true)
            .setColor(ContextCompat.getColor(context, R.color.black))
            .setChannelId(notificationChannel)

        // In case we want to setup notification piority
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            notificationBuilder.setPriority(NotificationManager.IMPORTANCE_HIGH)
        } else {
            notificationBuilder.setPriority(NotificationCompat.PRIORITY_MAX)
        }

        val bigTextStyle = NotificationCompat.BigTextStyle()
        bigTextStyle.setBigContentTitle(title)
        bigTextStyle.bigText(message)
        notificationBuilder.setStyle(bigTextStyle)

        // Setup content that should be open on click
        val contentIntent: PendingIntent
        PendingIntent.getActivity(context.getApplicationContext(), 0, Intent(), 0)
        val intent = Intent(context, MainActivity::class.java)

        // Add data to send to your activity
        // E.g. send productId and let MainActivity to redirect to product screen.
        intent.putExtra(YOUR_KEY, YOUR_VALUE)

        // PendingIntent.FLAG_UPDATE_CURRENT with same ID will update existing notification
        contentIntent =
            PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        notificationBuilder.setContentIntent(contentIntent)

        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val mChannel = NotificationChannel(
                notificationChannel,
                context.getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH
            )
            notificationManager.createNotificationChannel(mChannel)
        }

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
    }

    private fun getNotificationIcon(): Int {
        // Be aware that previously Android has colored icons and now prefers white
        val useWhiteIcon =
            android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP
        return if (useWhiteIcon) R.drawable.ic_icon_white_24dp else R.mipmap.ic_launcher
    }
}

В самом сообщение можно послать данные, которые говорят о том, какой экран в приложении нужно открыть. Например добавить в данные productId и подразумевать это как DeepLink до конкретного продукта.

Notification channel

Начиная с Android 8 поддерживаются каналы уведомлений. Это нужно для того, чтобы пользователь смог отключить только те уведомления, которые ему не интересны. Например можно отключить все, что касается «новостей в приложении», но оставить важные «системные» уведомления.

Каналы уведомлений в Android

Каналы уведомлений в Android

Иконка и цвет push уведомления

Опционально на стороне клиента можно задать какую иконку и какой цвет использовать при показе вашего сообщения. Для этого необходимо добавить соответствующую meta-data в AndroidManifest:

<!-- 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/ic_stat_ic_notification" />
<!-- 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" />

Если ваше приложение получает Push уведомления с вашего же сервера, то в notification payload можно настроить внешний вид сообщения.

Отправление push уведомления с сервера

Push уведомления могут отправляться с вашего сервера. Для этого необходимо реализовать Firebase Admin Sdk на стороне сервера и передать Token с клиента, чтобы backend мог знать какому пользователю отправлять сообщение.

Отправления Firebase token на свой сервер

Чтобы сервер мог понять на какое устройство отправить сообщение ему необходимо знать Token. При реализации FirebaseMessagingService нужно переопределить метод onNewToken

    override fun onNewToken(token: String) {
        super.onNewToken(token)
        cacheManager.fcmToken = token
        AppsFlyerLib.getInstance().updateServerUninstallToken(applicationContext, token)
        AirshipFirebaseIntegration.processNewToken(applicationContext)
    }

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


Серверная реализация Firebase Cloud Message

Описание интеграции можно найти в документации к Firebase. Остановимся только на том, что интересно нам, как андроид разработчикам. А именно то, какие типы сообщений может отсылать сервер. Это могут быть Notification Message или же Data Message

Push сообщения типа Notification message

Такие уведомления должны нравится ребятам из маркетинга. Они позволяют отправлять произвольный текст и картинку пользователю. Это в свою очередь используется для повышения вовлеченности и увеличению retention.

Данное сообщение будет обработано самой системой и показано уведомление на устройстве (если приложение в фоне). Оно также может содержать произвольные данные в data payload. Внутри notification payload можно определить разные параметры push уведомления. Через них контролируется внешний вид сообщения на стороне пользователя.

Данные, отправленные как notification payload, будут доступны в remoteMessage.notification.

Push сообщения типа Data message

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

Данные, отправленные как data payload будут доступны в remoteMessage.data.

In-app уведомления

Что такое In-app уведомления

In-app уведомления — это собирательное понятие, которое обозначает сообщения, которые вы показываете пользователю, когда тот находится внутри приложения. Внешне это может быть как heads-up сообщение, так и контент в bottomSheet. Можно сделать обычный диалог или RICH контент на весь экран.

Heads-up уведомление

Heads-up уведомление

Уведомление как dialog

Уведомление как dialog

UrbanAirship, к примеру поддерживает 3 вида разных in-app уведомлений

In-app уведомления в airship

In-app уведомления в airship

Реализация in-app уведомлений

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

  • Data Push уведомления, когда до клиента доходят лишь данные, а он сам решает как их показать
  • Один из сервисов, который уже делает это за вас, напирмер Airship
  • Если ваше приложение уже поддерживает realtime коммуникацию, то можно доставлять данные через уже установленный канал связи, например socket или long pool

В любом случае, всегда важно иметь в виду — а кто пользователь вашей реализации? Если это отдел макретинга, то, скорее всего, им важно удобство создания сообщений и интеграция с сервисами аналитики. Тогда лучше обратиться к готовым решениям. Может быть такие уведомления будут только системным, и можно посылать их уже через открытый сокет. Решать надо исходят из задачи.

Сервисы для работы с уведомлениями

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

Самих сервисов много, остановлюсь лишь на нескольких.

AirShip

Пользовался AirShip лично и скажу что довольно удобно. Из коробки поддерживаются отправка Push, In-app, а также Message Center. Последний позволяет организовывать входящие пуши в inbox, чтобы пользователь их не терял и мог обратиться, когда будет время.

PushWoosh

Лично не пользовался данным инструментом, но выглядит многообещающе. Позволяет догонять пользователя там, где ему должно быть удобно. Например послать пуш, а потом отправить письмо.

PubNup

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

Amazon Simple Notification Service (Amazon SNS)

Если вы уже используете сервисы Амазона у себя в проекте, то можно подключить и доставку Push уведомлений через Amason simple notification service.

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

Хочешь обсудить Android разработку?
Заходи к нам Вконтакте, на Facebook и в Телеграм!

Добавить комментарий

Может быть интересно

Этот сайт использует Cookie файлы для улучшения вашего пользовательского взаимодействия. Используя данный сайт вы соглашается с этим. Принять Читать

Политика конфиденциальности и Cookies