IOS开发之XMPP

  一.什么是XMPP

  XMPP是一种基于XML的即时通讯协议. 服务器为openfire

  二、XMPP配置 

  a、导入xmpp框架 XMPPFramework;

  b、添加依赖库:libresolv.dylib、libxml2.dylib

  c、在Build Settings 中的 Header Search Paths中添加 /usr/include/libxml2

  三、开始代码

  0、前期

  a、创建XMPPManager管理类,导入XMPP框架XMPPFramework.h,并将该类写成单例

  b、声明需要用到的对象:  

@interface QFXMPPManager ()
<XMPPStreamDelegate>
{
    
    XMPPStream *_xmppStream; //xmpp流
    XMPPRoster *_xmppRoster; //xmpp花名册
    XMPPRosterCoreDataStorage *_xmppStorage; //xmpp花名册存储类
    XMPPReconnect *_xmppReconnect; //xmpp的重连机制类
    
    
    //保存用户数据
    QFUserModel *userModel;
    
    //保存所有好友
    NSMutableArray *allFriends;
    
    //判断是否在注册(注册/登录)
    BOOL isRegister;
    
    //注册结果的block
    void (^registerResultBlock)(BOOL success, NSError *error);
    
    //登陆结果的block
    void (^loginResultBlock)(BOOL success, NSError *error);
    
    //获取好友结果的block
    void (^getFriendsResultBlock)(NSArray *friends);
    
    //发送信息结果的block
    void (^sendMessageResultBlock)(BOOL success);
    
    //接收信息结果的block
    void (^getMessageResultBlock)(QFChatModel *model);
    
}

@end

  c、创建用户模型QFUserModel、消息模型QFMessageModel

  1、初始化需要用到的XMPP类

  

// 1、初始化xmpp流
        _xmppStream = [[XMPPStream alloc] init];
        
        // 设置主机
        [_xmppStream setHostName:@"1000phone.net"];
        
        // 设置端口
        [_xmppStream setHostPort:5222];
        
        // 设置代理
        [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        
        // 2、初始化断线重连机制
        _xmppReconnect = [[XMPPReconnect alloc] init];
        [_xmppReconnect activate:_xmppStream];
        
        
        // 3、初始化花名册
        //初始化花名册存储对象
        _xmppStorage = [[XMPPRosterCoreDataStorage alloc] init];
        
        //初始化花名册
        _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppStorage];
        [_xmppRoster activate:_xmppStream];
        
        
        //初始化用户model
        userModel = [[QFUserModel alloc] init];
        
        //初始化allFriends
        allFriends = [[NSMutableArray alloc] init];

  2、用户注册(通过Jid连接XMPP服务器)

  <用户注册分两步:1、通过Jid连接服务器;2、通过密码注册>

  技术分享技术分享

// 先注册用户名, 然后再注册密码
- (void)registerWithName:(NSString *)name andPassword:(NSString *)password result:(void (^)(BOOL, NSError *))resultBlock
{
    registerResultBlock = [resultBlock copy];
    
    //正在注册
    isRegister = YES;
    
    
    //保存用户名和密码
    userModel.name = name;
    userModel.password = password;
    
    
    //将name转换成jid
    XMPPJID *jid = [XMPPJID jidWithString:name];
    [_xmppStream setMyJID:jid];
    
    //如果已经连接了,则先断开连接
    if ([_xmppStream isConnected] || [_xmppStream isConnecting] ) {
        [_xmppStream disconnect];
    }
    
    //连接服务器
    NSError *error = nil;
    BOOL ret = [_xmppStream connectWithTimeout:-1 error:&error];
    if ( !ret ) {
        NSLog(@"连接失败");
        
        if ( registerResultBlock ) {
            registerResultBlock (NO, error);
        }
    }
}

  3、用户登陆(通过Jid连接XMPP服务器)

  <用户登陆分两步:1、通过Jid连接服务器;2、验证密码登陆>

  

- (void)loginWithName:(NSString *)name
          andPassword:(NSString *)password
               result:( void(^)(BOOL success, NSError *error) )resultBlock
{
    loginResultBlock = [resultBlock copy];
    
    //正在登录(不是正在注册)
    isRegister = NO;
    
    //保存用户名和密码
    userModel.name = name;
    userModel.password = password;
    
    //把name转换成jid
    XMPPJID *jid = [XMPPJID jidWithString:name];
    _xmppStream.myJID = jid;
    
    
    //先断开旧连接
    if ( [_xmppStream isConnected] || [_xmppStream isConnecting] ) {
        [_xmppStream disconnect];
    }
    
    //开始连接服务器
    NSError *error = nil;
    BOOL ret = [_xmppStream connectWithTimeout:-1 error:&error];
    if ( !ret ) {
        NSLog(@"连接失败");
        if ( loginResultBlock ) {
            loginResultBlock (NO, error);
        }
    }
}

  连接服务器成功后,通过密码注册/验证密码登陆 

-(void)xmppStreamDidConnect:(XMPPStream *)sender
{
    
    if ( isRegister ) {
        
        //注册密码
        [_xmppStream registerWithPassword:userModel.password error:nil];
    }
    
    else {
        
        //登陆,验证密码
        [_xmppStream authenticateWithPassword:userModel.password error:nil];
    }
} 

  注册的回调方法(注册成功/注册失败)

  

-(void)xmppStreamDidRegister:(XMPPStream *)sender
{
    NSLog(@"注册成功");
    if ( registerResultBlock ) {
        registerResultBlock (YES, nil);
    }
}

#pragma mark -- 注册失败
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error
{
    NSLog(@"注册失败");
    
    NSError *myError = [NSError errorWithDomain:error.description code:-1 userInfo:nil];
    if ( registerResultBlock ) {
        registerResultBlock (NO, myError);
    }
} 

  登陆的回调方法(登陆成功/登陆失败),登陆成功后: a、申请上线;b、请求服务器获取好友

  

- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
    NSLog(@" 登录成功 ");
    
    if ( loginResultBlock ) {
        loginResultBlock(YES, nil);
    }
    
    // 申请上线
    [self online];
    
    // 请求获取好友列表
    [self requestFriends];
    
}

#pragma  mark -- 登陆失败
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
    NSLog(@" 登录失败 ");
    
    NSError *myError = [NSError errorWithDomain:error.description code:-1 userInfo:nil];
    if ( loginResultBlock ) {
        loginResultBlock (NO, myError);
    }
}

  4、申请上线(申请下线)

- (void)online
{
    // 创建一个xml对象,并发送给服务器
    XMPPPresence *presence = [XMPPPresence presence];
    //"available"
//    NSLog(@"presence: %@", presence);
    
    [_xmppStream sendElement:presence];
}

- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
    
//    NSLog(@"presence:%@", presence);
    
   
    
    NSString *from = [presence attributeStringValueForName:@"from"];
//    NSLog(@"from: %@", from);
    //[email protected]/67f1ed1a
    XMPPJID *fromJid = [XMPPJID jidWithString:from];
    
    NSString *friendStr = [NSString stringWithFormat:@"%@@%@", fromJid.user, fromJid.domain];
    XMPPJID *friendJid = [XMPPJID jidWithString:friendStr];
    
//    NSLog(@"friendStr: %@", friendStr);

    
    
    
    //好友状态
    NSString *type = [presence type];
    NSLog(@" === type :%@", type);

    NSString *status = @"available"; //默认是在线状态
    
    //如果有好友上线了
    if ( [type isEqualToString:@"available"] ) {
        NSLog(@"有好友上线了:%@ ", friendStr);
        status = @"available";
    }
    
    //有好友下线了
    else if ( [type isEqualToString:@"unavailable"] ){
        NSLog(@"有好友下线了:%@", friendStr);
        status = @"unavailable";
    }
    
    //有人请求添加我为好友
    else if ( [type isEqualToString:@"subscribe"] ) {
        
        NSLog(@" 有人要加我为好友,这个人是:%@", friendStr);
        //接受别人的加好友请求,并且请求添加对方为好友
        [_xmppRoster acceptPresenceSubscriptionRequestFrom:friendJid andAddToRoster:YES];
        
    }
    
    //更新所有好友的某一个好友的状态
    [self updateFriend:friendStr withNewStatus:status];
    
}

  5、请求服务器获取好友(IQ:Information Query)

  

-(void)requestFriends
{
    //
    NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:roster"];
    NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];
    
    [iq addAttributeWithName:@"type" stringValue:@"get"];
    [iq addChild:query];
    
//    NSLog(@" iq :%@", iq);
    
    //发送xml数据,请求获取好友列表
    [_xmppStream sendElement:iq];
    
}

  成功获取好友

  

-(BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
//    NSLog(@" iq :%@", iq);
    
    NSXMLElement *query = iq.childElement;
    //遍历query的所有子节点
    for (NSXMLElement *item in query.children) {
        NSString *name = [item attributeStringValueForName:@"jid"];
        NSLog(@"friend Name: %@", name);
        
        //添加好友到allFriends中
        [self addFriendWithName:name andStatus:@"unavailable"];
    }
    
    return YES;
}

  6、添加好友 

- (void)addFriend:(NSString *)name

{

    XMPPJID *jid = [XMPPJID jidWithString:name];

    

    //请求添加好友

    [_xmppRoster subscribePresenceToUser:jid];

}

 7、更新好友状态

   

- (void)updateFriend:(NSString *)name withNewStatus:(NSString *)newStatus
{
    for (QFUserModel *model in allFriends) {
        
        //判断是否已经存在该好友,存在则修改其状态
        if ( [model.name isEqualToString:name] ) {
            model.status = newStatus;
            
            //返回更新状态后的最新的allFriends
            if ( getFriendsResultBlock ) {
                getFriendsResultBlock(allFriends);
            }
            
            return;
        }
    }
    
    //添加该好友
    [self addFriendWithName:name andStatus:newStatus];
    
} 

  添加好友到friends数组中 

- (void)addFriendWithName:(NSString *)name andStatus:(NSString *)status
{
    //遍历原本所有的好友
    for (QFUserModel *model in allFriends) {
        
        //如果存在相同名称的好友,不添加
        if ( [model.name isEqualToString:name] ) {
            NSLog(@" 已经存在该好友了 ,不添加了 ");
            return;
        }
    }
    
    //取得自己的名称
    NSString *myName = [NSString stringWithFormat:@"%@@%@", _xmppStream.myJID.user, _xmppStream.myJID.domain];
    
    if ( [name isEqualToString:myName] ) {
        NSLog(@" 是我自己,不添加 ");
        return;
    }
    
    //添加这个好友
    QFUserModel *model = [[QFUserModel alloc] init];
    model.name = name;
    model.status = status;
    
    [allFriends addObject:model];
    
//    NSLog(@"allFriends.count: %d", allFriends.count);
    
    //每添加一个好友,返回最新的allFriends
    if ( getFriendsResultBlock ) {
        getFriendsResultBlock(allFriends);
    }
    
}

  8、发送和接收消息

  

#pragma  mark - 发送信息
- (void)sendMessage:(NSString *)content to:(NSString *)name result:( void(^)(BOOL success) )resultBlock
{
    sendMessageResultBlock = [resultBlock copy];
    
    NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
    [body setStringValue:content];
    
    NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
    [message addAttributeWithName:@"type" stringValue:@"chat"];
    [message addAttributeWithName:@"to" stringValue:name];
    [message addChild:body];
    
    NSLog(@"message: %@", message);
    
    //发送信息
    [_xmppStream sendElement:message];
    
}

#pragma  mark -- 发送信息成功的回调方法
- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
{
    if ( sendMessageResultBlock ) {
        sendMessageResultBlock(YES);
    }
}

#pragma  mark -- 发送信息失败
- (void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error
{
    if ( sendMessageResultBlock ) {
        sendMessageResultBlock(NO);
    }
}

#pragma  mark - 接收信息
- (void)getMessage:( void(^)(QFChatModel *model) )resultBlock
{
    getMessageResultBlock = [resultBlock copy];
}

-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
    if ( [message isChatMessage] ) {
        
        if ([message isChatMessageWithBody]) {
            
            NSString *body = message.body;
            NSString *from = message.from.bare;
            NSString *to = message.to.bare;
            
            QFChatModel *model = [[QFChatModel alloc] init];
            model.content = body;
            model.from = from;
            model.to = to;
            
            if ( getMessageResultBlock ) {
                getMessageResultBlock(model);
            }
        }
        
    }
    
}

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。