基于環信實現在線聊天功能

由于最近接觸到的項目需要用到聊天功能,關于聊天的SDK跟安卓同事統一,最終選擇了環信。在官方下載好SDK,并研究了一波,最終實現自定義聊天功能。

實現前準備

1.下載環信SDK,我使用的版本是V3.2.0 2016-10-15,并且一開始我只使用了簡版的,沒有實時語音視頻通訊,沒有支付寶紅包。基于環信實現實時語音視頻通話功能

2.在下載的文件夾中找到HyphenateSDKEaseUI并在demo中找到emotion表情包,一起拖到新工程中。

3.向Build Phases → Link Binary With Libraries 中添加依賴庫。SDK 依賴庫有:

CoreMedia.framework
AudioToolbox.framework
AVFoundation.framework
MobileCoreServices.framework
ImageIO.framework
libc++.dylib
libz.dylib
libstdc++.6.0.9.dylib
libsqlite3.dylib

SDK 不支持 bitcode,向 Build Settings → Linking → Enable Bitcode 中設置 NO。在Build Settings-->Other Linker Flags-->雙擊 填寫上:-all_load

4.在工程中設置EaseUI-Prefix.pch的路徑。Build Settings-->Prefix Header 復制粘貼路徑。如果你工程中有.pch文件,那么就只需要將EaseUI-Prefix.pch中的代碼復制進原有的pct文件中就行。(我就只復制了這些)

#define DEMO_CALL 1
#import <UIKit/UIKit.h>
#import <Availability.h>
#import <Foundation/Foundation.h>
#endif

5.在AppDelegate.m中配置環信SDK相關代碼。首先在環信后臺注冊項目,并提交測試版的遠程推送證書anps,需要提供的是.p12文件。(推送證書及p12相關,請自行百度)導入頭文件#import "EMSDK.h"
AppDelegate.m中的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}方法中初始化環信相關配置。

//自動同意加好友.
    BOOL accept = [[EMClient sharedClient].options isAutoAcceptFriendInvitation];
    accept = YES;
    
    //iOS8 注冊APNS
    if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) {
        [application registerForRemoteNotifications];
        UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge |
        UIUserNotificationTypeSound |
        UIUserNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil];
        [application registerUserNotificationSettings:settings];
    }
    else{
        UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge |
        UIRemoteNotificationTypeSound |
        UIRemoteNotificationTypeAlert;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
    }
    //AppKey:注冊的AppKey,詳細見下面注釋。
    //apnsCertName:推送證書名(不需要加后綴),詳細見下面注釋。
    
    NSString *apnsCertName = nil;
#if DEBUG
    apnsCertName = @"xxxx";//填寫自己的推送證書名字
#else
    apnsCertName = @"XXXX";//同上
#endif
    
    
    EMOptions *options = [EMOptions optionsWithAppkey:@"AppKey"];//填寫自己注冊的AppKey
    

    options.apnsCertName = apnsCertName;//
    [[EMClient sharedClient] initializeSDKWithOptions:options];

并加上如下代碼

#pragma mark - 獲取及上傳deviceToken
/*!
 @method  系統方法
 @abstract 系統方法,獲取deviceToken,并上傳環信
 */
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    
    [[EMClient sharedClient] bindDeviceToken:deviceToken];
}
/*!
 @method  系統方法
 @abstract 系統方法,獲取deviceToken 失敗
 */
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"error -- %@",error);
}

#pragma mark - 進入前后臺 (環信)

- (void)applicationDidEnterBackground:(UIApplication *)application {
    
    [[EMClient sharedClient] applicationDidEnterBackground:application];
}


- (void)applicationWillEnterForeground:(UIApplication *)application {
    
    [[EMClient sharedClient] applicationWillEnterForeground:application];
    
}

具體的SDK導入過程也就這些,編譯一下,如果沒報錯,就導入成功了。有報錯也沒關系,找到報錯的地方,有時候就是頭文件找不到,或者文件重復。仔細看看,把不需要的刪掉,出現了連接錯誤就復制百度。放緩心態,要相信SDK是一定能導入成功的。

這里也把環信的官方文檔一并貼上

導入這三個文件夾

分析需求(一)

我沒有用環信demo的UI,大部分是自定義的。因為我覺得自定義的好一些,別人做的再好,那也是別人根據自己的需求做的,不一定滿足我們的需求。項目工程不便上傳,所以我就根據功能點,一步步地往下寫。(根據功能點來,更方便自定義)

第一個面圖

從上圖中可以看到需要做到的一些功能點有:頭像、名稱、會話列表、消息、消息發送的時間、未讀消息標記;還有一點就是會話列表能左劃刪除。這六點中名稱跟頭像環信是不提供的,注冊過環信的都知道,它的ID是數字跟字母的組合,沒有像這樣顯示自定義名稱的。關于頭像,環信服務器也是不提供存儲的。

實現相關功能(一)

1.登錄或注冊環信賬號,獲取會話列表。(賬號密碼是按照我的項目來的,通過本地數據庫存儲好友信息,對照著替換)首先導入頭文件#import "EMSDK.h"#import "EaseUI.h"

/*!
 @method  登錄并加載會話列表。
 @abstract 登錄并加載會話列表。
 
 */
- (void)loginAndLoadData
{
    //-----------------------登錄邏輯----------------------//
    FDAccountItem *item = [FDLoginTool fd_account];
    NSString *psw       = [item.key substringFromIndex:12];
    
    NSLog(@"psw=%@==%@",psw,item.perName);
    //---首先判斷能不能以該身份證為賬號進行登錄----//
    EMError *error = [[EMClient sharedClient] loginWithUsername:[item.key md5String]  password:[psw md5String]];
    if (!error) {
        //設置遠程推送用戶名字
        [[EMClient sharedClient] setApnsNickname:item.perName];
        
        if (!error) {
            NSLog(@"添加成功");
        }
        
        NSLog(@"登錄成功");
        //自動登錄
        [[EMClient sharedClient].options setIsAutoLogin:YES];
        [MBProgressHUD hideHUD];
        
    }
    else
    {
        NSLog(@"%@", error);
        //-------不能以該身份證號為賬號登錄,就已該身份證號進行注冊-------//
        EMError *regError = [[EMClient sharedClient]registerWithUsername:[item.key md5String] password:[psw md5String]];
        
        if (regError ==nil) {
            
            //-----注冊成功之后就進行登錄-----//
            EMError *logError = [[EMClient sharedClient] loginWithUsername:[item.key md5String] password:[psw md5String]];
            if (!logError) {
                //自動登錄
                [[EMClient sharedClient].options setIsAutoLogin:YES];
                [MBProgressHUD hideHUD];
            }
            else
            {
                NSLog(@"登錄失敗");
                [MBProgressHUD hideHUD];
            }
        }
        else
        {
            NSLog(@"error=%@",error);
            [MBProgressHUD hideHUD];
        }
    }
    //-------------------------end---------------------------//
    //獲取所有會話
    NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
    self.dataArr = [[NSMutableArray alloc]initWithArray:conversations];
    [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];//聊天模塊注冊監聽
    
}

/*!
 @method  環信方法,監聽收到消息
 @abstract 不管app前臺、后臺,收到消息都會來到這個方法
 */
- (void)messagesDidReceive:(NSArray *)aMessages
{
    [self getUnReadCountFromEM];
    [self.tableView reloadData];
    
}
/*!
 @method  從環信獲取所有的未讀消息
 @abstract 從環信獲取所有的未讀消息
 */
- (NSInteger)getUnReadCountFromEM {
    NSInteger unReadCount = 0;
    // 獲取所有回話列表
    NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
    self.dataArr = [NSMutableArray arrayWithArray:conversations];
    for (EMConversation *conversation in conversations) {
        unReadCount += conversation.unreadMessagesCount;
    }
    if (unReadCount > 0) {
        [self.tabBarController.tabBar huanX_showBadgeOnItemIndex:0];//自定義界面上顯示未讀消息小紅點
    }
    else
    {
        [self.tabBarController.tabBar fd_hideBadgeOnItemIndex:0];//同上
    }
    return unReadCount;
}

2.單元格cell界面的配置以及消息的處理。

XiaoXiTableViewCell *cell = [[[NSBundle mainBundle]loadNibNamed:@"XiaoXiTableViewCell" owner:nil options:nil]lastObject];
    
    
    EMConversation *conversation = self.dataArr[indexPath.row];
    
    int a = conversation.unreadMessagesCount;
    if (a > 0) {
        cell.hongDianImage.hidden = NO;
    }else
    {
        cell.hongDianImage.hidden = YES;
    }
    //獲得最后一條消息
    EMMessage *message = conversation.latestMessage;
    //獲得消息體
    EMMessageBody *messageBody = message.body;
    NSString *str;
    if (messageBody.type==EMMessageBodyTypeText) {
        //消息為文本時,強轉為EMTextMessageBody 獲取文本消息
        EMTextMessageBody *textBody =(EMTextMessageBody *)messageBody;
        str = [EaseConvertToCommonEmoticonsHelper convertToSystemEmoticons:textBody.text];
        //str = textBody.text;
    }
    //判斷消息類型,輸出響應類型
    else if (messageBody.type==EMMessageBodyTypeImage)
    {
        str = @"[圖片]";
    }
    else if (messageBody.type==EMMessageBodyTypeVoice)
    {
        str = @"[語音]";
    }
    else if (messageBody.type==EMMessageBodyTypeLocation)
    {
        str = @"[位置]";
    }
    else if (messageBody.type==EMMessageBodyTypeVideo)
    {
        str = @"[視頻]";
    }
    else if (messageBody.type==EMMessageBodyTypeFile)
    {
        str = @"[文件]";
    }
    else
    {
        str = @"";
    }
    cell.xiaoXiLabel.text = str;
    //-----------------end--------------------//
    //找到會話

    EaseConversationModel *model = [[EaseConversationModel alloc]initWithConversation:conversation];
    //SaveHaoYouModel *haoYouModel = [HaoYouDao selectedFromPeopleTableWithMDsfz:model.title];
    //設置消息時間
    cell.timeLabel.text = [self timeStr:message.timestamp];
    //設置消息發送者昵稱
    
    // 打開數據庫
    [HaoYouDao createYiShengTable];
    // 搜尋名醫模型
    SaveMingYiModel *mYModel = [HaoYouDao selectedFromPeopleTableWithMDsfz:model.title];
    
    NSLog(@"ss%@----%@-",mYModel.docName,mYModel.idcardno);
    
    cell.nameLabel.text = mYModel.docName;
    NSString *imageUrl  = [NSString stringWithFormat:@"https://219.140.163.100:2265/FDAPP/app_upload/%@.jpg",mYModel.idcardno];
    [cell.headImage sd_setImageWithURL:[NSURL URLWithString:imageUrl]
                      placeholderImage:[UIImage imageNamed:@"touxiang"]];

    //通過擴展消息獲得,該消息的擴展消息,即用戶的頭像,昵稱
    //統一設置單元格分割線,和單元格選中樣式
    cell.layoutMargins  = UIEdgeInsetsMake(0, 0, 0, 0);
    cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0);
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    return cell;

3.時間的處理。

/*!
 @method  計算消息時間。
 @abstract 計算接收到消息的時間,并判斷。
 */
- (NSString *)timeStr:(long long)timestamp
{
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDate *currentDate  = [NSDate date];
    
    // 獲取當前時間的年、月、日
    NSDateComponents *components = [calendar components:NSCalendarUnitYear| NSCalendarUnitMonth|NSCalendarUnitDay fromDate:currentDate];
    NSInteger currentYear  = components.year;
    NSInteger currentMonth = components.month;
    NSInteger currentDay   = components.day;
    
    
    NSDate *msgDate = nil;
    // 獲取消息發送時間的年、月、日
    if (timestamp == 0) {
        msgDate = currentDate;
    } else {
        msgDate  = [NSDate dateWithTimeIntervalSince1970:timestamp/1000.0];
    }
    components = [calendar components:NSCalendarUnitYear| NSCalendarUnitMonth|NSCalendarUnitDay fromDate:msgDate];
    CGFloat msgYear  = components.year;
    CGFloat msgMonth = components.month;
    CGFloat msgDay   = components.day;
    
    // 判斷
    NSDateFormatter *dateFmt = [[NSDateFormatter alloc] init];
    if (currentYear == msgYear && currentMonth == msgMonth && currentDay == msgDay) {
        //今天
        dateFmt.dateFormat = @"HH:mm";
    }else if (currentYear == msgYear && currentMonth == msgMonth && currentDay-1 == msgDay ){
        //昨天
        dateFmt.dateFormat = @"昨天 HH:mm";
    }else{
        //昨天以前
        dateFmt.dateFormat = @"yyyy-MM-dd";
    }
    
    return [dateFmt stringFromDate:msgDate];
}

4.刪除會話。

/*!
 @method  開啟tableview刪除功能。
 @abstract 開啟tableview刪除功能.
 */
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // 刪除會話
    EMConversation *conversation = self.dataArr[indexPath.row];
    [[EMClient sharedClient].chatManager deleteConversation:conversation.conversationId isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError) {
        
        
    }];
    // 刷新表
    [self.dataArr removeObjectAtIndex:indexPath.row];
    [self.tableView reloadData];
    
}

5.點擊消息,與相應的id進行聊天。

//點擊消息,與相應的id進行聊天
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    //找到會話
    EMConversation *conversation = self.dataArr[indexPath.row];
    
    EaseConversationModel *model = [[EaseConversationModel alloc]initWithConversation:conversation];
    //從本地數據庫中匹配,找到好友信息
    SaveMingYiModel *mingYiModel = [HaoYouDao selectedFromPeopleTableWithMDsfz:model.title];
    //model.title = haoYouModel.name;
    
    EaseMessageViewController *viewController = [[EaseMessageViewController alloc] initWithConversationChatter:model.conversation.conversationId conversationType:model.conversation.type];
//   viewController.title = model.title;
    viewController.title = mingYiModel.docName;
    [self.navigationController pushViewController:viewController animated:YES];  
}

分析需求(二)

第二個界面

這個界面的UI大部分都已經有了,需要改的是導航控制器標題、昵稱、頭像。

實現相關功能(二)

1.標題在上一個界面調用跳轉聊天控制器EaseMessageViewController的時候就已經傳過來了。

2.關于昵稱跟頭像,需要修改環信的消息擴展類。消息擴展類在發送各種消息的時候都要設置。(文字、語音、表情、圖片、視頻)

昵稱跟頭像URL
發送語音增加消息擴展類
發送視頻增加消息擴展類
發送文本消息增加消息擴展類
發送表情增加消息擴展類

最后需要用到的地方,在EaseMessageViewController.m- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{}方法的最后加上如下代碼:

注意字典里的關鍵字要跟前面設置的一樣

如果URL中沒有頭像,就需要設置默認頭像。如下

沒有頭像就加載頭像

需要注意的是,字典中值不能為空,要考慮各種情況,避免字典為空。還要注意的是,如果項目既有iOS版本,又有安卓版本,字典中鍵字符串需要保持一致。用戶的昵稱是本地存的,頭像是我服務器存的,URL也是我服務器給的。

分析需求(三)

第三個界面

這個界面的需求就是獲取環信好友列表,并按首字母進行排序。昵稱跟頭像同樣需要自己處理。

實現相關功能(三)

1.獲取環信好友列表。

 //------------------從環信服務器獲取所有的好友 異步加載-------------------//
    [[EMClient sharedClient].contactManager getContactsFromServerWithCompletion:^(NSArray *aList, EMError *aError) {
        if (!aError) {
            
            self.dataArr = [[NSMutableArray alloc]initWithArray:aList];
            
            NSLog(@"haoyou==%ld",self.dataArr.count);
        
            //-------主線程刷新UI---------
            [self performSelectorOnMainThread:@selector(refreshUI) withObject:nil waitUntilDone:YES];
        }
    }];

2.將獲取到的環信ID跟本地數據庫匹配,獲取中文昵稱。

//1. 利用好友賬號在數據庫中檢索,好友模型
    SaveMingYiModel *model = [[SaveMingYiModel alloc]init];
    self.modelArr = [[NSMutableArray alloc]init];
    for (NSString *str in self.dataArr) {
        
        model = [HaoYouDao selectedFromPeopleTableWithMDsfz:str];
        if (model) {
            [self.modelArr addObject:model];
        }
        
    }
    //2. 通過好友模型,輸出好友名字,并添加到數組中
    NSLog(@"%ld",self.dataArr.count);
    if (self.modelArr.count>0) {
        NSMutableArray *arr = [[NSMutableArray alloc]init];
        for (SaveMingYiModel *model in self.modelArr) {
            
            NSString *name = model.docName;
            if (name) {
                [arr addObject:name];
            }
        }
        
    //3. 將漢字轉換為拼音,并進行排序
    self.indexArray      = [ChineseString IndexArray:arr];
    self.letterResultArr = [ChineseString LetterSortArray:arr];
    [self.tableView reloadData];

關于按拼音首字母排序,需要導入兩個類文件ChineseStringpinyin,網上可以搜到。需要的話也可以留郵箱,我發過去。下面貼上這個界面的全部代碼。有些是關于本地數據庫的類,關于數據庫的操作這里不寫。

#import "HaoYouViewController.h"
#import "HaoYouTableViewCell.h"

#import "EMSDK.h"
#import "EaseUI.h"http://環信相關
#import "ChineseString.h"http://按照拼音首字母排序
#import "MyDoctorItem.h"http://好友模型
#import "FDLoginTool.h"http://登錄工具類
#import "HaoYouDao.h"http://數據庫DAO類
#import "SaveMingYiModel.h"http://數據庫相關的好友模型
#define APP_WIDTH [[UIScreen mainScreen]applicationFrame].size.width
#define APP_HEIGHT [[UIScreen mainScreen]applicationFrame].size.height
@interface HaoYouViewController ()<UITableViewDelegate,UITableViewDataSource,EMChatManagerDelegate,EMContactManagerDelegate>

@property (nonatomic,strong) UITableView *tableView;
@property (nonatomic,strong) NSMutableArray *dataArr;
@property (nonatomic,strong) NSMutableArray *modelArr;
@property (nonatomic,strong) NSMutableArray *indexArray;
@property (nonatomic,strong) NSMutableArray *letterResultArr;
@property (nonatomic,strong) UILabel *sectionTitleView;
@property (nonatomic,strong) NSTimer *timer;
@end

@implementation HaoYouViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.title = @"醫生列表";
    self.view.backgroundColor = kGlobalBackgroundColor;
    
    // 打開數據庫
    [HaoYouDao createYiShengTable];
    // 創建表
    self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH) style:UITableViewStylePlain];
    
    self.tableView.delegate   = self;
    self.tableView.dataSource = self;
    self.tableView.rowHeight  = 65;
    
    [self.view addSubview:_tableView];
    //去掉多余的分割線
    self.tableView.tableFooterView = [[UIView alloc]init];
    
    //改變索引字的顏色,索引背景的顏色
    self.tableView.sectionIndexColor =[UIColor colorWithRed:153/255.0 green:153/255.0 blue:153/255.0 alpha:1];
    self.tableView.sectionIndexBackgroundColor = [UIColor clearColor];
    
    //------------------從環信服務器獲取所有的好友 異步加載-------------------//
    [[EMClient sharedClient].contactManager getContactsFromServerWithCompletion:^(NSArray *aList, EMError *aError) {
        if (!aError) {
            
            self.dataArr = [[NSMutableArray alloc]initWithArray:aList];
            
            NSLog(@"haoyou==%ld",self.dataArr.count);
            
            
            //-------主線程刷新UI---------
            [self performSelectorOnMainThread:@selector(refreshUI) withObject:nil waitUntilDone:YES];
        }
    }];

    
}

/*!
 @method  刷新UI。
 @abstract 加載好友列表,按首字母排序.
 
 */
- (void)refreshUI
{
    self.sectionTitleView = ({
        UILabel *sectionTitleView = [[UILabel alloc] initWithFrame:CGRectMake((APP_WIDTH-100)/2, (APP_HEIGHT-100)/2,100,100)];
        sectionTitleView.textAlignment = NSTextAlignmentCenter;
        sectionTitleView.font          = [UIFont boldSystemFontOfSize:60];
        sectionTitleView.textColor     = [UIColor grayColor];
        sectionTitleView.backgroundColor     = [UIColor whiteColor];
        sectionTitleView.layer.cornerRadius  = 6;
        sectionTitleView.layer.masksToBounds = YES;
        sectionTitleView.layer.borderWidth   = 1.f/[UIScreen mainScreen].scale;
        _sectionTitleView.layer.borderColor  = [UIColor groupTableViewBackgroundColor].CGColor;
        sectionTitleView;
    });
    [self.navigationController.view addSubview:self.sectionTitleView];
    self.sectionTitleView.hidden = YES;

    //1. 利用好友賬號在數據庫中檢索,好友模型
    SaveMingYiModel *model = [[SaveMingYiModel alloc]init];
    self.modelArr = [[NSMutableArray alloc]init];
    for (NSString *str in self.dataArr) {
        
        model = [HaoYouDao selectedFromPeopleTableWithMDsfz:str];
        if (model) {
            [self.modelArr addObject:model];
        }
        
    }
    //2. 通過好友模型,輸出好友名字,并添加到數組中
    NSLog(@"%ld",self.dataArr.count);
    if (self.modelArr.count>0) {
        NSMutableArray *arr = [[NSMutableArray alloc]init];
        for (SaveMingYiModel *model in self.modelArr) {
            
            NSString *name = model.docName;
            if (name) {
                [arr addObject:name];
            }
        }
        
    //3. 將漢字轉換為拼音,并進行排序
    self.indexArray      = [ChineseString IndexArray:arr];
    self.letterResultArr = [ChineseString LetterSortArray:arr];
    [self.tableView reloadData];

    }
}
//------------------tableview 的delegate,dataSource 方法--------------//

// 返回區頭索引數組
-(NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView
{
    return self.indexArray;
}
// 返回區頭標題
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    
    NSString *key = [self.indexArray objectAtIndex:section];
    return key;
}
// 返回區個數
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.indexArray count];
}
// 返回每區的行數
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [[self.letterResultArr objectAtIndex:section] count];
}
// 配置單元格
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    HaoYouTableViewCell *cell = [[[NSBundle mainBundle]loadNibNamed:@"HaoYouTableViewCell" owner:nil options:nil]lastObject];
    
    cell.nameLabel.text = [[self.letterResultArr objectAtIndex:indexPath.section]objectAtIndex:indexPath.row];
    
    SaveMingYiModel *model = [HaoYouDao selectedFromPeopleTableWithName:[[self.letterResultArr objectAtIndex:indexPath.section]objectAtIndex:indexPath.row]];
    
    //將小寫x轉換為大寫X
    NSString *upStr = [model.idcardno uppercaseString];
    NSLog(@"sss=%@",upStr);
    //拼接頭像URL地址
    NSString *imgUrl = [@"https://219.140.163.100:2265/FDAPP/app_upload/" stringByAppendingFormat:@"%@.jpg",upStr];
    
    [cell.headImage sd_setImageWithURL:[NSURL URLWithString:imgUrl] placeholderImage:[UIImage imageNamed:@"touxiang.png"]];
    
    
    
    //統一設置單元格分割線,和單元格選中樣式
    cell.layoutMargins  = UIEdgeInsetsMake(0, 0, 0, 0);
    cell.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0);
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    
    return cell;

}

// 設置行高
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (self.indexArray.count>0) {
        
        return 50;
    }
    else
    {
        return kScreenH - 64;
    }
    
}

- (NSInteger)tableView:(UITableView *)tableView sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index
{
    [self showSectionTitle:title];
    return index;
}

#pragma mark - private
- (void)timerHandler:(NSTimer *)sender
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView animateWithDuration:.3 animations:^{
            self.sectionTitleView.alpha = 0;
        } completion:^(BOOL finished) {
            self.sectionTitleView.hidden = YES;
        }];
    });
}

-(void)showSectionTitle:(NSString*)title{
    [self.sectionTitleView setText:title];
    self.sectionTitleView.hidden = NO;
    self.sectionTitleView.alpha  = 1;
    [self.timer invalidate];
    self.timer = nil;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerHandler:) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

#pragma mark - UITableViewDelegate
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    UIView *headerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, WIDTH, 25)];
    headerView.backgroundColor = [UIColor colorWithRed:240/255.0 green:240/255.0 blue:240/255.0 alpha:1];
    UILabel *lab = [[UILabel alloc]initWithFrame:CGRectMake(10, 0, 40, 25)];
    lab.backgroundColor = [UIColor colorWithRed:240/255.0 green:240/255.0 blue:240/255.0 alpha:1];
    
    lab.font = [UIFont systemFontOfSize:12];
    lab.text = [self.indexArray objectAtIndex:section];
    lab.textColor = [UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1];
    [headerView addSubview:lab];
    return headerView;
}

// 點擊好友,進入詳情界面
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    
    // 找到好友模型
    SaveMingYiModel *model = [HaoYouDao selectedFromPeopleTableWithName:[[self.letterResultArr objectAtIndex:indexPath.section]objectAtIndex:indexPath.row]];
    // 根據好友的身份證MD5 跳轉聊天界面
    EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:model.sfzMD5 conversationType:EMConversationTypeChat];
    // 隱藏底部tabBar
    chatController.hidesBottomBarWhenPushed = YES;
    // 聊天標題
    chatController.title = model.docName;
    [self.navigationController pushViewController:chatController animated:YES];
}
// 設置區頭區尾高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    return 25;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    return 0.01;
    
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.tabBarController.title = @"醫生列表";
    
}

至此,聊天功能大部分寫完,下面貼一張本地數據庫的圖。

關鍵信息要打碼~

環信ID要的是數字跟字母,所以在項目中,我就用身份證MD5加密作為環信的ID,數據庫中每條好友信息都是從服務器中請求的,存入數據庫,方便通過mdSfz(也就是通過環信請求到的好友ID)這個字段去數據庫檢索信息。

最后說一下消息推送部分

1.遠程推送。之前在AppDelegate中的設置如果沒有什么問題,并且推送證書 p12文件都是正確的話,(p12文件要上傳到環信后臺)遠程推送就沒有任何問題。

2.本地推送。在MainViewController.m中處理,(進入程序的第一個視圖控制器)首先導入頭文件EaseSDKHelper.hviewDidLoad中注冊聊天模塊監聽
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];然后寫入如下代碼:

/*!
 @method  環信方法,監聽收到消息
 @abstract 不管app前臺、后臺,收到消息都會來到這個方法
 */
- (void)messagesDidReceive:(NSArray *)aMessages
{
    // 前臺就不跳轉
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        // 震動
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        
    }
    
    EMMessage *message = aMessages[0];
    
    //獲得消息體
    EMMessageBody *messageBody = message.body;
    
    NSString *str;
    if (messageBody.type==EMMessageBodyTypeText) {
        //消息為文本時,強轉為EMTextMessageBody 獲取文本消息
        EMTextMessageBody *textBody =(EMTextMessageBody *)messageBody;
        str = textBody.text;
        
    }
    //判斷消息類型,輸出相應類型
    else if (messageBody.type==EMMessageBodyTypeImage)
        
    {
        str = @"[圖片]";
        
    }
    else if (messageBody.type==EMMessageBodyTypeVoice)
    {
        str = @"[語音]";
        
    }
    else if (messageBody.type==EMMessageBodyTypeLocation)
    {
        str = @"[位置]";
        
    }
    else if (messageBody.type==EMMessageBodyTypeVideo)
    {
        str = @"[視頻]";
        
    }
    else if (messageBody.type==EMMessageBodyTypeFile)
    {
        str = @"[文件]";
    }
    else
    {
        str = @"";
    }
    
    //message.ext[@"img"];//頭像
    //message.ext[@"accountName"];//昵稱
    
    NSString *notifyMessage = [NSString stringWithFormat:@"%@:%@",message.ext[@"accountName"],str];
    NSLog(@"notifyMessage%@",notifyMessage);
    
    UILocalNotification *notify = [[UILocalNotification alloc]init];
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:1];
    notify.fireDate = fireDate;
    
    //時區
    notify.timeZone = [NSTimeZone defaultTimeZone];
    
    //通知內容
    notify.alertBody = notifyMessage;
    
    //通知被觸發時播放的聲音
    notify.soundName = UILocalNotificationDefaultSoundName;
    //通知參數
    
    
    NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:message.ext[@"accountName"],@"好友",@(badgeNum),@"badgeNum",nil];
    
    notify.userInfo = dic;
    
    // ios8后,需要添加這個注冊,才能得到授權
    if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationType type =  UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:type
                                                                                 categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    }
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
             // 執行通知注冊
            [[UIApplication sharedApplication] scheduleLocalNotification:notify];
        });
    }
}

本地通知發送完成,若需要本地通知相關信息,需要在AppDelegate.m中接收本地通知并處理。

本地推送

基于環信實現實時語音視頻通話功能

轉載請注明出處

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容