Use communication notifications

This commit is contained in:
Thomas Ricouard 2023-02-14 08:54:23 +01:00
parent 05815e6d35
commit d73b6952d9
4 changed files with 61 additions and 4 deletions

View file

@ -8,6 +8,8 @@
<array>
<string>app-usage</string>
</array>
<key>com.apple.developer.usernotifications.communication</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.application-groups</key>

View file

@ -17,6 +17,10 @@
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>NSUserActivityTypes</key>
<array>
<string>INSendMessageIntent</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>remote-notification</string>

View file

@ -4,6 +4,13 @@
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>IntentsSupported</key>
<array>
<string>INSendMessageIntent</string>
</array>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>

View file

@ -5,6 +5,8 @@ import KeychainSwift
import Models
import UIKit
import UserNotifications
import Intents
import Network
@MainActor
class NotificationService: UNNotificationServiceExtension {
@ -15,7 +17,7 @@ class NotificationService: UNNotificationServiceExtension {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent {
if var bestAttemptContent {
let privateKey = PushNotificationsService.shared.notificationsPrivateKeyAsKey
let auth = PushNotificationsService.shared.notificationsAuthKeyAsKey
@ -57,12 +59,13 @@ class NotificationService: UNNotificationServiceExtension {
bestAttemptContent.body = notification.body.escape()
bestAttemptContent.userInfo["plaintext"] = plaintextData
bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "glass.caf"))
let preferences = UserPreferences.shared
preferences.pushNotificationsCount += 1
bestAttemptContent.badge = .init(integerLiteral: preferences.pushNotificationsCount)
if let urlString = notification.icon,
let url = URL(string: urlString)
{
@ -75,8 +78,16 @@ class NotificationService: UNNotificationServiceExtension {
if let (data, _) = try? await URLSession.shared.data(for: .init(url: url)) {
if let image = UIImage(data: data) {
try? image.pngData()?.write(to: fileURL)
if let attachment = try? UNNotificationAttachment(identifier: filename, url: fileURL, options: nil) {
bestAttemptContent.attachments = [attachment]
if let remoteNotification = await toRemoteNotification(localNotification: notification) {
let intent = buildMessageIntent(remoteNotification: remoteNotification, avatarURL: fileURL)
bestAttemptContent = try bestAttemptContent.updating(from: intent) as! UNMutableNotificationContent
let newBody = "\(bestAttemptContent.userInfo["i"] as? String ?? "") \n\(notification.title)\n\(notification.body.escape())"
bestAttemptContent.body = newBody
} else {
if let attachment = try? UNNotificationAttachment(identifier: filename, url: fileURL, options: nil) {
bestAttemptContent.attachments = [attachment]
}
}
}
contentHandler(bestAttemptContent)
@ -89,4 +100,37 @@ class NotificationService: UNNotificationServiceExtension {
}
}
}
private func toRemoteNotification(localNotification: MastodonPushNotification) async -> Models.Notification? {
do {
if let account = AppAccountsManager.shared.availableAccounts.first(where: { $0.oauthToken?.accessToken == localNotification.accessToken }) {
let client = Client(server: account.server, oauthToken: account.oauthToken)
let remoteNotification: Models.Notification = try await client.get(endpoint: Notifications.notification(id: String(localNotification.notificationID)))
return remoteNotification
}
} catch {
return nil
}
return nil
}
private func buildMessageIntent(remoteNotification: Models.Notification, avatarURL: URL) -> INSendMessageIntent {
let handle = INPersonHandle(value: remoteNotification.account.id, type: .unknown)
let avatar = INImage(url: avatarURL)
let sender = INPerson(personHandle: handle,
nameComponents: nil,
displayName: remoteNotification.account.safeDisplayName,
image: avatar,
contactIdentifier: nil,
customIdentifier: nil)
let intent = INSendMessageIntent(recipients: nil,
outgoingMessageType: .outgoingMessageText,
content: nil,
speakableGroupName: nil,
conversationIdentifier: remoteNotification.account.id,
serviceName: nil,
sender: sender,
attachments: nil)
return intent
}
}