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

融云即时通讯开发

作者: 江湖闹士 | 来源:发表于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 {
    }
    
    位置实时共享

    相关文章

      网友评论

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

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