iOS开发之环信(二)--基础功能
六.集成SDK基础功能
(仔细研习,结合实际操作)
由于环信官方文档比较详细,因此,根据项目需求,把用到的方法记录详细即可
先写项目,再学EaseUI使用指南
注意:SDK同步/异步方法区分:
SDK中,大部分与网络有关的操作,提供的是同步方法(注:同步方法会阻塞主线程,需要用户自己创建异步线程执行(如何创建,参考官方demo);带有async的方法为异步方法。)
好友管理
总结:所有的请求都为:
1.初始化SDK
第1步:将SDK(HyphenateSDK)拖入到项目,编译不会报错
第2步:引入相关头文件#import “EMSDK.h”。
第3步:在工程的AppDelegate中的以下方法中,调用SDK对应方法。
修改Appkey
推送证书名(CertName)我们先设置为nil
//1.app加载完成
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
//AppKey:注册的AppKey
//apnsCertName:推送证书名
EMOptions*options = [EMOptionsoptionsWithAppkey:@"comzhonghua123#zhemcchat"];
options.apnsCertName=nil;
[[EMClientsharedClient]initializeSDKWithOptions:options];
returnYES;
}
//2. APP进入后台
- (void)applicationDidEnterBackground:(UIApplication*)application
{
[[EMClientsharedClient]applicationDidEnterBackground:application];
}
// 3.APP将要从后台返回
- (void)applicationWillEnterForeground:(UIApplication*)application
{
[[EMClientsharedClient]applicationWillEnterForeground:application];
}
开始时,把SDK才开始拖入框架时不会报错,但在此时编译,就会报错,因此我们要配置工程,导入框架
2.配置工程,添加依赖库
向Build Phases → Link
Binary With Libraries中添加依赖库。
SDK依赖库有:
CoreMedia.framework
AVFoundation.framework
MobileCoreServices.framework
ImageIO.framework
libc++.tbd
libz.tbd
libsqlite3.tbd
//前七个必须的(下面好像不需要)
AudioToolbox.framework
libstdc++.6.0.9.tbd
若拖入HyphenateFullSDK时导入框架:
libiconv.tbd
(如果使用的是xcode7之前,后缀为dylib。)
SDK不支持bitcode,向Build Settings → Linking → Enable
Bitcode中设置NO。(好像不需要)
编译即可
3.登录
手动注册一个环信账号:打开环信-登录我们的账号-找到我们创建的应用点击-点击IM用户-注册IM用户(自己注册然后点击确定即可,一会就用这个账号试用meng123 :123456)
注意:在环信后台可以操作该用户:查看用户好友/查看用户黑名单/修改信息/删除/重置密码/发送消息/封禁/强制下线
iOS 9之后,苹果限制了正常的HTTP请求,如果我们要继续用,就得先配置一下
Info.plist文件,直接添加
•App Transport Security Settings
Allow Arbitrary LoadsYES
1)搭建登录界面
2)监听登录方法
//登录
- (IBAction)login:(id)sender {
NSString*username =self.accountTextfield.text;
NSString*password =self.passwordTextfield.text;
if(username.length==0|| password.length==0) {
NSLog(@"请输入账号和密码");
return;
}
EMError*error = [[EMClientsharedClient]loginWithUsername:usernamepassword:password];
if(!error) {
NSLog(@"登录成功");
}else{
NSLog(@"登录失败");
}
}
4.注册
注册模式分两种,开放注册和授权注册。
只有开放注册时,才可以客户端注册。开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号。
授权注册的流程应该是您服务器通过环信提供的REST
API注册,之后保存到您的服务器或返回给客户端(就是说服务器给我们注册)
实现监听注册方法
//注册
- (IBAction)register:(id)sender {
NSLog(@"点击了注册");
EMError*error = [[EMClientsharedClient]registerWithUsername:self.accountTextfield.textpassword:self.passwordTextfield.text];
if(error==nil) {
NSLog(@"注册成功");
}else{
NSLog(@"注册失败");
}
}
5.UI搭建
main.storyboard中,删除原来的控制器,拖一个uitabbarcontroller,删除两个自带自控制器,加上初始化箭头-拖三个导航控制器,分别拖线viewcontrollers-分别给三个导航控制器命名(与官方demo一样)conversations(会话控制器)、AddressBook(列表控制器)、setting(设置控制器)
当登录成功后,进入会话控制器界面,因此,登录成功后要替换window的根控制器为会话控制器(conversation),因此在登录成功方法中添加
self.view.window.rootViewController= [UIStoryboardstoryboardWithName:@"Main"bundle:nil].instantiateInitialViewController;
6.自动登录
自动登录:当程序再次启动时,如果用户已经成功登录过,不需要用户再输入用户名和密码进行登录
实现方法原理:第一次登录时,把账号密码保存到沙盒,当程序加载完毕时检查是否设置自动登录,若设置直接加载会话页面
环信已经实现了自动登录,只需要在第一次登录成功后调用 下面的方法即可
//1.登录成功后,设置自动登录
[[EMClient sharedClient].optionssetIsAutoLogin:YES];
自动登录在以下几种情况下会被取消:
用户调用了SDK的登出动作;
用户在别的设备上更改了密码,导致此设备上自动登录失败;
用户的账号被从服务器端删除;
用户从另一个设备登录,把当前设备上登录的用户踢出。
所以,在您调用登录方法前,应该先判断是否设置了自动登录,如果设置了,则不需要您再调用。
//登录方法
//若自动登录为YES,则不需要登录,反之要登录
BOOLisAutoLogin = [EMClientsharedClient].options.isAutoLogin;
if(!isAutoLogin) {
EMError*error = [[EMClientsharedClient]loginWithUsername:usernamepassword:password];
if(!error) {
NSLog(@"登录成功");
//设置自动登录
[[EMClientsharedClient].optionssetIsAutoLogin:YES];
//登录成功加载会话页面
self.view.window.rootViewController= [UIStoryboardstoryboardWithName:@"Main"bundle:nil].instantiateInitialViewController;
}else{
NSLog(@"登录失败");
}
}
//2. AppDelegate程序加载完成时,监听自动登录的状态
[[EMClientsharedClient]addDelegate:selfdelegateQueue:nil];
//3.在AppDelegate程序加载完成时判断是否自动登录
//判断是否自动登录
BOOLisAutoLogin = [EMClientsharedClient].options.isAutoLogin;
if(isAutoLogin) {
self.window.rootViewController= [UIStoryboardstoryboardWithName:@"Main"bundle:nil].instantiateInitialViewController;
}
//4.AppDelegate遵守代理,实现监听方法
//自动登录时调用
-(void)didAutoLoginWithError:(EMError*)aError{
NSLog(@"自动登录了");
}
7.自动连接
当掉线时,iOS SDK会自动重连,只需要监听重连相关的回调,无需进行任何操作。
实现提示用户:没网时显示未连接,一但有网显示:连接中。。。
自定义会话控制器conversation,在该控制器中实现
//1.viewdidload方法中设置代理
[[EMClientsharedClient]addDelegate:selfdelegateQueue:nil];
//2.代理方法监听网络状态
//有以下几种情况,会引起该方法的调用:
//登录成功后,手机无法上网时,会调用该回调
//登录成功后,网络状态变化时,会调用该回调
-(void)didConnectionStateChanged:(EMConnectionState)aConnectionState{
/**
EMConnectionConnected已连接
EMConnectionDisconnected未连接
*/
if(aConnectionState ==EMConnectionDisconnected) {
NSLog(@"网络断开,未连接...");
self.title=@"未连接.";
}else{
NSLog(@"网络通了...");
self.title=@"已连接";
}
}
8.退出登录
自定义settings控制器,设置为静态单元格,只留一个cell,在cell上拖一个button,点击button,退出登录
退出登录分两种类型:主动退出登录和被动退出登录。
主动退出登录:调用SDK的退出接口;
被动退出登录:1.正在登录的账号在另一台设备上登录;2.正在登录的账号被从服务器端删除。
#import"SettingsController.h"
#import"EMSDK.h"
@interfaceSettingsController()
@property(weak,nonatomic)IBOutletUIButton*loginOut;
@end
@implementationSettingsController
- (void)viewDidLoad {
[superviewDidLoad];
//获得当前登录的用户名
NSString*loginUsername = [EMClientsharedClient].currentUsername;
[[EMClientsharedClient]addDelegate:selfdelegateQueue:nil];
//1.设置退出按钮的文字
[self.loginOutsetTitle:titleforState:UIControlStateNormal];
}
//点击退出登录
- (IBAction)loginOut:(id)sender {
//logout:YES:是否解除device token的绑定,在被动退出时SDK内部处理,不需要调用退出方法。
EMError*error = [[EMClientsharedClient]logout:YES];
if(!error) {
NSLog(@"退出成功");
//回到登录界面
self.view.window.rootViewController= [UIStoryboardstoryboardWithName:@"Login"bundle:nil].instantiateInitialViewController;
}else{
}
}
//当前登录账号在其它设备登录时会接收到此回调
- (void)userAccountDidLoginFromOtherDevice{
}
//当前登录账号已经被从服务器端删除时会收到该回调
- (void)userAccountDidRemoveFromServer{
}
@end
小结:使用环信思想:
a.所有网络请求使用[EMClientsharedClient]环信客户端
b.结果(自动登录/自动连接)通过代理来回调,通过[EMClientsharedClient]的- (void)addDelegate:(id)delegate
delegateQueue:(dispatch_queue_t)queue;方法来添加代理
好友管理
总结:
a.所有请求都使用[EMClient sharedClient].contactManager联系人管理者对象
b.该对象的方法都在IEMContactManager中
添加代理方法为:addDelegate:(id)aDelegatedelegateQueue:(dispatch_queue_t)aQueue;
c.代理方法都在EMContactManagerDelegate协议中
9.发送好友请求
实现步骤:
创建添加好友控制器(addfriendController),由通讯录右上角点击”+”号时,跳到该控制器.在该控制器中输入好友名称,点击添加即可发送添加请求.
点击添加按钮:
//发送好友请求,
如果您已经发过,并且对方没有处理,您将不能再次发送
- (IBAction)addFriend:(id)sender {
//1.获取要添加的好友名字
NSString*friendName=self.friendNameTextfield.text;
//2.向服务器发送添加好球请求
EMError*error = [[EMClientsharedClient].contactManageraddContact:friendNamemessage:@"我想加您为好友"];
if(!error) {
NSLog(@"添加成功");
}
}
//监听对方有没有接收我的好友请求
注意
1.该步骤最好放在会话控制器(conversation),因为若对方已经处理(同意或者拒绝)我发送的请求,我一登录app就因该弹出处理结果.
2.添加联系人管理器的代理时,在控制器被dealloc的时候,应该移除代理(非常重要)
补充:只要是单粒的都要这样做,因为若在不同的代理控制器中实现了相同的代理方法,那么该方法都会调用
分别给各个地方添加
-(void)dealloc{
[[EMClientsharedClient]removeDelegate:self];}
步骤:
在会话控制器中:
viewdidload中添加代理,并遵守代理协议
//1.设置联系人管理者代理
[[EMClientsharedClient].contactManageraddDelegate:selfdelegateQueue:nil];
//2.监听代理方法
#pragma mark -EMContactManagerDelegate
//好友请求被同意
- (void)didReceiveAgreedFromUsername:(NSString*)aUsername{
//提醒用户,好友请求被同意
NSString*message = [NSStringstringWithFormat:@"%@同意了你的好友请求",aUsername];
UIAlertView*alert = [[UIAlertViewalloc]initWithTitle:@"好友添加消息"message:messagedelegate:nilcancelButtonTitle:@"知道了"otherButtonTitles:nil,nil];
[alertshow];
}
//好友请求被拒绝
- (void)didReceiveDeclinedFromUsername:(NSString*)aUsername{
//提醒用户,好友请求被同意
NSString*message = [NSStringstringWithFormat:@"%@拒绝了你的好友请求",aUsername];
UIAlertView*alert = [[UIAlertViewalloc]initWithTitle:@"好友添加消息"message:messagedelegate:nilcancelButtonTitle:@"知道了"otherButtonTitles:nil,nil];
[alertshow];
}
//3.移除代理
-(void)dealloc{
[[EMClientsharedClient]removeDelegate:self];
[[EMClientsharedClient].contactManagerremoveDelegate:self];
}
10.处理好友的请求(同意/拒绝)
当然也是放在会话控制器了
步骤:
//1.给控制器添加一个属性,接收好友的名字
/**好友的名称*/
@property(nonatomic,copy)NSString*buddyUsername;
//2.监听到好友的添加请求
//用户A发送加用户B为好友的申请,用户B会收到这个回调
-(void)didReceiveFriendInvitationFromUsername:(NSString*)aUsername message:(NSString*)aMessage{
self.buddyUsername= aUsername;
//弹出对话框
UIAlertView*alert = [[UIAlertViewalloc]initWithTitle:@"好友添加请求"message:aMessagedelegate:selfcancelButtonTitle:@"拒绝"otherButtonTitles:@"同意",nil];
[alertshow];
}
//3.让控制器遵守UIAlertViewDelegate代理监听点击
-(void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex ==0) {//4.拒绝好友请求
EMError*error = [[EMClientsharedClient].contactManagerdeclineInvitationForUsername:self.buddyUsername];
if(!error) {
NSLog(@"发送拒绝成功");
}
}else{//5.同意好友请求
EMError*error = [[EMClientsharedClient].contactManageracceptInvitationForUsername:self.buddyUsername];
if(!error) {
NSLog(@"发送同意成功");
}
}
}
11.获取好友列表(注意此地与2.x版本有很大不同)
新建通讯录控制器AddressBookViewController,修改mainstoryboard中的对应的控制器class改为该类,同时给cell填写重用标识为boddycell,将官方demo中的图片文件拖到该项目
#import"AddressBookViewController.h"
#import"EMSDK.h"
@interfaceAddressBookViewController()
//添加数据源数组
@property(nonatomic,strong)NSArray*boddyList;
@end
@implementationAddressBookViewController
- (void)viewDidLoad {
[superviewDidLoad];
//获取好友列表数据
/*注意
* 1.buddyList的数据是从本地数据库获取(此时的本地数据库指的是沙盒中larbary)
* 2.如果当前有添加好友请求,环信的SDK内部会往数据库的buddy表添加好友记录(也就是说,此时会自动向服务器获取好友列表)
* 3.如果程序删除或者用户第一次登录,buddyList表是没记录,
解决方案
1.先从从本地数据库获取好友列表
2.若本地没有再从远程获取
*/
//先从从本地数据库获取好友列表
self.boddyList= [[EMClientsharedClient].contactManagergetContacts];
//若本地没有再从远程获取
if(self.boddyList.count==0) {
//得到的为一个字符串数组
EMError*error =nil;
self.boddyList= [[EMClientsharedClient].contactManagergetContactsFromServerWithError:&error];
}
NSLog(@"====%@",self.boddyList);
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
returnself.boddyList.count;
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
staticNSString*ID =@"boddyCell";
UITableViewCell*cell = [tableViewdequeueReusableCellWithIdentifier:ID];
//1.获取好友模型
NSString*buddyName =self.boddyList[indexPath.row];
cell.textLabel.text= buddyName;
cell.imageView.image=[UIImageimageNamed:@"chatListCellHead"];
returncell;
}
12.邀请对方为好友,对方同意后,要刷新我的好友列表
将app的初始化SDK中的appkey替换为官方demo的appkey,然后和官方demo进行联调
步骤:在通讯录控制器AddressBookViewController进行操作
//1.添加代理
[[EMClientsharedClient].contactManageraddDelegate:selfdelegateQueue:nil];
//2.代理方法的实现
//监听到对方同意我为好友,刷新好友列表
//用户B同意用户A的加好友请求后,用户A会收到这个回调
//此时,系统会自动向环信服务器获取新的好友列表加载到本地服务器,因此我们只需到本地服务器获取新的好友列表即可
- (void)friendRequestDidApproveByUser:(NSString*)aUsername{
//从本地数据库获取好友列表
self.boddyList= [[EMClientsharedClient].contactManagergetContacts];
NSLog(@"====%@",self.boddyList);
[self.tableViewreloadData];
}
13.删除好友
通讯录控制器AddressBookViewController进行操作
//1.只要实现该方法就回出现左滑删除
-(void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath{
NSString*friendName =self.boddyList[indexPath.row];
if(editingStyle ==UITableViewCellEditingStyleDelete) {
//删除好友
EMError*error = [[EMClientsharedClient].contactManagerdeleteContact:friendName];
if(!error) {
NSLog(@"删除成功");
//从本地获取好友列表
self.boddyList= [[EMClientsharedClient].contactManagergetContacts];
[self.tableViewreloadData];
}
}
}
//2.监听自己被好友删除
//该方法也要在会话控制器写一份,我一登录就能看见对方把我删除的消息
- (void)friendshipDidRemoveByUser:(NSString*)aUsername{
NSLog(@"你已经被好友%@删除了",aUsername);
//从本地获取好友列表
self.boddyList= [[EMClientsharedClient].contactManagergetContacts];
[self.tableViewreloadData];
}
//3.会话控制器ConversationController
//监听自己被好友删除
- (void)friendshipDidRemoveByUser:(NSString*)aUsername{
NSLog(@"你已经被好友%@删除了",aUsername);
NSString*message = [aUsernamestringByAppendingString:@"把你删除"];
UIAlertView*alert = [[UIAlertViewalloc]initWithTitle:@"xxxx"message:messagedelegate:nilcancelButtonTitle:@"知道了"otherButtonTitles:nil,nil];
[alertshow];
}
界面搭建在环信开发(三)