Реалізація Rich Push Notifications (зображення, кнопки) у мобільному додатку
Стандартне сповіщення — заголовок та текст. Rich Push додає зображення, кнопки дій, розширений текст, іноді відео або GIF. На iOS це вимагає Notification Service Extension. На Android — нативно через NotificationCompat.BigPictureStyle. Розберемо обидва шляхи.
iOS: Notification Service Extension
Без NSE зображення у push на iOS не працюють. NSE — окремий target у Xcode, який перехоплює сповіщення до показу, завантажує медіа та прикріплює його як UNNotificationAttachment.
// NotificationService.swift
class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
let content = request.content.mutableCopy() as! UNMutableNotificationContent
guard let urlString = content.userInfo["image_url"] as? String,
let url = URL(string: urlString) else {
contentHandler(content)
return
}
downloadImage(from: url) { localURL in
if let localURL,
let attachment = try? UNNotificationAttachment(identifier: "image",
url: localURL) {
content.attachments = [attachment]
}
contentHandler(content)
}
}
private func downloadImage(from url: URL, completion: @escaping (URL?) -> Void) {
URLSession.shared.downloadTask(with: url) { tempURL, _, _ in
completion(tempURL)
}.resume()
}
}
NSE має ліміт часу виконання — близько 30 секунд. Якщо за цей час медіа не завантажилось, iOS покаже сповіщення без зображення. Тому оптимізація розміру медіа важлива: рекомендований розмір зображення — до 1 МБ, формат JPEG або PNG.
Кнопки дій на iOS. Категорії сповіщень реєструються при старті додатку:
let likeAction = UNNotificationAction(identifier: "LIKE", title: "❤️ Лайк", options: [])
let replyAction = UNNotificationAction(identifier: "REPLY", title: "Відповісти", options: [.foreground])
let category = UNNotificationCategory(identifier: "POST_CATEGORY",
actions: [likeAction, replyAction],
intentIdentifiers: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
У payload сповіщення вказуємо category: "POST_CATEGORY" — iOS покаже кнопки. Обробка натиску:
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
switch response.actionIdentifier {
case "LIKE":
likePost(id: response.notification.request.content.userInfo["post_id"] as? String)
case "REPLY":
openReplyScreen(for: response.notification.request.content.userInfo)
default:
break
}
completionHandler()
}
Android: BigPictureStyle та Action Buttons
На Android кастомний UI нативно:
val bitmap = BitmapFactory.decodeStream(
URL(imageUrl).openConnection().getInputStream()
)
val notification = NotificationCompat.Builder(context, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setStyle(
NotificationCompat.BigPictureStyle()
.bigPicture(bitmap)
.setSummaryText(body)
)
.addAction(
R.drawable.ic_like,
"Лайк",
getLikePendingIntent(postId)
)
.addAction(
R.drawable.ic_reply,
"Відповісти",
getReplyPendingIntent(postId)
)
.build()
Завантаження bitmap неможливо робити на main thread. Або Glide з Glide.with(context).asBitmap().load(url).submit().get() у окремому потоці, або WorkManager task при отриманні data message.
FCM Data Message (не Notification Message) — правильний підхід для Rich Push на Android при додатку на передньому плані. Notification Message Android обробляє сам, без вашого коду, і там неможливо прикріпити зображення через стандартний механізм. Data Message завжди йде в onMessageReceived вашого FirebaseMessagingService.
Формати медіа
| Платформа | Зображення | Відео | GIF |
|---|---|---|---|
| iOS NSE | JPEG, PNG, GIF (статичний превью), HEIC | MP4 (до 50 МБ) | Ні нативно |
| Android | JPEG, PNG | Ні нативно | Ні нативно |
GIF у iOS-сповіщенні — лише через .gif файл у NSE, iOS покаже перший кадр як превью. Повна анімація працює лише у Notification Content Extension (другий target, для кастомного UI при long press).
Типічні помилки
OneSignal та подібні автоматично завантажують зображення у NSE через свій SDK-код. Але якщо у вас кастомний NSE або ви забули додати OneSignalNotificationServiceExtension у список targetів App Groups — зображення не з'являться, і помилок у логах не буде.
На Android: якщо додаток убитий та прийшов FCM з notification + data полем одночасно — Android покаже системне сповіщення (без зображення) та onMessageReceived не викличеться. Використовуйте лише data payload для повного контролю.
Терміни
Налаштування NSE для iOS, реалізація кнопок дій для iOS та Android, кастомний NotificationCompat.Builder з BigPictureStyle — 4–7 робочих днів.







