 集成环信IM(单聊)

简单总结一下,仅对日后再次集成更加快速便捷,多数是对文档的简单概括.

一.快速集成环信SDK

1 注册环信账号,创建新应用,获取应用的AppKey.
2 参照官方文档,导入SDK:
(1).下载官网SDK (http://www.easemob.com/download/im:), 从官网上下载下来的包中分为如下五部分:
• 环信 iOS HyphenateSDK 开发使用(不包含实时通话功能)
• 环信 iOS HyphenateFullSDK 开发使用(包含实时通话功能)
• 环信 iOS doc SDK 相关API文档
• 环信 iOS ChatUIDemo3.0 工程源码
• 环信 iOS EaseUI 工程源码
• iOS chatdemo-ui-3.x.x.ipa 打包的 ipa
(2).将SDK文件夹(HyphenateSDK)拖入项目中, 并勾选上 Destination。
(其中,SDK 不支持 bitcode,向 Build Settings → Linking → Enable Bitcode 中设置 NO。)
添加以下库:

 集成环信IM(单聊)_第1张图片
ios_import3.0sdk.jpg

3 增加预编译头文件pch,保证头文件的全局引用.( 【Build Settings】中搜索框输入prefix header 将【Precompile Prefix Header】设置为【YES】,将PCH文件地址填写进【Prefix Header】中

方法一:也可以通过将PCH文件直接拖入【Prefix Header】框中.
方法二: "$(SRCROOT)/当前工程名字/需要包含头文件所在文件夹").

特别注意(否则会报一堆错):
导入等OC框架时需要添加:
# ifdef OBJC
# endif

以上步骤经过command + b 编译没错,即代表导入环信SDK成功.

二.搭建界面实现单聊功能

初始化SDK:
在AppDelegate.m加入如下代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//AppKey:注册的AppKey,详细见下面注释。

//apnsCertName:推送证书名(不需要加后缀),详细见下面注释。

   EMOptions *options = [EMOptions     optionsWithAppkey:@"douser#istore"];
options.apnsCertName = @"istore_dev";
[[EMClient sharedClient] initializeSDKWithOptions:options];

return YES;
}
    // APP进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[EMClient sharedClient] applicationDidEnterBackground:application];
}

    // APP将要从后台返回
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[EMClient sharedClient] applicationWillEnterForeground:application];
}

简单的搭了一个界面:

 集成环信IM(单聊)_第2张图片
屏幕快照 2016-08-22 12.45.03.png

按照文档加入以下代码:
注册事件:
- (IBAction)hdRegister:(id)sender {
//其中@"hd222"是自己设置的用户名
EMError *error = [[EMClient sharedClient] registerWithUsername:@"hd222" password:@"111111"];
if (error==nil) {
NSLog(@"注册成功");
}
}

登录事件:

- (IBAction)login:(id)sender {
//其中@"hd222"是自己设置的用户名
EMError *error = [[EMClient sharedClient] loginWithUsername:@"hd222" password:@"111111"];
if (!error) {
    NSLog(@"登录成功");
}
}

退出事件:
- (IBAction)goOut:(id)sender {
EMError *error = [[EMClient sharedClient] logout:YES];
if (!error) {
NSLog(@"退出成功");
}
}

发送消息:
- (IBAction)sendMessage:(id)sender {

EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message, 其中@"hd111"是自己设置的消息的接收方
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"hd111" body:body ext:nil];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息

//发送Message
[[EMClient sharedClient].chatManager asyncSendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}]; 
}
注意:

发送消息过程中,需要在viewDidLoad方法中添加EMChatManagerDelegate协议的代理.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
}
一定不要忘了遵守协议:

 集成环信IM(单聊)_第3张图片
屏幕快照 2016-08-22 13.06.17.png

调用接收消息的代理方法(直接复制粘贴即可):
#pragma mark -接收消息的代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{

for (EMMessage *message in aMessages) {
    EMMessageBody *msgBody = message.body;
    switch (msgBody.type) {
        case EMMessageBodyTypeText:
        {
            // 收到的文字消息
            EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
            NSString *txt = textBody.text;
            NSLog(@"收到的文字是 txt -- %@",txt);
        }
            break;
        case EMMessageBodyTypeImage:
        {
            // 得到一个图片消息body
            EMImageMessageBody *body = ((EMImageMessageBody *)msgBody);
            NSLog(@"大图remote路径 -- %@"   ,body.remotePath);
            NSLog(@"大图local路径 -- %@"    ,body.localPath); // // 需要使用sdk提供的下载方法后才会存在
            NSLog(@"大图的secret -- %@"    ,body.secretKey);
            NSLog(@"大图的W -- %f ,大图的H -- %f",body.size.width,body.size.height);
            NSLog(@"大图的下载状态 -- %lu",body.downloadStatus);
            
            
            // 缩略图sdk会自动下载
            NSLog(@"小图remote路径 -- %@"   ,body.thumbnailRemotePath);
            NSLog(@"小图local路径 -- %@"    ,body.thumbnailLocalPath);
            NSLog(@"小图的secret -- %@"    ,body.thumbnailSecretKey);
            NSLog(@"小图的W -- %f ,大图的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height);
            NSLog(@"小图的下载状态 -- %lu",body.thumbnailDownloadStatus);
        }
            break;
        case EMMessageBodyTypeLocation:
        {
            EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
            NSLog(@"纬度-- %f",body.latitude);
            NSLog(@"经度-- %f",body.longitude);
            NSLog(@"地址-- %@",body.address);
        }
            break;
        case EMMessageBodyTypeVoice:
        {
            // 音频sdk会自动下载
            EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody;
            NSLog(@"音频remote路径 -- %@"      ,body.remotePath);
            NSLog(@"音频local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在(音频会自动调用)
            NSLog(@"音频的secret -- %@"        ,body.secretKey);
            NSLog(@"音频文件大小 -- %lld"       ,body.fileLength);
            NSLog(@"音频文件的下载状态 -- %lu"   ,body.downloadStatus);
            NSLog(@"音频的时间长度 -- %lu"      ,body.duration);
        }
            break;
        case EMMessageBodyTypeVideo:
        {
            EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
            
            NSLog(@"视频remote路径 -- %@"      ,body.remotePath);
            NSLog(@"视频local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
            NSLog(@"视频的secret -- %@"        ,body.secretKey);
            NSLog(@"视频文件大小 -- %lld"       ,body.fileLength);
            NSLog(@"视频文件的下载状态 -- %lu"   ,body.downloadStatus);
            NSLog(@"视频的时间长度 -- %lu"      ,body.duration);
            NSLog(@"视频的W -- %f ,视频的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height);
            
            // 缩略图sdk会自动下载
            NSLog(@"缩略图的remote路径 -- %@"     ,body.thumbnailRemotePath);
            NSLog(@"缩略图的local路径 -- %@"      ,body.thumbnailLocalPath);
            NSLog(@"缩略图的secret -- %@"        ,body.thumbnailSecretKey);
            NSLog(@"缩略图的下载状态 -- %lu"      ,body.thumbnailDownloadStatus);
        }
            break;
        case EMMessageBodyTypeFile:
        {
            EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
            NSLog(@"文件remote路径 -- %@"      ,body.remotePath);
            NSLog(@"文件local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
            NSLog(@"文件的secret -- %@"        ,body.secretKey);
            NSLog(@"文件文件大小 -- %lld"       ,body.fileLength);
            NSLog(@"文件文件的下载状态 -- %lu"   ,body.downloadStatus);
        }
            break;
            
        default:
            break;
    }
}
}

可以利用真机和模拟器之间发送消息测试,以上是简单的发送消息

单聊:
打开单聊界面按钮集成了基于EaseUI的单聊界面(建议当对界面要求不高的时候直接使用环信UI):

集成方式:
直接将EaseUI拖入已经集成SDK的项目中,然后进行初始化:
第 1 步:引入相关头文件 #import “EaseUI.h”。
第 2 步:在工程的 AppDelegate 中的以下方法中,调用 EaseUI 对应方法。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[[EaseSDKHelper shareHelper] easemobApplication:application
didFinishLaunchingWithOptions:launchOptions
appkey:@"douser#istore"
apnsCertName:@"istore_dev"
otherConfig:@{kSDKConfigEnableConsoleLogger:[NSNumber numberWithBool:YES]}];
return YES;
}

直接创建聊天会话:
//打开单聊界面
- (IBAction)openChat:(id)sender {

//hd111是注册在真机上的账号  用于真机和模拟器实现聊天
EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:@"hd111" conversationType:EMConversationTypeChat];

chatController.title = @"环信单聊";

    //    UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:chatController];

[self.navigationController pushViewController:chatController animated:YES];
    }
 集成环信IM(单聊)_第4张图片
屏幕快照 2016-08-22 13.09.56.png

点击单聊界面按钮利用真机和模拟器即测试实现单聊功能.

swift代码:(处理头像)

import UIKit

class HuanXinChatViewController: EaseMessageViewController {

var blackArr:NSArray!

override init!(conversationChatter: String!, conversationType: EMConversationType) {
    super.init(conversationChatter: conversationChatter, conversationType: conversationType)
}

override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
    super.init(nibName: nil, bundle: nil)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.post(name: NSNotification.Name(rawValue: KRemoveMessageAlterNotification), object: nil)
}

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.delegate = self
    self.dataSource = self
    
    self.chatBarMoreView.removeItematIndex(3)
    self.chatBarMoreView.removeItematIndex(3)
    //        EMAlbum
    self.chatBarMoreView.updateItem(with: UIImage(named:"EMAlbum"), highlightedImage: UIImage(named:"EMAlbumClick"), title: "", at: 0)
    self.chatBarMoreView.updateItem(with: UIImage(named:"EMLocation"), highlightedImage: UIImage(named:"EMLocationClick"), title: "", at: 1)
    self.chatBarMoreView.updateItem(with: UIImage(named:"EMTakePhotos"), highlightedImage: UIImage(named:"EMTakePhotosClick"), title: "", at: 2)
    
    IQKeyboardManager.sharedManager().enableAutoToolbar = false
    
    //设置自己头像
    if UserDefaults.standard.value(forKey: "headpath") == nil{
        getUserHeadPic()
    }
    //        print("打印头像路径\(UserDefaults.standard.value(forKey: "headpath"))")
    getBlackList()
}

//获取头像
func  getUserHeadPic(){
    NetworkTool.GET(URLString: GETUSERINFO, parameters: nil, token: true, success: { (response) in
        if let headPic = response["headpath"]{
            UserDefaults.standard.setValue("\(OSS)\(headPic!)", forKey: "headpath")
        }
    }, failure: { (error) in
        
    })
}

//黑名单
func getBlackList(){
    
    var error:EMError? = nil
    blackArr = EMClient.shared().contactManager.getBlackListFromServerWithError(&error) as NSArray!
    
//        if blackList?.count == 0{
//
//        }else{
//           
//        }
    
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}
}

extension HuanXinChatViewController:EaseMessageViewControllerDataSource,EaseMessageViewControllerDelegate{

//不显示已读
func messageViewControllerShouldMarkMessages(asRead viewController: EaseMessageViewController!) -> Bool {
    return true
}

//    func messageViewController(_ viewController: EaseMessageViewController!, shouldSendHasReadAckFor message: EMMessage!, read: Bool) -> Bool {
//        return false
//    }

func messageViewController(_ viewController: EaseMessageViewController!, modelFor message: EMMessage!) -> IMessageModel! {
    
    let model = EaseMessageModel.init(message: message)
    
    let currentName = EMClient.shared().currentUsername
    
    let messageName = model?.message.from
    
    let messageTo = model?.message.to
    
    
    print("打印环信消息的拓展\(model?.messageStatus)")
    
    if model?.messageStatus == EMMessageStatusFailed{
         print("信息发送失败或已被屏蔽")
//            Alert.showBottomWithText(text: "信息发送失败或已被屏蔽", bottomOffset: 200, duration: 5)
//            
    }
    //        print("打印环信消息的拓展\(messageTo)")
    
    if currentName! == messageName {
        
        if blackArr.contains(currentName!) {
//                Alert.showText(text: "信息发送失败或已被屏蔽")
            print("信息发送失败或已被屏蔽")
        }
        
        model?.avatarURLPath = UserDefaults.standard.value(forKey: "headpath") as! String!
        model?.nickname = UserDefaults.standard.value(forKey: "userName") as! String!
        model?.failImageName = "icon_avatar"
    }else{
        //            print("打印环信消息的拓展\(messageName)")
        if message.ext != nil{
            //                print("打印拓展消息的字典\((message.ext as Dictionary)["userName"])")
            if (message.ext as Dictionary)["userName"] != nil{
                model?.nickname = (message.ext as? Dictionary)?["userName"]
            }
            model?.avatarURLPath = (message.ext as? Dictionary)?["userPic"]
            model?.failImageName = "icon_avatar"
        }
    }
    //        http://oss.hp.etong.tech/images/ed2cf47424a55b2a213316b8ab68b535.png
    return model
}
//点击头像
func messageViewController(_ viewController: EaseMessageViewController!, didSelectAvatarMessageModel messageModel: IMessageModel!) {
    //        let userProfile = UserProfileViewController()
    print("点击头像啦")
}
}

环信获取消息的未读数量

//获取消息的未读数量
func getUnReadNum() -> Int {
    
    var unReadObj = 0
    if UserDefaults.standard.value(forKey: "token") != nil {
        if EMClient.shared().isLoggedIn == true{
            if EMClient.shared().chatManager != nil{
                let conversations: NSArray? = EMClient.shared().chatManager.getAllConversations() as NSArray?
                if (conversations != nil && conversations!.count > 0) {
                    for  conversation: EMConversation in conversations as! [EMConversation] {
                        unReadObj += Int(conversation.unreadMessagesCount)
                    }
                }
            }
        }
    }
    return unReadObj
}

实时收到消息的代理:

//环信聊天代理
extension AppDelegate:EMChatManagerDelegate{
func messagesDidReceive(_ aMessages: [Any]!) {
    //收到新消息后 提示音
    playSoundEffect("sound.caf")
    
    if aMessages.count > 0 {
        
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: KReceivedNewMessageNotification), object: nil)
    }
    for message in aMessages {
        let messageMo = message as! EMMessage
        let msgBody = messageMo.body
        if msgBody?.type == EMMessageBodyTypeText{
            let textBody = msgBody as! EMTextMessageBody
            messageDetail = textBody.text!
        }else if msgBody?.type == EMMessageBodyTypeImage{
            messageDetail = "[图片]"
        }else if msgBody?.type == EMMessageBodyTypeLocation{
            messageDetail = "[位置]"
        }else if msgBody?.type == EMMessageBodyTypeVoice{
            messageDetail = "[语音消息]"
        }else if msgBody?.type == EMMessageBodyTypeVideo{
            messageDetail = "[视频]"
        }
    }
}
}

音效

/** 收到新消息播放音效文件 */
func playSoundEffect(_ name: String) {
    // 获取音效
    let audioFile: String? = Bundle.main.path(forResource: name, ofType: nil)
    let fileUrl = URL(fileURLWithPath: audioFile!)
    // 1、获得系统声音ID
    var soundID: SystemSoundID = 0
    AudioServicesCreateSystemSoundID(((fileUrl as CFURL) ), &soundID)
    // 2、播放音频
    AudioServicesPlaySystemSound(soundID)
    
}

你可能感兴趣的:( 集成环信IM(单聊))