GitHub: https://github.com/robbiehanson/XMPPFramework
git clone https://github.com/robbiehanson/XMPPFramework.git cd XMPPFramework git checkout
Vendor/CocoaLumberjack 到項目,Add Files 選擇該文件夾。Vendor/CocoaAsyncSocket,Add Files。需在 Target → Build Phases → Link Binary With Libraries 添加 CFNetwork.framework、Security.framework。Vendor/KissXML,Add Files。添加 libxml2.dylib,Build Settings → Other Linker Flags 加 -lxml2,Header Search Paths 加 /usr/include/libxml2。Vendor/libidn,添加 libidn.a、idn-int.h、stringprep.h。複製源碼目錄下 Authentication、Categories、Core、Utilities 到項目並 Add Files。
添加動態庫 libresolv.dylib (Link Binary With Libraries)。
從 Extensions 選擇需要的模塊(如 XMPPMUC 多人聊天、XMPPvCardTempModule 名片等)加入項目。
常見編譯錯誤補充:添加 CoreData.framework、SystemConfiguration.framework、CoreLocation.framework。
XMPPFramework 使用 ARC。若項目非 ARC,選擇 Edit → Refactor → Convert to Objective-C ARC 消除警告,否則會導致內存洩漏崩潰。
根據使用模塊刪改,例如:
#import "XMPP.h" #import "XMPPReconnect.h" #import "XMPPRoster.h" #import "XMPPRosterCoreDataStorage.h" #import "XMPPvCardTempModule.h" #import "XMPPvCardAvatarModule.h" #import "XMPPvCardCoreDataStorage.h" #import "XMPPCapabilities.h" #import "XMPPCapabilitiesCoreDataStorage.h" #import "XMPPMUC.h" #import "XMPPRoomCoreDataStorage.h"
- (void)connect {
if (!self.xmppStream) self.xmppStream = [[XMPPStream alloc] init];
[self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
if (![self.xmppStream isConnected]) {
NSString *user = [[NSUserDefaults standardUserDefaults] objectForKey:@"username"];
XMPPJID *jid = [XMPPJID jidWithUser:user domain:@"lizhen" resource:@"Ework"];
[self.xmppStream setMyJID:jid];
[self.xmppStream setHostName:@"10.4.125.113"]; // 或域名
NSError *err = nil;
if (![self.xmppStream connect:&err])
NSLog(@"Connect Error: %@", err);
}
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender {
NSString *pwd = [[NSUserDefaults standardUserDefaults] objectForKey:@"password"];
NSError *err = nil;
if (![self.xmppStream authenticateWithPassword:pwd error:&err])
NSLog(@"Auth Error: %@", err);
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
[self.xmppStream sendElement:presence];
}
- (void)disconnect {
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[self.xmppStream sendElement:presence];
[self.xmppStream disconnect];
}
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {
NSString *type = [presence type]; // available, away, dnd, unavailable
NSString *fromUser = [[presence from] user];
if (![fromUser isEqualToString:[[sender myJID] user]]) {
if ([type isEqualToString:@"available"]) { /* 上線 */ }
else if ([type isEqualToString:@"unavailable"]) { /* 下線 */ }
}
}
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {
NSString *body = [[message elementForName:@"body"] stringValue];
// 處理 body...
}
- (void)sendMessage:(NSString *)text toUser:(NSString *)user {
NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
[body setStringValue:text];
NSXMLElement *msg = [NSXMLElement elementWithName:@"message"];
[msg addAttributeWithName:@"type" stringValue:@"chat"];
[msg addAttributeWithName:@"to" stringValue:[NSString stringWithFormat:@"%@@example.com", user]];
[msg addChild:body];
[self.xmppStream sendElement:msg];
}
- (void)queryRoster {
NSXMLElement *query = [NSXMLElement elementWithName:@"query" xmlns:@"jabber:iq:roster"];
NSXMLElement *iq = [NSXMLElement elementWithName:@"iq"];
XMPPJID *myJID = self.xmppStream.myJID;
[iq addAttributeWithName:@"from" stringValue:myJID.description];
[iq addAttributeWithName:@"to" stringValue:myJID.domain];
[iq addAttributeWithName:@"id" stringValue:[self generateID]];
[iq addAttributeWithName:@"type" stringValue:@"get"];
[iq addChild:query];
[self.xmppStream sendElement:iq];
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq {
if ([@"result" isEqualToString:iq.type]) {
NSXMLElement *query = [iq elementForName:@"query"];
if (query && [@"jabber:iq:roster" isEqualToString:[query xmlns]]) {
for (NSXMLElement *item in [query elementsForName:@"item"]) {
NSString *jidStr = [item attributeStringValueForName:@"jid"];
XMPPJID *jid = [XMPPJID jidWithString:jidStr];
[self.roster addObject:jid];
}
}
}
return NO;
}
dispatch_get_main_queue(),否則 UI 更新崩潰。XMPPReconnect 模塊自動處理。