研究環信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 () <EMChatManagerDelegate>
@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 () <EMChatManagerDelegate>
@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 () <EMChatManagerDelegate>
@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,希望能幫到遇到困難的網友~