首页了解用户唯一标识有什么组成(JID):
JID 一般由三部分构成:用户名,域名和资源名,例如 [email protected]/Anthony
如果没有设置主机名,则使用 JID 的域名作为主机名
端口号是可选的,默认是 5222
下面动手开始,来创建一个单例,用于全权负责管理与XMPP交互,
@interface HYBXMPPHelper : NSObject <XMPPStreamDelegate, XMPPRosterDelegate> /** * Singleton shared method */ + (HYBXMPPHelper *)shared; - (BOOL)connect; - (BOOL)disconnect; // 上线 - (void)goOnline; // 下线 - (void)goOffline; - (void)destroyResources; @end
@property (nonatomic, strong) XMPPStream *xmppStream; @property (nonatomic, strong) XMPPReconnect *xmppReconnect; // 花名册相关 @property (nonatomic, strong) XMPPRoster *xmppRoster; @property (nonatomic, strong) XMPPRosterCoreDataStorage *xmppRosterStorage;
+ (HYBXMPPHelper *)shared { static HYBXMPPHelper *sg_xmppSharedObject = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!sg_xmppSharedObject) { sg_xmppSharedObject = [[self alloc] init]; [sg_xmppSharedObject setupXmppStream]; } }); return sg_xmppSharedObject; }
- (void)setupXmppStream { NSAssert(_xmppStream == nil, @"-setupXmppStream method called multiple times"); _jid = [[NSUserDefaults standardUserDefaults] objectForKey:kUserJIDKey]; _password = [[NSUserDefaults standardUserDefaults] objectForKey:kUserPasswordKey]; _xmppStream = [[XMPPStream alloc] init]; #if !TARGET_IPHONE_SIMULATOR // 设置此行为YES,表示允许socket在后台运行 // 在模拟器上是不支持在后台运行的 _xmppStream.enableBackgroundingOnSocket = YES; #endif // XMPPReconnect模块会监控意外断开连接并自动重连 _xmppReconnect = [[XMPPReconnect alloc] init]; // 配置花名册并配置本地花名册储存 _xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init]; _xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:_xmppRosterStorage]; _xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES; _xmppRoster.autoFetchRoster = YES; // 配置vCard存储支持,vCard模块结合vCardTempModule可下载用户Avatar _xmppvCardStorage = [[XMPPvCardCoreDataStorage alloc] init]; _xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:_xmppvCardStorage]; _xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:_xmppvCardTempModule]; // XMPP特性模块配置,用于处理复杂的哈希协议等 _xmppCapailitiesStorage = [[XMPPCapabilitiesCoreDataStorage alloc] init]; _xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:_xmppCapailitiesStorage]; _xmppCapabilities.autoFetchHashedCapabilities = YES; _xmppCapabilities.autoFetchNonHashedCapabilities = NO; // 激活XMPP stream [_xmppReconnect activate:_xmppStream]; [_xmppRoster activate:_xmppStream]; [_xmppvCardTempModule activate:_xmppStream]; [_xmppvCardAvatarModule activate:_xmppStream]; [_xmppCapabilities activate:_xmppStream]; // 消息相关 _xmppMessageStorage = [[XMPPMessageArchivingCoreDataStorage alloc] init]; _xmppMessageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:_xmppMessageStorage]; [_xmppMessageArchiving setClientSideMessageArchivingOnly:YES]; [_xmppMessageArchiving activate:_xmppStream]; // 添加代理 [_xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; [_xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()]; [_xmppMessageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()]; }
- (void)destroyResources { [_xmppStream removeDelegate:self]; [_xmppRoster removeDelegate:self]; [_xmppReconnect deactivate]; [_xmppRoster deactivate]; [_xmppvCardTempModule deactivate]; [_xmppvCardAvatarModule deactivate]; [_xmppCapabilities deactivate]; [_xmppMessageArchiving deactivate]; [_xmppStream disconnect]; _xmppStream = nil; _xmppRoster = nil; _xmppReconnect = nil; _xmppRosterStorage = nil; _xmppvCardAvatarModule = nil; _xmppvCardStorage = nil; _xmppvCardTempModule = nil; _xmppCapabilities = nil; _xmppCapailitiesStorage = nil; _xmppMessageStorage = nil; _xmppMessageArchiving = nil; }
- (void)applicationWillTerminate:(UIApplication *)application { [[HYBXMPPHelper shared] destroyResources]; }
先对外公开一个注册API,然后实现:
- (void)registerWithJid:(NSString *)jidString password:(NSString *)password completion:(HYBCompletionBlock)completion { _isLogining = NO; if (_isRegistering) { return; } if (jidString == nil || password == nil) { if (completion) { completion(NO, @"用户名或者密码不能为空"); } return; } _jid = jidString; _password = password; self.completionBlock = completion; _isRegistering = YES; if (![_xmppStream isConnected]) { if (![self connect]) { _isRegistering = NO; if (completion) { completion(NO, @"连接服务器失败"); } } return; } [self registerWithJid:jidString]; } - (void)registerWithJid:(NSString *)jidString { if (![jidString hasSuffix:kServer]) { jidString = [NSString stringWithFormat:@"%@@%@", jidString, kServer]; } [_xmppStream setMyJID:[XMPPJID jidWithString:jidString]]; // 设置服务器 [_xmppStream setHostName:kServer]; NSError *error = nil; _isRegistering = YES; if (![_xmppStream registerWithPassword:_password error:&error]) { NSLog(@"注册账号失败:%@", [error description]); _isRegistering = NO; if (self.completionBlock) { self.completionBlock(NO, [error description]); } } }
- (BOOL)connect { if (![_xmppStream isDisconnected]) { return NO; } if (_jid == nil || _password == nil) { return NO; } [_xmppStream setMyJID:[XMPPJID jidWithString:_jid]]; [_xmppStream setHostName:kServer]; // 连接 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]; NSLog(@"Error connecting: %@", [error description]); return NO; } return YES; }
// @begin // 注册相关 - (void)xmppStreamDidRegister:(XMPPStream *)sender { NSLog(@"注册成功"); if (self.completionBlock && _isRegistering) { self.completionBlock(YES, nil); } _isRegistering = NO; } - (void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error { /* <iq xmlns="jabber:client" type="error" to="127.0.0.1/347f0596"> <query xmlns="jabber:iq:register"> <username>test</username> <password>test</password> </query> <error code="409" type="cancel"> <conflict xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"></conflict> </error> </iq> */ NSLog(@"注册失败: %@", error); DDXMLElement *query = [error elementForName:@"query"]; DDXMLElement *username = [query elementForName:@"username"]; DDXMLElement *password = [query elementForName:@"password"]; DDXMLElement *errorNode = [error elementForName:@"error"]; int code = [errorNode attributeIntValueForName:@"code"]; NSLog(@"%@ %@", [username stringValue], [password stringValue]); if (self.completionBlock && _isRegistering && !_isLogining) { self.completionBlock(NO, [self errorMessageWithErrorCode:code]); } _isRegistering = NO; } // @end
下面看看登录:
1、先对外公开一个登录API:
- (void)loginWithJid:(NSString *)jidString password:(NSString *)password completion:(HYBCompletionBlock)completion { _isRegistering = NO; if (_xmppStream.isAuthenticated) {// 已经登录了,就无须再登录 if (completion) { completion(YES, nil); } return; } if (_isLogining) { return; } if (jidString == nil || password == nil) { if (completion) { completion(NO, @"用户名或者密码不能为空"); } return; } _jid = jidString; _password = password; self.completionBlock = completion; _isLogining = YES; if (![_xmppStream isConnected]) { if (![self connect]) { _isLogining = NO; if (completion) { completion(NO, @"连接服务器失败"); } } return; } [self loginWithJid:jidString]; } - (void)loginWithJid:(NSString *)jidString { if (![jidString hasSuffix:kServer]) { jidString = [NSString stringWithFormat:@"%@@%@", jidString, kServer]; } [_xmppStream setMyJID:[XMPPJID jidWithString:jidString]]; // 设置服务器 [_xmppStream setHostName:kServer]; NSError *error = nil; _isLogining = YES; if (![_xmppStream authenticateWithPassword:_password error:&error]) { NSLog(@"登录失败:%@", [error description]); _isLogining = NO; if (self.completionBlock) { self.completionBlock(NO, [error description]); } } }
// @begin // 登录相关 - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender { if (_isRegistering) { [self registerWithJid:_jid]; return; } // 登录成功 if (self.completionBlock && _isLogining) { self.completionBlock(YES, nil); } NSLog(@"密码校验成功,用户将要上线"); _isLogining = NO; [self goOnline]; } - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error { if (_isRegistering) { [self registerWithJid:_jid]; return; } if (_isLogining) { [self loginWithJid:_jid]; return; } _isLogining = NO; NSLog(@"didNotAuthenticate :密码校验失败,登录不成功,原因是:%@", [error XMLString]); } // @end
- (void)goOnline { // 获取现场节点,默认type = "available" XMPPPresence *presence = [XMPPPresence presence]; NSString *domain = [_xmppStream.myJID domain]; // Google set their presence priority to 24, so we do the same to be compatible. if ([domain isEqualToString:@"gmail.com"] || [domain isEqualToString:@"gtalk.com"] || [domain isEqualToString:@"talk.google.com"]) { NSXMLElement *priority = [NSXMLElement elementWithName:@"priority" stringValue:@"24"]; [presence addChild:priority]; } // 发送下线信息 [_xmppStream sendElement:presence]; }
到此就完成了登录、注册功能了!!!