查了资料发现 现在的聊天服务器有开源的 有很多种 很多都是机遇xmpp协议来实现的,xmpp的前身是什么jabber 这个就自己去百度了 我用的一个开源服务器是 openfire 他有 linux mac window版本 他的安装都是比较简单的就部介绍了 网上找到了这个很好的博客
http://www.cnblogs.com/dyingbleed/archive/2013/05/09/3069145.html
http://blog.csdn.net/ihefe/article/details/8230414
想想其实他的实现方式 还是相对比较简单的 很多都是靠xmpp自己来实现的 我们只要在协议方法里面获得数据 其他的我们都不用考虑
实现xmpp 要用到一个框架 自己到网上去下载
XMPPFramework
网上下的demo要修改几个地方 一个是要连接的服务器的地址 本及其的话 就127.0.0.1 其他地方的话 就对应他的ip 还有一点就是 域名的概念 登陆的用户名 是这样的格式 :用户名@域名 域名可以在你的openfire的服务器设置里面查看
(以下代码为了方便使用-调用都写在appdeleage里面)
第一步:算是初始化吧
.h里面
- #import <</span>UIKit/UIKit.h>
- #import "XMPPFramework.h"
- @interface AppDelegate : UIResponder <</span>UIApplicationDelegate>
- {
- // XMPPStream *xmppStream;
- // XMPPRoster *xmppRoster;
- // XMPPRosterCoreDataStorage *xmppRosterStorage;
- // XMPPReconnect *xmppReconnect;
- // XMPPMessageArchivingCoreDataStorage *xmppMessageArchivingCoreDataStorage;
- // XMPPMessageArchiving *xmppMessageArchivingModule;
-
-
-
- XMPPReconnect *xmppReconnect;
- XMPPStream *xmppStream;
- XMPPvCardCoreDataStorage*xmppvCardStorage ;
- XMPPvCardTempModule*xmppvCardTempModule ;
- XMPPvCardAvatarModule* xmppvCardAvatarModule ;
-
- // 初始化 capabilities
-
-
- XMPPCapabilitiesCoreDataStorage * xmppCapabilitiesStorage ;
- XMPPCapabilities* xmppCapabilities;
- XMPPRosterCoreDataStorage* xmppRosterStorage;
- // xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
- BOOL isXmppConnected;
- NSString *password;
- XMPPRoster* xmppRoster ;
-
- XMPPMessageArchivingCoreDataStorage *xmppMessageArchivingCoreDataStorage;
- XMPPMessageArchiving *xmppMessageArchivingModule;
-
- BOOL allowSelfSignedCertificates;
- BOOL allowSSLHostNameMismatch;
- }
- //---------------------------------------------------------------------
- @property (nonatomic, strong) XMPPStream *xmppStream;
- @property (nonatomic, strong) XMPPRosterCoreDataStorage *xmppRosterStorage;
- @property (nonatomic, strong) XMPPRoster *xmppRoster;
- @property (nonatomic, strong) XMPPReconnect *xmppReconnect;
- @property (nonatomic, strong) XMPPMessageArchivingCoreDataStorage *xmppMessageArchivingCoreDataStorage;
- @property (nonatomic, strong) XMPPMessageArchiving *xmppMessageArchivingModule;
- @property (strong, nonatomic) UIWindow *window;
- - (BOOL)connect:(NSString *)loginName;
- -(void)showAlertView:(NSString *)message;
-
- @property (nonatomic, strong) NSMutableArray *friendArray;
- @end
.m里面
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
- {
- [self setupStream];
- return YES;
- }
- - (void)setupStream
- {
- NSAssert(xmppStream == nil, @"Method setupStream invoked multiple times");
-
- // 初始化XmppStream
-
- xmppStream = [[XMPPStream alloc] init];
-
- #if !TARGET_IPHONE_SIMULATOR
- {
- // 想要xampp在后台也能运行?
- //
- // P.S. - 虚拟机不支持后台
-
- xmppStream.enableBackgroundingOnSocket = YES;
- }
- #endif
-
- // 初始化 reconnect
- //
- // 这东西可以帮你把意外断开的状态连接回去...具体看它的头文件定义
-
- xmppReconnect = [[XMPPReconnect alloc] init];
-
- // 初始化 roster
-
- xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
- // xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] initWithInMemoryStore];
-
- xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];
-
- xmppRoster.autoFetchRoster = YES;
- xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
-
- // 初始化 vCard support
-
- xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
- xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:xmppvCardStorage];
-
- xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:xmppvCardTempModule];
-
- // 初始化 capabilities
-
-
- xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
- xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:xmppCapabilitiesStorage];
-
- xmppCapabilities.autoFetchHashedCapabilities = YES;
- xmppCapabilities.autoFetchNonHashedCapabilities = NO;
-
- // 激活xmpp的模块
-
- [xmppReconnect activate:xmppStream];
- [xmppRoster activate:xmppStream];
- [xmppvCardTempModule activate:xmppStream];
- [xmppvCardAvatarModule activate:xmppStream];
- [xmppCapabilities activate:xmppStream];
-
- // 我们可以加添加委托来获取我们感兴趣的东西
-
- [xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
- [xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
-
- // 下面可以替换成自己的域名和端口
-
- // 如果你没有提供一个地址,JID也是一样可以代替的,JID的格式类似这样"用户名@域名/roster",框架会自动抓取域名作为你的地址
-
- // 如果没有设置特殊的端口,默认为5222
-
- [xmppStream setHostName:@"223.4.32.64"];//AY130618164649Z
- [xmppStream setHostPort:5222];
-
-
- //下面这两个根据你自己配置需要来设置
- allowSelfSignedCertificates = NO;
- allowSSLHostNameMismatch = NO;
- }
//连接的代码
//连接到openfire
- (BOOL)connect:(NSString *)loginName{
NSString *jid =loginName;
NSString *ps = @"123的";//没用
if (jid == nil || ps ==nil) {
return NO;
}
if (jid == nil || ps ==nil) {
return NO;
}
XMPPJID *myjid = [XMPPJIDjidWithString:jid];
NSError *error ;
[xmppStreamsetMyJID:myjid];
if (![xmppStreamconnectWithTimeout:XMPPStreamTimeoutNoneerror:&error]) {
NSLog(@"my connected error : %@",error.description);
return NO;
}
return YES;
}
以下是主要的一些会使用到的方法
- //将要连接
- - (void)xmppStreamWillConnect:(XMPPStream *)sender
- {
- NSLog(@"xmppStreamWillConnect");
- }
- //已经连接
- - (void)xmppStreamDidConnect:(XMPPStream *)sender
- {
- NSLog(@"xmppStreamDidConnect");
- NSError *error ;
- if (![self.xmppStream authenticateWithPassword:@"123" error:&error]) { //密码跟 [email protected] 的密码对应
- NSLog(@"error authenticate : %@",error.description);
- }
- }
-
- //注册
- - (void)xmppStreamDidRegister:(XMPPStream *)sender
- {
- NSLog(@"xmppStreamDidRegister");
-
- NSError *error ;
- if (![self.xmppStream authenticateWithPassword:@"123" error:&error]) {
- NSLog(@"error authenticate : %@",error.description);
- }
- }
- -(void)goOnline{
-
- //发送在线状态
- XMPPPresence *presence = [XMPPPresence presence];
- [[self xmppStream] sendElement:presence];
-
- }
- - (void)goOffline
- {
- XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
-
- [[self xmppStream] sendElement:presence];
- }
-
- - (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error
- {
- [self showAlertView:@"当前用户已经存在"];
- }
- //上线
- - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
- {
- [self goOnline];
- }
- - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
- {
- NSLog(@"didNotAuthenticate:%@",error.description);
- }
- - (NSString *)xmppStream:(XMPPStream *)sender alternativeResourceForConflictingResource:(NSString *)conflictingResource
- {
- NSLog(@"alternativeResourceForConflictingResource: %@",conflictingResource);
- return @"XMPPIOS";
- }
- //获取到好友列表
- - (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
- {
- NSString *str=@"";
- self.friendArray =[[NSMutableArray alloc] init];
- // NSLog(@"获取到好友列表didReceiveIQ: %@",iq.description);
- if ([@"result" isEqualToString:iq.type]) {
- NSXMLElement *query = iq.childElement;
- if ([@"query" isEqualToString:query.name]) {
- NSArray *items = [query children];
- for (NSXMLElement *item in items) {
- NSString *jid = [item attributeStringValueForName:@"jid"];
- XMPPJID *xmppJID = [XMPPJID jidWithString:jid];
- NSLog(@"好友:%@",xmppJID);
- str = [NSString stringWithFormat:@"%@\n%@",str,xmppJID];
- [self.friendArray addObject:[NSString stringWithFormat:@"%@",xmppJID]];
- }
- //通知
- [[NSNotificationCenter defaultCenter] postNotificationName:@"user" object:nil userInfo:[NSDictionary dictionaryWithObject:self.friendArray forKey:@"userlist"]];
- }
- }
-
- return YES;
- }
- //收到信息
- - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
- {
- NSString *msg = [[message elementForName:@"body"] stringValue];
- NSString *from = [[message attributeForName:@"from"] stringValue];
- NSLog(@"消息内容:\n%@ 信息来源:\n%@ ",msg,from);
- NSString *str = [NSString stringWithFormat:@"消息内容:\n%@ 信息来源:\n%@ ",msg,from];
- UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"好友" message:str delegate:nil cancelButtonTitle:@"ok" otherButtonTitles:nil, nil];
- [alert show];
- [[NSNotificationCenter defaultCenter] postNotificationName:@"userMSG" object:nil userInfo:[NSDictionary dictionaryWithObject:str forKey:@"MSG"]];
- }
- //获取好友状态,通过实现
- //available 上线
- //away 离开
- //do not disturb 忙碌
- //unavailable 下线
- - (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
- {
- //取得好友状态
- NSString *presenceType = [presence type]; //online/offline
- //当前用户
- // NSString *userId = [[sender myJID] user];
- //在线用户
- NSString *presenceFromUser = [[presence from] user];
-
- NSLog(@"状态:%@ 帐号:%@",presenceType,presenceFromUser);
- }
这里要强调一个 方法
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
这个协议方法是获取好友的状态的 我发现 只有 有好友是在线的 他才会调用!
注册注意点
要先创建一个匿名的连接才可以进行注册
[[selfappDelegate] connect:@"匿名连接"];
//获取appdelegate的连接方法
- (AppDelegate *)appDelegate
{
return (AppDelegate *)[[UIApplicationsharedApplication] delegate];
}
注册代码
- (IBAction)RegAction:(id)sender {
NSError *error ;
if ([[[selfappDelegate] xmppStream]isConnected] && [[[selfappDelegate]xmppStream]supportsInBandRegistration])
{
[[selfappDelegate].xmppStreamsetMyJID:[XMPPJIDjidWithUser:self.userName.textdomain:@"AY130618164649Z"resource:@"xmpp"]];
// [[self appDelegate]setIsRegistration:YES];
if (![[selfappDelegate].xmppStreamregisterWithPassword:@"123"error:&error]) {
[[selfappDelegate] showAlertView:[NSStringstringWithFormat:@"%@",error.description]];
}
UIAlertView *alert = [[UIAlertViewalloc] initWithTitle:@"Success"message:@"Resgister Success"delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:nil,nil];
[alertshow];
}
else
{
UIAlertView *alert = [[UIAlertViewalloc] initWithTitle:@"Fail"message:@"Resgister Fail"delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:nil,nil];
[alertshow];
}
}
登陆的代码
- (IBAction)connectAction:(id)sender {
//断开连接
[[[selfappDelegate] xmppStream]disconnect];
//重新请求连接登陆
[[selfappDelegate] connect:self.loginName.text];
//接受好友列表的通知
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(show:)name:@"user"object:nil];
[self.loginNameresignFirstResponder];
}
添加好友的代码
//添加好友
- (IBAction)AddAction:(id)sender {
[[[selfappDelegate] xmppRoster]addUser:[XMPPJIDjidWithString:[NSStringstringWithFormat:@"%@@AY130618164649Z",self.jidName.text]]withNickname:self.jidName.text];
}
//
AY130618164649Z ===》域名