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);

            }

        }

        

    }

    

}

 

你可能感兴趣的:(ios开发)