通信通知 Communication Notifications 的实现 (iOS 15+)
Posted iMazy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了通信通知 Communication Notifications 的实现 (iOS 15+)相关的知识,希望对你有一定的参考价值。
WWDC 2021 苹果在 ios 15 系统中对通知做了很多改变, 让通知更加个性化.
这里只有讨论通信通知 Communication Notifications
, 苹果自带的很多应用, 以及第三方App 飞书, 都使用了这个通知功能。
通信通知 Communication Notifications 简介
iOS 15系统后, Apple 添加了通信通知的功能。这些通知将包含发送它们的联系人的头像,并且可以与 SiriKit 集成,以便 Siri 可以智能地根据常用联系人提供通信操作的快捷方式和建议。
图例:
通信通 Communication Notifications 具体实现:
要使用通信通知,App 需要在 Xcode 中将通信通知功能添加到其应用程序,并在应用程序通知服务扩展中实现 UNNotificationContentProviding
协议。
1.首先将以下键值添加到主应用程序 Info.plist 文件中
NSUserActivityTypes (Array)
- INStartCallIntent
- INSendMessageIntent
具体位置如图所示:
2.在 Xcode
-> Capabilities
中添加 Communication Notifications
功能
如图所示:
3.添加 Notification Service Extension
扩展
大多数社交媒体通知都是从服务器发送到 Apple 的 APN 服务器,然后再发送到设备。
我们需要使用通知服务扩展, 该扩展用于处理通知,然后将它们显示在屏幕上。
首先,将扩展Notification Service Extension
添加到项目中
然后将以下键和值添加到 Notification Service Extension
扩展 Info.plist
中
4.在 Notification Service Extension
扩展下 NotificationService
文件中, 重写 didReceive
方法
Apple APN 服务器每次在通知出现在用户屏幕上之前,都会调用此方法
初始代码如下:
import UIKit
import Intents
import UserNotifications
class NotificationService: UNNotificationServiceExtension
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void)
if let bestAttemptContent = bestAttemptContent
// ...
我们可以通过使用 INPerson
或INSendMessageIntent
创建此信息将其添加到您的推送通知消息中
具体实现代码如下:
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
// Modify the notification content here...
// 获取通信消息
if let senderAccountID = bestAttemptContent.userInfo["sender_id"] as? String,
// 发送者名称
let senderName = bestAttemptContent.userInfo["sender_name"] as? String,
// 发送者图像url地址
let senderImageURLString = bestAttemptContent.userInfo["sender_image_url"] as? String,
// 发送者昵称
let senderDisplayName = bestAttemptContent.userInfo["sender_nickname"] as? String,
// 通信id
let chatSessionID = bestAttemptContent.userInfo["chat-session_id"] as? String
// Here you need to download the image data from the URL.
self.getMediaAttachment(for: senderImageURLString) image in
guard let groupIcon = image else
contentHandler(bestAttemptContent)
return
let avatar = INImage(imageData: groupIcon.pngData()!)
// 消息发送方
let messageSender = INPerson(
personHandle: INPersonHandle(value: nil, type: .unknown),
nameComponents: try? PersonNameComponents(senderName),
displayName: senderDisplayName,
image: avatar,
contactIdentifier: nil,
customIdentifier: senderAccountID,
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, messageSender],
outgoingMessageType: .outgoingMessageText,
content: bestAttemptContent.body,
speakableGroupName: INSpeakableString(spokenPhrase: senderDisplayName),
conversationIdentifier: chatSessionID,
serviceName: nil,
sender: messageSender,
attachments: nil)
intent.setImage(avatar, forParameterNamed: \\.speakableGroupName)
let interaction = INInteraction(intent: intent, response: nil)
interaction.direction = .incoming
interaction.donate(completion: nil)
do
let messageContent = try request.content.updating(from: intent)
contentHandler(messageContent)
catch
print(error.localizedDescription)
contentHandler(bestAttemptContent)
contentHandler(bestAttemptContent)
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)
使用到的工具扩展, 包含图片下载和本地保存
extension NotificationService
// 保存图片到本地 并返回 本地 url 地址
private func saveImageAttachment(image: UIImage, forIdentifier identifier: String) -> URL?
// 1 获取临时文件夹
let tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory())
// 2 拼接文件路径
let directoryPath = tempDirectory.appendingPathComponent(
ProcessInfo.processInfo.globallyUniqueString,
isDirectory: true)
do
// 3 如果文件夹不存在 创建文件夹
try FileManager.default.createDirectory(
at: directoryPath,
withIntermediateDirectories: true,
attributes: nil)
// 4 文件地址URL
let fileURL = directoryPath.appendingPathComponent(identifier)
// 5 文件二进制
guard let imageData = image.pngData() else
return nil
// 6 保存二进制文档到本地路径
try imageData.write(to: fileURL)
return fileURL
catch
return nil
// 通过本地 url 地址 获取图片资源
private func getMediaAttachment(for urlString: String, completion: @escaping (UIImage?) -> Void)
// 1
guard let url = URL(string: urlString) else
completion(nil)
return
// 2 通过远程图片URL下载图片
downloadImage(forURL: url) result in
// 3
guard let image = try? result.get() else
completion(nil)
return
// 4
completion(image)
// 通过远程图片url地址 下载图片文件
public enum DownloadError: Error
case emptyData
case invalidImage
private func downloadImage(forURL url: URL, completion: @escaping (Result<UIImage, Error>) -> Void)
let task = URLSession.shared.dataTask(with: url) data, response, error in
if let error = error
completion(.failure(error))
return
guard let data = data else
completion(.failure(DownloadError.emptyData))
return
guard let image = UIImage(data: data) else
completion(.failure(DownloadError.invalidImage))
return
completion(.success(image))
task.resume()
额外补充: 通知 Notifications 实现附件图片展示
在回调 bestAttemptContent 之前, 给它设置 attachments
属性即可
@available(iOS 10.0, *)
open class UNMutableNotificationContent : UNNotificationContent
/// ...
// Optional array of attachments.
open var attachments: [UNNotificationAttachment]
/// ...
核心代码如下:
// 创建图片附件
let imageAttachment = try? UNNotificationAttachment(
identifier: "image",
url: "图片本地路径, 和上面设置 Avatar 地址一样",
options: nil)
// 赋值给 bestAttemptContent
if let imageAttachment = imageAttachment
bestAttemptContent.attachments = [imageAttachment]
// 回调出去
contentHandler(bestAttemptContent)
以上是关于通信通知 Communication Notifications 的实现 (iOS 15+)的主要内容,如果未能解决你的问题,请参考以下文章
通信通知 Communication Notifications 的实现 (iOS 15+)
操作系统之三Linux下进程间通信-IPC(Inter-Process Communication)
网络通信中的单工(Simplex Communication)半双工(Half-duplex Communication)全双工(Full-duplex Communication)是什么意思?
网络通信中的单工(Simplex Communication)半双工(Half-duplex Communication)全双工(Full-duplex Communication)是什么意思?