Standard notifications—just a title and text. Clients complain they are ignored. We implement Rich Push: images, action buttons, sometimes video. On iOS, this requires a Notification Service Extension; on Android, BigPictureStyle. Our experience shows such notifications increase CTR by 40% and engagement by up to 70%. Below we cover both approaches with real examples.
How to Configure Rich Push on iOS?
Without NSE, images in push on iOS won't work. NSE is a separate target in Xcode that intercepts the notification before display. It downloads media and attaches it as a UNNotificationAttachment. We guarantee compatibility with the latest iOS versions.
// 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 has a run limit of about 30 seconds. If media does not download, iOS shows the notification without an image. We optimize media: size up to 1 MB, JPEG or PNG format. According to Apple documentation, exceeding the limit hides the image.
Action buttons on iOS. Register categories at app launch:
let likeAction = UNNotificationAction(identifier: "LIKE", title: "Like", options: []) let replyAction = UNNotificationAction(identifier: "REPLY", title: "Reply", options: [.foreground]) let category = UNNotificationCategory(identifier: "POST_CATEGORY", actions: [likeAction, replyAction], intentIdentifiers: []) UNUserNotificationCenter.current().setNotificationCategories([category]) In the notification payload, include category: "POST_CATEGORY" — iOS will display the buttons. Handle taps:
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() } Why Data Message is Preferable to Notification Message on Android?
On Android, custom UI natively:
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, "Like", getLikePendingIntent(postId) ) .addAction( R.drawable.ic_reply, "Reply", getReplyPendingIntent(postId) ) .build() Loading bitmap must not be on main thread. Use Glide or WorkManager. FCM Data Message is the correct approach, because Notification Message is handled by the system without calling your code. Data Message always goes to onMessageReceived. In real projects, Data Message is more reliable: when the app is killed, Notification Message does not guarantee image display, but Data Message does.
Media Formats
| Platform | Image | Video | GIF |
|---|---|---|---|
| iOS NSE | JPEG, PNG, GIF (preview), HEIC | MP4 (up to 50 MB) | Not natively |
| Android | JPEG, PNG | Not supported | Not natively |
Step-by-Step Integration Guide
- Assess push architecture — determine whether FCM or a third-party service is used.
- Design categories and payload — define notification types, action buttons, media fields.
- Implement NSE on iOS — create target, add download and attachment code.
- Implement BigPictureStyle on Android — configure Data Message, use NotificationCompat.
- Test on real devices — verify all scenarios (active/background/killed app).
- Deploy and monitor — publish to stores, track clicks.
Timeline and What's Included
| Stage | Description | Duration |
|---|---|---|
| Analytics | Assess current push architecture, select approach | 1 day |
| Design | Create category scheme, payload, media design | 1–2 days |
| Implementation | Write NSE, BigPictureStyle, action buttons, handlers | 2–3 days |
| Testing | Test on real devices, error scenarios | 1 day |
| Deployment | Publish to App Store/Google Play, monitoring | 0.5 day |
Included: NSE setup, category registration and tap handling on iOS; FCM Data Message and BigPictureStyle integration on Android; testing on both platforms; documentation. Not included: custom Notification Content Extension and analytics — discussed separately. Pricing is determined after analyzing your project.
Common Mistakes
- OneSignal and NSE. If using OneSignal, add the OneSignalNotificationServiceExtension target to App Groups. Otherwise images won't appear without error logs.
- Dual payload on Android. Using both notification and data fields in FCM when the app is killed causes onMessageReceived not to be called. Use only data payload.
- Media size. On iOS, media over 1 MB may not download within 30 seconds. On Android, large images cause OutOfMemoryError. Optimize to 500 KB.
Why Trust Us
We have many years of experience in mobile development and have delivered over 30 projects with push notifications. We guarantee compatibility with the latest iOS and Android versions, compliance with App Store Review Guidelines. We handle up to 1000 notifications per minute without performance loss. Request rich push integration for your app — we'll prepare a proposal within one day. Get a free consultation for your project to estimate savings.
Sources: UNNotificationServiceExtension — Apple Developer Documentation, BigPictureStyle — Android Developers







