Уведомления в мобильном приложении бывают разных видов: 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 поддерживаются каналы уведомлений. Это нужно для того, чтобы пользователь смог отключить только те уведомления, которые ему не интересны. Например можно отключить все, что касается «новостей в приложении», но оставить важные «системные» уведомления.
Иконка и цвет 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 контент на весь экран.
UrbanAirship, к примеру поддерживает 3 вида разных in-app уведомлений
Реализация 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.
Встречал реализации, когда через пуши посылается откровенная реклама. Я считаю что так делать плохо. Про то, как правильно встроить рекламу в ваше приложение, читайте в отдельной статье.