XMPP及时通讯 - 环信第三方

1.什么是XMPP(Extensible Messaging and Presence Protocol)

XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性。因此,基于XMPP的应用具有超强的可扩展性。经过扩展以后的XMPP可以通过发送扩展的信息来处理用户的需求,以及在XMPP的顶端建立如内容发布系统和基于地址的服务等应用程序。而且,XMPP包含了针对服务器端的软件协议,使之能与另一个进行通话,这使得开发者更容易建立客户应用程序或给一个配好系统添加功能。

可扩展通讯和表示协议 (XMPP) 可用于服务类实时通讯、表示和需求响应服务中的XML数据元流式传输。XMPP以Jabber协议为基础,而Jabber是即时通讯中常用的开放式协议

XMPP的前身是Jabber,一个开源形式组织产生的网络即时通信协议

XMPP配置

1.下载第三方库

gitHub下载

2.导入对应的库文件
这里写图片描述

3.需要在Header Search Paths中配置路径/usr/include/libxml2

XMPP使用
1.注册
2.登录
3.登录状态

presence 的状态:
available 上线
away 离开
do not disturb 忙碌
unavailable 下线

XMPPPresence presenceWithType:@”available” 为上线状态

XMPPPresence *presence = [XMPPPresence presenceWithType:@”unavailable”]; 下线状态

4.得到好友列表 (具体实现见代码).
好友列表,在 XMPP 中被称为 roster,花名册?

要像服务器发送 一个 IQ 请求:

iq type=”get”
  from=”[email protected]
  to=”example.com”
  id=”1234567”>
  >query xmlns=”jabber:iq:roster”/>
iq />

type 属性,说明了该 iq 的类型为 get,与 HTTP 类似,向服务器端请求信息
from 属性,消息来源,这里是你的 JID
to 属性,消息目标,这里是服务器域名
id 属性,标记该请求 ID,当服务器处理完毕请求 get 类型的 iq 后,响应的 result 类型 iq 的 ID 与 请求 iq 的 ID 相同

服务器返回的一个 IQ 响应:

iq type=”result”
  id=”1234567”
  to=”[email protected]”>
  >query xmlns=”jabber:iq:roster”>
    >item jid=”[email protected]” name=“哈哈“ />
    >item jid=”[email protected]” name=“呵呵”/>
  >query />
iq />

解析数据取得所有好友

5.接收消息
当接收到 >message /> 标签的内容时,XMPPFramework 框架回调该方法
根据 XMPP 协议,消息体的内容存储在标签 >body /> 内

6.发送消息
发送消息
发送消息,我们需要根据 XMPP 协议,将数据放到 >message /> 标签内,例如:

message type=”chat” to=”[email protected]”>
  >body>Hello World!>body />
message />

7.添加好友

XMPP Demo

TQXMPPManager.h

import “XMPPFramework.h”

//ret default is NO 如果 为 NO说明注册或者登录失败
typedef void (^CheckUserBlock)(BOOL ret,NSError *error);

//获取好友列表的Block
typedef void (^GetAllFirendBlock)(NSArray *friendArray);

//接受到消息
typedef void (^RecvMsgBlock)(NSData *data);

@interface TQXMPPManager : NSObject

//xmpp管理的单例对象
+(TQXMPPManager *)sharedXMPPManager;

//注册和登录的接口
//state 登录 或者 注册的状态
-(void)checkUserInfo:(NSString )userName passwd:(NSString )userPasswd state:(BOOL)state success:(CheckUserBlock)checkBlock;

//上线
-(void)OnLine;

//获取好友列表
-(void)getAllFrends:(GetAllFirendBlock)friendBlock;

//发送消息
-(void)sendMsg:(NSString )userJid content:(NSString )content;

@end

TQXMPPManager.m
@interface TQXMPPManager () >XMPPStreamDelegate>

//NO register YES is login default is NO
@property (nonatomic) BOOL isLogin;

@property (nonatomic,strong) XMPPStream *streamManager;

//回调的block
@property (nonatomic,strong) CheckUserBlock checkBlock;

//保存用户的信息
@property (nonatomic,strong) TQUserModel *userModel;

//保存当前获得好友列表的block
@property (nonatomic,strong) GetAllFirendBlock friendBlock;

//保存当前所有好友
@property (nonatomic,strong) NSMutableArray *friendArray;

@end

@implementation TQXMPPManager

  • (instancetype)init
    {
    self = [super init];
    if (self) {
    self.streamManager = [[XMPPStream alloc] init];

    self.friendArray = [[NSMutableArray alloc] init];
    
    //实例化用户模型的信息.
    self.userModel = [[TQUserModel alloc] init];
    
    //设置代理
    [self.streamManager addDelegate:self delegateQueue:dispatch_get_main_queue()];
    

    }
    return self;
    }

+(TQXMPPManager *)sharedXMPPManager
{
static TQXMPPManager *manager = nil;

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    manager = [[TQXMPPManager alloc] init];
});

return manager;

}

-(void)checkUserInfo:(NSString )userName passwd:(NSString )userPasswd state:(BOOL)state success:(CheckUserBlock)checkBlock
{
//断开连接
[_streamManager disconnect];

//记录当前状态  是登录还是注册
self.isLogin = state;
self.checkBlock = checkBlock;

//注册
self.userModel.userJID = userName;
self.userModel.userPasswd = userPasswd;

if(state)
{
    //使用当前用户名和密码登录

    XMPPJID *newJID = [XMPPJID jidWithString:self.userModel.userJID];
    self.streamManager.myJID = newJID;
}
else
{
    //使用千锋的XMPP服务器   注册用户
    XMPPJID *jid = [XMPPJID jidWithString:@"[email protected]"];
    _streamManager.myJID = jid;
}

NSError *error = nil;

BOOL ret = [self.streamManager connectWithTimeout:-1 error:&error];

//如果连接超时,注册失败
if(ret == NO)
{
    if(self.checkBlock)
    {
        self.checkBlock(NO,error);
    }
}

}

//连接成功后 要重新设置用户名和发送密码
-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSError *err = nil;

//重新设置用户名  使用当前用户名登录 或者 注册
XMPPJID *newJID = [XMPPJID jidWithString:self.userModel.userJID];
self.streamManager.myJID = newJID;

BOOL ret = NO;

//输入密码  --->  判断是注册还是登陆

if(self.isLogin){
    ret = [self.streamManager authenticateWithPassword:self.userModel.userPasswd error:&err];
}else{
    ret = [self.streamManager registerWithPassword:self.userModel.userPasswd error:&err];
}

//实现回调
if(ret == NO){
    if(self.checkBlock){
        self.checkBlock(NO,err);
    }
}

}

pragma mark - 注册完成的相关代理方法
//注册成功
-(void)xmppStreamDidRegister:(XMPPStream *)sender
{
if(self.checkBlock){
self.checkBlock(YES,nil);
}
}

//注册失败
-(void)xmppStream:(XMPPStream )sender didNotRegister:(DDXMLElement )error
{
if(self.checkBlock)
{
NSError *err = [NSError errorWithDomain:error.description code:0 userInfo:nil];
self.checkBlock(NO,err);
}
}

pragma mark - 登录完成的相关代理方法
//授权密码失败
-(void)xmppStream:(XMPPStream )sender didNotAuthenticate:(DDXMLElement )error
{
if(self.checkBlock)
{
NSError *err = [NSError errorWithDomain:error.description code:0 userInfo:nil];
self.checkBlock(NO,err);
}
}

//授权密码成功
-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
if(self.checkBlock){
self.checkBlock(YES,nil);
}
}

pragma mark - 上线
//上线
-(void)OnLine
{
XMPPPresence *presence = [XMPPPresence presence];
[self.streamManager sendElement:presence];
}

pragma mark - 获取好友列表
//获取好友列表
-(void)getAllFrends:(GetAllFirendBlock)friendBlock
{
self.friendBlock = friendBlock;

NSXMLElement *element = [NSXMLElement elementWithName:@"query"];
[element addAttributeWithName:@"xmlns" stringValue:@"jabber:iq:roster"];

NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];
[iq addAttributeWithName:@"type" stringValue:@"get"];
[iq addChild:element];

[self.streamManager sendElement:iq];

}

-(BOOL)xmppStream:(XMPPStream )sender didReceiveIQ:(XMPPIQ )iq
{
//解析好友列表
//elementForName 取出一个节点
NSXMLElement *query = [iq elementForName:@”query”];
//elementsForName 取出所有同名的节点
//以下数组中的每个元素都为NSXMLElement对象
NSArray *items = [query elementsForName:@”item”];
for (NSXMLElement *it in items)
{
//每个it对象就是一个item
NSString *jid = [[it attributeForName:@”jid”] stringValue];

    TQUserModel *friend = [[TQUserModel alloc] init];
    friend.userJID = jid;
    [self.friendArray addObject:friend];
}

if(self.friendBlock)
{
    self.friendBlock(self.friendArray);
}

return YES;

}

-(void)sendMsg:(NSString )userJid content:(NSString )content
{
//目标好友的id
XMPPJID *toJid = [XMPPJID jidWithString:userJid];
//消息对象
XMPPMessage *msg = [XMPPMessage messageWithType:@”chat” to:toJid];
//设置消息内容
[msg addBody:content];
NSLog(@”msg = %@”, msg);

//发送消息
[self.streamManager sendElement:msg];

}

-(void)xmppStream:(XMPPStream )sender didReceiveMessage:(XMPPMessage )message
{
if ([message isChatMessageWithBody])
{
NSLog(@”%@,%@”,message.body,message.from.bare);
}
}

@end

添加好友Controller

@interface TQNewFriendViewController ()
@property (weak, nonatomic) IBOutlet UITextField *friendName;
@end

@implementation TQNewFriendViewController
- (IBAction)addFriend:(id)sender {
//[[TQXMPPManager sharedXMPPManager] addFriend:self.friendName.text];
}

  • (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.navigationItem.title = @”添加好友”;
    }

  • (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

-(void)touchesBegan:(NSSet>UITouch > )touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}

主界面Controller
- (void)viewDidLoad {
[super viewDidLoad];

// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;

// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addFriend)];

self.navigationItem.title = @"好友列表";

[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];

//上线
[[TQXMPPManager sharedXMPPManager] OnLine];

//获取好友列表
[[TQXMPPManager sharedXMPPManager] getAllFrends:^(NSArray *friendArray) {
    self.friendArray = friendArray;
    [self.tableView reloadData];
}];

}

-(void)addFriend
{
[[TQXMPPManager sharedXMPPManager] sendMsg:@”[email protected]” content:@”哈哈哈哈”];
}

  • (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 1;
    }

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    warning Incomplete implementation, return the number of rows
    return self.friendArray.count;
    }

  • (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@”cell”];

    TQUserModel *userModel = self.friendArray[indexPath.row];
    cell.textLabel.text = userModel.userJID;

    return cell;
    }

登录Controller
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UITextField *userName;
@property (weak, nonatomic) IBOutlet UITextField *userPasswd;
- (IBAction)login:(id)sender;

@end

@implementation ViewController

  • (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.navigationItem.title = @”登录”;
    }

  • (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

  • (IBAction)login:(id)sender {
    [[TQXMPPManager sharedXMPPManager] checkUserInfo:self.userName.text passwd:self.userPasswd.text state:YES success:^(BOOL ret, NSError *error) {
    if(ret)
    {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@”提示” message:@”登录成功” preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
    
            id vc = [sb instantiateViewControllerWithIdentifier:@"MainVC"];
    
    
            [self.navigationController pushViewController:vc animated:YES];
        }];
    
        [alertController addAction:action];
    
        [self presentViewController:alertController animated:YES completion:nil];
    }
    else
    {
        NSLog(@"%@",error);
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"登录失败" preferredStyle:UIAlertControllerStyleAlert];
    
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    
        }];
    
        [alertController addAction:action];
    
        [self presentViewController:alertController animated:YES completion:nil];
    }
    

    }];
    }
    @end

注册
@interface TQRegisterViewController ()
@property (weak, nonatomic) IBOutlet UITextField *userName;
@property (weak, nonatomic) IBOutlet UITextField *userPasswd;
- (IBAction)registerUser:(id)sender;

@end

@implementation TQRegisterViewController

  • (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    self.navigationItem.title = @”注册”;
    }

  • (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

/*
pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/

  • (IBAction)registerUser:(id)sender {
    //注册用户
    [[TQXMPPManager sharedXMPPManager] checkUserInfo:self.userName.text passwd:self.userPasswd.text state:NO success:^(BOOL ret, NSError *error) {
    if(ret)
    {
    UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@”提示” message:@”注册成功” preferredStyle:UIAlertControllerStyleAlert];

        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
            [self.navigationController popViewControllerAnimated:YES];
        }];
    
        [alertController addAction:action];
    
        [self presentViewController:alertController animated:YES completion:nil];
    }
    else
    {
        NSLog(@"%@",error);
        UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"注册失败" preferredStyle:UIAlertControllerStyleAlert];
    
        UIAlertAction *action = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    
        }];
    
        [alertController addAction:action];
    
        [self presentViewController:alertController animated:YES completion:nil];
    }
    

    }];
    }
    @end

TQUserModel.h

@interface TQUserModel : NSObject

//保存用户名
@property (nonatomic,strong) NSString *userJID;

//保存用户名的密码
@property (nonatomic,strong) NSString *userPasswd;

//保存用户的登录状态
@property (nonatomic,strong) NSString *state;

@end

猜你喜欢

转载自blog.csdn.net/weixin_35966617/article/details/53099785