XMPP是一種基於XML的即時通信協議. 服務器爲openfire數組
a、導入xmpp框架 XMPPFramework;服務器
b、添加依賴庫:libresolv.dylib、libxml2.dylib併發
c、在Build Settings 中的 Header Search Paths中添加 /usr/include/libxml2框架
a、建立XMPPManager管理類,導入XMPP框架XMPPFramework.h,並將該類寫成單例dom
b、聲明須要用到的對象: ui
@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、消息模型QFMessageModelspa
// 一、初始化xmpp流 _xmppStream = [[XMPPStream alloc] init]; // 設置主機 [_xmppStream setHostName:@"1000phone.net"]; // 設置端口 [_xmppStream setHostPort:5222]; // 設置代理 [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; // 二、初始化斷線重連機制 _xmppReconnect = [[XMPPReconnect alloc] init]; [_xmppReconnect activate:_xmppStream]; // 三、初始化花名冊 //初始化花名冊存儲對象 _xmppStorage = [[XMPPRosterCoreDataStorage alloc] init]; //初始化花名冊 _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppStorage]; [_xmppRoster activate:_xmppStream]; //初始化用戶model userModel = [[QFUserModel alloc] init]; //初始化allFriends allFriends = [[NSMutableArray alloc] init];
// 先註冊用戶名, 而後再註冊密碼 - (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); } } }
- (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); } } }
鏈接服務器成功後,經過密碼註冊/驗證密碼登錄 .net
-(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、請求服務器獲取好友code
- (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); } }
四、申請上線(申請下線)
- (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); //nie@1000phone.net/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]; }
五、請求服務器獲取好友(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; }
六、添加好友
- (void)addFriend:(NSString *)name
{
XMPPJID *jid = [XMPPJID jidWithString:name];
//請求添加好友
[_xmppRoster subscribePresenceToUser:jid];
}
七、更新好友狀態
- (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); } }
八、發送和接收消息
#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); } } } }