Skip to content

Instantly share code, notes, and snippets.

@lambiengcode
Last active November 1, 2023 03:38
Show Gist options
  • Select an option

  • Save lambiengcode/dd0d73bcac57cd6c5875dc0301d54ca2 to your computer and use it in GitHub Desktop.

Select an option

Save lambiengcode/dd0d73bcac57cd6c5875dc0301d54ca2 to your computer and use it in GitHub Desktop.
NotificationService
//
// NotificationService.swift
// NotificationService
//
// Created by lambiengcode on 31/10/2023.
//
import UserNotifications
import Intents
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
// Set interruption level to time-sensitive
if #available(iOS 15.0, *) {
bestAttemptContent.interruptionLevel = .timeSensitive
let title = bestAttemptContent.title // The original title
let body = bestAttemptContent.body // The original body
print(title)
// Modify the notification content here to know this works
//REMOVE THIS LATER
bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
//accessing custom data in the payload from fcm
if let imageURLString = request.content.userInfo["image"] as? String,
let senderThumbnailUrl = URL(string: imageURLString),
let senderThumbnailImageData = try? Data(contentsOf: senderThumbnailUrl),
let senderThumbnailImageFileUrl = try? downloadAttachment(data: senderThumbnailImageData, fileName: senderThumbnailUrl.lastPathComponent),
let senderThumbnailImageFileData = try? Data(contentsOf: senderThumbnailImageFileUrl) {
// profile picture that will be displayed in the notification (left side)
let senderAvatar = INImage(imageData: senderThumbnailImageFileData)
var personNameComponents = PersonNameComponents()
personNameComponents.nickname = title
let senderPerson = INPerson(
personHandle: INPersonHandle(
value: title,
type: .unknown
),
nameComponents: personNameComponents,
displayName: title,
image: senderAvatar,
contactIdentifier: nil,
customIdentifier: nil,
isMe: false, // this makes the OS recognize this as a sender
suggestionType: .none
)
// this is just a dummy person that will be used as the recipient
let selfPerson = INPerson(
personHandle: INPersonHandle(
value: "00000000-0000-0000-0000-000000000000", // no need to set a real value here
type: .unknown
),
nameComponents: nil,
displayName: nil,
image: nil,
contactIdentifier: nil,
customIdentifier: nil,
isMe: true, // this makes the OS recognize this as "US"
suggestionType: .none
)
let conversationIdentifier = "test-conversation-identifier"
// the actual message. We use the OS to send us ourselves a message.
let incomingMessagingIntent = INSendMessageIntent(
recipients: [selfPerson],
outgoingMessageType: .outgoingMessageText, // This marks the message as outgoing
content: body, // this will replace the content.body
speakableGroupName: nil,
conversationIdentifier: conversationIdentifier, // this will be used as the conversation title
serviceName: nil,
sender: senderPerson, // this marks the message sender as the person we defined above
attachments: []
)
incomingMessagingIntent.setImage(senderAvatar, forParameterNamed: \.sender)
let interaction = INInteraction(intent: incomingMessagingIntent, response: nil)
interaction.direction = .incoming
if let bestAttemptContents = try? bestAttemptContent.updating(from: incomingMessagingIntent) as? UNMutableNotificationContent {
// Deliver the modified content if available
contentHandler(bestAttemptContents)
return
}
}
}
return super.didReceive(request, withContentHandler: 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 {
contentHandler(bestAttemptContent)
}
}
func downloadAttachment(data: Data, fileName: String) -> URL? {
// Create a temporary file URL to write the file data to
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
// prepare temp subfolder
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let fileURL: URL = tmpSubFolderURL.appendingPathComponent(fileName)
// Save the image data to the local file URL
try data.write(to: fileURL)
return fileURL
} catch let error {
print("error \(error)")
}
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment