1、环信管理后台有的用户显示证书名称有的不显示证书名称?
1)显示证书名称:用户是不是绑定证书要看是不是在app端登录过,只有登录环信服务器登录成功之后才会绑定证书,也才会显示证书名称,用户离线时接收消息才有推送通知。
2)不显示证书名称:如果用户没在app端登录过,就不会显示证书名称,还有在app端登录之后,调用环信SDK方法退出登录(如果方法内传的是YES,解绑devicetoken和证书),这样也不会显示证书名称。
2、iOS没有通知栏提示?
通知栏分本地通知和apns推送通知
1).如果指的是app进入后台没有超过150秒左右,接收消息没有通知栏提示的话,这个情况要配置本地通知,先先注册本地通知(系统方法),然后在看下文档介绍: 如何实现本地通知
2).如果不是本地通知,app退到后台超过150秒左右,接收消息没有通知栏提示的话,这个情况属于apns推送。
如果没有配置apns推送,那么先按照文档配置: APNS推送配置
如果配置过了apns推送,那么在初始化SDK方法之后调用下这个方法试下
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[EMClient sharedClient] applicationDidEnterBackground:application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[EMClient sharedClient] applicationWillEnterForeground:application];
}
3、iOS本地通知栏如何展示?
本地通知栏的显示属于本地自己设置的,这个可以参考下环信demo的做法,判断apns推送通知栏是不是显示详情的,是的话,那就将本地通知栏也显示成‘昵称:消息内容’,如果是默认的就显示‘您有一条新消息’。
在EMRemindManager.m类
- (void)_localNotification:(EMMessage *)message needInfo:(BOOL)isNeed 方法中
环信Demo: Demo下载链接
4、APNS推送收不到怎么办?
如果是iOS13及以上的系统,那么需要将sdk更新到3.6.4或以上版本。如果更新后还不行那么退出登录、重启app、再登录试下。
如果不是iOS的原因,可根据以下链接中的内容进行排查: 推送排查文档
如果以上都确认无误,请将appkey、devicetoken、bundle id、证书的.p12文件(附件中上传给我,若无法上传,则把后缀改成.txt试下)、证书名称、证书密码、收不到推送的环信id、测试的环境(development or production)、推送消息的内容、发送的时间以及消息id(请勿遗漏,以免工单反复询问耽误您的时间) 这些信息提交工单,环信技术支持团队将会对您反馈的问题进行排查。 工单入口:登录IM环信管理后台–应用列表–应用基本信息–右下角技术支持按钮
5、环信推送的角标怎么和极光推送的角标合并?
可以通过 NotificationServiceExtension 功能实现。(此方案需要极光那边也支持mutable-content)
在发消息时,加“mutable-content”:1 字段,参考iOS端文档:http://docs-im.easemob.com/im/ios/apns/content#开启_apns_通知扩展 那么环信服务器给苹果apns推送服务器发消息时,也会把这个字段传给苹果那边,苹果那边识别到有“mutable-content”:1字段,会假唤醒app,配置NotificationServiceExtension之后,你可取到环信和极光的推送角标数进行加法,然后自己再修改推送通知栏显示的样式和角标数,具体可以看苹果NotificationServiceExtension的文档介绍。
6、离线推送角标数跳跃
问:
杀死app后测试离线推送,角标计数有时候会不准。
例如:我们连续发了4条消息,但是APP的角标数有时候会从4闪一下变成2。;还有时候比如现在发了8条消息。然后APP的角标是4 但是当我们再发送一条消息,角标又变成9了。
答:
您好,发送第一条消息,这条消息携带的角标数是1,发送第二条消息,这条消息携带的角标数是2,发送第n条消息,这条消息携带的角标数是n,有可能是某条消息的离线推送有些延迟,导致角标数跳跃。
7、iOS推送通知栏如何显示消息详情?
参考文档设置: 推送显示详情
8、如果没有登录环信,可以收到推送吗?
1.注册完没有登录过的用户。——— 不会收到推送,因为没有绑定devicetoken,只有登录后才会绑定。
2.登录后,退出登录。 ——— 要看调用环信SDK的退出登录方法传的是NO还YES,传YES是解绑devicetoken,不会收到推送。 传NO是不解绑devicetoken,会收到推送,但不建议传NO,如果多个账号在同一台设备登录过的情况,会出现多个用户绑定同一个devicetoken,这样多个用户的离线消息都会推送到同一台设备上。
3.登录后。直接杀掉app或者app在后台,锁屏超过3分钟。——— 这种情况用户的长连接会环信服务器断开,但devicetoken不会解绑,有离线消息的话就会有推送。
1、从环信服务器上下载消息中的附件没有后缀怎么办?
附件类型的消息(图片,语音,视频,文件消息等)发送到环信服务器后是不带后缀的,这个可以在构建消息的时候,给附件消息命名时加上后缀名
比如图片消息的话,可以给displayName设置image.png 构建图片消息
这样接收消息方在接收到消息时,可以从消息的body中通过displayName拿到名称就可以知道附件的格式,地理位置消息的话,可以在发送消息的时候,给消息的ext里面加个参加把附件名称和格式带上,这样接收消息方通过解析消息的ext也可以知道附件消息的类型。
2、环信id是什么?
环信id就是指在环信appkey下注册的账号并且是唯一的,用于客户端环信SDK登录以及收发消息使用的。
在注册环信 id 时,建议不要使用有序的 id 进行注册,防止其他人知道注册 id 的顺序,恶意发送大量的垃圾消息。
一般是服务器端给自己用户注册账号的同时,在调用环信的rest接口给用户在注册一个环信id与自己的用户绑定,并返回给客户端,客户端拿到自己服务器用户的账号密码登录后,在拿环信id密码在登录环信服务器。 用户管理
社区版的appkey只能注册100个环信id,企业版没有注册的限制。
3、开启消息漫游之后 为什么不可以进行删除消息的操作了?
删除聊天记录是删除本地数据库的,不是环信服务器的,开通漫游消息后,如果调用的是从环信服务器获取历史消息的api(asyncFetchHistoryMessagesFromServer),就会出现这种情况。 您可以自己记录下删除了哪条消息,然后在加载历史消息的时候遍历过滤不展示;或者使用从本地数据库获取历史消息的api
4、获取会话列表为空情况有以下几种:
1)可能是本地数据库中没有会话或者将会话都删除掉了
2)没有登录环信成功,SDK数据库没有打开,取不到会话列表
3)可能是老版本SDK的问题,可以尝试先升级到最新版本的SDK,在测试下: SDK下载
4)换新设备登录,因为会话列表是存设备本地数据库的,如果用户换新设备登录,就获取不到之前设备上的会话列表
5)卸载app,因为会话列表是存设备本地数据库的,如果卸载app本地数据库文件会被清理掉,导致会话列表获取不到
5、消息漫游功能,比如账号在A设备上登录接收了3条没有已读,未读消息数是3,然后在B设备上登录这个账号,也想显示这个会话并把会话的这3条未读消息数也获取到,如何处理?
先调用SDK方法拉取漫游的消息,然后在获取到这个会话,在取会话的未读消息数。不能创建会话后在进入聊天页面,如果用的环信的聊天页面UI,进入聊天页面时就会把会话中的所有未读消息标记已读,这样就获取不到会话的未读消息数了。 按照下面的方法登录成功后测试,u2换成对方的环信id。
[EMClient.sharedClient.chatManager asyncFetchHistoryMessagesFromServer:@"u2" conversationType:EMConversationTypeChat startMessageId:nil pageSize:50 completion:^(EMCursorResult *aResult, EMError *aError) {
if (!aError) {
} else {
}
}];
EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"u2" type:EMConversationTypeChat createIfNotExist:YES];
NSLog(@"未读消息消息数---%d", [conversation unreadMessagesCount]);
(因为消息接收都是存设备本地数据库的,这个获取会话的方法是从本地数据库取的,并不是到环信服务器取,所以在换设备登录的时候,正常是不会把另外一台的设备上的会话和消息主动同步过来。 因为开了消息漫游,可以同步消息,但是并不能将其他设备上的会话给同步过来,得需要主动调用SDK消息漫游方法到服务器上拉取消息,SDK在将消息存到本地数据库,所以得先拉取消息,本地数据库中才会有会话和消息,才能通过会话取到未读消息数。)
6、用户个人信息如何存储获取?
环信这边是不涉及用户个人信息的,所以获取好友列表的方法返回的都是环信id,用户的个人信息可以在自己服务器与环信id绑定存储维护,知道环信id就可以到自己服务器下载这个环信id对应的用户信息(注意在注册环信id时传的昵称并不是个人信息的昵称,那个是在设置显示推送通知栏详情时,显示的推送昵称)。
7、如何自己实现漫游消息功能?
根据自己服务器端的返回给app端的消息内容,在app端创建会话,插入消息,以难度大的图片消息为例
创建会话: 创建会话
构造图片消息: 构建图片消息
插入消息: 插入消息
插入图片消息示例代码:
// 创建会话,以单聊会话为例
// fdh333就是对方的环信id,EMConversationTypeChat单聊会话类型
EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"fdh3333" type:EMConversationTypeChat createIfNotExist:YES];
// 取到登录方的环信id
NSString *from = [[EMClient sharedClient] currentUsername];
// 创建图片消息body,Data要传nil,因为都是从服务器上取的图片url,没有本地图片转data传,所以传nil
EMImageMessageBody *newBody = [[EMImageMessageBody alloc] initWithData:nil displayName:@"image"];
// 缩略图在环信服务器上的url,替换成自己的图片消息中的url
newBody.thumbnailRemotePath = @"https://a1.easemob.com/easemob-demo/chatdemoui/chatfiles/50742590-96ef-11e9-9b3e-9b44203ccce8";
// 缩略图的密钥,替换成自己的图片消息中的SecretKey
newBody.thumbnailSecretKey = @"UHQlmpbvEemzBC-5fkLNP8hQJlbKYOQNxcesOSeP-cMg9KAH";
// 缩略图的本地路径,沙盒路径下,fdh8888换成自己登录的环信id,fdh3333换成对方的环信id,也是会话id,thumb_50742590-96ef-11e9-9b3e-9b44203ccce8中的"50742590-96ef-11e9-9b3e-9b44203ccce8"就是图片的uuid
newBody.thumbnailLocalPath = @"/Users/easemob-dn0164/Library/Developer/CoreSimulator/Devices/8B048B3E-61DB-4A28-BA20-98564F4ABAB2/data/Containers/Data/Application/4E796EDA-E478-4834-9927-BFA3AFDCAE5A/Library/Application Support/HyphenateSDK/appdata/fdh8888/fdh3333/thumb_50742590-96ef-11e9-9b3e-9b44203ccce8";
// 缩略图名称
newBody.thumbnailDisplayName = @"thumbnail.png";
// 缩略图下载状态
newBody.thumbnailDownloadStatus = 0;
// 缩略图大小
newBody.thumbnailSize = CGSizeMake(0, 0);
// remotePath,secretKey与thumbnailRemotePath,thumbnailSecretKey的参数相同
newBody.remotePath = @"https://a1.easemob.com/easemob-demo/chatdemoui/chatfiles/50742590-96ef-11e9-9b3e-9b44203ccce8";
newBody.secretKey = @"UHQlmpbvEemzBC-5fkLNP8hQJlbKYOQNxcesOSeP-cMg9KAH";
// 大图的本地路径与缩略图本地路径的唯一差别就是图片的uuid前面不加thumb_前缀
newBody.localPath = @"/Users/easemob-dn0164/Library/Developer/CoreSimulator/Devices/8B048B3E-61DB-4A28-BA20-98564F4ABAB2/data/Containers/Data/Application/4E796EDA-E478-4834-9927-BFA3AFDCAE5A/Library/Application Support/HyphenateSDK/appdata/fdh8888/fdh3333/50742590-96ef-11e9-9b3e-9b44203ccce8";
// 大图的尺寸,替换成自己的图片消息中的size
newBody.size = CGSizeMake(1800, 1202);
// 大图的下载状态,
newBody.downloadStatus = 3;
// 大图的大小,替换成自己的图片消息中的fileLength
newBody.fileLength = 539787;
// 创建消息
EMMessage *newMsg = [[EMMessage alloc] initWithConversationID:self.conversationModel.emModel.conversationId from:from to:self.conversationModel.emModel.conversationId body:newBody ext:nil];
// 消息类型
newMsg.chatType = EMChatTypeChat;
// 控制消息的显示方向
newMsg.direction = 1;
EMError *error;
// 向会话中插入消息
[conversation insertMessage:newMsg error:&error];
NSLog(@"insertMessageError---%@", error.errorDescription);
8、iOS如何发送文件消息?
环信demo中没有发送文件消息的功能,不过SDK是提供了构建文件消息方法,把文件的本地路径传进去,然后调用SDK的发送消息方法发送文件,参考文档: 构建文件消息
聊天页面的工具栏是可以扩展的,UI代码都是开源的,需要自己看下代码进行修改,在EMChatBar.m类中
9、iOS如何将消息的扩展内容自定义cell?
向会话中插入一条文本消息或者发送一条消息,将需要展示到cell上的内容加到消息的ext中。 可以给插入消息的ext加个字段标识,然后根据这个标识显示自己自定义的cell展示,大致就是这个实现思路。
以发送消息为例的参考demo:
链接:https://pan.baidu.com/s/1YXqdbvp8tKtLyHXhl1ULXA 密码:vuys
10、iOS本地通知栏的展示
本地通知栏的显示属于本地自己设置的,这个可以参考下环信demo的做法,在接收消息的回调中,判断apns推送通知栏是不是显示详情的,是的话,那就将本地通知栏也显示成‘昵称:消息内容’,如果是默认的就显示‘您有一条新消息’。
EMRemindManager.m
- (void)remindMessage:(EMMessage *)aMessage方法中
11、群组管理员将用户禁言后,用户仍然可以在群内发消息?
需要确认下在调用禁言方法时,传的禁言时长是多久,单位是毫秒,如果传的时间较短,那用户禁言效果会很快消失,将时间戳参数传大一些在进行禁言测试。
12、iOS端关于环信账号离线常见的几种情况:
1.主动调用环信SDK退出登录方法 (不会触发环信SDK的重连机制)
2.app退到后台超过150秒左右
前提是调用将app进入后台的状态传给环信SDK:
- void)applicationDidEnterBackground:(UIApplication *)application {
[[EMClient sharedClient] applicationDidEnterBackground:application];
}
app返回前台时,SDK自动重连,需要将app返回前台的状态传给环信SDK
- (void)applicationWillEnterForeground:(UIApplication *)application {
[[EMClient sharedClient] applicationWillEnterForeground:application];
}
3.主动kill掉app,或者app在后台挂起被系统kill掉
4.断网或者网络不好的情况下,长连接断开,当网络恢复时SDK会自动重连
5.在线情况下,账号在其他设备登录被踢下线
2、4情况用这个回调监听: 重连
5情况用这个回调监听: 被动退出登录
1、3没监听
13、单点登录:A手机登录后杀掉app,然后B手机登录(A杀死后是离线状态,不存在被踢),然后A手机再打开应用,此时会自动登录上(如果开启了自动登录功能的话),所以B手机会被踢掉。
14、background task有问题,输出: Can't end BackgroundTask: no background task exists with identifier 1 (0x1), or it may have already been ended. Break in UIApplicationEndBackgroundTaskError() to debug.
这个是ios13的bug,不是环信SDK的问题 :https://developer.apple.com/forums/thread/121990
0、EaseCallKit报错信息:“Reason: image not found” 解决方案: 由于EaseCallKit是动态库,在podfile中必须加入use_frameworks! 参考文档:导入UI库
1、报错信息:“Reason: image not found”
解决方案: 在TARGETS → General → Frameworks, Libraries, and Embedded Content中添加Hyphenate.framework依赖库,且依赖库的Status必须是Embed & Sign
2、报错信息:
解决方案: 删掉重新添加试一下。添加时先粘贴到项目的finder文件内,再从finder往项目中拖。
3、报错信息:
解决方案: 把plugin文件夹删掉(删掉不会影响到功能)。
4、xcode12.3运行报错,报错信息:
解决方案: 打开Xcode,左上方点击File—>Workspace Settings—>将Shard Workspace Settings:中的New Build System(Default)修改成Legacy Build System,点击done,再试下。
5、报错信息:i386
解决方案:
Demo下载地址:环信音视频云下载
1.视频会议demo下载下来 podfile 里面的 Hyphenate 是注释的,需要先打开
2.视频会议demo只支持3.6.6以上版本的sdk。 您在 pod install 前先 pod search Hyphenate看下能不能搜到3.6.6版本,如果搜不到,可以执行下 pod repo update 更新本地cocoapods的spec资源配置信息后再试下,如果还搜不到,那么需要您自己再看下是什么原因。
1、pod install 执行完成后运行会报错,报错信息:
解决方案:
打开xcode,最上方点击File—>Workspace Settings—>将Shard Workspace Settings:中的New Build System(Default)修改成Legacy Build System,点击done,最后运行项目。
2、报错信息:
解决方案:
3、xcode12模拟器运行报错,报错信息:
解决方案:
Build Settings里最下面的VALID_ARCHS,添加上x86_64。
iOS登录报303是什么原因?
报303一般是用户客户端网络不好没有连接上环信服务器,可以切换网络再登录试试(4G网络可以试试),如果开了VPN的话,将VPN关掉。 如果还是登录不了的话,提供下登录不了的环信id和密码,提交工单联系环信技术。
1、个人消息免打扰
自己服务器端维护下好友免打扰列表,发消息前判断下对方有没有将自己设置为免打扰,如果设置了,就用静默消息,文档:发送静默消息,这样在离线时,就不会有这个人发来的消息的离线推送。 在线和后台活跃时,在收到消息的代理方法中( - (void)messagesDidReceive:(NSArray *)aMessages)判断消息的from在不在自己的免打扰列表内,如果在,就不播放声音。
2、接收群组消息但不提示(消息免打扰)
(1)先屏蔽这个群组的离线推送,参考文档:设置指定群组是否接收_apns
(2)登录之后先调用“从服务器获取推送属性”方法:
//调用这个方法后sdk会自动更新本地的“屏蔽了推送的群组ID列表”
[[EMClient sharedClient] getPushNotificationOptionsFromServerWithCompletion:^(EMPushOptions *aOptions, EMError *aError) {
if (!aError) {
NSLog(@"从服务器获取推送属性成功");
} else {
NSLog(@"从服务器获取推送属性失败的原因 --- %@", aError.errorDescription);
}
}];
(3)在收到消息的代理方法中( - (void)messagesDidReceive:(NSArray *)aMessages),判断如果app处于后台活跃状态(正常是需要发送本地通知,提醒用户有消息的),就调用下面这个方法取到屏蔽了离线推送的群组ID列表,判断下消息是否来自于被屏蔽了离线推送的群组,是的话就不发本地通知。
NSArray *igGroupIds = [[EMClient sharedClient].groupManager getGroupsWithoutPushNotification:nil];
3、群主撤回群成员的消息
群主进行撤回操作时,给所有群成员发送一条cmd消息,cmd添加扩展,把消息id携带过去,群成员收到这条cmd消息时,解析出消息id,然后从本地删除这条消息,然后刷新UI。
注:只能删除本地数据库的,无法删除环信服务器端的。如果使用漫游功能从环信服务器端获取历史消息,还是能把撤回的那条消息拉取下来,这时候还要过滤下再删掉。
构造透传消息文档:构造透传消息
构造扩展消息文档:构造扩展消息
删除消息:
4、消息提示音(消息提醒、震动、响铃)
在线消息:可以全局(在根控制器或者AppDelegate里)监听收到消息的代理方法(messagesDidReceive),在这个方法里播放响铃和震动。
离线消息:可以自定义推送提示音,参考文档:自定义推送提示音,但这个只能是播放本地音频文件,无法震动。想要震动,可以在发消息时,加“mutable-content”:1 字段,参考文档:开启_apns_通知扩展,那么环信服务器给苹果apns推送服务器发消息时,也会把这个字段传给苹果那边,苹果那边识别到有“mutable-content”:1字段,会假唤醒app,配置NotificationServiceExtension之后,您可以播放响铃和震动,具体可以看苹果NotificationServiceExtension的文档介绍。
5、iOS在线与离线未读消息数累加
在线未读消息数与离线消息数累加的功能,可以按照下面的方案实现
在发消息时,加“mutable-content”:1 扩展字段,参考iOS端文档:开启 APNs 通知扩展, 那么环信服务器给苹果apns推送服务器发消息时,也会把这个字段传给苹果那边,苹果那边识别到有“mutable-content”:1字段,会假唤醒app,配置NotificationServiceExtension之后,您可取到环信的推送角标数,然后自己再修改推送通知栏显示的样式和角标数,具体可以看苹果NotificationServiceExtension的文档介绍。
(1)先新建一个NotificationServiceExtension的Targets
(2)主工程打开Remote notifications权限
(3)两个Targets都打开App Groups,并添加共享沙盒
(4)主工程将当前本地未读消息数动态存到共享沙盒
(5)在NotificationService中取出共享沙盒的角标数,与收到的APNs角标数累加重置。
6、不是好友不让发消息
环信目前的机制是只要知道对方的环信id就可以给对方发消息,环信有好友的机制,对应的功能可以看下文档介绍: 好友功能 如果使用环信的好友功能,比如A与B不是好友,那么A进入与B的聊天页面时,可以获取A的好友列表看是否存在B,如果不存在可以在UI上做限制,不让A发送消息。 如果使用的是自己的好友体系,那么就换成自己的业务进行判断是不是好友,从而在UI上做是否可以发送消息的限制。
7、用环信的消息做给自己的用户全量推送功能
如果想要环信的消息来做给自己用户全量推送功能,还不想让客户端用户看到这条会话,那么可以用环信服务器端rest接口批量发送消息实现,可以使用一个或者几个固定的环信id作为from批量给自己的用户发送消息(推送消息),然后客户端在取会话列表的时候,发现会话id如果是服务器端用于批量发消息的环信id,那么就将这个会话删除掉即可。
文档: rest发送消息接口 iOS端删除会话
8、iOS EaseUI如何自定义表情
参考链接中的demo实现自定义表情即可 自定义表情
9、iOS EaseUI聊天页面怎么显示群组的昵称头像
因为环信这边是不涉及用户个人信息的,所以通过环信id是获取不到用户昵称头像的,用户的个人信息可以在自己服务器与环信id绑定存储维护,知道环信id就可以到自己服务器下载这个环信id对应的用户信息(注意在注册环信id时传的昵称并不是个人信息的昵称,那个是在设置显示推送通知栏详情时,显示的推送昵称)。
环信UI上的处理,如果使用的是EaseUI的话,我建议是在EaseBaseMessageCell.m类, - (void)setModel:(id<IMessageModel>)model方法中,通过 self.model.message.chatType 判断出来是群组类型消息的话,在取到消息的from就是在群内发送消息的环信id,再根据环信id到自己服务器上取到用户的昵称,头像,在赋值给 _nameLabel.text和 self.avatarView (注意单聊和群聊显示昵称,头像的逻辑要区分开)
10、iOS 漫游消息能否拉取会话列表?
这个漫游只能是拉取聊天记录,不能拉取聊天会话列表。
比如在A设备上,登录环信id:user1,然后有3个会话,那user1在设备B上登录时拉取不到A设备上的3个会话,只能是先通过漫游消息的方法,传A设备上的3个会话id,本地创建会话后,再从环信服务器上拉取下拉消息,这样本地就生成会话列表,也能看到会话中的消息。
如果你们有好友体系的话,账号在多个设备,或者多端登录时,可以先遍历自己的好友列表,然后分别调用一次漫游消息的方法,如果跟某个好友收发过消息,那么就会拉取下拉漫游消息,本地也就自动生成会话了,间接的实现了拉取会话列表的功能。
// 创建会话
EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"username" type:EMConversationTypeChat createIfNotExist:YES];
// 漫游消息,漫游下来的消息会自动添加到会话中
[EMClient.sharedClient.chatManager asyncFetchHistoryMessagesFromServer:@"username" conversationType:EMConversationTypeChat startMessageId:nil pageSize:5 completion:^(EMCursorResult *aResult, EMError *aError) {
if (!aError) {
} else {
}
}];
11、iOS新版UI如何自定义cell
下载这个demo参考,新版UI的自定义cell实现,工程中搜索 “自定义cell相关”: 自定义cell
12、用户撤回消息,实时消息回调会怎样处理?
撤回消息的事件是没有回调的,可以这样,如果想通过实时消息回调知道哪条消息是撤回的消息,那么在客户端撤回消息后,在发条cmd消息,cmd消息的ext里面加上撤回消息的标识然后在加上撤回消息的消息id,这样这条cmd消息也会回调到你们服务器上,这样就可以知道哪条消息是撤回消息了
13、如何知道对方的环信id是否在线
可以在客户端先请求自己的服务器,然后让服务器端调用环信获取用户在线状态的接口,将用户是否在线的状态返回给客户端即可: 用户是否在线
1、新版UI,点击群组语音消息后,未读红点不消失
在EMChatViewController.m类, - (void)_audioMessageCellDidSelected:(EMMessageCell *)aCell方法中,在截图中标注的位置添加以下代码
EMMessage *chatMessage = aCell.model.emModel;
NSMutableDictionary *dict = [chatMessage.ext mutableCopy];
if (chatMessage.ext) {
if (![[dict objectForKey:@"isPlayed"] boolValue]) {
[dict setObject:@YES forKey:@"isPlayed"];
chatMessage.ext = [dict copy];
}
} else {
chatMessage.ext = @{@"isPlayed":@YES};
}
[[EMClient sharedClient].chatManager updateMessage:chatMessage completion:nil];
然后在EMMessageCell.m类, - (void)setModel:(EMMessageModel *)model方法中,在截图中标注的位置修改成以下代码
if (model.emModel.chatType == EMChatTypeChat) {
self.statusView.hidden = model.emModel.isReadAcked;
} else {
self.statusView.hidden = [[model.emModel.ext objectForKey:@"isPlayed"] boolValue];
}
2、iOS 3.6.0demo,聊天页面弹出的工具栏遮挡消息怎么处理?
EMChatViewController.m类 这个方法中- (void)keyBoardWillHide:(NSNotification *)note
改成这样
[UIView animateWithDuration:animationTime animations:animation completion:^(BOOL finished) {
if (self.dataArray.count > 0) {
[self.tableView reloadData];
NSIndexPath *lastIndex = [NSIndexPath indexPathForRow:self.dataArray.count - 1 inSection:0];
[self.tableView scrollToRowAtIndexPath:lastIndex atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
}];
3、聊天页面发送过消息后,第一次刷新会出现重复的数据
按照以下来修改:
- (NSMutableArray *)messsagesSource
{
if (_messsagesSource == nil) {
_messsagesSource = [NSMutableArray array];
}
return _messsagesSource;
}
[weakself.messsagesSource addObject:msg];
[self.messsagesSource addObject:message];
然后将 tableViewDidTriggerHeaderRefresh 替换为下面的:
- (void)tableViewDidTriggerHeaderRefresh
{
NSString *messageId = nil;
if ([self.messsagesSource count] > 0) {
messageId = [(EMMessage *)self.messsagesSource.firstObject messageId];
}
else {
messageId = nil;
}
[self _loadMessagesBefore:messageId];
}
- (void)_loadMessagesBefore:(NSString*)messageId
{
__weak typeof(self) weakself = self;
void (^block)(NSArray *aMessages, EMError *aError) = ^(NSArray *aMessages, EMError *aError) {
if (!aError && [aMessages count]) {
// EMMessage *msg = aMessages[0];
// weakself.moreMsgId = msg.messageId;
dispatch_async(self.msgQueue, ^{
NSArray *formated = [weakself _formatMessages:aMessages];
NSInteger scrollToIndex = 0;
[weakself.messsagesSource insertObjects:aMessages atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [aMessages count])]];
id object = [weakself.dataArray firstObject];
if ([object isKindOfClass:[NSString class]]) {
NSString *timestamp = object;
[formated enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id model, NSUInteger idx, BOOL *stop) {
if ([model isKindOfClass:[NSString class]] && [timestamp isEqualToString:model]) {
[weakself.dataArray removeObjectAtIndex:0];
*stop = YES;
}
}];
}
scrollToIndex = [weakself.dataArray count];
[weakself.dataArray insertObjects:formated atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [formated count])]];
dispatch_async(dispatch_get_main_queue(), ^{
[weakself.tableView reloadData];
if (weakself.isFirstLoadMsg) {
weakself.isFirstLoadMsg = NO;
[weakself _scrollToBottomRow];
}
});
});
}
[weakself tableViewDidFinishTriggerHeader:YES reload:NO];
};
if ([EMDemoOptions sharedOptions].isPriorityGetMsgFromServer) {
EMConversation *conversation = self.conversationModel.emModel;
[EMClient.sharedClient.chatManager asyncFetchHistoryMessagesFromServer:conversation.conversationId conversationType:conversation.type startMessageId:messageId pageSize:5 completion:^(EMCursorResult *aResult, EMError *aError) {
block(aResult.list, aError);
}];
} else {
[self.conversationModel.emModel loadMessagesStartFromId:messageId count:5 searchDirection:EMMessageSearchDirectionUp completion:block];
}
}
4、转发自己发送出去的图片失败
参考截图添加代码:
body.thumbnailLocalPath = imgPath;
5、在聊天页面点击查看过图片、视频消息后,回到会话列表页,再收到消息,未读消息数就不准确了
由于聊天页面(EMChatViewController)的block里使用了强引用self,造成了循环引用,导致退出聊天页面回到会话列表页面(EMConversationsViewController)时,聊天页面的 dealloc 方法没有执行,所以聊天页面的代理没有移除( [[EMClient sharedClient].chatManager removeDelegate:self]; );然后,用户在会话列表页面收到消息时,聊天页面的 messagesDidReceive 执行了,这个方法里将消息置为已读了,所以,导致会话列表页不显示未读消息数了。
按照截图修改:
6、汉字转拼音的工具类(EMChineseToPinyin)对各别汉字不识别
(1)拼音为er的汉字,例如“二”、“儿”
将 if(nCode >= /* DISABLES CODE */ (2288) && nCode ⇐ 2231)
改为 if(nCode >= 2288 && nCode ⇐ 2301)
(2)汉字“妗”
添加代码 case 7001:
7、EaseUI收到web端发来的视频消息显示“获取缩略图失败”,点击无法播放
按照截图修改:
EMMessageBody *msgBody = aMessage.body;
if (msgBody.type == EMMessageBodyTypeVideo) {
EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
if (![body.thumbnailRemotePath isEqualToString:@""]) {
[weakSelf showHint:@"获取缩略图失败!"];
}
}
// 下载视频
if (videoBody.type == EMMessageBodyTypeVideo) {
EMVideoMessageBody *body = (EMVideoMessageBody *)videoBody;
if ([body.thumbnailRemotePath isEqualToString:@""]) {
NSString *localPath = [model.fileLocalPath length] > 0 ? model.fileLocalPath : videoBody.localPath;
if ([localPath length] == 0) {
[[EMClient sharedClient].chatManager downloadMessageAttachment:model.message progress:nil completion:^(EMMessage *message, EMError *error) {
if (!error) {
NSLog(@"x下载成功!");
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *videoURL = [NSURL fileURLWithPath:body.localPath];
AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.player = [AVPlayer playerWithURL:videoURL];
playerViewController.videoGravity = AVLayerVideoGravityResizeAspect;
playerViewController.showsPlaybackControls = YES;
[self presentViewController:playerViewController animated:YES completion:^{
[playerViewController.player play];
}];
});
} else {
NSLog(@"下载失败---%@", error.errorDescription);
}
}];
} else {
NSURL *videoURL = [NSURL fileURLWithPath:localPath];
AVPlayerViewController *playerViewController = [[AVPlayerViewController alloc] init];
playerViewController.player = [AVPlayer playerWithURL:videoURL];
playerViewController.videoGravity = AVLayerVideoGravityResizeAspect;
playerViewController.showsPlaybackControls = YES;
[self presentViewController:playerViewController animated:YES completion:^{
[playerViewController.player play];
}];
}
} else {
[weakSelf showHint:NSEaseLocalizedString(@"message.thumImageFail", @"thumbnail for failure!")];
}
}