研究环信SDK也有一段时间了,之前看了下环信的官方文档,写的很详细,我们只需要照葫芦画瓢就可以了,但是要独立的完成以款即时通讯的app难度还是很大的,因为需要考虑的地方太多,工作量也很大,楼主上个月辞职了,正好可以静下心来好好研究一下技术,当然做完这个项目还是要继续找工作的(说到这里 不得不吐槽一下,找工作的人真多呀),话不多说,开干,我会每天在上更新,希望在成长自己的同时能帮到一些朋友~
- 集成环信SDK,集成这一步官方文档都写的很清楚了,我就不再赘述:
- SDK下载地址http://www.easemob.com/download/im
- 官方文档:http://docs.easemob.com/start/300iosclientintegration/20iossdkimport
-
集成完后我们需要删除两个东西,这两个是轻量级的SDK,里面功能有限,适合简单的测试,我们这里用完整版本的,所以我们进入项目原文件把这两个东西干掉:
-
这里要注意一下,如果删除了轻量级的SDK,前面的配置就不能用这个轻量级的,必须用完整版的
- 万事俱备,可以开干!,首先导入头文件然后再初始化SDK,这些操作都在
AppDelegate.m
中: - 导入头文件
#import "EaseMob.h"
- 初始化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/**
* @prama registerSDKWithAppKey 环信官网的appKey
* @prama apnsCertName 苹果官网注册的推送证书,楼主没有申请99刀,嘿嘿,这里就不用啦
* @prama otherConfig
*/
[[EaseMob sharedInstance] registerSDKWithAppKey:kEaseMobAppKey
apnsCertName:nil
otherConfig:nil];
return YES;
}
- 集成完SDK后,先做生命周期的跟踪
- 启动
- 进入后台
- 从后台进入前台
- 销毁
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/**
* @prama registerSDKWithAppKey 环信官网的appKey
* @prama apnsCertName 苹果官网注册的推送证书,楼主没有申请99刀,嘿嘿,这里就不用啦
* @prama otherConfig
*/
[[EaseMob sharedInstance] registerSDKWithAppKey:kEaseMobAppKey
apnsCertName:nil
otherConfig:nil];
// 启动
[[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 进入后台
[[EaseMob sharedInstance] applicationDidEnterBackground:application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 从后台进入前台
[[EaseMob sharedInstance] applicationWillEnterForeground:application];
}
- (void)applicationWillTerminate:(UIApplication *)application {
// 销毁
[[EaseMob sharedInstance] applicationWillTerminate:application];
}
-
搭建登录注册界面,完成拖线:
注册
- 注册模式分两种,开放注册和授权注册。只有开放注册时,才可以客户端注册。
- 开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号,授权注册的流程应该是您服务器通过环信提供的 REST API 注册,之后保存到您的服务器或返回给客户端。
- 注册提供了三种方法,在这里我们选择第三种(IChatManagerDelegate 回调方法).
- 注册步骤: 调用注册接口 -> 添加代理 -> 遵守协议 -> 监听回调方法,
ViewController.m
中代码如下:
//
// ViewController.m
// EMWeiChat
//
// Created by admin on 16/11/4.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "ViewController.h"
#import "EaseMob.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameLabel;
@property (weak, nonatomic) IBOutlet UITextField *pwdLabel;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 添加代理
[[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil];
}
// 登录
- (IBAction)loginBtn:(id)sender {
}
// 注册(代理回调方法注册)
- (IBAction)registerBtn:(id)sender {
// 接口调用
[[EaseMob sharedInstance].chatManager asyncRegisterNewAccount:self.usernameLabel.text password:self.pwdLabel.text];
}
// 监听回调方法
- (void)didRegisterNewAccount:(NSString *)username password:(NSString *)password error:(EMError *)error
{
NSLog(@"%s", __func__);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
- 运行程序,输入注册的账号和密码:
-
我们再去环信后台看看是否注册成功
登录
- 登录:调用 SDK 的登录接口进行的操作。
- 提供了三种方法,这里我们采用第二种方法(block 异步方法):
// 登录
- (IBAction)loginBtn:(id)sender {
[[EaseMob sharedInstance].chatManager asyncLoginWithUsername:self.usernameLabel.text password:self.pwdLabel.text completion:^(NSDictionary *loginInfo, EMError *error) {
if (!error && loginInfo) {
NSLog(@"登录成功");
}
} onQueue:nil];
}
- 登录过后而已看到登录成功,但是这里也打印了一些xmpp控制台的输出信息,我们可以把它屏蔽掉
- 屏蔽方法:来到
AppDelegate.m
:我们初始化SDK的时候有个参数是otherConfig
,点击该方法可以看到右边的解释:
- 把该参数改为@NO,就可以屏蔽啦~
退出登录
退出登录分两种类型:主动退出登录和被动退出登录。
主动退出登录:调用SDK的退出接口;
被动退出登录:1. 正在登录的账号在另一台设备上登录;2. 正在登录的账号被从服务器端删除。
退出登录提供了三种方法,这里用第二种(block 异步方法)
logoffWithUnbindDeviceToken:是否解除 device token 的绑定,在被动退出时传 NO,在主动退出时传 YES。
#pragma mark - 退出登录
- (IBAction)loginOut:(id)sender {
/*
asyncLogoffWithUnbindDeviceToken:
主动退出的时候,传YES
被动退出的时候,传NO
被动退出:
其他设备登录
被服务器移除
// 退出,传入YES,会解除device token绑定,不再收到群消息;传NO,不解除device token
*/
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:YES completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"退出成功");
}
} onQueue:nil];
}
// 从其他设备登录
- (void)didLoginFromOtherDevice
{
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"从其他设备登录");
}
} onQueue:nil];
}
// 被服务器移除
- (void)didRemovedFromServer
{
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"被服务器移除");
}
} onQueue:nil];
}
自动重连
- 当掉线时,iOS SDK 会自动重连,只需要监听重连相关的回调,无需进行任何操作。
#pragma mark - 自动重连
/*!
@method
@brief 将要发起自动重连操作时发送该回调
@discussion
@result
*/
- (void)willAutoReconnect
{
NSLog(@"将要自动重连");
}
/*!
@method
@brief 自动重连操作完成后的回调(成功的话,error为nil,失败的话,查看error的错误信息)
@discussion
@result
*/
- (void)didAutoReconnectFinishedWithError:(NSError *)error
{
if (!error) {
NSLog(@"自动重连成功");
}
}
- 在这里呢,我连接成功后就拔掉电脑网线模拟掉线的情况,然后再插上网线,可以看到控制台打印:
自动登录
- 自动登录:即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息。
- SDK 中自动登录属性默认是关闭的,需要您在登录成功后设置,以便您在下次 APP 启动时不需要再次调用环信登录,并且能在没有网的情况下得到会话列表。
- 在登录成功后设置自动登录
// 登录
- (IBAction)loginBtn:(id)sender {
[[EaseMob sharedInstance].chatManager asyncLoginWithUsername:self.usernameLabel.text password:self.pwdLabel.text completion:^(NSDictionary *loginInfo, EMError *error) {
if (!error && loginInfo) {
NSLog(@"登录成功");
// 设置自动登录
[[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES];
}
} onQueue:nil];
}
-
自动登录在以下几种情况下会被取消:
用户调用了 SDK 的登出动作;
用户在别的设备上更改了密码,导致此设备上自动登录失败;
用户的账号被从服务器端删除;
用户从另一个设备登录,把当前设备上登录的用户踢出。 所以,在您调用登录方法前,应该先判断是否设置了自动登录,如果设置了,则不需要您再调用。
我们在
AppDelegate.m
的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中判断:
BOOL isAutoLogin = [[EaseMob sharedInstance].chatManager isAutoLoginEnabled];
if (isAutoLogin) {
NSLog(@"切换根控制器");
}
- SDK中,如果发生自动登录,会有以下回调:
#pragma mark - 自动登录
- (void)willAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
NSLog(@"将要自动登录");
}
- (void)didAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
NSLog(@"已经自动登录");
}
接下来我们就要进行微信框架的搭建了
- 首先导入素材,设置AppIcon和LaunchImage, 这两步比较简单,我就不细讲了,如果有不清楚的朋友可以留言.如果大家有需要,后面我会讲一下怎样获取到微信里面的图片素材,之前有很多网友说Assets.car里面的素材拿不到,别担心,总是有方法的,后面再一一讲解,我们现在主要把精力放在即时通讯上面,素材我也会贴上来的~
微信架构搭建,这里我采用纯代码,storyboard适合页面多的时候,像这种复杂的界面建议用纯代码加xib.
-
进入文件夹,重构一下文件,大家个人重构习惯自由发挥
把文件拖入到工程中,注意我们之前在build setting中设置了Other Linker Flags,在我们重构文件夹的时候改变了路径,所以运行会报错:找不到libEaseMobClientSDK.a文件,所以我们需要再来到Other Linker Flags重新指定一下路径:
- 创建文件:
(tabBar)LHLTabBarController->UITabBarController
(导航条)LHLNavViewController->UINavigationController
(微信模块)LHLChatViewController->UITableViewController
(联系人模块)LHLContactViewController->UITableViewController
(发现模块)LHLDiscoverViewController->UITableViewController
(我模块)LHLMeViewController->UITableViewController
(登录)LHLLoginViewController->UIViewController
- 之前测试的功能我们全部重新写一遍(比如登录注册...):
AppDelegate.m
中:
//
// AppDelegate.m
// EMWeiChat
//
// Created by admin on 16/11/4.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "AppDelegate.h"
#define kEaseMobAppKey @"lengleng#lengleng"
#import "LHLTabBarController.h"
#import "LHLLoginViewController.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/**
* @prama registerSDKWithAppKey 环信官网的appKey
* @prama apnsCertName 苹果官网注册的推送证书,楼主没有申请99刀,嘿嘿,这里就不用啦
* @prama otherConfig
*/
// 1.注册APPKey
[[EaseMob sharedInstance] registerSDKWithAppKey:kEaseMobAppKey
apnsCertName:nil
otherConfig:@{kSDKConfigEnableConsoleLogger : @NO}];
// 2.跟踪app生命周期
[[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
// 3.添加监听代理
[[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil];
// 4.判断是否是自动登录
BOOL isAutoLogin = [[EaseMob sharedInstance].chatManager isAutoLoginEnabled];
if (isAutoLogin) {
NSLog(@"已经设置自动登录,切换根控制器");
// 1.显示正在自动登录
[SVProgressHUD showWithStatus:@"正在自动登录中..."];
// 2.在 didAutoLoginWithInfo 方法中切换至主页面
}
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 进入后台
[[EaseMob sharedInstance] applicationDidEnterBackground:application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 从后台进入前台
[[EaseMob sharedInstance] applicationWillEnterForeground:application];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
// 销毁
[[EaseMob sharedInstance] applicationWillTerminate:application];
// 移除代理
[[EaseMob sharedInstance].chatManager removeDelegate:self];
}
#pragma mark - 自动登录
- (void)didAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
[SVProgressHUD dismiss];
if (error) { // 显示错误信息,不登录
[JDStatusBarNotification showWithStatus:error.description dismissAfter:2.0];
}else // 切换窗口根控制器
{
LHLTabBarController *tabBarVc = [[LHLTabBarController alloc] init];
self.window.rootViewController = tabBarVc;
[self.window makeKeyAndVisible];
}
}
#pragma mark - 监听被动退出
- (void)didRemovedFromServer
{
NSLog(@"账号被服务器删除");
[self lhl_LogOffPassively];
}
- (void)didLoginFromOtherDevice
{
NSLog(@"从其他设备登录");
[self lhl_LogOffPassively];
}
#pragma mark - 被动LogOff
- (void)lhl_LogOffPassively
{
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) {
// 被动退出后回调, 切换根控制器
LHLLoginViewController *loginVC = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"LHLLoginViewController"];
self.window.rootViewController = loginVC;
} onQueue:nil];
}
@end
LHLTabBarController.m
中:
//
// LHLTabBarController.m
// EMWeiChat
//
// Created by admin on 16/11/6.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLTabBarController.h"
#import "LHLChatViewController.h"
#import "LHLContactViewController.h"
#import "LHLDiscoverViewController.h"
#import "LHLMeViewController.h"
#import "LHLNavViewController.h"
@interface LHLTabBarController ()
@end
@implementation LHLTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
// 创建所有子控制器
[self setUpChildViewControllers];
// 设置tabBar按钮和标题
[self setUpAllTitles];
}
- (void)setUpChildViewControllers
{
// 微信
LHLChatViewController *chatVC = [[LHLChatViewController alloc] init];
LHLNavViewController *nav = [[LHLNavViewController alloc] initWithRootViewController:chatVC];
[self addChildViewController:nav];
// 通讯录
LHLContactViewController *contactVc = [[LHLContactViewController alloc] init];
LHLNavViewController *nav1 = [[LHLNavViewController alloc] initWithRootViewController:contactVc];
[self addChildViewController:nav1];
// 发现
LHLDiscoverViewController *discoverVC = [[LHLDiscoverViewController alloc] init];
LHLNavViewController *nav2 = [[LHLNavViewController alloc] initWithRootViewController:discoverVC];
[self addChildViewController:nav2];
// 我
LHLMeViewController *meVC = [[UIStoryboard storyboardWithName:@"LHLMeViewController" bundle:nil] instantiateViewControllerWithIdentifier:@"LHLMeViewController"];
LHLNavViewController *nav3 = [[LHLNavViewController alloc] initWithRootViewController:meVC];
[self addChildViewController:nav3];
}
- (void)setUpAllTitles
{
// 设置按钮的标题和图片
LHLNavViewController *nav = self.childViewControllers[0];
[nav setTabBarItemImage:@"tabbar_mainframe" selectImage:@"tabbar_mainframeHL" title:@"微信"];
LHLNavViewController *nav1 = self.childViewControllers[1];
[nav1 setTabBarItemImage:@"tabbar_contacts" selectImage:@"tabbar_contactsHL" title:@"通讯录"];
LHLNavViewController *nav2 = self.childViewControllers[2];
[nav2 setTabBarItemImage:@"tabbar_discover" selectImage:@"tabbar_discoverHL" title:@"发现"];
LHLNavViewController *nav3 = self.childViewControllers[3];
[nav3 setTabBarItemImage:@"tabbar_me" selectImage:@"tabbar_meHL" title:@"我"];
}
@end
LHLNavViewController.m
中:
//
// LHLNavViewController.m
// EMWeiChat
//
// Created by admin on 16/11/6.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLNavViewController.h"
@interface LHLNavViewController ()
@end
@implementation LHLNavViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 设置导航栏背景颜色
[self.navigationBar lhl_setBackgroundColor:[UIColor blackColor]];
// 修改左右UIBarButtonItem主题色
self.navigationBar.tintColor = [UIColor whiteColor];
// 修改标题颜色
[self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}];
}
// 设置状态栏颜色
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)setTabBarItemImage:(NSString *)image selectImage:(NSString *)selectImage title:(NSString *)title
{
self.tabBarItem.image = [UIImage imageOriginalWithName:image];
self.tabBarItem.selectedImage = [UIImage imageOriginalWithName:selectImage];
self.title = title;
[self.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor colorWithRed:9 green:187 blue:7]} forState:UIControlStateSelected];
}
@end
- 到这里,基本架构已经搭建完毕我们现在做登录模块,这里直接用了系统的storyboard搭建登录界面
LHLLoginViewController.m
中:
//
// ViewController.m
// EMWeiChat
//
// Created by admin on 16/11/4.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLLoginViewController.h"
#import "LHLTabBarController.h"
@interface LHLLoginViewController ()
@property (weak, nonatomic) IBOutlet UITextField *usernameLabel;
@property (weak, nonatomic) IBOutlet UITextField *pwdLabel;
@end
@implementation LHLLoginViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 获取到保存的用户名
NSString *lastUser = [[NSUserDefaults standardUserDefaults] valueForKeyPath:@"username"];
if (lastUser) {
self.usernameLabel.text = lastUser;
}
}
// 登录
- (IBAction)loginBtn:(id)sender {
[SVProgressHUD showWithStatus:@"登录中..."];
[[EaseMob sharedInstance].chatManager asyncLoginWithUsername:self.usernameLabel.text password:self.pwdLabel.text completion:^(NSDictionary *loginInfo, EMError *error) {
[SVProgressHUD dismiss];
if (!error) {
NSLog(@"登录成功");
// 1.设置自动登录
[[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES];
[JDStatusBarNotification showWithStatus:@"登录成功!" dismissAfter:2.0 styleName:JDStatusBarStyleSuccess];
// 2.切换至主页面
LHLTabBarController *tabBarVc = [[LHLTabBarController alloc] init];
[UIApplication sharedApplication].keyWindow.rootViewController = tabBarVc;
}else
{
NSLog(@"error: %@", error);
[JDStatusBarNotification showWithStatus:[NSString stringWithFormat:@"登录失败!"] dismissAfter:2.0 styleName:JDStatusBarStyleError];
}
} onQueue:nil];
}
// 注册(代理回调方法注册)
- (IBAction)registerBtn:(id)sender {
[SVProgressHUD showWithStatus:@"注册中..."];
// 接口调用
[[EaseMob sharedInstance].chatManager asyncRegisterNewAccount:self.usernameLabel.text password:self.pwdLabel.text withCompletion:^(NSString *username, NSString *password, EMError *error) {
[SVProgressHUD dismiss];
if (!error) {
NSLog(@"注册成功 : username = %@ password = %@", error, password);
[JDStatusBarNotification showWithStatus:@"注册成功,请登录!" dismissAfter:2.0 styleName:JDStatusBarStyleSuccess];
}else
{
NSLog(@"error : %@", error);
[JDStatusBarNotification showWithStatus:[NSString stringWithFormat:@"注册失败!"] dismissAfter:2.0 styleName:JDStatusBarStyleError];
}
} onQueue:nil];
}
@end
- 微信模块
LHLChatViewController.m
中:
//
// LHLChatViewController.m
// EMWeiChat
//
// Created by admin on 16/11/6.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLChatViewController.h"
/**
在微信中,它的微信界面的标题切换的是 titleView
除了下面4种状态,还有
听筒模式
未读消息数量展示
等等
此处我们通过简单的模仿,来了解 连接状态改变,以及消息接收带来的对标题view的影响
*/
NSString * const LHLWeChatTitleNormal = @"微信";
NSString * const LHLWeChatTitleWillConnect = @"连接中...";
NSString * const LHLWeChatTitleDisconnect = @"微信(未连接)";
NSString * const LHLWeChatTitleWillReceiveMsg = @"收取中...";
@interface LHLChatViewController ()
@end
@implementation LHLChatViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = LHLWeChatTitleNormal;
[[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
#warning Incomplete implementation, return the number of sections
return 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
#warning Incomplete implementation, return the number of rows
return 0;
}
/*
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:<#@"reuseIdentifier"#> forIndexPath:indexPath];
// Configure the cell...
return cell;
}
*/
#pragma mark - 自动重连
/*!
@method
@brief 将要发起自动重连操作时发送该回调
@discussion
@result
*/
- (void)willAutoReconnect
{
NSLog(@"将要自动重连");
self.title = LHLWeChatTitleWillConnect;
}
/*!
@method
@brief 自动重连操作完成后的回调(成功的话,error为nil,失败的话,查看error的错误信息)
@discussion
@result
*/
- (void)didAutoReconnectFinishedWithError:(NSError *)error
{
if (!error) {
NSLog(@"自动重连成功");
self.title = LHLWeChatTitleNormal;
}else
{
NSLog(@"自动重连失败");
self.title = LHLWeChatTitleDisconnect;
}
}
#pragma mark - 连接状态改变
- (void)didConnectionStateChanged:(EMConnectionState)connectionState
{
switch (connectionState) {
case eEMConnectionConnected: // 连接成功
{
self.title = LHLWeChatTitleNormal;
}
break;
case eEMConnectionDisconnected: // 未连接
{
self.title = LHLWeChatTitleDisconnect;
}
break;
default:
break;
}
}
#pragma mark - 移除代理
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[EaseMob sharedInstance].chatManager removeDelegate:self];
}
@end
- 通讯录模块
LHLContactViewController.m
中:
//
// LHLContactViewController.m
// EMWeiChat
//
// Created by admin on 16/11/6.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLContactViewController.h"
@interface LHLContactViewController ()
/** 本地的好友列表 */
@property (nonatomic, strong) NSMutableArray *friends;
/** 服务器获取的好友列表 */
@property (nonatomic, strong) NSArray *buddies;
@end
@implementation LHLContactViewController
static NSString *cellID = @"UITableViewCell";
- (NSMutableArray *)friends
{
// 好友列表(由EMBuddy对象组成)
if (_friends == nil) {
_friends = [NSMutableArray array];
_buddies = [[EaseMob sharedInstance].chatManager buddyList];
if (_buddies.count) {
[_friends addObjectsFromArray:_buddies];
}
}
return _friends;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"通讯录";
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"contacts_add_friend"] style:UIBarButtonItemStylePlain target:self action:@selector(addFriend)];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID];
}
- (void)addFriend
{
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:@"添加好友" message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertVC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"请输入账号";
}];
[alertVC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"请输入理由";
}];
[alertVC addAction:[UIAlertAction actionWithTitle:@"发送" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
EMError *error = nil;
BOOL isSuccess = [[EaseMob sharedInstance].chatManager addBuddy:alertVC.textFields.firstObject.text message:alertVC.textFields.lastObject.text error:&error];
if (!error) {
NSLog(@"发送好友请求成功 - %d", isSuccess);
}
}]];
[alertVC addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
// 取消添加
}]];
[self presentViewController:alertVC animated:YES completion:^{
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.friends.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
EMBuddy *buddy = self.friends[indexPath.row];
cell.textLabel.text = buddy.username;
return cell;
}
@end
- 我的模块也是结合了storyboard,利用静态cell搭建一些固定不变的界面真的很便捷
-
LHLMeViewController.m
中:
//
// LHLMeViewController.m
// EMWeiChat
//
// Created by admin on 16/11/6.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLMeViewController.h"
#import "LHLSettingViewController.h"
@interface LHLMeViewController ()
@property (weak, nonatomic) IBOutlet UILabel *username;
@end
@implementation LHLMeViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.title = @"我";
self.username.text = [[EaseMob sharedInstance].chatManager loginInfo][@"username"];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 3) {
LHLSettingViewController *settingVC = [[UIStoryboard storyboardWithName:@"LHLSettingViewController" bundle:nil] instantiateViewControllerWithIdentifier:@"LHLSettingViewController"];
self.hidesBottomBarWhenPushed = YES;
[self.navigationController pushViewController:settingVC animated:YES];
self.hidesBottomBarWhenPushed = NO;
}
}
@end
- ```LHLSettingViewController.m`` 中
//
// LHLSettingViewController.m
// EMWeiChat
//
// Created by admin on 16/11/6.
// Copyright © 2016年 冷洪林. All rights reserved.
//
#import "LHLSettingViewController.h"
#import "LHLLoginViewController.h"
@interface LHLSettingViewController ()
@end
@implementation LHLSettingViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
// 退出登录
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section == 3) {
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:YES completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"退出登录");
// 1.记录退出的用户名(为了用户再次登录的时候不用重新输入用户名.optional)
[[NSUserDefaults standardUserDefaults] setObject: [[EaseMob sharedInstance].chatManager loginInfo][@"username"] forKey:@"username"];
// 2.切换窗口根控制器
LHLLoginViewController *loginVC = [[UIStoryboard storyboardWithName:@"Main" bundle:nil] instantiateViewControllerWithIdentifier:@"LHLLoginViewController"];
[UIApplication sharedApplication].keyWindow.rootViewController = loginVC;
}else
{
NSLog(@"error : %@", error);
}
} onQueue:nil];
}
}
@end
-
有网友提到官方SDK集成的问题,我之前以为大家跟着官方文档一步步来就会没问题的,所以文章开头就直接放了官方文档的连接,鉴于网友们的问题,我接下来就从零开始集成环信SDK 2.x 和 3.x,希望能帮到遇到困难的网友~