IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 通过iOS15 Communication Notifications实现自定义通知图标 -> 正文阅读

[移动开发]通过iOS15 Communication Notifications实现自定义通知图标

前言

昨天产品观察到飞书和钉钉在收到通知消息的时候,通知图标是发信人的头像,让我也实现一下,经过一天多的探索终于搓出来了一个可用的方案。效果图如下。
实现效果

原理

实现原理很简单,就是通过Notifiction Service Extension 在通知内容展示到通知栏里前进行一次处理,其中使用了SiriKit中的INPersonINmage
Notifiction Service Extension

实现

MainTarget的配置

1.配置info.plist文件

将以下配置添加到项目的info.plist文件中

NSUserActivityTypes (Array)
    - INStartCallIntent
    - INSendMessageIntent

![配置效果](https://img-blog.csdnimg.cn/26ebfbeb47044a1abcf6f50c0c54fffd.png

2.配置Capability

Signing&Capability中添加** Communication Notifications** 和 Push Notifications
添加
效果

3.配置推送

通知的配置就不再这里详细说明了,我是用的友盟推送。只要能正常推送消息到通知栏即可。

Notifiction Service Extension配置

1.添加Notifiction Service Extension到Targets

Xcode->New->Target->选择Notifiction Service Extension->Next->填写Product Name->选择开发语言(Swift Or Objective-C) ->Finish。我用的是OC开发,所以下面的代码都是OC版本。
add target

1.配置info.plist文件

Notifiction Service Extensioninfo.plist也需要加入下面的字段,千万注意位置,很重要!加错位置都不生效!

NSUserActivityTypes (Array)
    - INStartCallIntent
    - INSendMessageIntent

info

2.配置Capability

Notifiction Service ExtensionSigning&Capability中添加Push Notifications即可。

3.检查Notifiction Service Extension代码是否正常运行

创建Notifiction Service Extension后会生成NotificationService.hNotificationService.m(Swift版本会生成NotificationService.swift)文件。

//
//  NotificationService.m
//  NotificationService

#import "NotificationService.h"

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    // Modify the notification content here...
    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];
    self.contentHandler(self.bestAttemptContent);
}

- (void)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.
    self.contentHandler(self.bestAttemptContent);
}
@end

这时,测试发送通知,通知的标题后面带着 [modified]证明已经成功。或者在Debug模式下断点能进入到这个方法内就算配置成功了。
注意:要使用 Notifiction Service Extension 需要在高级设置的内容链接中添加键值对

// 这是必须的
mutable-content : 1 

// 注意格式层级是和 alert一个级别的
{
    "payload":{
        "aps":{
            "alert":{
                "body":"测试一下内容",
                "title":"测试一下标题",
                "subtitle":"测试一下副标题"
            },
            "sound":"default",
            "mutable-content":"1"
        }
    }
}

push

4.推送添加字段

我需要在通知的自定义参数内配置一个字段来传递头像的URLKey定为sender_image_urlValue是我随便在百度上找的一张表情
https://img2.baidu.com/it/u=1880320954,1568482765&fm=253&fmt=auto&app=138&f=JPEG?w=542&h=500
配置

// json结构大致如下
{
    "payload":{
        "aps":{
            "alert":{
                "body":"测试一下内容",
                "title":"测试一下标题",
                "subtitle":"测试一下副标题"
            },
            "sound":"default",
            "mutable-content":"1"
        },
        "sender_image_url":"https://img2.baidu.com/it/u=1880320954,1568482765&fm=253&fmt=auto&app=138&f=JPEG?w=542&h=500"
    }
}

5.处理并显示通知

首先,我们需要一个下载并保存图片到本地的方法。将图片下载并保存到本地后取出配置给通知。详细的说明见下面的示例代码吧!

#import "NotificationService.h"
#import <Intents/Intents.h>
@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService
// 下载并保存图片的方法
- (void)downloadINPersonWithURLString:(NSString *)urlStr completionHandle:(void(^)(NSData *data))completionHandler{
    __block NSData *data = nil;
    NSURL *imageURL = [NSURL URLWithString:urlStr];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    [[session downloadTaskWithURL:imageURL completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
        if (error != nil) {
            NSLog(@"%@", error.localizedDescription);
        } else {
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:@".png"]];
            [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];

            NSLog(@"localURL = %@", localURL);
            data = [[NSData alloc] initWithContentsOfURL:localURL];
        }
        completionHandler(data);

    }]resume];
}

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    // 这一行只是方便查看,记得在上线前去掉哦!
    self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];
    // 头像
    NSString *senderImageURLString = self.bestAttemptContent.userInfo[@"sender_image_url"];
    // 标题
    NSString *title = self.bestAttemptContent.title;
    // 副标题
    NSString *subtitle = self.bestAttemptContent.subtitle;
    // 内容
    NSString *body = self.bestAttemptContent.body;
    // 下载并获取图片
    [self loadINPersonWithURLString:senderImageURLString completionHandle:^(NSData *data) {
        if (data) {
        	// 将图片数据转换成INImage(需要 #import <Intents/Intents.h>)
            INImage *avatar = [INImage imageWithImageData:data];
            // 创建发信对象
            INPersonHandle *messageSenderPersonHandle = [[INPersonHandle alloc] initWithValue:@"" type:INPersonHandleTypeUnknown];
            NSPersonNameComponents *components = [[NSPersonNameComponents alloc] init];
            INPerson *messageSender = [[INPerson alloc] initWithPersonHandle:messageSenderPersonHandle
                                                              nameComponents:components
                                                                 displayName:title
                                                                       image:avatar
                                                           contactIdentifier:nil
                                                            customIdentifier:nil
                                                                        isMe:NO
                                                              suggestionType:INPersonSuggestionTypeNone];
            // 创建自己对象
            INPersonHandle *mePersonHandle = [[INPersonHandle alloc] initWithValue:@"" type:INPersonHandleTypeUnknown];
            INPerson *mePerson = [[INPerson alloc] initWithPersonHandle:mePersonHandle
                                                         nameComponents:nil
                                                            displayName:nil
                                                                  image:nil
                                                      contactIdentifier:nil
                                                       customIdentifier:nil
                                                                   isMe:YES
                                                         suggestionType:INPersonSuggestionTypeNone];
            
            
            // 创建intent
            INSpeakableString *speakableString = [[INSpeakableString alloc] initWithSpokenPhrase:subtitle];
            INSendMessageIntent *intent = [[INSendMessageIntent alloc] initWithRecipients:@[mePerson, messageSender]
                                                                      outgoingMessageType:INOutgoingMessageTypeOutgoingMessageText
                                                                                  content:body
                                                                       speakableGroupName:speakableString
                                                                   conversationIdentifier:nil
                                                                              serviceName:nil
                                                                                   sender:messageSender
                                                                              attachments:nil];
            
            [intent setImage:avatar forParameterNamed:@"speakableGroupName"];
            // 创建 interaction
            INInteraction *interaction = [[INInteraction alloc] initWithIntent:intent response:nil];
            interaction.direction = INInteractionDirectionIncoming;
            [interaction donateInteractionWithCompletion:nil];
            // 创建 处理后的 UNNotificationContent
            NSError *error = nil;
            UNNotificationContent *messageContent = [request.content contentByUpdatingWithProvider:intent error:&error];
            
            if (!error && messageContent) {
            	// 处理过的
                self.contentHandler(messageContent);
            } else {
            	// 处理失败的情况
                self.contentHandler(self.bestAttemptContent);
            }
        } else {
       		// 处理下载失败的情况
            self.contentHandler(self.bestAttemptContent);
        }
    }];
}

- (void)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.
    self.contentHandler(self.bestAttemptContent);
}
@end

至此,发送测试通知后即可得到前言中的效果图了。

容易出现问题的地方

1、info.plist文件配置错误,一定要看好键值对配置的位置。

2、Capability的配置,一定要记得MainTarget里是2个,Extension里是1个。

3、测试推送一定要记得加上 mutable-content : 1哦!

4、项目运行要注意是否存在Build的缓存,如果写了代码没反应记得清除一下缓存。

参考文献

Apple Developer Documentation - Implementing Communication Notifications.
Apple Developer Forums - iOS 15 Communication Notifications not working!.
Stackoverflow - iOS 15 Communication Notification picture not shown.
GitHub - Dexwell/LocalCommunicationNotification.swift
CSDN - 通信通知 Communication Notifications 的实现 (iOS 15+)
友盟+开发者文档 - iOS集成文档
51cto - 这份 iOS 15 推送通知设计指南,值得设计师们仔细阅读!
likecs - Ios 推送扩展Notification Service Extension 与简单的语音合成 (学习笔记)
CSDN - iOS10推送通知进阶(Notification Extension)

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 01:04:20  更:2022-09-30 01:05:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 0:01:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码