研究環(huán)信SDK也有一段時(shí)間了,之前看了下環(huán)信的官方文檔,寫(xiě)的很詳細(xì),我們只需要照葫蘆畫(huà)瓢就可以了,但是要獨(dú)立的完成以款即時(shí)通訊的app難度還是很大的,因?yàn)樾枰紤]的地方太多,工作量也很大,樓主上個(gè)月辭職了,正好可以靜下心來(lái)好好研究一下技術(shù),當(dāng)然做完這個(gè)項(xiàng)目還是要繼續(xù)找工作的(說(shuō)到這里 不得不吐槽一下,找工作的人真多呀),話不多說(shuō),開(kāi)干,我會(huì)每天在簡(jiǎn)書(shū)上更新,希望在成長(zhǎng)自己的同時(shí)能幫到一些朋友~
- 集成環(huán)信SDK,集成這一步官方文檔都寫(xiě)的很清楚了,我就不再贅述:
- SDK下載地址http://www.easemob.com/download/im
- 官方文檔:http://docs.easemob.com/start/300iosclientintegration/20iossdkimport
-
集成完后我們需要?jiǎng)h除兩個(gè)東西,這兩個(gè)是輕量級(jí)的SDK,里面功能有限,適合簡(jiǎn)單的測(cè)試,我們這里用完整版本的,所以我們進(jìn)入項(xiàng)目原文件把這兩個(gè)東西干掉:
-
這里要注意一下,如果刪除了輕量級(jí)的SDK,前面的配置就不能用這個(gè)輕量級(jí)的,必須用完整版的
- 萬(wàn)事俱備,可以開(kāi)干!,首先導(dǎo)入頭文件然后再初始化SDK,這些操作都在
AppDelegate.m
中: - 導(dǎo)入頭文件
#import "EaseMob.h"
- 初始化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/**
* @prama registerSDKWithAppKey 環(huán)信官網(wǎng)的appKey
* @prama apnsCertName 蘋(píng)果官網(wǎng)注冊(cè)的推送證書(shū),樓主沒(méi)有申請(qǐng)99刀,嘿嘿,這里就不用啦
* @prama otherConfig
*/
[[EaseMob sharedInstance] registerSDKWithAppKey:kEaseMobAppKey
apnsCertName:nil
otherConfig:nil];
return YES;
}
- 集成完SDK后,先做生命周期的跟蹤
- 啟動(dòng)
- 進(jìn)入后臺(tái)
- 從后臺(tái)進(jìn)入前臺(tái)
- 銷毀
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/**
* @prama registerSDKWithAppKey 環(huán)信官網(wǎng)的appKey
* @prama apnsCertName 蘋(píng)果官網(wǎng)注冊(cè)的推送證書(shū),樓主沒(méi)有申請(qǐng)99刀,嘿嘿,這里就不用啦
* @prama otherConfig
*/
[[EaseMob sharedInstance] registerSDKWithAppKey:kEaseMobAppKey
apnsCertName:nil
otherConfig:nil];
// 啟動(dòng)
[[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 進(jìn)入后臺(tái)
[[EaseMob sharedInstance] applicationDidEnterBackground:application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 從后臺(tái)進(jìn)入前臺(tái)
[[EaseMob sharedInstance] applicationWillEnterForeground:application];
}
- (void)applicationWillTerminate:(UIApplication *)application {
// 銷毀
[[EaseMob sharedInstance] applicationWillTerminate:application];
}
-
搭建登錄注冊(cè)界面,完成拖線:
注冊(cè)
- 注冊(cè)模式分兩種,開(kāi)放注冊(cè)和授權(quán)注冊(cè)。只有開(kāi)放注冊(cè)時(shí),才可以客戶端注冊(cè)逮矛。
- 開(kāi)放注冊(cè)是為了測(cè)試使用,正式環(huán)境中不推薦使用該方式注冊(cè)環(huán)信賬號(hào)揽咕,授權(quán)注冊(cè)的流程應(yīng)該是您服務(wù)器通過(guò)環(huán)信提供的 REST API 注冊(cè)蟋座,之后保存到您的服務(wù)器或返回給客戶端勉失。
- 注冊(cè)提供了三種方法,在這里我們選擇第三種(IChatManagerDelegate 回調(diào)方法).
- 注冊(cè)步驟: 調(diào)用注冊(cè)接口 -> 添加代理 -> 遵守協(xié)議 -> 監(jiān)聽(tīng)回調(diào)方法,
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 {
}
// 注冊(cè)(代理回調(diào)方法注冊(cè))
- (IBAction)registerBtn:(id)sender {
// 接口調(diào)用
[[EaseMob sharedInstance].chatManager asyncRegisterNewAccount:self.usernameLabel.text password:self.pwdLabel.text];
}
// 監(jiān)聽(tīng)回調(diào)方法
- (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
- 運(yùn)行程序,輸入注冊(cè)的賬號(hào)和密碼:
-
我們?cè)偃キh(huán)信后臺(tái)看看是否注冊(cè)成功
登錄
- 登錄:調(diào)用 SDK 的登錄接口進(jìn)行的操作。
- 提供了三種方法,這里我們采用第二種方法(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];
}
- 登錄過(guò)后而已看到登錄成功,但是這里也打印了一些xmpp控制臺(tái)的輸出信息,我們可以把它屏蔽掉
- 屏蔽方法:來(lái)到
AppDelegate.m
:我們初始化SDK的時(shí)候有個(gè)參數(shù)是otherConfig
,點(diǎn)擊該方法可以看到右邊的解釋:
- 把該參數(shù)改為@NO,就可以屏蔽啦~
退出登錄
退出登錄分兩種類型:主動(dòng)退出登錄和被動(dòng)退出登錄皂林。
主動(dòng)退出登錄:調(diào)用SDK的退出接口朗鸠;
被動(dòng)退出登錄:1. 正在登錄的賬號(hào)在另一臺(tái)設(shè)備上登錄蚯撩;2. 正在登錄的賬號(hào)被從服務(wù)器端刪除础倍。
退出登錄提供了三種方法,這里用第二種(block 異步方法)
logoffWithUnbindDeviceToken:是否解除 device token 的綁定,在被動(dòng)退出時(shí)傳 NO胎挎,在主動(dòng)退出時(shí)傳 YES沟启。
#pragma mark - 退出登錄
- (IBAction)loginOut:(id)sender {
/*
asyncLogoffWithUnbindDeviceToken:
主動(dòng)退出的時(shí)候,傳YES
被動(dòng)退出的時(shí)候,傳NO
被動(dòng)退出:
其他設(shè)備登錄
被服務(wù)器移除
// 退出,傳入YES犹菇,會(huì)解除device token綁定德迹,不再收到群消息;傳NO揭芍,不解除device token
*/
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:YES completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"退出成功");
}
} onQueue:nil];
}
// 從其他設(shè)備登錄
- (void)didLoginFromOtherDevice
{
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"從其他設(shè)備登錄");
}
} onQueue:nil];
}
// 被服務(wù)器移除
- (void)didRemovedFromServer
{
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) {
if (!error) {
NSLog(@"被服務(wù)器移除");
}
} onQueue:nil];
}
自動(dòng)重連
- 當(dāng)?shù)艟€時(shí)胳搞,iOS SDK 會(huì)自動(dòng)重連,只需要監(jiān)聽(tīng)重連相關(guān)的回調(diào)称杨,無(wú)需進(jìn)行任何操作肌毅。
#pragma mark - 自動(dòng)重連
/*!
@method
@brief 將要發(fā)起自動(dòng)重連操作時(shí)發(fā)送該回調(diào)
@discussion
@result
*/
- (void)willAutoReconnect
{
NSLog(@"將要自動(dòng)重連");
}
/*!
@method
@brief 自動(dòng)重連操作完成后的回調(diào)(成功的話,error為nil姑原,失敗的話悬而,查看error的錯(cuò)誤信息)
@discussion
@result
*/
- (void)didAutoReconnectFinishedWithError:(NSError *)error
{
if (!error) {
NSLog(@"自動(dòng)重連成功");
}
}
- 在這里呢,我連接成功后就拔掉電腦網(wǎng)線模擬掉線的情況,然后再插上網(wǎng)線,可以看到控制臺(tái)打印:
自動(dòng)登錄
- 自動(dòng)登錄:即首次登錄成功后,不需要再次調(diào)用登錄方法锭汛,在下次 APP 啟動(dòng)時(shí)笨奠,SDK 會(huì)自動(dòng)為您登錄。并且如果您自動(dòng)登錄失敗唤殴,也可以讀取到之前的會(huì)話信息般婆。
- SDK 中自動(dòng)登錄屬性默認(rèn)是關(guān)閉的,需要您在登錄成功后設(shè)置朵逝,以便您在下次 APP 啟動(dòng)時(shí)不需要再次調(diào)用環(huán)信登錄腺兴,并且能在沒(méi)有網(wǎng)的情況下得到會(huì)話列表。
- 在登錄成功后設(shè)置自動(dòng)登錄
// 登錄
- (IBAction)loginBtn:(id)sender {
[[EaseMob sharedInstance].chatManager asyncLoginWithUsername:self.usernameLabel.text password:self.pwdLabel.text completion:^(NSDictionary *loginInfo, EMError *error) {
if (!error && loginInfo) {
NSLog(@"登錄成功");
// 設(shè)置自動(dòng)登錄
[[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES];
}
} onQueue:nil];
}
-
自動(dòng)登錄在以下幾種情況下會(huì)被取消:
用戶調(diào)用了 SDK 的登出動(dòng)作廉侧;
用戶在別的設(shè)備上更改了密碼页响,導(dǎo)致此設(shè)備上自動(dòng)登錄失敗段誊;
用戶的賬號(hào)被從服務(wù)器端刪除闰蚕;
用戶從另一個(gè)設(shè)備登錄,把當(dāng)前設(shè)備上登錄的用戶踢出连舍。 所以没陡,在您調(diào)用登錄方法前,應(yīng)該先判斷是否設(shè)置了自動(dòng)登錄,如果設(shè)置了盼玄,則不需要您再調(diào)用贴彼。
我們?cè)?code>AppDelegate.m的
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
方法中判斷:
BOOL isAutoLogin = [[EaseMob sharedInstance].chatManager isAutoLoginEnabled];
if (isAutoLogin) {
NSLog(@"切換根控制器");
}
- SDK中,如果發(fā)生自動(dòng)登錄埃儿,會(huì)有以下回調(diào):
#pragma mark - 自動(dòng)登錄
- (void)willAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
NSLog(@"將要自動(dòng)登錄");
}
- (void)didAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
NSLog(@"已經(jīng)自動(dòng)登錄");
}
接下來(lái)我們就要進(jìn)行微信框架的搭建了
- 首先導(dǎo)入素材,設(shè)置AppIcon和LaunchImage, 這兩步比較簡(jiǎn)單,我就不細(xì)講了,如果有不清楚的朋友可以留言.如果大家有需要,后面我會(huì)講一下怎樣獲取到微信里面的圖片素材,之前有很多網(wǎng)友說(shuō)Assets.car里面的素材拿不到,別擔(dān)心,總是有方法的,后面再一一講解,我們現(xiàn)在主要把精力放在即時(shí)通訊上面,素材我也會(huì)貼上來(lái)的~
微信架構(gòu)搭建,這里我采用純代碼,storyboard適合頁(yè)面多的時(shí)候,像這種復(fù)雜的界面建議用純代碼加xib.
-
進(jìn)入文件夾,重構(gòu)一下文件,大家個(gè)人重構(gòu)習(xí)慣自由發(fā)揮
把文件拖入到工程中,注意我們之前在build setting中設(shè)置了Other Linker Flags,在我們重構(gòu)文件夾的時(shí)候改變了路徑,所以運(yùn)行會(huì)報(bào)錯(cuò):找不到libEaseMobClientSDK.a文件,所以我們需要再來(lái)到Other Linker Flags重新指定一下路徑:
- 創(chuàng)建文件:
(tabBar)LHLTabBarController->UITabBarController
(導(dǎo)航條)LHLNavViewController->UINavigationController
(微信模塊)LHLChatViewController->UITableViewController
(聯(lián)系人模塊)LHLContactViewController->UITableViewController
(發(fā)現(xiàn)模塊)LHLDiscoverViewController->UITableViewController
(我模塊)LHLMeViewController->UITableViewController
(登錄)LHLLoginViewController->UIViewController
- 之前測(cè)試的功能我們?nèi)恐匦聦?xiě)一遍(比如登錄注冊(cè)...):
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 環(huán)信官網(wǎng)的appKey
* @prama apnsCertName 蘋(píng)果官網(wǎng)注冊(cè)的推送證書(shū),樓主沒(méi)有申請(qǐng)99刀,嘿嘿,這里就不用啦
* @prama otherConfig
*/
// 1.注冊(cè)APPKey
[[EaseMob sharedInstance] registerSDKWithAppKey:kEaseMobAppKey
apnsCertName:nil
otherConfig:@{kSDKConfigEnableConsoleLogger : @NO}];
// 2.跟蹤app生命周期
[[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
// 3.添加監(jiān)聽(tīng)代理
[[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil];
// 4.判斷是否是自動(dòng)登錄
BOOL isAutoLogin = [[EaseMob sharedInstance].chatManager isAutoLoginEnabled];
if (isAutoLogin) {
NSLog(@"已經(jīng)設(shè)置自動(dòng)登錄,切換根控制器");
// 1.顯示正在自動(dòng)登錄
[SVProgressHUD showWithStatus:@"正在自動(dòng)登錄中..."];
// 2.在 didAutoLoginWithInfo 方法中切換至主頁(yè)面
}
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 進(jìn)入后臺(tái)
[[EaseMob sharedInstance] applicationDidEnterBackground:application];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 從后臺(tái)進(jìn)入前臺(tái)
[[EaseMob sharedInstance] applicationWillEnterForeground:application];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
// 銷毀
[[EaseMob sharedInstance] applicationWillTerminate:application];
// 移除代理
[[EaseMob sharedInstance].chatManager removeDelegate:self];
}
#pragma mark - 自動(dòng)登錄
- (void)didAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
[SVProgressHUD dismiss];
if (error) { // 顯示錯(cuò)誤信息,不登錄
[JDStatusBarNotification showWithStatus:error.description dismissAfter:2.0];
}else // 切換窗口根控制器
{
LHLTabBarController *tabBarVc = [[LHLTabBarController alloc] init];
self.window.rootViewController = tabBarVc;
[self.window makeKeyAndVisible];
}
}
#pragma mark - 監(jiān)聽(tīng)被動(dòng)退出
- (void)didRemovedFromServer
{
NSLog(@"賬號(hào)被服務(wù)器刪除");
[self lhl_LogOffPassively];
}
- (void)didLoginFromOtherDevice
{
NSLog(@"從其他設(shè)備登錄");
[self lhl_LogOffPassively];
}
#pragma mark - 被動(dòng)LogOff
- (void)lhl_LogOffPassively
{
[[EaseMob sharedInstance].chatManager asyncLogoffWithUnbindDeviceToken:NO completion:^(NSDictionary *info, EMError *error) {
// 被動(dòng)退出后回調(diào), 切換根控制器
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];
// 創(chuàng)建所有子控制器
[self setUpChildViewControllers];
// 設(shè)置tabBar按鈕和標(biāo)題
[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];
// 發(fā)現(xiàn)
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
{
// 設(shè)置按鈕的標(biāo)題和圖片
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:@"發(fā)現(xiàn)"];
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];
// 設(shè)置導(dǎo)航欄背景顏色
[self.navigationBar lhl_setBackgroundColor:[UIColor blackColor]];
// 修改左右UIBarButtonItem主題色
self.navigationBar.tintColor = [UIColor whiteColor];
// 修改標(biāo)題顏色
[self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor whiteColor]}];
}
// 設(shè)置狀態(tài)欄顏色
- (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
- 到這里,基本架構(gòu)已經(jīng)搭建完畢我們現(xiàn)在做登錄模塊,這里直接用了系統(tǒng)的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.設(shè)置自動(dòng)登錄
[[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES];
[JDStatusBarNotification showWithStatus:@"登錄成功!" dismissAfter:2.0 styleName:JDStatusBarStyleSuccess];
// 2.切換至主頁(yè)面
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];
}
// 注冊(cè)(代理回調(diào)方法注冊(cè))
- (IBAction)registerBtn:(id)sender {
[SVProgressHUD showWithStatus:@"注冊(cè)中..."];
// 接口調(diào)用
[[EaseMob sharedInstance].chatManager asyncRegisterNewAccount:self.usernameLabel.text password:self.pwdLabel.text withCompletion:^(NSString *username, NSString *password, EMError *error) {
[SVProgressHUD dismiss];
if (!error) {
NSLog(@"注冊(cè)成功 : username = %@ password = %@", error, password);
[JDStatusBarNotification showWithStatus:@"注冊(cè)成功,請(qǐng)登錄!" dismissAfter:2.0 styleName:JDStatusBarStyleSuccess];
}else
{
NSLog(@"error : %@", error);
[JDStatusBarNotification showWithStatus:[NSString stringWithFormat:@"注冊(cè)失敗!"] 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"
/**
在微信中,它的微信界面的標(biāo)題切換的是 titleView
除了下面4種狀態(tài),還有
聽(tīng)筒模式
未讀消息數(shù)量展示
等等
此處我們通過(guò)簡(jiǎn)單的模仿,來(lái)了解 連接狀態(tài)改變,以及消息接收帶來(lái)的對(duì)標(biāo)題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 - 自動(dòng)重連
/*!
@method
@brief 將要發(fā)起自動(dòng)重連操作時(shí)發(fā)送該回調(diào)
@discussion
@result
*/
- (void)willAutoReconnect
{
NSLog(@"將要自動(dòng)重連");
self.title = LHLWeChatTitleWillConnect;
}
/*!
@method
@brief 自動(dòng)重連操作完成后的回調(diào)(成功的話器仗,error為nil,失敗的話童番,查看error的錯(cuò)誤信息)
@discussion
@result
*/
- (void)didAutoReconnectFinishedWithError:(NSError *)error
{
if (!error) {
NSLog(@"自動(dòng)重連成功");
self.title = LHLWeChatTitleNormal;
}else
{
NSLog(@"自動(dòng)重連失敗");
self.title = LHLWeChatTitleDisconnect;
}
}
#pragma mark - 連接狀態(tài)改變
- (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;
/** 服務(wù)器獲取的好友列表 */
@property (nonatomic, strong) NSArray *buddies;
@end
@implementation LHLContactViewController
static NSString *cellID = @"UITableViewCell";
- (NSMutableArray *)friends
{
// 好友列表(由EMBuddy對(duì)象組成)
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 = @"請(qǐng)輸入賬號(hào)";
}];
[alertVC addTextFieldWithConfigurationHandler:^(UITextField * _Nonnull textField) {
textField.placeholder = @"請(qǐng)輸入理由";
}];
[alertVC addAction:[UIAlertAction actionWithTitle:@"發(fā)送" 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(@"發(fā)送好友請(qǐng)求成功 - %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
- 我的模塊也是結(jié)合了storyboard,利用靜態(tài)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.記錄退出的用戶名(為了用戶再次登錄的時(shí)候不用重新輸入用戶名.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
-
有網(wǎng)友提到官方SDK集成的問(wèn)題,我之前以為大家跟著官方文檔一步步來(lái)就會(huì)沒(méi)問(wèn)題的,所以文章開(kāi)頭就直接放了官方文檔的連接,鑒于網(wǎng)友們的問(wèn)題,我接下來(lái)就從零開(kāi)始集成環(huán)信SDK 2.x 和 3.x,希望能幫到遇到困難的網(wǎng)友~