You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

关于iOS本地发送带联系人名称与头像的通讯类通知的可行性及问题咨询

iOS本地发送带联系人名称与头像的通讯类通知的可行性及问题解决

我完全懂你现在的困扰——想把本地通知做成通讯消息的样式(显示发件人头像、名称),试了代码却没效果,还不确定是不是只有Push通知才能实现这种样式对吧?先给你吃个定心丸:本地通知完全可以实现带联系人信息的通讯样式,不是只有Push才能做,你的方向没问题,问题出在代码细节和配置上。

下面我拆解一下你的问题,再给你修正后的代码和验证步骤:

一、核心问题:你的代码里的几个关键疏漏

  1. 头像参数错误
    你在创建INPerson时把image传成了nil,而且就算传UIImage也不对——INPersonimage参数需要是INImage类型,不是直接传UIImage。得把图片转成Data再初始化INImage,还要给图片加唯一标识让系统缓存,避免重复加载。

  2. 缺少错误排查逻辑
    你在捐赠INInteraction和更新通知内容时都没处理错误,根本不知道是哪一步失败了(比如intent更新失败、interaction捐赠失败),这很难定位问题。

  3. 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 NotificationsIntents,并在Intents的权限列表里勾选INSendMessageIntent
  • Notification Service Extension配置
    1. 确保Extension的Info.plist里,NSExtensionPointIdentifiercom.apple.usernotifications.service
    2. NSExtensionAttributes里添加UNNotificationExtensionCategory(可以设为message-category,和主App发送通知时的categoryIdentifier对应)。
  • 主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失败的原因、更新内容失败的原因,这些日志是定位问题的关键。

总结一下:本地通知完全支持通讯消息样式,你之前的思路是对的,只要把头像转换、错误处理、配置项这几个细节补全,就能实现带联系人名称和头像的消息通知啦!

火山引擎 最新活动