基于融云的及时通讯

来源:互联网 发布:kitti数据集下载 编辑:程序博客网 时间:2024/04/28 03:07

注册开发者帐号

请前往 融云官方网站 注册开发者帐号。注册时,您需要提供真实的邮箱和手机号,以方便我们向您发送重要通知并在紧急时刻能够联系到您。如果您没有提供正确可用的邮箱和手机号,我们随时可能关闭您的应用。

下载 SDK

您可以到 融云官方网站 下载融云 SDK。

SDK 下载包中分为如下两部分:

  • 融云 IM 界面组件 - Rong Cloud IMKit (包含 IMLib)
  • 融云 IM 通讯能力库 - Rong Cloud IMLib

好的,下载应该已经开始了,您可以在下载过程中继续向下阅读。

首先,让我们先创建您的第一个应用吧!

注:由于 iOS 开发编译原理的特殊性,下载的 SDK 包中的 .a 文件尺寸较大,但并不等于会让最终的 ipa 文件尺寸有相应的增加。实际最终会增加您的 App 尺寸大概 2MB 左右。

创建应用

您要进行应用开发之前,需要先在融云开发者平台创建应用。如果您已经注册了融云开发者帐号,请前往 融云开发者平台 创建应用;如果您还没有注册融云开发者帐号,请前往 融云官方网站 首先注册开发者帐号,注册后创建应用。

您创建完应用后,最需要了解的就是 App Key / Secret,它们是融云 SDK 连接服务器所必须的标识,每一个 App 对应一套 App Key / Secret。针对开发者的生产环境和开发环境,我们提供两套 App Key / Secret,您在应用最终上线前,使用开发环境即可,两套环境的功能完全一致。

image
App Key / Secret 位置
开发环境 App Key / Secret 是专门为您提供的仅供开发使用的,开发环境将和生产环境的数据隔离,避免开发环境数据和线上生产环境数据互相冲突。在“开发环境”分类下,您可以找到开发 App Key / Secret。您在申请上线前可以一直使用开发环境的 App Key / Secret 开发。 

生产环境的 App Key / Secret 默认先不提供,等您提交上线后,我们会提供生产环境的 App Key / Secret。

开发准备

以下文档将向大家介绍 IMKit 界面组件的开发方法。如果您想了解如何使用 IMLib,我们提供了 API 文档。 

我们的 SDK 最低支持到 iOS 6.0,请您在构建项目时注意。随着苹果官方的支持情况变化,我们很快会转而支持 iOS 7.0 和 8.0,6.0 的兼容性我们不再主动维护,但是如果您发现兼容性问题,可以发工单联系我们修复。

1、创建项目

创建 Demo 项目时,为了方便演示,请选择创建一个 Empty Application 。

image
创建 Empty Application

2.1、通过 CocoaPods 安装 SDK

CocoaPods 是流行的 Cocoa 项目依赖管理工具,我们推荐您优先使用 CocoaPods 来安装 SDK,这样可以极大的简化安装过程。下面介绍具体步骤:

在您的项目根目录创建一个 Podfile 文件,添加如下内容来引用 IMKit 界面组件库:

pod 'RongCloudIMKit'

如果您需要引用 IMLib 通讯能力库,可以添加:

pod 'RongCloudIMLib'
请不要同时引用 IMKit 和 IMLib,因为 IMKit 中已经包含了 IMLib。重复引用会导致引用冲突,无法正常编译。

然后,执行命令 pod install 安装 融云 SDK。

注意:以后打开项目时,需要使用 CocoaPods 生成的 .xcworkspace 打开,而不是之前的 .xcodeproj。

您可以参考 《CocoaPods 安装和使用教程》 这篇文章来学习如何使用 CocoaPods。

此处特别感谢求攻略的 Zhuohui Yu 帮助创建和维护融云的 CocoaPods 项目。

2.2、手动安装融云 SDK

引用文件

将官网下载的 Rong_Cloud_iOS_SDK_vx_x_x.zip 包解压到任意目录。打开 imkit 目录,将 Headers 目录头文件、iOS_IMKit.a 文件和 RongCloud.bundle 文件加入到工程中。

请不要同时引用 IMKit 和 IMLib,因为 IMKit 中已经包含了 IMLib。重复引用会导致引用冲突,无法正常编译。

添加依赖库

工程中需要依赖的库如下(根据使用的功能不同,某些库并不是所有情况下都需要):

  • AudioToolbox.framework
  • AVFoundation.framework
  • CFNetwork.framework
  • CoreAudio.framework
  • CoreGraphics.framework
  • CoreImage.framework
  • CoreLocation.framework
  • CoreMedia.framework
  • CoreTelephony.framework
  • CoreVideo.framework
  • Foundation.framework
  • libc++.dylib
  • libsqlite3.dylib
  • libstdc++.dylib
  • libz.dylib
  • MapKit.framework
  • OpenGLES.framework
  • QuartzCore.framework
  • SystemConfiguration.framework
  • UIKit.framework

编写代码

1、初始化 SDK

请使用您之前从融云开发者平台注册得到的 App Key,传入 initWithAppKey:deviceToken: 方法,初始化 SDK。deviceToken 是用于 Apple Push Notification Service 的设备唯一标识,获取方法请参阅苹果官方的 Local and Push Notification Programming Guide

在整个应用程序全局,只需要调用一次 initWithAppKey:deviceToken: 方法。这里,我们选择在 App 初始化时,来调用 initWithAppKey:deviceToken: 方法。当获取到 Push 通知权限时,使用 setDeviceToken 方法设置 deviceToken

initWithAppKey:deviceToken: 方法中的 deviceToken 参数已经被废弃,目前传入 nil 即可,后续版本中会去掉此参数。

AppDelegate.m 文件如下:

#import "AppDelegate.h"// 引用 IMKit 头文件。#import "RCIM.h"// 引用 ViewController 头文件。#import "ViewController.h"@interface AppDelegate ()@end@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    // Override point for customization after application launch.    // 初始化 SDK,传入 App Key,deviceToken 暂时为空,等待获取权限。    [RCIM initWithAppKey:@"e7x8xycsx6flq" deviceToken:nil];#ifdef __IPHONE_8_0    // 在 iOS 8 下注册苹果推送,申请推送权限。    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge                                                                                         |UIUserNotificationTypeSound                                                                                         |UIUserNotificationTypeAlert) categories:nil];    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];#else    // 注册苹果推送,申请推送权限。    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];#endif    // 初始化 ViewController。    ViewController *viewController = [[ViewController alloc]initWithNibName:nil bundle:nil];    // 初始化 UINavigationController。    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:viewController];    // 设置背景颜色为黑色。    [nav.navigationBar setBackgroundColor:[UIColor blackColor]];    // 初始化 rootViewController。    self.window.rootViewController = nav;    self.window.backgroundColor = [UIColor whiteColor];    [self.window makeKeyAndVisible];    return YES;}#ifdef __IPHONE_8_0- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{    // Register to receive notifications.    [application registerForRemoteNotifications];}- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler{    // Handle the actions.    if ([identifier isEqualToString:@"declineAction"]){    }    else if ([identifier isEqualToString:@"answerAction"]){    }}#endif// 获取苹果推送权限成功。-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{    // 设置 deviceToken。    [[RCIM sharedRCIM] setDeviceToken:deviceToken];}-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {}- (void)applicationWillResignActive:(UIApplication *)application {    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.}- (void)applicationDidEnterBackground:(UIApplication *)application {    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.}- (void)applicationWillEnterForeground:(UIApplication *)application {    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.}- (void)applicationDidBecomeActive:(UIApplication *)application {    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.}- (void)applicationWillTerminate:(UIApplication *)application {    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.}@end
以上代码中的 App Key 值 e7x8xycsx6flq 仅为示例,直接拷贝执行将返回错误,请注意替换为您自己的 App Key 值。
以上示例方法不是唯一的解决方案,你可以选择合适的时机对 SDK 进行初始化操作。

2、获取 Token

Token 也叫用户令牌,是 SDK 端用来连接融云服务器的凭证,每个用户连接服务器都需要一个 Token。每次初始化连接服务器(请看下节)时,都需要向服务器提交 Token。

要想获取用户 Token,流程如下:首先需要您的 App 查询您的应用程序服务器,然后您的应用程序服务器再访问融云服务器获取,最后返回给 App,App 用返回的 Token 连接服务器登录。详细描述请参考 Server 开发指南 中的身份认证服务小节。

为了方便您进行测试开发,我们还提供了 API 调试工具,以便您不用部署服务器端程序,即可直接获得测试开发所需的用户令牌。请访问我们的 融云开发者平台,打开您想测试的应用,在左侧菜单中选择“API 调试”即可。
image
API 调试工具

3、连接服务器

将您在上一节请求身份认证服务器时获取的 Token 传入 connectWithToken 方法,开始连接服务器。在整个应用程序全局,只需要调用一次 connectWithToken 方法,SDK 会负责自动重连。

您可以用在上一节介绍的 API 调试工具生成一个 Token,这里我们假设您生成 Token 时使用的参数如下:

用户 Id:

userId = "1"

用户在融云系统中唯一的身份 Id,可为任意数字或字符串,但必须保证全局唯一。

用户名称:

name = "韩梅梅"

用户的显示名称,用来在 Push 推送时,或者客户端没有提供用户信息时,显示用户的名称。

用户头像图片:

portraitUri = "http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png"

这里为了测试,您可以随意提供一个地址,如果此图片不存在,IMKit 会显示默认的头像。

假设返回的 Token 是 mKmyKqTSf7aNDinwAFMnz7NXKILeV3X0+CCRBOxmtOApmvQjMathViWrePIfq0GuTu9jELQqsckv4AhfjCAKgQ==。

以下代码展示了如何连接到融云服务器,完整代码请看下节。

    // 连接融云服务器。    [RCIM connectWithToken:@"mKmyKqTSf7aNDinwAFMnz7NXKILeV3X0+CCRBOxmtOApmvQjMathViWrePIfq0GuTu9jELQqsckv4AhfjCAKgQ==" completion:^(NSString *userId) {        // 此处处理连接成功。        NSLog(@"Login successfully with userId: %@.", userId);    } error:^(RCConnectErrorCode status) {        // 此处处理连接错误。        NSLog(@"Login failed.");    }];
以上代码中的 Token 值 mKmyKqTSf7aNDinwAFMnz7NXKILeV3X0+CCRBOxmtOApmvQjMathViWrePIfq0GuTu9jELQqsckv4AhfjCAKgQ== 仅为示例,直接拷贝执行将返回错误,请注意替换为您自己的 Token 值。
以上示例方法不是唯一的解决方案,你可以选择合适的时机对 SDK 进行初始化和连接操作。

4.1、启动单聊界面

单聊是最基本的聊天界面,在您的 App 中,您可以通过直接点击用户头像或者点击一个启动聊天按钮,直接调起单聊界面。

下面的代码,我们提供一个完整的案例来演示如何启动一个自己与自己单聊的例子(仅为演示,实际业务中不存在自己和自己聊天的场景)。在这个例子中,通过点击一个按钮来启动单聊界面。

ViewController.h 文件如下:

#import <UIKit/UIKit.h>@interface ViewController : UIViewController// 定义一个按钮。@property (nonatomic,strong) UIButton *button;@end

ViewController.m 文件如下:

#import "ViewController.h"// 引用 IMKit 头文件。#import "RCIM.h"// 引用 RCChatViewController 头文件。#import "RCChatViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.    // 创建一个按钮    self.button = [UIButton buttonWithType:UIButtonTypeRoundedRect];    [self.button setFrame:CGRectMake(50, 100, 80, 40)];    [self.button setTitle:@"Start Chat" forState:UIControlStateNormal];    [self.button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];    [self.button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];    [self.view addSubview:self.button];}// 按钮点击事件。-(IBAction)buttonClicked:(id)sender{    // 连接融云服务器。    [RCIM connectWithToken:@"mKmyKqTSf7aNDinwAFMnz7NXKILeV3X0+CCRBOxmtOApmvQjMathViWrePIfq0GuTu9jELQqsckv4AhfjCAKgQ==" completion:^(NSString *userId) {        // 此处处理连接成功。        NSLog(@"Login successfully with userId: %@.", userId);        // 创建单聊视图控制器。        RCChatViewController *chatViewController = [[RCIM sharedRCIM]createPrivateChat:@"1" title:@"自问自答" completion:^(){            // 创建 ViewController 后,调用的 Block,可以用来实现自定义行为。        }];        // 把单聊视图控制器添加到导航栈。        [self.navigationController pushViewController:chatViewController animated:YES];    } error:^(RCConnectErrorCode status) {        // 此处处理连接错误。        NSLog(@"Login failed.");    }];}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end

4.2、启动客服聊天界面

原理同上,通过以下代码,您的 App 可以直接调起客服聊天界面。

其中,customerServiceId 的值,可以在 融云开发者平台 的客服模块中找到。位置为:xx应用 / 功能模块 / 客服模块 / 开发环境 / 查看详情。查看customerServiceId 之前,请您先开启客服功能。

image
customerServiceId 值的位置
        // 创建客服聊天视图控制器。        RCChatViewController *chatViewController = [[RCIM sharedRCIM]createCustomerService:customerServiceId title:@"在线客服" completion:^(){            // 创建 ViewController 后,调用的 Block,可以用来实现自定义行为。        }];        // 把客服聊天视图控制器添加到导航栈。        [self.navigationController pushViewController:chatViewController animated:YES];

4.3、启动会话列表

如果您需要会话列表界面,可以启动聊天会话列表,在聊天会话列表中,用户可以通过点击右上角的加号按钮创建聊天会话。当然,在有些场景下,您可能不需要会话列表,直接启动聊天会话窗口。

        // 创建会话列表视图控制器。        RCChatListViewController *chatListViewController = [[RCIM sharedRCIM]createConversationList:^(){            // 创建 ViewController 后,调用的 Block,可以用来实现自定义行为。        }];        // 把会话列表视图控制器添加到导航栈。        [self.navigationController pushViewController:chatListViewController animated:YES];
启用会话列表前,请务必实现好友信息提供者 setFriendsFetcherWithDelegate,否则好友列表将不显示任何好友信息。关于好友信息提供者的信息,请参看下节文档。

5、群组功能

群组业务的描述,请参见快速入门中的说明。

因群组信息与群成员信息是由 App 维护管理并提供的,所以,处理群组的业务逻辑就是处理数据同步的逻辑。主要逻辑如下:

融云当前群组的架构设计决定,您不需要调用融云服务器去“创建”群组,也就是告诉融云服务器哪些群组有哪些用户。您只需要同步当前用户所属的群组信息给融云服务器,即相当于“订阅”或者“取消订阅”了所属群组的消息。融云会根据用户同步的群组数据,计算群组的成员信息并群发消息。

同步群组信息 syncGroup

开发文档链接:syncGroups:completion:error:

用于同步当前登录用户已经加入的群组信息,需要提交当前用户所有加入的群组信息(群组信息包含 groupId:群唯一标识,groupName:群名称)。 融云服务器会根据你提交的群信息与之前提交的群信息进行比对,根据差异结果进行加入或退出操作。提交此信息后该用户可以收到这些群的消息,且可以向这些群内发送数据。

为了确保群组关系的正确同步,最好在每次完成初始化并成功连接融云服务后调用此方法。

加入群 joinGroup

开发文档链接:joinGroup:groupName:completion:error:

此方法可以在 App 运行过程中实现将当前登录用户加入群组。在方法响应成功后,该用户可以收到所加入的群组的消息,且可以向该群组发送数据。请在您的 App 中实现当前用户加入群组时,调用此方法。

退出群 quitGroup

开发文档链接:quitGroup:completion:error:

此方法可以在 App 运行过程中实现当前登录用户退出已加入的群组。在方法响应成功后,该用户将不会再收到该群组的消息,且不再可以向该群组发送数据。请在您的 App 中实现当前用户退出群组时,调用此方法。

6、聊天室功能

聊天室业务的描述,请参见快速入门中的说明。

聊天室与群组最大的不同在于,聊天室的消息没有 Push 通知,也没有成员的概念。想参与聊天室聊天,接收聊天室消息,加入聊天室即可;不参与聊天室聊天,不接收消息,退出聊天室即可。IMKit 组件中已经内置了加入和退出讨论组的接口调用,您直接启动即可:

// 启动聊天室RCChatViewController *temp = [[RCChatViewController alloc]init];temp.currentTarget = @"19527";temp.conversationType = ConversationType_CHATROOM;temp.enableSettings = NO;temp.currentTargetName = @"聊天室标题";[self.navigationController pushViewController:temp animated:YES];
因聊天室没有成员关系,需要在每次显示聊天室聊天界面之前,执行加入聊天室的操作,并在退出聊天室聊天界面之后执行退出聊天室的操作。否则,您的 App 将消耗不必要的流量(不退出聊天室将会持续接收来自该聊天室的消息),请在使用 IMLib 开发时注意。

功能进阶

实现了以上功能以后,您就可以实现在 App 中的简单一对一聊天服务了,但是您还看不到用户昵称、头像等信息。所以,为了实现上述功能,您还需要在 App 真正发布前继续完善一些代码。

显示用户昵称和头像

设计原理说明:

融云认为,每一个设计良好且功能健全的 App 都应该能够在本地获取、缓存并在合适的时机更新 App 中的用户信息。所以,融云不维护和管理用户的基本信息(用户 Id、昵称、头像)的获取、缓存、变更和同步。此外,App 提供用户信息也避免了由于缓存导致的用户信息更新不及时,App 中不同界面上的用户信息不统一(比如:一部分 App 从 App 服务器上获取并显示,一部分由融云服务器获取并显示),能够获得最佳的用户体验。

融云通过让开发者在 IMKit 中设置用户信息提供者的方式来实现在聊天界面和会话列表页中实现通过 App 的数据源来显示用户昵称和头像。

设置用户信息提供者即通过调用 setUserInfoFetcherWithDelegate:isCacheUserInfo: 方法设置 RCIMUserInfoFetcherDelegagte。用户信息提供者采用 Provider 模式,即您提供给融云的 IMKit 一个 RCIMUserInfoFetcherDelegagte,当融云的 IMKit 需要使用用户信息的时候,调用您传入的getUserInfoWithUserId: 方法,向您获取用户信息。所以您在 getUserInfoWithUserId: 方法中,需要根据传入的 userId 参数,向我们返回对应的用户信息。

代码请参见下节 - 设置好友关系提供者,我们将一起展示。

虽然您可以通过调用 [https://api.cn.rong.io/user/getToken.[format]](/server.html#_身份认证服务接口说明) 换取 Token 的方式将用户昵称和头像提供给我们,并且可以通过重新换取 Token 的方式刷新用户资料,但是我们非常不推荐这种方式。这种方式会造成客户端的性能问题和用户信息更新不及时。 

我们强烈推荐您实现本地的 RCIMUserInfoFetcherDelegagte,并在客户端对用户信息进行缓存。

设置好友列表

为了客户隐私考虑,融云既不同步又不保存用户的好友关系。所以,当界面组件创建会话需要显示好友列表时,需要向 App 获取。App 需要设置一个好友关系提供者给 IMKit,以便 IMKit 读取好友关系。好友关系提供者 RCIMFriendsFetcherDelegate 的设计模式与用户信息提供者 RCIMUserInfoFetcherDelegagte 相同,可以参考用户信息提供者 RCIMUserInfoFetcherDelegagte 的说明。

只有您使用融云 IMKit 提供的从好友列表中选择用户的功能时,才需要设置好友关系提供者。如果您自行实现选择用户界面,则不需要设置好友关系提供者。

显示群组信息

在群组业务中,融云只是同步群组关系数据,并不保存群组的具体信息。所以,当界面组件创建会话需要显示群组信息时,需要向 App 获取。App 需要设置一个群组信息提供者给 IMKit,以便 IMKit 读取好友关系。群组信息提供者 RCIMGroupInfoFetcherDelegate 的设计模式与用户信息提供者 RCIMUserInfoFetcherDelegagte相同,可以参考用户信息提供者 RCIMUserInfoFetcherDelegagte 的说明。

只有您使用融云 IMKit 提供的群组功能时,才需要设置群组信息提供者。如果您没有使用群组功能,则不需要设置群组信息提供者。

代码分成两部分,分别是 AppDelegate.h 文件和 AppDelegate.m 文件。

AppDelegate.h 文件如下:

#import <UIKit/UIKit.h>// 引用 IMKit 头文件。#import "RCIM.h"// 添加获取用户信息、好友列表和群组信息的 Protocol。@interface AppDelegate : UIResponder <UIApplicationDelegate, RCIMFriendsFetcherDelegate, RCIMUserInfoFetcherDelegagte, RCIMGroupInfoFetcherDelegate>@property (strong, nonatomic) UIWindow *window;@end

AppDelegate.m 文件如下:

#import "AppDelegate.h"// 引用 IMKit 头文件。#import "RCIM.h"// 引用 ViewController 头文件。#import "ViewController.h"@interface AppDelegate ()@end@implementation AppDelegate- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];    // Override point for customization after application launch.    // 初始化 SDK,传入 App Key,deviceToken 暂时为空,等待获取权限。    [RCIM initWithAppKey:@"e7x8xycsx6flq" deviceToken:nil];    // 设置用户信息提供者。    [RCIM setUserInfoFetcherWithDelegate:self isCacheUserInfo:NO];    // 设置好友信息提供者。    [RCIM setFriendsFetcherWithDelegate:self];    // 设置群组信息提供者。    [RCIM setGroupInfoFetcherWithDelegate:self];#ifdef __IPHONE_8_0    // 在 iOS 8 下注册苹果推送,申请推送权限。    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge                                                                                         |UIUserNotificationTypeSound                                                                                         |UIUserNotificationTypeAlert) categories:nil];    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];#else    // 注册苹果推送,申请推送权限。    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];#endif    // 初始化 ViewController。    ViewController *viewController = [[ViewController alloc]initWithNibName:nil bundle:nil];    // 初始化 UINavigationController。    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:viewController];    // 设置背景颜色为黑色。    [nav.navigationBar setBackgroundColor:[UIColor blackColor]];    // 初始化 rootViewController。    self.window.rootViewController = nav;    self.window.backgroundColor = [UIColor whiteColor];    [self.window makeKeyAndVisible];    return YES;}#ifdef __IPHONE_8_0- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{    // Register to receive notifications.    [application registerForRemoteNotifications];}- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler{    // Handle the actions.    if ([identifier isEqualToString:@"declineAction"]){    }    else if ([identifier isEqualToString:@"answerAction"]){    }}#endif// 获取苹果推送权限成功。-(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{    // 设置 deviceToken。    [[RCIM sharedRCIM] setDeviceToken:deviceToken];}-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {}// 获取好友列表的方法。-(NSArray*)getFriends{    NSMutableArray *array = [[NSMutableArray alloc]init];    RCUserInfo *user1 = [[RCUserInfo alloc]init];    user1.userId = @"1";    user1.name = @"韩梅梅";    user1.portraitUri = @"http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png";    [array addObject:user1];    RCUserInfo *user2 = [[RCUserInfo alloc]init];    user2.userId = @"2";    user2.name = @"李雷";    user2.portraitUri = @"http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png";    [array addObject:user2];    return array;}// 获取用户信息的方法。-(RCUserInfo*)getUserInfoWithUserId:(NSString *)userId{    if ([@"1" isEqual:userId]) {        RCUserInfo *user = [[RCUserInfo alloc]init];        user.userId = @"1";        user.name = @"韩梅梅";        user.portraitUri = @"http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png";        return user;    }    if ([@"2" isEqual:userId]) {        RCUserInfo *user = [[RCUserInfo alloc]init];        user.userId = @"2";        user.name = @"李雷";        user.portraitUri = @"http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png";        return user;    }    return nil;}// 获取群组信息的方法。-(RCGroup*)getGroupInfoWithGroupId:(NSString *)groupId{    if ([@"1" isEqual:groupId]) {        RCGroup *group = [[RCGroup alloc]init];        group.groupId = @"1";        group.groupName = @"同城交友";        //group.portraitUri = @"http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png";        return group;    }    if ([@"2" isEqual:groupId]) {        RCGroup *group = [[RCGroup alloc]init];        group.groupId = @"2";        group.groupName = @"跳蚤市场";        //group.portraitUri = @"http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png";        return group;    }    return nil;}- (void)applicationWillResignActive:(UIApplication *)application {    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.}- (void)applicationDidEnterBackground:(UIApplication *)application {    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.}- (void)applicationWillEnterForeground:(UIApplication *)application {    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.}- (void)applicationDidBecomeActive:(UIApplication *)application {    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.}- (void)applicationWillTerminate:(UIApplication *)application {    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.}@end

UI 自定义

融云 IMKit SDK 使用 UIViewController 方式实现组件的自定义和调用关系的任意组合,提供 UIVIewController 能力的组件包括会话列表:RCChatListViewController、群组列表:RCGroupListViewController、选择好友:RCSelectPersonViewController、聊天会话:RCChatViewController、会话设置:RCChatSettingViewController

开发者可以通过继承 IMKit SDK 提供的 UI 组件来实现自定义,或者自由组合调用关系:部分 UI 使用融云 SDK,部分UI 由自己开发。例如,好友列表根据自身需求自己实现,其他界面使用融云 SDK 的 UI 组件。

下面以会话列表为例,阐述以继承的方法实现自定义功能。

继承 RCChatListViewController

@interface DemoChatListViewController : RCChatListViewController@end

设置导航的标题、颜色、左右按钮事件,重载自己需要的功能的方法

-(void)viewDidLoad{    [super viewDidLoad];    // 自定义导航标题颜色    [self setNavigationTitle:@"会话" textColor:[UIColor whiteColor]];    // 自定义导航左右按钮    UIBarButtonItem *leftButton = [[UIBarButtonItem alloc]initWithTitle:@"返回" style:UIBarButtonItemStyleBordered target:self action:@selector(leftBarButtonItemPressed:)];    [leftButton setTintColor:[UIColor whiteColor]];    self.navigationItem.leftBarButtonItem = leftButton;    // 自定义导航左右按钮    UIBarButtonItem *rightButton = [[UIBarButtonItem alloc]initWithTitle:@"选择" style:UIBarButtonItemStyleBordered target:self action:@selector(rightBarButtonItemPressed:)];    [rightButton setTintColor:[UIColor whiteColor]];    self.navigationItem.rightBarButtonItem = rightButton;}

注意导航左右按钮的方法名称,必须是:

leftBarButtonItemPressed

rightBarButtonItemPressed

功能模块自定义

实现左右按钮事件的方法,确定跳转关系

-(void)leftBarButtonItemPressed:(id)sender{    [super leftBarButtonItemPressed:sender];}-(void)rightBarButtonItemPressed:(id)sender{    // 跳转好友列表界面,可是是融云提供的 UI 组件,也可以是自己实现的UI    RCSelectPersonViewController *temp = [[RCSelectPersonViewController alloc]init];    // 控制多选    temp.isMultiSelect = YES;    UINavigationController * nav = [[UINavigationController alloc]initWithRootViewController:temp];    // 导航和的配色保持一直    UIImage *image= [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault];    [nav.navigationBar setBackgroundImage:image forBarMetrics:UIBarMetricsDefault];    temp.delegate = self;    [self presentModalViewController:nav animated:YES];}

重载 TableView 表格点击事件

-(void)onSelectedTableRow:(RCConversation*)conversation{    if(conversation.conversationType == ConversationType_GROUP)    {        DemoGroupListViewController* groupVC = [[DemoGroupListViewController alloc] init];        self.currentGroupListView = groupVC;        [self.navigationController pushViewController:groupVC animated:YES];        return;    }    // 该方法目的延长会话聊天 UI 的生命周期    DemoChatViewController* chat = [self getChatController:conversation.targetId conversationType:conversation.conversationType];    if (nil == chat) {        chat =[[DemoChatViewController alloc]init];        [self addChatController:chat];    }    chat.currentTarget = conversation.targetId;    chat.conversationType = conversation.conversationType;    //chat.currentTargetName = curCell.userNameLabel.text;    chat.currentTargetName = conversation.conversationTitle;    [self.navigationController pushViewController:chat animated:YES];}

自定义选择好友

开发者自己自定义选择好友界面,选择好友之后,需要重载启动私聊(一对一)方法或者重载启动讨论组方法。

/** *  启动一对一聊天。 * *  @param userInfo */-(void)startPrivateChat:(RCUserInfo*)userInfo{    DemoChatViewController* chat = [self getChatController:userInfo.userId conversationType:ConversationType_PRIVATE];    if (nil == chat) {        chat =[[DemoChatViewController alloc]init];        [self addChatController:chat];    }    chat.currentTarget = userInfo.userId;    chat.currentTargetName = userInfo.name;    chat.conversationType = ConversationType_PRIVATE;    [self.navigationController pushViewController:chat animated:YES];}/** *  启动讨论组。 * *  @param userInfos */-(void)startDiscussionChat:(NSArray*)userInfos{    NSMutableString *discussionName = [NSMutableString string] ;    NSMutableArray *memberIdArray =[NSMutableArray array];    NSInteger count = userInfos.count ;    for (int i=0; i<count; i++) {        RCUserInfo *userinfo = [userInfos objectAtIndex:i];        //NSString *name = userinfo.name;        if (i == userInfos.count - 1) {            [discussionName appendString:userinfo.name];        }else{            [discussionName  appendString:[NSString stringWithFormat:@"%@%@",userinfo.name,@","]];        }        [memberIdArray addObject:userinfo.userId];    }    // 创建讨论组    [[RCIMClient sharedRCIMClient]createDiscussion:discussionName userIdList:memberIdArray completion:^(RCDiscussion *discussInfo) {        NSLog(@"create discussion ssucceed!");        dispatch_async(dispatch_get_main_queue(), ^{            DemoChatViewController* chat = [self getChatController:discussInfo.discussionId conversationType:ConversationType_PRIVATE];            if (nil == chat) {                chat =[[DemoChatViewController alloc]init];                [self addChatController:chat];            }            chat.currentTarget = discussInfo.discussionId;            chat.currentTargetName = discussInfo.discussionName;            chat.conversationType = ConversationType_DISCUSSION;            [self.navigationController pushViewController:chat animated:YES];        });    } error:^(RCErrorCode status) {        dispatch_async(dispatch_get_main_queue(), ^{            NSLog(@"DISCUSSION_INVITE_FAILED %d",status);            UIAlertView *alert= [[UIAlertView alloc]initWithTitle:@"" message:@"创建讨论组失败" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil];            [alert show];        });    }];}

在 IMKit 中使用 IMLib 方法

在 IMKit 是对 IMLib 的 UI 封装,在 IMKit 中可以直接使用 IMLib 中的所有方法,代码如下:

NSArray *messageArray = [[RCIMClient sharedRCIMClient] getLatestMessages:self.conversationType targetId:self.currentTarget count:10];

更多的融云 SDK UI 组件请参考融云开源的 Demo 例子。

https://github.com/rongcloud/demo-app-ios

配置应用

应用标识

应用标识是为了我们的 API 能够正确识别并验证您的应用请求而所必要的信息,对于防止账户盗用和滥用有着重要的作用。针对 iOS 平台,需要填写 Bundle Identifier,在 XCode 中的位置如图所示。

image
Bundle Identifier 位置
如果您只是采用开发环境 App Key / Secret 进行测试开发,暂时不需要填写相关信息;但是您在提请应用上线前必须完善应用配置信息,否则无法提请上线。
请务必确保您填写的 Bundle Identifier 信息和您应用程序包中的信息一致。上线后,每次连接我们都将会验证这个信息,如果信息不一致,服务端将会拒绝接受连接,您的 App 将无法使用融云的相关服务。

iOS 推送证书设置

如果您希望您的 iOS 应用程序具备接收推送的能力,您必须要上传 iOS 推送证书。证书生成的方法,请参考:

Cooper's Blog 撰写的 一步一步实现 iOS 应用 PUSH 功能

风雨雷电堂 撰写的 苹果推送通知服务教程 Apple Push Notification Services Tutorial

讨论组人数上限设置

讨论组人数在服务端有上限限制,为 500 人,在客户端,根据具体的业务需求,可以通过配置文件配置讨论组人数上限,配置的方法如下:

设置定义在 RCSelectPersonViewController.h 文件中,开发时请设置相关值:

/** *  讨论组人员最大限制,默认50个 */@property (nonatomic,assign) NSInteger discussion_members_limit;

Demo 示例

为了您能够更好的理解如何使用融云 IMKit SDK,我们在 GitHub 上提供了开源的 Demo App。

Demo App 中使用了我们提供的 App Key,Demo App 连接的是我们为了演示用搭建的 Demo App Server,Demo App Server 中使用了和 Demo App 相同的 App Key / App Secret。如果您只更换了 Demo App 的 App Key 为自己申请的 App Key,是无法成功连接到我们的 Demo App Server 的。这种情况下,您需要自己架设您自己的 Demo App Server 并正确设置其中的 App Key / App Secret。

请移步访问:

https://github.com/rongcloud/demo-app-ios

https://github.com/rongcloud/demo-server-php

https://github.com/rongcloud/demo-server-nodejs

0 0