I’ve arrange my Ktor server to ship Firebase Distant Notifications, every thing works fantastic besides Photographs not being hooked up with the Notification.
Right here is my code:
AppDelegate.swift
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
let gcmMessageIDKey = "gcm.Message_ID"
//referred to as when app launched
func software(
_ software: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
print("AppDelegate App launch referred to as")
//must generate a debug token and print it to the console
//seek for "App Verify debug token:" within the console to learn the debug token
#if DEBUG
let providerFactory = AppCheckDebugProviderFactory()
AppCheck.setAppCheckProviderFactory(providerFactory)
#endif
FirebaseApp.configure()
UNUserNotificationCenter.present().delegate = self
Messaging.messaging().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.present().requestAuthorization(
choices: authOptions,
completionHandler: { _, _ in }
)
//simply registers to acquired notifications, doesn't ask permission
software.registerForRemoteNotifications()
//get a app verify token
AppCheck.appCheck().token(forcingRefresh: true) { token, error in
if let error = error {
print("App Verify Error fetching token: (error.localizedDescription)")
return
}
if let token = token {
print("App Verify token (String(describing: token.token)) created at (token.expirationDate)")
}
}
//register all of the background duties
registerBackgroundTasks()
return true
}
//referred to as when registering for distant notifications is profitable
func software(
_ software: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Knowledge
) {
print("AppDelegate didRegisterForRemoteNotificationsWithDeviceToken referred to as")
//this technique units the apns token to the system token which is required to establish the system
Messaging.messaging().apnsToken = deviceToken
}
//referred to as when firebase fcm token recieved
func messaging(
_ messaging: Messaging,
didReceiveRegistrationToken fcmToken: String?
) {
print("AppDelegate Firebase registration token referred to as: (String(describing: fcmToken))")
let dataDict: [String: String] = ["token": fcmToken ?? ""]
NotificationCenter.default.submit(
identify: FirebaseMessaging.Notification.Title("FCMToken"),
object: nil,
userInfo: dataDict
)
// Word: This callback is fired at every app startup and each time a brand new token is generated.
if let token = fcmToken {
// Persist it on native storage
persistViaUserDefaultsToLocalStorage(token, key: UserDefaultsFileKeys.notificationTokenPreferencesUDKey.rawValue)
// Add token to ktor
uploadNotificationToken(token: token, appManager: AppSingleton.occasion)
}
}
//obtain displayed notifications for iOS 10 gadgets.
//calld when app is in foreground and distant notification acquired
func userNotificationCenter(
_ heart: UNUserNotificationCenter,
willPresent notification: UNNotification
) async -> UNNotificationPresentationOptions {
let userInfo = notification.request.content material.userInfo
print("AppDelegate userNotificationCenter willPresent referred to as userInfo is (userInfo)")
return [[.banner, .badge, .sound]]
}
//referred to as when notification acquired
func userNotificationCenter(
_ heart: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler : @escaping () -> Void
) {
print("userNotificationCenter didReceive referred to as")
//get the person data
let userInfo = response.notification.request.content material.userInfo
//submit the notification for the system to indicate it
NotificationCenter.default.submit(identify: Basis.Notification.Title("didReceiveRemoteNotification"), object: nil, userInfo: userInfo)
completionHandler()
print(userInfo)
}
func software(
_ software: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void
) {
// Deal with incoming notifications
print("App Delegate Obtained distant notification referred to as: (userInfo)")
completionHandler(.newData)
}
//used to deal with google sign up
func scene(
_ scene: UIScene,
openURLContexts URLContexts: Set
) {
guard let url = URLContexts.first?.url else { return }
GIDSignIn.sharedInstance.deal with(url)
}
}
I’ve adopted the steps right here to create a Notification Service goal.
NotificationService.swift
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
print("NotificationService didReceive referred to as") //This doesnt get printed when a brand new distant message is acquired in app foreground or background
self.contentHandler = contentHandler
bestAttemptContent = (request.content material.mutableCopy() as? UNMutableNotificationContent)
guard let bestAttemptContent = bestAttemptContent else { return }
// Verify if the notification payload accommodates a picture URL
guard let imageURLString = bestAttemptContent.userInfo["image-url"] as? String,
let imageURL = URL(string: imageURLString) else {
contentHandler(bestAttemptContent)
return
}
// Obtain and course of the picture
downloadAndAttachImage(from: imageURL, to: bestAttemptContent) { updatedContent in
contentHandler(updatedContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
personal func downloadAndAttachImage(from url: URL, to content material: UNMutableNotificationContent, completion: @escaping (UNNotificationContent) -> Void) {
let process = URLSession.shared.downloadTask(with: url) { localURL, _, error in
guard let localURL = localURL, error == nil else {
completion(content material)
return
}
do {
let attachment = strive UNNotificationAttachment(identifier: "picture", url: localURL, choices: nil)
content material.attachments = [attachment]
completion(content material)
} catch {
print("Error creating attachment: (error.localizedDescription)")
completion(content material)
}
}
process.resume()
}
}
My Notification Service Extension has additionally been added the Push Notification Signing Functionality in XCode.
Right here is how I’m establishing the notification at Ktor through Firebase admin:
val messageBuilder = Message.builder()
messageBuilder.setApnsConfig(
ApnsConfig.builder()
.setAps(
Aps.builder()
.setAlert(
ApsAlert.builder()
.setTitle(notification.heading?.removeSquareBrackets())
.setBody(notification.message.removeSquareBrackets())
.construct()
)
.setSound("default")
.setBadge(1)
.setCategory(notification.notificationChannelId + notificationChannelIdVersion)
.setMutableContent(true)
.setContentAvailable(true)
.construct()
)
.putHeader("apns-priority", "10")
.setFcmOptions(
ApnsFcmOptions.builder()
.setImage("https://firebasestorage.googleapis.com/v0/b/jinarya-315507.appspot.com/o/FCMImagespercent2Fzitykach_3d_animation_BB-8_robot_holding_a_chart_containing_a_53875512-7623-4931-9d91-11764eb364f8_0.jpg?alt=media&token=ea2c8a40-4adf-48f1-89f3-4fe82d738724")
.construct()
)
.putCustomData("image-url", "https://firebasestorage.googleapis.com/v0/b/jinarya-315507.appspot.com/o/FCMImagespercent2Fzitykach_3d_animation_BB-8_robot_holding_a_chart_containing_a_53875512-7623-4931-9d91-11764eb364f8_0.jpg?alt=media&token=ea2c8a40-4adf-48f1-89f3-4fe82d738724")
.construct()
)
The difficulty I’m going through right here is that the pictures are usually not getting hooked up to the notification earlier than exhibiting it on the shopper(I’m testing on a Actual Machine), in any other case every thing else works fantastic.