刚开始接触XMPP的时候,由于下载的库有问题,后期做起来很困难,在这里我推荐给大家的库:github:https://github.com/robbiehanson/XMPPFramework
本人做的项目demo:https://github.com/humengchi/test.git
第一步、添加依赖
> 拷贝 <XMPPFramework>/Vendor/CocoaLumberjack 到项目根目录下,add files...,选择 CocoaLumberjack 文件夹
> 同样的步骤,拷贝 CocoaAsyncSocket 和 KissXML 并添加到项目中
CocoaAsyncSocket 依赖 CFNetwork.framework 和 Security.framework,在 TARGETS -> Build Phases -> Link Binary With Libraries 添加
KissXML 使用了 libxml2 解析 XML,所以
首先,我们需要在 TARGETS -> Build Phases -> Link Binary With Libraries 添加 libXML2.dylib
然后,在 TARGETS -> Build Settings -> Other Linker Flags 添加 -lxml2,TARGETS -> Build Settings -> Header Search Paths 添加 /usr/include/libxml2
> 拷贝 <XMPPFramework>/Vendor/libidn 到项目根目录下,添加静态库文件 libidn.a 和头文件 idn-int.h 和 stringprep.h
第二步、添加 XMPPFramework
拷贝源码目录下的 Authentication Categories Core 和 Utilities 到项目根目录下并添加到项目中
此外,需要添加动态连接库 libresolv.dylib ,在 TARGETS -> Build Phases -> Link Binary With Libraries 添加
第三步、代码详解
<pre name="code" class="objc">//XMPP方法method
-(void)setupStream{
//初始化XMPPStream
xmppStream = [[XMPPStream alloc] init];
[xmppStream addDelegate:self delegateQueue:dispatch_get_current_queue()];
// dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
//dispatch_get_current_queue()
xmppPing = [[XMPPPing alloc]init];
xmppPing.respondsToQueries = YES;
[xmppPing activate:xmppStream];
xmppReconnect = [[XMPPReconnect alloc]init];
xmppReconnect.autoReconnect = YES;
[xmppReconnect activate:xmppStream];
}
-(void)goOnline{
//发送在线状态
XMPPPresence *presence = [XMPPPresence presence];
[[self xmppStream] sendElement:presence];
}
-(void)goOffline{
//发送下线状态
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[[self xmppStream] sendElement:presence];
}
-(BOOL)connect{
[self setupStream];
//从本地取得用户名,密码和服务器地址
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
#ifndef LOGIN_XMPP
[defaults setObject:@"zjf1" forKey:USERID];
[defaults setObject:@"111111" forKey:PASS];
#endif
[defaults setObject:@"180.166.124.142:9983" forKey:SERVER]; //180.166.124.142:9983 192.168.0.163
[defaults synchronize];
NSString *userId = [defaults stringForKey:USERID];
NSString *pass = [defaults stringForKey:PASS];
NSString *server = [defaults stringForKey:SERVER];
if (![xmppStream isDisconnected]) {
return YES;
}
if (userId == nil) {
return NO;
}
//设置用户
// [xmppStream setMyJID:[XMPPJID jidWithString:userId]];
xmppStream.myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@pc163.anydata.sh",userId]];
//设置服务器
[xmppStream setHostName:server];
// [xmppStream setHostPort:(UInt16)9983];
//密码
password = pass;
//连接服务器
NSError *error = nil;
if (![xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error connecting"
message:@"See console for error details."
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
DDLogError(@"Error connecting: %@", error);
return NO;
}
return YES;
}
-(void)disconnect{
[self goOffline];
[xmppStream disconnect];
}
#pragma mark -XMPPRoom
-(void)initxmpproom
{
xmppRoomStorage = [[XMPPRoomCoreDataStorage alloc] init];
if (xmppRoomStorage==nil) {
NSLog(@"nil");
xmppRoomStorage = [[XMPPRoomCoreDataStorage alloc] init];
}
XMPPJID *roomJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@pc163.anydata.sh",@"groupchat2"]];
xmppRoom = [[XMPPRoom alloc] initWithRoomStorage:xmppRoomStorage jid:roomJID
dispatchQueue:dispatch_get_main_queue()];
[xmppRoom activate:xmppStream];
// 在聊天是显示的昵称
[xmppRoom joinRoomUsingNickname:@"hmc" history:nil];
[xmppRoom fetchConfigurationForm];
[xmppRoom addDelegate:self delegateQueue:dispatch_get_main_queue()];
}
-(void)joinroom
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[xmppRoom fetchConfigurationForm];
[xmppRoom joinRoomUsingNickname:[NSString stringWithFormat:@"%@@pc163.anydata.sh",[defaults stringForKey:USERID]] history:nil];
}
- (void)xmppRoomDidCreate:(XMPPRoom *)sender
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
[sender fetchConfigurationForm];
}
- (void)xmppRoomDidJoin:(XMPPRoom *)sender
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}
#pragma mark -XMPPRoomDelegate
- (void)xmppRoom:(XMPPRoom *)sender didReceiveMessage:(XMPPMessage *)message fromOccupant:(XMPPJID *)occupantJID
{
NSLog(@"群发言了。。。。");
NSString *type = [[message attributeForName:@"type"] stringValue];
if ([type isEqualToString:@"groupchat"]) {
NSString *msg = [[message elementForName:@"body"] stringValue];
// NSString *timexx = [[message attributeForName:@"stamp"] stringValue];
NSString *from = [[message attributeForName:@"from"] stringValue];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
[dict setObject:msg forKey:@"body"];
[dict setObject:from forKey:@"from"];
//消息委托
[messageDelegate newMessageReceived:dict];
}
}
- (void)xmppRoom:(XMPPRoom *)sender occupantDidJoin:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
{
NSLog(@"新人加入群聊");
}
- (void)xmppRoom:(XMPPRoom *)sender occupantDidLeave:(XMPPJID *)occupantJID withPresence:(XMPPPresence *)presence
{
NSLog(@"有人退出群聊");
}
#pragma mark -XmppStreamDelegate
//连接服务器
- (void)xmppStreamDidConnect:(XMPPStream *)sender{
isOpen = YES;
NSError *error = nil;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults stringForKey:PASS] == nil){
return;
}
//验证密码
[[self xmppStream] authenticateWithPassword:password error:&error];
}
//验证通过
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
if(![ADSingletonUtil sharedInstance].chattingIsLogin)
[[NSNotificationCenter defaultCenter] postNotificationName:@"NoticeChattingLoginIsSuccess" object:@"success"];
[self goOnline];
}
//验证失败
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
if(![ADSingletonUtil sharedInstance].chattingIsLogin)
[[NSNotificationCenter defaultCenter] postNotificationName:@"NoticeChattingLoginIsSuccess" object:@"fail"];
NSLog(@"验证失败!");
}
//收到消息
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
if(![[[message attributeForName:@"type"] stringValue] isEqualToString:@"chat"])
return;
NSString *msg = [[message elementForName:@"body"] stringValue];
NSString *from = [[message attributeForName:@"from"] stringValue];
if(msg == nil) return;
//如果用户存在黑名单中,则消息收不到
if([[[[NSUserDefaults standardUserDefaults] objectForKey:@"blacklist"] mutableCopy] containsObject:[[from componentsSeparatedByString:@"@"] firstObject]]){
return;
}
//收到消息声音提示
NSString *path = [[NSBundle mainBundle] pathForResource:@"msgcome" ofType:@"wav"];
NSURL *url = [NSURL fileURLWithPath:path];
SystemSoundID soundId;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)url, &soundId);
AudioServicesPlaySystemSound(soundId);
// AudioServicesPlaySystemSound (kSystemSoundID_Vibrate); //震动
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
//存储接收到的语音消息
if([msg hasPrefix:@"#*audio_s*"]){
NSString *audioString = [msg substringFromIndex:10];
NSDate *date = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyyMMddhhmmss"];
NSString *urlAsString = [NSString stringWithFormat:@"%@%@.amr", GET_URL, audioString];
NSURL *url = [NSURL URLWithString:urlAsString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSError *error = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil
error:&error];
NSString *dateTime = [formatter stringFromDate:date];
NSLog(@"url%@", urlAsString);
/* 下载的数据 */
if (data != nil){
NSLog(@"下载成功");
NSString* wavFileDirectory = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:dateTime]stringByAppendingPathExtension:@"wav"];
NSString *tempUrl = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:audioString]stringByAppendingPathExtension:@"amr"];
if ([data writeToFile:tempUrl atomically:YES]) {
NSData *tempData = [[NSData alloc] initWithContentsOfFile:tempUrl];
NSLog(@"%lu---%lu", (unsigned long)data.length, (unsigned long)tempData.length);
[VoiceConverter amrToWav:tempUrl wavSavePath:wavFileDirectory];
[dict setObject:dateTime forKey:@"audioUrl"];
[dict setObject:@"audio1211" forKey:@"msg"];
[dict setObject:from forKey:@"sender"];
// [dict setObject:[Statics getCurrentTime] forKey:@"time"];
[dict setObject:@"2015-09-01" forKey:@"time"];
NSData *wavData = [[NSData alloc] initWithContentsOfFile:wavFileDirectory];
AVAudioPlayer *player = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:wavFileDirectory] error:nil];
NSLog(@"%lu", (unsigned long)wavData.length);
[dict setObject:[NSString stringWithFormat:@"%d", ((int)player.duration)>60?60:((int)player.duration)] forKey:@"recoderVoiceTime"];
NSString* chatWithUser = [NSString stringWithFormat:@"%@_%@", [self xmppStream].myJID.user, [[from componentsSeparatedByString:@"@"] firstObject]];
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSMutableArray *theArray = [[NSMutableArray alloc] init];
if([userDefault objectForKey:chatWithUser])
theArray = [[userDefault objectForKey:chatWithUser] mutableCopy];
[theArray addObject:dict];
[userDefault setObject:theArray forKey:chatWithUser];
[userDefault synchronize];
}
else
{
NSLog(@"保存失败.");
}
} else {
NSLog(@"%@", error);
}
}else{
//存储接收到的消息
[dict setObject:msg forKey:@"msg"];
[dict setObject:from forKey:@"sender"];
// [dict setObject:[Statics getCurrentTime] forKey:@"time"];
[dict setObject:@"2015-09-01" forKey:@"time"];
NSString* chatWithUser = [NSString stringWithFormat:@"%@_%@", [self xmppStream].myJID.user, [[from componentsSeparatedByString:@"@"] firstObject]];
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSMutableArray *theArray = [[NSMutableArray alloc] init];
if([userDefault objectForKey:chatWithUser])
theArray = [[userDefault objectForKey:chatWithUser] mutableCopy];
[theArray addObject:dict];
[userDefault setObject:theArray forKey:chatWithUser];
[userDefault synchronize];
}
//记录接收消息的数量
NSString* chatWithUser = [NSString stringWithFormat:@"%@_%@", [self xmppStream].myJID.user, [[from componentsSeparatedByString:@"@"] firstObject]];
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSString *key = [NSString stringWithFormat:@"%@_newsnumber", chatWithUser];
if([userDefault objectForKey:key]){
NSInteger n = [[userDefault objectForKey:key] integerValue];
n++;
[userDefault setObject:[NSString stringWithFormat:@"%d",n] forKey:key];
[userDefault synchronize];
}else{
[userDefault setObject:@"1" forKey:key];
[userDefault synchronize];
}
//设置最近联系人
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *_rosterArray = [[NSMutableArray alloc] init];
if([userDefaults objectForKey:[NSString stringWithFormat:@"%@_nearContactFriends", [self xmppStream].myJID.user]]){
_rosterArray = [[userDefaults objectForKey:[NSString stringWithFormat:@"%@_nearContactFriends", [self xmppStream].myJID.user]] mutableCopy];
}
NSString *userContacts = [NSString stringWithFormat:@"%@", [[from componentsSeparatedByString:@"@"] firstObject]];
if([_rosterArray containsObject:userContacts]){
if(_rosterArray.count == 1){
[_rosterArray removeAllObjects];
}else{
[_rosterArray removeObject:userContacts];
}
}
[_rosterArray insertObject:userContacts atIndex:0];
[userDefaults setObject:_rosterArray forKey:[NSString stringWithFormat:@"%@_nearContactFriends", [self xmppStream].myJID.user]];
[userDefaults synchronize];
//通知好友列表有消息,基数+1(消息的数量),刷新tableview
[[NSNotificationCenter defaultCenter] postNotificationName:@"refreshTableView" object:nil];
//消息委托(这个后面讲)
// 接收到的所有未读的新消息
NSString* allNumberChats = [NSString stringWithFormat:@"%@_ALLNUMBERCHAT", [self xmppStream].myJID.user];
if([userDefault objectForKey:allNumberChats]){
NSInteger n = [[userDefault objectForKey:allNumberChats] integerValue];
n++;
[userDefault setObject:[NSString stringWithFormat:@"%d",n] forKey:allNumberChats];
[userDefault synchronize];
}else{
[userDefault setObject:@"1" forKey:allNumberChats];
[userDefault synchronize];
}
//通知车友主界面获得到新的数据,更新UI
[[NSNotificationCenter defaultCenter] postNotificationName:@"GETNEWINFO_ALLNUMBER" object:nil];
[messageDelegate newMessageReceived:dict];
}
//收到好友状态
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
//取得好友状态
NSString *presenceType = [presence type]; //online/offline
//当前用户
NSString *userId = [[sender myJID] user];
//在线用户
NSString *presenceFromUser = [[presence from] user];
if (![presenceFromUser isEqualToString:userId]) {
//在线状态
if ([presenceType isEqualToString:@"available"]) {
//用户列表委托(后面讲)
[chatDelegate newBuddyOnline:[NSString stringWithFormat:@"%@", presenceFromUser]];
}else if ([presenceType isEqualToString:@"unavailable"]) {
//用户列表委托(后面讲)
[chatDelegate buddyWentOffline:[NSString stringWithFormat:@"%@", presenceFromUser]];
}
}
}
//获取好友列表
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
if([@"get" isEqualToString:iq.type]){
DDLogVerbose(@"---------- xmppStream:didReceiveIQ: ----------");
}
NSMutableArray *roster = [[NSMutableArray alloc] init];
if ([@"result" isEqualToString:iq.type]) {
NSXMLElement *query = iq.childElement;
if([@"jabber:iq:roster" isEqualToString:query.xmlns]){
if ([@"query" isEqualToString:query.name]) {
NSArray *items = [query children];
for (NSXMLElement *item in items) {
NSString *jid = [item attributeStringValueForName:@"jid"];
XMPPJID *xmppJID = [XMPPJID jidWithString:jid];
[roster addObject:xmppJID];
}
}
}
}
//
[chatDelegate getRoster:roster];
return YES;
}
#pragma mark -register
- (void)xmppStreamDidRegister:(XMPPStream *)sender
{
NSLog(@"register success!!");
}
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error
{
NSLog(@"register fail!!");
}
@end