关于iOS本地发送带联系人名称与头像的通讯类通知的可行性及问题咨询
iOS本地发送带联系人名称与头像的通讯类通知的可行性及问题解决
我完全懂你现在的困扰——想把本地通知做成通讯消息的样式(显示发件人头像、名称),试了代码却没效果,还不确定是不是只有Push通知才能实现这种样式对吧?先给你吃个定心丸:本地通知完全可以实现带联系人信息的通讯样式,不是只有Push才能做,你的方向没问题,问题出在代码细节和配置上。
下面我拆解一下你的问题,再给你修正后的代码和验证步骤:
一、核心问题:你的代码里的几个关键疏漏
头像参数错误
你在创建INPerson时把image传成了nil,而且就算传UIImage也不对——INPerson的image参数需要是INImage类型,不是直接传UIImage。得把图片转成Data再初始化INImage,还要给图片加唯一标识让系统缓存,避免重复加载。缺少错误排查逻辑
你在捐赠INInteraction和更新通知内容时都没处理错误,根本不知道是哪一步失败了(比如intent更新失败、interaction捐赠失败),这很难定位问题。Intent构建的细节缺失
虽然你创建了INSendMessageIntent,但没确保主App发送的通知请求和intent的配置对应,比如通知的threadIdentifier要和intent的conversationIdentifier关联,还有Extension的配置是否正确。
二、修正后的完整代码示例
下面是调整后的didReceive方法,补上了所有关键细节:
func didReceive( request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { // 1. 正确构建发件人信息(包含头像) let handle = INPersonHandle(value: "unique-user-id", type: .unknown) // 处理头像:UIImage转INImage var senderImage: INImage? if let avatar = UIImage(named: "user-avatar"), let avatarData = avatar.pngData() { senderImage = INImage(data: avatarData) senderImage?.identifier = "unique-avatar-id" // 唯一标识,系统会缓存图片 } let sender = INPerson( personHandle: handle, nameComponents: nil, displayName: "张三", image: senderImage, contactIdentifier: nil, customIdentifier: "unique-user-id" ) // 2. 构建消息Intent let intent = INSendMessageIntent( recipients: nil, outgoingMessageType: .outgoingMessageText, content: "这是一条测试消息内容", speakableGroupName: nil, conversationIdentifier: "unique-user-id-conv", serviceName: nil, sender: sender, attachments: nil ) // 3. 捐赠交互(带错误处理) let interaction = INInteraction(intent: intent, response: nil) interaction.direction = .incoming // 标记为收到的消息 interaction.donate { error in if let error = error { print("Interaction捐赠失败:\(error.localizedDescription)") } else { print("Interaction捐赠成功") } } // 4. 更新通知内容(带错误处理) let content = request.content do { let updatedContent = try content.updating(from: intent) guard let mutableContent = updatedContent.mutableCopy() as? UNMutableNotificationContent else { contentHandler(content) return } mutableContent.threadIdentifier = "unique-user-id-conv" // 和conversationIdentifier保持一致 mutableContent.userInfo = request.content.userInfo contentHandler(mutableContent) } catch { print("更新通知内容失败:\(error.localizedDescription)") contentHandler(content) // 失败时返回原内容兜底 } }
三、必须检查的配置项
除了代码,这几个配置没做好也会导致样式不生效:
- 主App Capabilities:打开
Local Notifications和Intents,并在Intents的权限列表里勾选INSendMessageIntent。 - Notification Service Extension配置:
- 确保Extension的
Info.plist里,NSExtensionPointIdentifier是com.apple.usernotifications.service。 - 在
NSExtensionAttributes里添加UNNotificationExtensionCategory(可以设为message-category,和主App发送通知时的categoryIdentifier对应)。
- 确保Extension的
- 主App发送通知的代码:发送本地通知时,要用
UNMutableNotificationContent,并且设置threadIdentifier和Extension里的一致,比如:let content = UNMutableNotificationContent() content.body = "测试消息内容" content.threadIdentifier = "unique-user-id-conv" content.categoryIdentifier = "message-category" // 和Extension配置对应 let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request)
四、测试注意事项
- 测试时要把App退到后台或者杀掉进程,前台收到的通知会走
willPresent代理,需要手动调用completionHandler(.alert)才能显示通知。 - 头像图片尽量用60x60左右的尺寸,避免系统拉伸变形。
- 如果还是没生效,看Xcode控制台的错误日志,比如捐赠interaction失败的原因、更新内容失败的原因,这些日志是定位问题的关键。
总结一下:本地通知完全支持通讯消息样式,你之前的思路是对的,只要把头像转换、错误处理、配置项这几个细节补全,就能实现带联系人名称和头像的消息通知啦!




