I am using OneSignal for the notifications in my messaging app. I have a standard OneSignal's NotificationServiceExtension. And I also need to add a NotificationContentExtension to customize my notifications' UI. What exactly I need to customize: I need to replace the app icon on the left of the notification with the avatar of the person who sent me a message. The only way I currently see to do that is by using NotificationContentExtension, but please do let me know if there is a simpler way. I don't need to customzie anything else - just this picture, but Apple doesn't give me a simple way to do it.
What's wrong: When the noti comes - I see the standard push UI in notification centre. When I long press and hold, I see my custom UI (btw not quickly, only after a while). What I need - is to see only my custom UI from the beginning. I think it's unlikely that OneSignal has anything to do with this, but in any case I cannot try without it.
I created a basic version of my app - only containing the noti setup, here is all of its code without the api keys
import SwiftUI
import OneSignalFramework
@main
struct qqqqApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
if #available(iOS 10.0, *) {
let options: UNAuthorizationOptions = [.alert]
UNUserNotificationCenter.current().requestAuthorization(options: options) { (authorized, error) in
if authorized {
let categoryIdentifier = "OSNotificationCarousel"
let carouselNext = UNNotificationAction(identifier: "OSNotificationCarousel.next", title: "👉", options: [])
let carouselPrevious = UNNotificationAction(identifier: "OSNotificationCarousel.previous", title: "👈", options: [])
let carouselCategory = UNNotificationCategory(identifier: categoryIdentifier, actions: [carouselNext, carouselPrevious], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([carouselCategory])
}
}
}
// Remove this method to stop OneSignal Debugging
OneSignal.Debug.setLogLevel(.LL_VERBOSE)
// OneSignal initialization
OneSignal.initialize("API_KEY", withLaunchOptions: launchOptions)
// requestPermission will show the native iOS notification permission prompt.
// We recommend removing the following code and instead using an In-App Message to prompt for notification permission
OneSignal.Notifications.requestPermission({ accepted in
print("User accepted notifications: \(accepted)")
}, fallbackToSettings: true)
return true
}
}
import UserNotifications
import OneSignalExtension
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var receivedRequest: UNNotificationRequest!
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.receivedRequest = request
self.contentHandler = contentHandler
self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
/* DEBUGGING: Uncomment the 2 lines below to check this extension is executing
Note, this extension only runs when mutable-content is set
Setting an attachment or action buttons automatically adds this */
// print("Running NotificationServiceExtension")
// bestAttemptContent.body = "[Modified] " + bestAttemptContent.body
OneSignalExtension.didReceiveNotificationExtensionRequest(self.receivedRequest, with: bestAttemptContent, withContentHandler: self.contentHandler)
}
}
override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
OneSignalExtension.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
contentHandler(bestAttemptContent)
}
}
}
import UIKit
import UserNotifications
import UserNotificationsUI
class NotificationViewController: UIViewController, UNNotificationContentExtension {
@IBOutlet var titleLabel: UILabel?
@IBOutlet var subtitle: UILabel?
override func viewDidLoad() {
super.viewDidLoad()
// Do any required interface initialization here.
}
func didReceive(_ notification: UNNotification) {
self.titleLabel?.text = notification.request.content.title
self.subtitle?.text = notification.request.content.body
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>UNNotificationExtensionDefaultContentHidden</key>
<true/>
<key>UNNotificationExtensionCategory</key>
<string>OSNotificationCarousel</string>
<key>UNNotificationExtensionInitialContentSizeRatio</key>
<real>0.3</real>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.content-extension</string>
</dict>
</dict>
</plist>
You can change the notification icon by using Intents. It is called communication notification. You don't need to use NotificationContentExtension.
There's an official document you can refer to implement. https://developer.apple.com/documentation/usernotifications/implementing-communication-notifications
You can also refer to the below link; there is a swift implementation with OneSignal in the question. iOS Communication Notification icon