♻️ Refactored iOS NES
🐛 Bug fixes of NES
This commit is contained in:
parent
20f4e780bc
commit
41dd7d0b64
@ -37,10 +37,14 @@
|
|||||||
<string>Grant access to Photo Library will allow Solian take photo or video for your post.</string>
|
<string>Grant access to Photo Library will allow Solian take photo or video for your post.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian record audio for your post.</string>
|
<string>Grant access to Photo Library will allow Solian record audio for your post.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
|
||||||
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||||
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
|
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
||||||
|
<key>NSUserActivityTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>INSendMessageIntent</string>
|
||||||
|
</array>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
@ -49,6 +53,7 @@
|
|||||||
<string>remote-notification</string>
|
<string>remote-notification</string>
|
||||||
<string>audio</string>
|
<string>audio</string>
|
||||||
<string>voip</string>
|
<string>voip</string>
|
||||||
|
<string>processing</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
@ -62,10 +67,6 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>NSUserActivityTypes</key>
|
|
||||||
<array>
|
|
||||||
<string>INSendMessageIntent</string>
|
|
||||||
</array>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
@ -23,6 +23,58 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
identifier.starts(with: "http") ? identifier : "\(serverBaseUrl)/cgi/uc/attachments/\(identifier)"
|
identifier.starts(with: "http") ? identifier : "\(serverBaseUrl)/cgi/uc/attachments/\(identifier)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func fetchAvatarImage(from url: String, completion: @escaping (INImage?) -> Void) {
|
||||||
|
guard let imageURL = URL(string: url) else {
|
||||||
|
completion(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a cache location based on the URL hash
|
||||||
|
let cacheFileName = imageURL.lastPathComponent
|
||||||
|
let tempDirectory = FileManager.default.temporaryDirectory
|
||||||
|
let cachedFileUrl = tempDirectory.appendingPathComponent(cacheFileName)
|
||||||
|
|
||||||
|
// Check if the image is already cached
|
||||||
|
if FileManager.default.fileExists(atPath: cachedFileUrl.path) {
|
||||||
|
do {
|
||||||
|
let data = try Data(contentsOf: cachedFileUrl)
|
||||||
|
let cachedImage = INImage(imageData: data) // No optional binding here
|
||||||
|
completion(cachedImage)
|
||||||
|
return
|
||||||
|
} catch {
|
||||||
|
print("Failed to load cached avatar image: \(error.localizedDescription)")
|
||||||
|
try? FileManager.default.removeItem(at: cachedFileUrl) // Clear corrupted cache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download the image if not cached
|
||||||
|
let session = URLSession(configuration: .default)
|
||||||
|
session.downloadTask(with: imageURL) { localUrl, response, error in
|
||||||
|
if let error = error {
|
||||||
|
print("Failed to fetch avatar image: \(error.localizedDescription)")
|
||||||
|
completion(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let localUrl = localUrl, let data = try? Data(contentsOf: localUrl) else {
|
||||||
|
print("Failed to fetch data for avatar image.")
|
||||||
|
completion(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Cache the downloaded file
|
||||||
|
try FileManager.default.moveItem(at: localUrl, to: cachedFileUrl)
|
||||||
|
} catch {
|
||||||
|
print("Failed to cache avatar image: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create INImage from the downloaded data
|
||||||
|
let inImage = INImage(imageData: data) // Create directly
|
||||||
|
completion(inImage)
|
||||||
|
}.resume()
|
||||||
|
}
|
||||||
|
|
||||||
override func didReceive(
|
override func didReceive(
|
||||||
_ request: UNNotificationRequest,
|
_ request: UNNotificationRequest,
|
||||||
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
||||||
@ -61,32 +113,35 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
throw ParseNotificationPayloadError.missingMetadata("The notification has no metadata.")
|
throw ParseNotificationPayloadError.missingMetadata("The notification has no metadata.")
|
||||||
}
|
}
|
||||||
|
|
||||||
guard var avatarUrl = metadata["avatar"] as? String else {
|
guard let avatarIdentifier = metadata["avatar"] as? String else {
|
||||||
throw ParseNotificationPayloadError.missingAvatarUrl("The notification has no avatar.")
|
throw ParseNotificationPayloadError.missingAvatarUrl("The notification has no avatar.")
|
||||||
}
|
}
|
||||||
avatarUrl = getAttachmentUrl(for: avatarUrl)
|
|
||||||
|
let avatarUrl = getAttachmentUrl(for: avatarIdentifier)
|
||||||
|
fetchAvatarImage(from: avatarUrl) { [weak self] inImage in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
let handle = INPersonHandle(value: "\(metadata["user_id"] ?? "")", type: .unknown)
|
let handle = INPersonHandle(value: "\(metadata["user_id"] ?? "")", type: .unknown)
|
||||||
let avatar = INImage(url: URL(string: avatarUrl)!)
|
|
||||||
let sender = INPerson(
|
let sender = INPerson(
|
||||||
personHandle: handle,
|
personHandle: handle,
|
||||||
nameComponents: nil,
|
nameComponents: nil,
|
||||||
displayName: content.title,
|
displayName: content.title,
|
||||||
image: avatar,
|
image: inImage,
|
||||||
contactIdentifier: nil,
|
contactIdentifier: nil,
|
||||||
customIdentifier: nil
|
customIdentifier: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
if content.categoryIdentifier == "messaging.callStart" {
|
if content.categoryIdentifier == "messaging.callStart" {
|
||||||
let intent = createCallIntent(with: sender)
|
let intent = self.createCallIntent(with: sender)
|
||||||
donateInteraction(for: intent)
|
self.donateInteraction(for: intent)
|
||||||
let updatedContent = try request.content.updating(from: intent)
|
let updatedContent = try? request.content.updating(from: intent)
|
||||||
contentHandler?(updatedContent)
|
self.contentHandler?(updatedContent ?? content)
|
||||||
} else {
|
} else {
|
||||||
let intent = createMessageIntent(with: sender, metadata: metadata, body: content.body)
|
let intent = self.createMessageIntent(with: sender, metadata: metadata, body: content.body)
|
||||||
donateInteraction(for: intent)
|
self.donateInteraction(for: intent)
|
||||||
let updatedContent = try request.content.updating(from: intent)
|
let updatedContent = try? request.content.updating(from: intent)
|
||||||
contentHandler?(updatedContent)
|
self.contentHandler?(updatedContent ?? content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,9 +161,56 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
|
|
||||||
private func attachMedia(to content: UNMutableNotificationContent, withIdentifier identifier: String) {
|
private func attachMedia(to content: UNMutableNotificationContent, withIdentifier identifier: String) {
|
||||||
let attachmentUrl = getAttachmentUrl(for: identifier)
|
let attachmentUrl = getAttachmentUrl(for: identifier)
|
||||||
if let url = URL(string: attachmentUrl), let attachment = try? UNNotificationAttachment(identifier: identifier, url: url) {
|
|
||||||
content.attachments = [attachment]
|
guard let remoteUrl = URL(string: attachmentUrl) else {
|
||||||
|
print("Invalid URL for attachment: \(attachmentUrl)")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define a cache location based on the identifier
|
||||||
|
let tempDirectory = FileManager.default.temporaryDirectory
|
||||||
|
let cachedFileUrl = tempDirectory.appendingPathComponent(identifier)
|
||||||
|
|
||||||
|
if FileManager.default.fileExists(atPath: cachedFileUrl.path) {
|
||||||
|
// Use cached file
|
||||||
|
attachLocalMedia(to: content, from: cachedFileUrl, withIdentifier: identifier)
|
||||||
|
} else {
|
||||||
|
// Download and cache the file
|
||||||
|
let session = URLSession(configuration: .default)
|
||||||
|
session.downloadTask(with: remoteUrl) { [weak content] localUrl, response, error in
|
||||||
|
guard let content = content else { return }
|
||||||
|
|
||||||
|
if let error = error {
|
||||||
|
print("Failed to download media: \(error.localizedDescription)")
|
||||||
|
self.contentHandler?(content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let localUrl = localUrl else {
|
||||||
|
print("No local file URL after download")
|
||||||
|
self.contentHandler?(content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
// Move the downloaded file to the cache
|
||||||
|
try FileManager.default.moveItem(at: localUrl, to: cachedFileUrl)
|
||||||
|
self.attachLocalMedia(to: content, from: cachedFileUrl, withIdentifier: identifier)
|
||||||
|
} catch {
|
||||||
|
print("Failed to cache media file: \(error.localizedDescription)")
|
||||||
|
self.contentHandler?(content)
|
||||||
|
}
|
||||||
|
}.resume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func attachLocalMedia(to content: UNMutableNotificationContent, from localUrl: URL, withIdentifier identifier: String) {
|
||||||
|
if let attachment = try? UNNotificationAttachment(identifier: identifier, url: localUrl) {
|
||||||
|
content.attachments = [attachment]
|
||||||
|
} else {
|
||||||
|
print("Failed to create attachment from cached file: \(localUrl.path)")
|
||||||
|
}
|
||||||
|
self.contentHandler?(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createCallIntent(with sender: INPerson) -> INStartCallIntent {
|
private func createCallIntent(with sender: INPerson) -> INStartCallIntent {
|
||||||
|
Loading…
Reference in New Issue
Block a user