上篇对XMPP进行了介绍,以及如果运行第一个XMPP应用程序,现在这篇就来介绍如何使用XMPPFramework第二方库和服务器进行连接。
#pragma mark Private
初始化 XMPPStream
- (void)setupStream
{
xmppStream = [[XMPPStream alloc] init];
#if !TARGET_IPHONE_SIMULATOR{
// 设置后台也进行连接
xmppStream.enableBackgroundingOnSocket = YES;
}
#endif
// 创建XMPPStream重联
xmppReconnect = [[XMPPReconnect alloc] init];
// 创建XMPP花名册.XMPPRosterCoreDataStorage为xmppRoster的代理,里面实现了coreData的保存。
xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];
xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];
xmppRoster.autoFetchRoster = YES;
xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;
// Setup vCard support
// 创建支持vCard
xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
xmppvCardTempModule = [[XMPPvCardTempModule alloc] initWithvCardStorage:xmppvCardStorage];
xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:xmppvCardTempModule];
// Setup capabilities
//
xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:xmppCapabilitiesStorage];
xmppCapabilities.autoFetchHashedCapabilities = YES;
xmppCapabilities.autoFetchNonHashedCapabilities = NO;
// Activate xmpp modules
[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()];
}
// 取消注册
- (void)teardownStream
{
[xmppStream removeDelegate:self];
[xmppRoster removeDelegate:self];
[xmppReconnect deactivate];
[xmppRoster deactivate];
[xmppvCardTempModule deactivate];
[xmppvCardAvatarModule deactivate];
[xmppCapabilities deactivate];
[xmppStream disconnect];
xmppStream = nil;
xmppReconnect = nil;
xmppRoster = nil;
xmppRosterStorage = nil;
xmppvCardStorage = nil;
xmppvCardTempModule = nil;
xmppvCardAvatarModule = nil;
xmppCapabilities = nil;
xmppCapabilitiesStorage = nil;
}
// 向服务器发送上线操作.
- (void)goOnline
{
XMPPPresence *presence = [XMPPPresence presence]; // type默认为available
[[self xmppStream] sendElement:presence];
}
// 向服务器发送下线操作
- (void)goOffline
{
XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
[[self xmppStream] sendElement:presence];
}
#pragma mark Connect/disconnect
连接服务器
- (BOOL)connect
{
if (![xmppStream isDisconnected]) { // 如果已经连接
return YES;
}
NSString *myJID = [[NSUserDefaults standardUserDefaults] stringForKey:kXMPPmyJID];
NSString *myPassword = [[NSUserDefaults standardUserDefaults] stringForKey:kXMPPmyPassword];
if (myJID == nil || myPassword == nil) {
return NO;
}
[xmppStream setMyJID:[XMPPJID jidWithString:myJID]];// 设置账号
// 设置服务器域名,如果不设置默认为账号后面的域名//
// [xmppStream setHostName:@""];
// 设置端口号,如果不设置默认为5222
// [xmppStreamsetHostPort:5222];
password = myPassword;
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 XMPPStream Delegate
// 正在连接中….
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
if (allowSelfSignedCertificates){
[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];
}
if (allowSSLHostNameMismatch)
{
[settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
}else{
// Google does things incorrectly (does not conform to RFC).
// Because so many people ask questions about this (assume xmpp framework is broken),
// I've explicitly added code that shows how other xmpp clients "do the right thing"
// when connecting to a google server (gmail, or google apps for domains).
NSString *expectedCertName = nil;
NSString *serverDomain = xmppStream.hostName;
NSString *virtualDomain = [xmppStream.myJID domain];
if ([serverDomain isEqualToString:@"talk.google.com"]){
if ([virtualDomain isEqualToString:@"gmail.com"]){
expectedCertName = virtualDomain;
}else{
expectedCertName = serverDomain;
}
}else if (serverDomain == nil){
expectedCertName = virtualDomain;
}else{
expectedCertName = serverDomain;
}
if (expectedCertName){
[settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
}
}
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
}
// 成功连接服务器
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSError *error = nil;
// 对用户进行认证
if (![[self xmppStream] authenticateWithPassword:password error:&error]){
DDLogError(@"Error authenticating: %@", error);
}
}
// 认证成功
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
[self goOnline];
}
// 认证失败
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
}
- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq
{
return NO;
}
// 收到消息
- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message
{
// A simple example of inbound message handling.
if ([message isChatMessageWithBody]){
XMPPUserCoreDataStorageObject *user = [xmppRosterStorage userForJID:[message from]
xmppStream:xmppStream
managedObjectContext:[self managedObjectContext_roster]];
NSString *body = [[message elementForName:@"body"] stringValue];
NSString *displayName = [user displayName];
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:displayName
message:body
delegate:nil
cancelButtonTitle:@"Ok"
otherButtonTitles:nil];
[alertView show];
}else{
// We are not active, so use a local notification instead
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertAction = @"Ok";
localNotification.alertBody = [NSString stringWithFormat:@"From: %@\n\n%@",displayName,body];
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
}
}
// 收到好友上线下线,正在输入等一些消息
- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence
{
DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, [presence fromStr]);
}
// 收到错误消息
- (void)xmppStream:(XMPPStream *)sender didReceiveError:(id)error
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
}
// 连接出错
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
if (!isXmppConnected)
{
DDLogError(@"Unable to connect to server. Check xmppStream.hostName");
}
}
#pragma mark XMPPRosterDelegate
// 收到花名册
- (void)xmppRoster:(XMPPRoster *)sender didReceiveBuddyRequest:(XMPPPresence *)presence
{
DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);
XMPPUserCoreDataStorageObject *user = [xmppRosterStorage userForJID:[presence from]
xmppStream:xmppStream
managedObjectContext:[self managedObjectContext_roster]];
NSString *displayName = [user displayName];
NSString *jidStrBare = [presence fromStr];
NSString *body = nil;
if (![displayName isEqualToString:jidStrBare]){
body = [NSString stringWithFormat:@"Buddy request from %@ <%@>", displayName, jidStrBare];
}else{
body = [NSString stringWithFormat:@"Buddy request from %@", displayName];
}
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive){
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:displayName
message:body
delegate:nil
cancelButtonTitle:@"Not implemented"
otherButtonTitles:nil];
[alertView show];
} else {
// We are not active, so use a local notification instead
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertAction = @"Not implemented";
localNotification.alertBody = body;
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
}