mirror of
https://github.com/Finb/Bark.git
synced 2025-12-08 21:36:01 +00:00
266 lines
10 KiB
Swift
266 lines
10 KiB
Swift
//
|
||
// NotificationService.swift
|
||
// NotificationServiceExtension
|
||
//
|
||
// Created by huangfeng on 2018/12/17.
|
||
// Copyright © 2018 Fin. All rights reserved.
|
||
//
|
||
|
||
import Intents
|
||
import Kingfisher
|
||
import MobileCoreServices
|
||
import RealmSwift
|
||
import UIKit
|
||
import UserNotifications
|
||
class NotificationService: UNNotificationServiceExtension {
|
||
var contentHandler: ((UNNotificationContent) -> ())?
|
||
|
||
lazy var realm: Realm? = {
|
||
let groupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bark")
|
||
let fileUrl = groupUrl?.appendingPathComponent("bark.realm")
|
||
let config = Realm.Configuration(
|
||
fileURL: fileUrl,
|
||
schemaVersion: 13,
|
||
migrationBlock: { _, oldSchemaVersion in
|
||
// We haven’t migrated anything yet, so oldSchemaVersion == 0
|
||
if oldSchemaVersion < 1 {
|
||
// Nothing to do!
|
||
// Realm will automatically detect new properties and removed properties
|
||
// And will update the schema on disk automatically
|
||
}
|
||
}
|
||
)
|
||
|
||
// Tell Realm to use this new configuration object for the default Realm
|
||
Realm.Configuration.defaultConfiguration = config
|
||
return try? Realm()
|
||
}()
|
||
|
||
/// 自动保存推送
|
||
/// - Parameters:
|
||
/// - userInfo: 推送参数
|
||
/// - bestAttemptContentBody: 推送body,如果用户`没有指定要复制的值` ,默认复制 `推送正文`
|
||
fileprivate func autoCopy(_ userInfo: [AnyHashable: Any], defaultCopy: String) {
|
||
if userInfo["autocopy"] as? String == "1"
|
||
|| userInfo["automaticallycopy"] as? String == "1"
|
||
{
|
||
if let copy = userInfo["copy"] as? String {
|
||
UIPasteboard.general.string = copy
|
||
}
|
||
else {
|
||
UIPasteboard.general.string = defaultCopy
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 保存推送
|
||
/// - Parameter userInfo: 推送参数
|
||
/// 如果用户携带了 `isarchive` 参数,则以 `isarchive` 参数值为准
|
||
/// 否则,以用户`应用内设置`为准
|
||
fileprivate func archive(_ userInfo: [AnyHashable: Any]) {
|
||
var isArchive: Bool?
|
||
if let archive = userInfo["isarchive"] as? String {
|
||
isArchive = archive == "1" ? true : false
|
||
}
|
||
if isArchive == nil {
|
||
isArchive = ArchiveSettingManager.shared.isArchive
|
||
}
|
||
let alert = (userInfo["aps"] as? [String: Any])?["alert"] as? [String: Any]
|
||
let title = alert?["title"] as? String
|
||
let body = alert?["body"] as? String
|
||
|
||
let url = userInfo["url"] as? String
|
||
let group = userInfo["group"] as? String
|
||
|
||
if isArchive == true {
|
||
try? realm?.write {
|
||
let message = Message()
|
||
message.title = title
|
||
message.body = body
|
||
message.url = url
|
||
message.group = group
|
||
message.createDate = Date()
|
||
realm?.add(message)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 下载推送图片
|
||
/// - Parameters:
|
||
/// - userInfo: 推送参数
|
||
/// - bestAttemptContent: 推送content
|
||
/// - complection: 下载图片完毕后的回调函数
|
||
fileprivate func downloadImage(_ imageUrl: String, complection: @escaping (_ imageFileUrl: String?) -> ()) {
|
||
guard let groupUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.bark"),
|
||
let cache = try? ImageCache(name: "shared", cacheDirectoryURL: groupUrl),
|
||
let imageResource = URL(string: imageUrl)
|
||
else {
|
||
complection(nil)
|
||
return
|
||
}
|
||
|
||
func downloadFinished() {
|
||
let cacheFileUrl = cache.cachePath(forKey: imageResource.cacheKey)
|
||
complection(cacheFileUrl)
|
||
}
|
||
|
||
// 先查看图片缓存
|
||
if cache.diskStorage.isCached(forKey: imageResource.cacheKey) {
|
||
downloadFinished()
|
||
return
|
||
}
|
||
|
||
// 下载图片
|
||
Kingfisher.ImageDownloader.default.downloadImage(with: imageResource, options: nil) { result in
|
||
guard let result = try? result.get() else {
|
||
complection(nil)
|
||
return
|
||
}
|
||
// 缓存图片
|
||
cache.storeToDisk(result.originalData, forKey: imageResource.cacheKey, expiration: StorageExpiration.never) { _ in
|
||
downloadFinished()
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 设置推送图片
|
||
/// - Parameters:
|
||
/// - bestAttemptContent: 推送content
|
||
/// - complection: 下载图片完毕后的回调函数
|
||
fileprivate func setImage(content bestAttemptContent: UNMutableNotificationContent,
|
||
complection: @escaping (_ content: UNMutableNotificationContent) -> ())
|
||
{
|
||
let userInfo = bestAttemptContent.userInfo
|
||
guard let imageUrl = userInfo["image"] as? String else {
|
||
complection(bestAttemptContent)
|
||
return
|
||
}
|
||
|
||
func finished(_ imageFileUrl: String?) {
|
||
guard let imageFileUrl = imageFileUrl else {
|
||
complection(bestAttemptContent)
|
||
return
|
||
}
|
||
let copyDestUrl = URL(fileURLWithPath: imageFileUrl).appendingPathExtension(".tmp")
|
||
// 将图片缓存复制一份,推送使用完后会自动删除,但图片缓存需要留着以后在历史记录里查看
|
||
try? FileManager.default.copyItem(
|
||
at: URL(fileURLWithPath: imageFileUrl),
|
||
to: copyDestUrl
|
||
)
|
||
|
||
if let attachment = try? UNNotificationAttachment(
|
||
identifier: "image",
|
||
url: copyDestUrl,
|
||
options: [UNNotificationAttachmentOptionsTypeHintKey: kUTTypePNG]
|
||
) {
|
||
bestAttemptContent.attachments = [attachment]
|
||
}
|
||
complection(bestAttemptContent)
|
||
}
|
||
|
||
downloadImage(imageUrl, complection: finished)
|
||
}
|
||
|
||
/// 设置推送 icon
|
||
/// - Parameters:
|
||
/// - bestAttemptContent: 推送 content
|
||
/// - complection: 设置完成后的回调参数
|
||
fileprivate func setIcon(content bestAttemptContent: UNMutableNotificationContent,
|
||
complection: @escaping (_ content: UNMutableNotificationContent) -> ())
|
||
{
|
||
if #available(iOSApplicationExtension 15.0, *) {
|
||
let userInfo = bestAttemptContent.userInfo
|
||
guard let imageUrl = userInfo["icon"] as? String else {
|
||
complection(bestAttemptContent)
|
||
return
|
||
}
|
||
|
||
func finished(_ imageFileUrl: String?) {
|
||
guard let imageFileUrl = imageFileUrl else {
|
||
complection(bestAttemptContent)
|
||
return
|
||
}
|
||
var personNameComponents = PersonNameComponents()
|
||
personNameComponents.nickname = bestAttemptContent.title
|
||
|
||
let avatar = INImage(imageData: NSData(contentsOfFile: imageFileUrl)! as Data)
|
||
let senderPerson = INPerson(
|
||
personHandle: INPersonHandle(value: "", type: .unknown),
|
||
nameComponents: personNameComponents,
|
||
displayName: personNameComponents.nickname,
|
||
image: avatar,
|
||
contactIdentifier: nil,
|
||
customIdentifier: nil,
|
||
isMe: false,
|
||
suggestionType: .none
|
||
)
|
||
let mePerson = INPerson(
|
||
personHandle: INPersonHandle(value: "", type: .unknown),
|
||
nameComponents: nil,
|
||
displayName: nil,
|
||
image: nil,
|
||
contactIdentifier: nil,
|
||
customIdentifier: nil,
|
||
isMe: true,
|
||
suggestionType: .none
|
||
)
|
||
|
||
let intent = INSendMessageIntent(
|
||
recipients: [mePerson],
|
||
outgoingMessageType: .outgoingMessageText,
|
||
content: bestAttemptContent.body,
|
||
speakableGroupName: INSpeakableString(spokenPhrase: personNameComponents.nickname ?? ""),
|
||
conversationIdentifier: bestAttemptContent.threadIdentifier,
|
||
serviceName: nil,
|
||
sender: senderPerson,
|
||
attachments: nil
|
||
)
|
||
|
||
intent.setImage(avatar, forParameterNamed: \.sender)
|
||
|
||
let interaction = INInteraction(intent: intent, response: nil)
|
||
interaction.direction = .incoming
|
||
|
||
interaction.donate(completion: nil)
|
||
|
||
do {
|
||
let content = try bestAttemptContent.updating(from: intent) as! UNMutableNotificationContent
|
||
complection(content)
|
||
}
|
||
catch {
|
||
// Handle error
|
||
}
|
||
|
||
complection(bestAttemptContent)
|
||
}
|
||
|
||
downloadImage(imageUrl, complection: finished)
|
||
}
|
||
else {
|
||
complection(bestAttemptContent)
|
||
}
|
||
}
|
||
|
||
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> ()) {
|
||
self.contentHandler = contentHandler
|
||
guard let bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) else {
|
||
contentHandler(request.content)
|
||
return
|
||
}
|
||
|
||
let userInfo = bestAttemptContent.userInfo
|
||
|
||
// 自动复制
|
||
autoCopy(userInfo, defaultCopy: bestAttemptContent.body)
|
||
// 保存推送
|
||
archive(userInfo)
|
||
// 设置推送图标
|
||
setIcon(content: bestAttemptContent) { result in
|
||
// 设置推送图片
|
||
self.setImage(content: result) { result in
|
||
contentHandler(result)
|
||
}
|
||
}
|
||
}
|
||
}
|