美文网首页
融云即时通讯开发

融云即时通讯开发

作者: 江湖闹士 | 来源:发表于2019-03-14 14:33 被阅读0次

写在开头:本片文章记录融云开发的流程以及开发过程中遇到的问题,由于项目中没有好友的概念,所以没有添加好友删除好友的功能,做的功能罗列如下:
1、集成sdk
2、注册登录
3、会话列表
4、会话页面
5、位置实时共享
6、头像昵称
7、未读角标
8、搜索历史记录

本人遇到的问题,相信大多数人都会遇到的问题在下面一一记录

一、集成sdk的时候遇到的问题
1、现在大多数iOS开发集成第三方都使用cocopods,很少用手动下载集成,一方面比较快捷方便,另一方面减少不比较的麻烦冲突。一般开发者都是想快速开发使用SDK自带的页面,那就
target 'MyApp' do
    pod 'RongCloudIM/IMKit', '~> 2.9.0'  
end
否则
target 'MyApp' do
    pod 'RongCloudIM/IMLib', '~> 2.9.0'
end
注意一点:后面的版本号最好用最新的,官网文档中写的不是最新的(2.8.3),不要直接复制粘贴过去就pod install,因为iOS(2.8.0之前老版本)和安卓版本差别大的话,可能会造成苹果和安卓互通音视频的时候出问题
2、还有可能出现冲突的问题,那就只能根据自己的情况去除重复文件了
二、连接服务器(登录融云)

//因为获取 Token 时需要提供 App Key 和 App Secret。如果在客户端请求 Token,假如您的 App 代码一旦被反编译,则会导致您的 App Key 和 App Secret 泄露。所以,务必在您的服务器端获取 Token,一句话:让后台登录接口返回融云的token,然后在登录成功后,调用下面的方法登录融云。
//登录融云
    [[RCIM sharedRCIM] connectWithToken:@"YourTestUserToken"     success:^(NSString *userId) {
    NSLog(@"登陆成功。当前登录的用户ID:%@", userId);
} error:^(RCConnectErrorCode status) {
    NSLog(@"登陆的错误码为:%d", status);
} tokenIncorrect:^{
    //token过期或者不正确。
    //如果设置了token有效期并且token过期,请重新请求您的服务器获取新的token
    //如果没有设置token有效期却提示token错误,请检查您客户端和服务器的appkey是否匹配,还有检查您获取token的流程。
    NSLog(@"token错误");
}];

注意:如果怕APP每次杀死在进入的时候会断开连接,所以在APPdelegate.m里面再调一次
三、会话列表
//融云 IMKit 已经实现了一个默认的会话列表视图控制器,您直接使用或继承 RCConversationListViewController,即可快速启动和使用会话列表界面。

- (void)viewDidLoad {
    //重写显示相关的接口,必须先调用super,否则会屏蔽SDK默认的处理
    [super viewDidLoad];

      //设置需要显示哪些类型的会话
      [self setDisplayConversationTypes:@[@(ConversationType_PRIVATE),
                                          @(ConversationType_DISCUSSION),
                                          @(ConversationType_CHATROOM),
                                          @(ConversationType_GROUP),
                                          @(ConversationType_APPSERVICE),
                                          @(ConversationType_SYSTEM)]];
      //设置需要将哪些类型的会话在会话列表中聚合显示
      [self setCollectionConversationType:@[@(ConversationType_DISCUSSION),
                                            @(ConversationType_GROUP)]];
}

1、这个页面如果断开连接有个红色的提示栏,网络断开如果想去掉,在本类中写:
self.isShowNetworkIndicatorView = NO;
2、如果想在头部加东西
self.conversationListTableView.tableHeaderView = self.header;
3、点击cell处理事件
//重写RCConversationListViewController的onSelectedTableRow事件
- (void)onSelectedTableRow:(RCConversationModelType)conversationModelType
         conversationModel:(RCConversationModel *)model
               atIndexPath:(NSIndexPath *)indexPath {
    RCConversationViewController *conversationVC = [[RCConversationViewController alloc]init];
    conversationVC.conversationType = model.conversationType;
    conversationVC.targetId = model.targetId;
    conversationVC.title = @"想显示的会话标题";
    [self.navigationController pushViewController:conversationVC animated:YES];
}
四、会话页面(单聊)
1、修改扩展内容中的图片和名字
//更新扩展部分的图片
[self.chatSessionInputBarControl.pluginBoardView updateItemWithTag:PLUGIN_BOARD_ITEM_ALBUM_TAG image:[UIImage imageNamed:@"actionbar_picture_icon"] title:@"照片"];
2、语音视频
//导入callkit
pod 'RongCloudRTC/RongCallKit', '~> 2.9.0'
注意:开通功能后自动显示出来
3、小视频(相册中可选视频)
从 SDK 2.8.29 版本开始支持小视频功能
下载小视频 SDK 将 RongSight.framework 编译连接到自己的项目里面就可以使用小视频功能,不需要写额外的代码。

/*!
 选择媒体资源时,是否包含视频文件,默认值是NO

 @discussion 默认是不包含
 */
@property(nonatomic, assign) BOOL isMediaSelectorContainVideo;


在APPdelegate.m中设置:
[[RCIM sharedRCIM] setIsMediaSelectorContainVideo:YES];
五、头像昵称
1、形状问题
    // 设置头像为圆形
    [RCIM sharedRCIM].globalMessageAvatarStyle = RC_USER_AVATAR_CYCLE;
    [RCIM sharedRCIM].globalConversationAvatarStyle = RC_USER_AVATAR_CYCLE;
在APPdelegate.m中设置,会话列表和会话页面中的头像变成圆形了、但是音视频的页面不会被修改的,如果你想修改那里的头像形状,就不能用cocopods来导入
pod 'RongCloudRTC/RongCallKit', '~> 2.9.0'
因为这样的话,页面是没有暴露出来的,就不能去修改。真的想修改,只能下载开源的callkit代码导入项目中,进行修改,只不过手动导入的话,可能还是会有一些不必要的麻烦。
2、头像
有两种情况,第一种是像demo中的一样头像是用背景色加上昵称的第一位字来生成一张image,存储到本地,进行展示。第二种是用自己的在线图片url。
第一种的做法:去demo中把图1这些类拉过来进行修改,保证不报错,能实现自己的功能,该删的删,该改的改~
第二种的做法:就不用这么麻烦了~
展示刷新头像的方法也有两种,最好不要都用,二选其一即可

*************第一种开始*****************
首先遵守协议:RCIMUserInfoDataSource,RCIMGroupInfoDataSource

在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中 设置代理:
[[RCIM sharedRCIM] setUserInfoDataSource:self];
[[RCIM sharedRCIM] setGroupInfoDataSource:self];

实现代理方法,以个人信息为例:(本地头像的情况,通过demo中的两个类来生成的图片)
- (void)getUserInfoWithUserId:(NSString *)userId
                   completion:(void (^)(RCUserInfo *userInfo))completion
{
    if ([userId isEqualToString:[RDAppDataManager instance].ucUserId]) {
        RCUserInfo *info = [[RCUserInfo alloc] init];
        info.userId = userId;
        info.name = [RDAppDataManager instance].nickName;
        FTAddressBookUserModel *model = [[FTAddressBookUserModel alloc] init];
        model.name = [RDAppDataManager instance].nickName;
        model.userId = [RDAppDataManager instance].ucUserId;
        model.color = [RDAppDataManager instance].color;
        info.portraitUri = [RCDUtilities defaultUserPortrait:model];
        [[RCIM sharedRCIM] refreshUserInfoCache:info withUserId:info.userId];
        return completion(info);
    }else{
        FTAddressBookUserModel *model = [[StorageManager sharedInstance] getUserWithUserID:userId];
        RCUserInfo *info = [[RCUserInfo alloc] init];
        info.userId = userId;
        info.name = model.name;
        info.portraitUri = [RCDUtilities defaultUserPortrait:model];
        [[RCIM sharedRCIM] refreshUserInfoCache:info withUserId:info.userId];
        return completion(info);
    }
}

(链接头像的情况)
- (void)getUserInfoWithUserId:(NSString *)userId
                   completion:(void (^)(RCUserInfo *userInfo))completion
{
    if ([userId isEqualToString:@"当前登录用户的融云id"]) {
        return completion([[RCUserInfo alloc] initWithUserId:userId name:@"当前登录用户的用户名" portrait:@"当前登录用户头像的url"]);
    }else
    {
        根据存储联系人信息的模型,通过 userId 来取得对应的name和头像url,进行以下设置(此处因为项目接口尚未实现,所以就只能这样给大家说说,请见谅)
        return completion([[RCUserInfo alloc] initWithUserId:userId name:@"name" portrait:@"http://pic32.nipic.com/20130827/12906030_123121414000_2.png"]);
    }
}

// 从 2.6.0 开始 IMKit 可以缓存用户信息到数据库里,开发者可以开启 RCIM.h 里的enablePersistentUserInfoCache (当然也可以不用写这个,个人感觉没有什么显著的用处)
[RCIM sharedRCIM].enablePersistentUserInfoCache = YES;

 /*!
     获取群组信息

     @param groupId                     群组ID
     @param completion                  获取群组信息完成之后需要执行的Block
     @param groupInfo(in completion)    该群组ID对应的群组信息

     @discussion SDK通过此方法获取用户信息并显示,请在completion的block中返回该用户ID对应的用户信息。
     在您设置了用户信息提供者之后,SDK在需要显示用户信息的时候,会调用此方法,向您请求用户信息用于显示。
     */
- (void)getGroupInfoWithGroupId:(NSString *)groupId
                         completion:(void (^)(RCGroup *groupInfo))completion
{
// 此处做相应的群组设置即可,获取群组信息的流程与获取用户信息的流程一致
}
************第一种结束******************
************第二种开始******************


//APPdelegate.m 设置消息体内是否携带用户信息
[RCIM sharedRCIM].enableMessageAttachUserInfo = YES;

// 设置当前用户信息
链接融云成功后在成功回调里面设置一下currentUserInfo就行了
[[RCIM sharedRCIM] connectWithToken:@"YourTestUserToken"     success:^(NSString *userId) {
    NSLog(@"登陆成功。当前登录的用户ID:%@", userId);
[RCIM sharedRCIM].currentUserInfo = [[RCUserInfo alloc] initWithUserId:@"当前登录用户的融云id" name:@"当前登录用户的用户名" portrait:@"用户头像的url"];
} error:^(RCConnectErrorCode status) {
    NSLog(@"登陆的错误码为:%d", status);
} tokenIncorrect:^{
    //token过期或者不正确。
    //如果设置了token有效期并且token过期,请重新请求您的服务器获取新的token
    //如果没有设置token有效期却提示token错误,请检查您客户端和服务器的appkey是否匹配,还有检查您获取token的流程。
    NSLog(@"token错误");
}];
************第二种结束******************
图1
六、位置实时共享
1、首先将下面的文件(融云demo里面关于位置的文件)拉进项目里
2、导入头文件
#import "RealTimeLocationEndCell.h"
#import "RealTimeLocationStartCell.h"
#import "RealTimeLocationStatusView.h"
#import "RealTimeLocationViewController.h"
3、遵守协议 < RCRealTimeLocationObserver, RealTimeLocationStatusViewDelegate,UIActionSheetDelegate>
4、属性
@property(nonatomic, weak) id<RCRealTimeLocationProxy> realTimeLocation;
@property(nonatomic, strong) RealTimeLocationStatusView *realTimeLocationStatusView;
5、在viewDidLoad中添加代码如下:
/*******************实时地理位置共享***************/
    [self registerClass:[RealTimeLocationStartCell class] forMessageClass:[RCRealTimeLocationStartMessage class]];
    [self registerClass:[RealTimeLocationEndCell class] forMessageClass:[RCRealTimeLocationEndMessage class]];
    
    WeakSelf;
    [[RCRealTimeLocationManager sharedManager] getRealTimeLocationProxy:self.conversationType
                                                               targetId:self.targetId
                                                                success:^(id<RCRealTimeLocationProxy> realTimeLocation) {
                                                                    weakSelf.realTimeLocation = realTimeLocation;
                                                                    [weakSelf.realTimeLocation addRealTimeLocationObserver:weakSelf];
                                                                    [weakSelf updateRealTimeLocationStatus];
                                                                }
                                                                  error:^(RCRealTimeLocationErrorCode status) {
                                                                      NSLog(@"get location share failure with code %d", (int)status);
                                                                  }];
    
    /******************实时地理位置共享**************/

6、代理中的几个方法
//选择位置按钮时弹出两个选项(位置实时共享,发送位置)
- (void)pluginBoardView:(RCPluginBoardView *)pluginBoardView
     clickedItemWithTag:(NSInteger)tag {
    switch (tag) {
        case PLUGIN_BOARD_ITEM_LOCATION_TAG:
        {
            if (self.realTimeLocation) {
                UIActionSheet *actionSheet = [[UIActionSheet alloc]
                                              initWithTitle:nil
                                              delegate:self
                                              cancelButtonTitle:@"取消"
                                              destructiveButtonTitle:nil
                                              otherButtonTitles:@"发送位置", @"位置实时共享", nil];
                [actionSheet showInView:self.view];
            } else {
                [super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
            }
            
        }
            break;
        default:
        {
            [super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
        }
            break;
    }
    
}
//结束定位
- (void)willMoveToParentViewController:(UIViewController*)parent{
    [super willMoveToParentViewController:parent];
    if (!parent) {
        [self.realTimeLocation quitRealTimeLocation];
    }
}
//发送位置和位置实时共享选择
#pragma mark - UIActionSheet Delegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
    switch (buttonIndex) {
        case 0: {
            [super pluginBoardView:self.pluginBoardView
                clickedItemWithTag:PLUGIN_BOARD_ITEM_LOCATION_TAG];
        } break;
        case 1: {
            [self showRealTimeLocationViewController];
        } break;
    }
}
//点击cell时,如果是地理位置,进行位置共享
#pragma mark override
- (void)didTapMessageCell:(RCMessageModel *)model {
    [super didTapMessageCell:model];
    if ([model.content isKindOfClass:[RCRealTimeLocationStartMessage class]]) {
        [self showRealTimeLocationViewController];
    }
}

以下代理方法 原封不动放下面
/*******************实时地理位置共享***************/
- (void)showRealTimeLocationViewController {
    RealTimeLocationViewController *lsvc = [[RealTimeLocationViewController alloc] init];
    lsvc.realTimeLocationProxy = self.realTimeLocation;
    if ([self.realTimeLocation getStatus] == RC_REAL_TIME_LOCATION_STATUS_INCOMING) {
        [self.realTimeLocation joinRealTimeLocation];
    } else if ([self.realTimeLocation getStatus] == RC_REAL_TIME_LOCATION_STATUS_IDLE) {
        [self.realTimeLocation startRealTimeLocation];
    }
    [self.navigationController presentViewController:lsvc
                                            animated:YES
                                          completion:^{
                                              
                                          }];
}
- (void)updateRealTimeLocationStatus {
    if (self.realTimeLocation) {
        [self.realTimeLocationStatusView updateRealTimeLocationStatus];
        WeakSelf;
        NSArray *participants = nil;
        switch ([self.realTimeLocation getStatus]) {
            case RC_REAL_TIME_LOCATION_STATUS_OUTGOING:
                [self.realTimeLocationStatusView updateText:@"你正在共享位置"];
                break;
            case RC_REAL_TIME_LOCATION_STATUS_CONNECTED:
            case RC_REAL_TIME_LOCATION_STATUS_INCOMING:
                participants = [self.realTimeLocation getParticipants];
                if (participants.count == 1) {
                    NSString *userId = participants[0];
                    [weakSelf.realTimeLocationStatusView
                     updateText:[NSString stringWithFormat:@"user<%@>正在共享位置", userId]];
                    [[RCIM sharedRCIM].userInfoDataSource
                     getUserInfoWithUserId:userId
                     completion:^(RCUserInfo *userInfo) {
                         if (userInfo.name.length) {
                             dispatch_async(dispatch_get_main_queue(), ^{
                                 [weakSelf.realTimeLocationStatusView
                                  updateText:[NSString stringWithFormat:@"%@正在共享位置", userInfo.name]];
                             });
                         }
                     }];
                } else {
                    if (participants.count < 1)
                        [self.realTimeLocationStatusView removeFromSuperview];
                    else
                        [self.realTimeLocationStatusView
                         updateText:[NSString stringWithFormat:@"%d人正在共享地理位置", (int)participants.count]];
                }
                break;
            default:
                break;
        }
    }
}

- (RealTimeLocationStatusView *)realTimeLocationStatusView {
    if (!_realTimeLocationStatusView) {
        _realTimeLocationStatusView =
        [[RealTimeLocationStatusView alloc] initWithFrame:CGRectMake(0, STATUS_BAR_HEIGHT + 44, self.view.frame.size.width, 0)];
        _realTimeLocationStatusView.delegate = self;
        [self.view addSubview:_realTimeLocationStatusView];
    }
    return _realTimeLocationStatusView;
}

#pragma mark - RealTimeLocationStatusViewDelegate
- (void)onJoin {
    [self showRealTimeLocationViewController];
}
- (RCRealTimeLocationStatus)getStatus {
    return [self.realTimeLocation getStatus];
}

- (void)onShowRealTimeLocationView {
    [self showRealTimeLocationViewController];
}

#pragma mark - RCRealTimeLocationObserver
- (void)onRealTimeLocationStatusChange:(RCRealTimeLocationStatus)status {
    WeakSelf;
    
    dispatch_async(dispatch_get_main_queue(), ^{
        [weakSelf updateRealTimeLocationStatus];
    });
}

- (void)onReceiveLocation:(CLLocation *)location type:(RCRealTimeLocationType)type fromUserId:(NSString *)userId {
    WeakSelf;
    dispatch_async(dispatch_get_main_queue(), ^{
        [weakSelf updateRealTimeLocationStatus];
    });
}

- (void)onParticipantsJoin:(NSString *)userId {
    WeakSelf;
    if ([userId isEqualToString:[RCIMClient sharedRCIMClient].currentUserInfo.userId]) {
        [self notifyParticipantChange:@"你加入了地理位置共享"];
    } else {
        [[RCIM sharedRCIM].userInfoDataSource
         getUserInfoWithUserId:userId
         completion:^(RCUserInfo *userInfo) {
             if (userInfo.name.length) {
                 [weakSelf notifyParticipantChange:[NSString stringWithFormat:@"%@加入地理位置共享",
                                                    userInfo.name]];
             } else {
                 [weakSelf notifyParticipantChange:[NSString stringWithFormat:@"user<%@>加入地理位置共享",
                                                    userId]];
             }
         }];
    }
}

- (void)onParticipantsQuit:(NSString *)userId {
    WeakSelf;
    if ([userId isEqualToString:[RCIMClient sharedRCIMClient].currentUserInfo.userId]) {
        [self notifyParticipantChange:@"你退出地理位置共享"];
    } else {
        [[RCIM sharedRCIM].userInfoDataSource
         getUserInfoWithUserId:userId
         completion:^(RCUserInfo *userInfo) {
             if (userInfo.name.length) {
                 [weakSelf notifyParticipantChange:[NSString stringWithFormat:@"%@退出地理位置共享",
                                                    userInfo.name]];
             } else {
                 [weakSelf notifyParticipantChange:[NSString stringWithFormat:@"user<%@>退出地理位置共享",
                                                    userId]];
             }
         }];
    }
}

- (void)onRealTimeLocationStartFailed:(long)messageId {
    dispatch_async(dispatch_get_main_queue(), ^{
        for (int i = 0; i < self.conversationDataRepository.count; i++) {
            RCMessageModel *model = [self.conversationDataRepository objectAtIndex:i];
            if (model.messageId == messageId) {
                model.sentStatus = SentStatus_FAILED;
            }
        }
        NSArray *visibleItem = [self.conversationMessageCollectionView indexPathsForVisibleItems];
        for (int i = 0; i < visibleItem.count; i++) {
            NSIndexPath *indexPath = visibleItem[i];
            RCMessageModel *model = [self.conversationDataRepository objectAtIndex:indexPath.row];
            if (model.messageId == messageId) {
                [self.conversationMessageCollectionView reloadItemsAtIndexPaths:@[ indexPath ]];
            }
        }
    });
}

- (void)notifyParticipantChange:(NSString *)text {
    WeakSelf;
    dispatch_async(dispatch_get_main_queue(), ^{
        [weakSelf.realTimeLocationStatusView updateText:text];
        [weakSelf performSelector:@selector(updateRealTimeLocationStatus) withObject:nil afterDelay:0.5];
    });
}

- (void)onFailUpdateLocation:(NSString *)description {
}
位置实时共享

相关文章

  • 融云即时通讯集成

    前期准备 注册开发者帐号 开发者在集成融云即时通讯、实时网络能力前,需前往融云官方网站注册创建融云开发者帐号。 得...

  • 关于集成融云的时候遇到的一些问题

    由于项目中需要集成融云的客服,进入融云官网SDK 快速入门 - 融云即时通讯技术文档_基础服务开发指南 根...

  • iOS IM即时通讯-[融云] [网易云信]简单集成聊天界面

    前言 IM即时通讯. 对于iOS开发, 融云, 环信, 网易云信, 都是还不错的选择. 作者今天就以 融云, 网...

  • 服务接入设计

    融云即时通讯服务接入可以反推设计微信开发者认证服务接入反推设计

  • 如何平滑迁移

    开发者已使用了第三方云服务,考虑到融云即时通讯云平台系统稳定、产品线丰富、功能高度可控可订制,希望迁移到融云平台,...

  • 融云即时通讯开发

    写在开头:本片文章记录融云开发的流程以及开发过程中遇到的问题,由于项目中没有好友的概念,所以没有添加好友删除好友的...

  • 极光推送,融云即时通讯 原理

    融云即时通讯: 1,App Key / Secret : 相当于当前 App 在融云的账号和密码,是融云SDK连接...

  • 【技术服务】客服服务开发

    一、业务介绍 客服服务是融云为开发者提供连接企业与客户的整体解决方案。通过融云你不但可以为 App 内加入即时通讯...

  • 【指南】广播推送开发

    一、概述 依托融云在即时通讯领域深厚的技术积累及多年稳定可靠的消息推送服务能力,融云决定推出广播推送产品。融云广播...

  • PMP是全球共享的知识体系

    北京融云项目管理中心负责人苏东升 苏东升现在就职于北京云中融信网络科技有限公司,简称融云。融云是国内专业的即时通讯...

网友评论

      本文标题:融云即时通讯开发

      本文链接:https://www.haomeiwen.com/subject/mgdqmqtx.html