iPhone平台下基于XMPP的IM研究

来源:互联网 发布:黑鹰直升机 中国 知乎 编辑:程序博客网 时间:2024/05/10 12:09

       空闲之余,看了下iphone平台下xmpp的使用。我是个懒人不喜欢重复发明轮子,也许这也就是为什么我写的代码难登大雅之堂的原因吧,呵呵!

      XmppFramework 是一个开源项目,使用Objective-C实现了XMPP协议,它和前面所说的smack使用起来一样的方便,不过官网上提供的资料远不及smack。

     源码地址:http://code.google.com/p/xmppframework/,目前需要使用git才能download到源码,。

   

    PC客户端使用Spark,不知是否是我的黑苹果原因,spark装上不能运行(郁闷中...)

    服务器使用Openfire

    数据库我使用还是MySQL

    怎样将XMPPFramework添加到我们自己的项目中,请参考http://kongkongbrain.blog.163.com/blog/static/17819901320114235295322/,感谢这位兄弟,因为网上关于这个框架的使用文章太少了。

     代码步骤:

1、初始化XMPPStream 

xmppStream = [[XMPPStream alloc] init];

xmppStream.hostName = @"127.0.0.1";

xmppStream.hostPort = 5222;

[xmppStreamaddDelegate:selfdelegateQueue:dispatch_get_main_queue()];

XmppFramework的消息监听方式使用delegate。在smack中我们使用的是listener,其实都一样。


2、设置JID;(注意JID的Domain一定要用主机名,不要用IP地址。我的疏忽让我晚上熬到了3点多)

xmppStream.myJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@liu-lavymatoMacBook-Pro.local",myJID]];

3、连接服务器

NSError *error = nil;

[xmppStream connect:&error];

接下来就是一系列依次调用delegate的方法

xmppStreamWillConnect

socketDidConnect

xmppStreamDidConnect 在这个方法中我们需要调用:         [xmppStreamauthenticateWithPassword:myPassworderror:&error]

验证成功:xmppStreamDidAuthenticate:

验证失败:xmppStream: didNotAuthenticate:


////  XmppTest1AppDelegate.h//  XmppTest1////  Created by liu lavy on 11-10-2.//  Copyright 2011 __MyCompanyName__. All rights reserved.//#import <UIKit/UIKit.h>#import "XMPPFramework.h"@class XmppTest1ViewController;@interface XmppTest1AppDelegate : NSObject <UIApplicationDelegate, XMPPRosterDelegate> {    UIWindow *window;    XmppTest1ViewController *viewController;XMPPStream *xmppStream;XMPPReconnect *xmppReconnect;NSString *myPassword;}@property (nonatomic, retain) IBOutlet UIWindow *window;@property (nonatomic, retain) IBOutlet XmppTest1ViewController *viewController;@property (nonatomic, retain) XMPPStream *xmppStream;@property (nonatomic, readonly) XMPPReconnect *xmppReconnect;@property (nonatomic, retain) NSString *myPassword;-(BOOL) connect:(NSString *)myJID password:(NSString *)myPassword;-(BOOL) authenticate;-(void) disConnect;@end


////  XmppTest1AppDelegate.m//  XmppTest1////  Created by liu lavy on 11-10-2.//  Copyright 2011 __MyCompanyName__. All rights reserved.//#import "XmppTest1AppDelegate.h"#import "XmppTest1ViewController.h"#import "DDLog.h"#import "DDTTYLogger.h"#if DEBUGstatic const int ddLogLevel = LOG_LEVEL_VERBOSE;#elsestatic const int ddLogLevel = LOG_LEVEL_VERBOSE;#endif@interface XmppTest1AppDelegate(PrivateMethod)-(void) setupStream;-(void) teardownStream;@end@implementation XmppTest1AppDelegate@synthesize window;@synthesize viewController;@synthesize xmppStream;@synthesize xmppReconnect;@synthesize myPassword;#pragma mark -#pragma mark Application lifecycle- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {        [DDLog addLogger:[DDTTYLogger sharedInstance]];    self.window.rootViewController = self.viewController;    [self.window makeKeyAndVisible];[self setupStream];    return YES;}-(void) setupStream {NSAssert(xmppStream == nil, @"Method setupStream invoked multiple times");xmppStream = [[XMPPStream alloc] init];xmppReconnect = [[XMPPReconnect alloc] init];[xmppReconnect activate:xmppStream];[xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];[xmppReconnect addDelegate:self delegateQueue:dispatch_get_main_queue()];xmppStream.hostName = @"127.0.0.1";xmppStream.hostPort = 5222;}-(void) teardownStream {[xmppStream removeDelegate:self];[xmppReconnect deactivate];[xmppStream disconnect];xmppStream = nil;xmppReconnect = nil;}-(BOOL) connect:(NSString *)myJID password:(NSString *)password {if([xmppStream isConnected]) {[self disConnect];}self.myPassword = password;if(!myPassword|| [myPassword length] == 0) {UIAlertView *alertViewValidate = [[UIAlertView alloc] initWithTitle:@"连接失败" message:@"密码不能为空"    delegate:nil  cancelButtonTitle:@"OK"   otherButtonTitles:nil];[alertViewValidate show];[alertViewValidate release];return NO;}NSError *error = nil;XMPPJID *myXmppJID = [XMPPJID jidWithString:[NSString stringWithFormat:@"%@@liu-lavymatoMacBook-Pro.local",myJID]];//XMPPJID *myXmppJID = [XMPPJID jidWithString:@"test1@liu-lavymatoMacBook-Pro.local"];xmppStream.myJID = myXmppJID;//NSLog(@"%@", [NSString stringWithFormat:@"%d",[xmppStream connect:&error]]);if(![xmppStream connect:&error]) {UIAlertView *alertViewFailedConn = [[UIAlertView alloc] initWithTitle:@"连接失败"   message:@"详细请查看控制台"  delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:nil];[alertViewFailedConn show];[alertViewFailedConn release];DDLogError(@"Error connecting: %@", error);return NO;}DDLogVerbose(@"连接成功");return YES;}-(BOOL) authenticate {return YES;}-(void) disConnect {XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];[[self xmppStream] sendElement:presence];[xmppStream disconnect];}#pragma mark XMPPStream Delegate- (void)xmppStreamWillConnect:(XMPPStream *)sender {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket  {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}- (void)xmppStreamDidConnect:(XMPPStream *)sender {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);DDLogVerbose(@"jid is %@@%@, password is %@", xmppStream.myJID.user, xmppStream.myJID.domain, myPassword);NSError *error;if(![xmppStream authenticateWithPassword:myPassword error:&error]) {UIAlertView *alertViewFailedConn = [[UIAlertView alloc] initWithTitle:@"验证失败"   message:@"详细请查看控制台"  delegate:nilcancelButtonTitle:@"OK"otherButtonTitles:nil];[alertViewFailedConn show];[alertViewFailedConn release];DDLogError(@"Error authenticating: %@", error);return;}}- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);XMPPPresence *presence = [XMPPPresence presence];[xmppStream sendElement:presence];}- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error{DDLogVerbose(@"%@: %@", xmppStream.myJID.user, xmppStream.myJID.domain);}- (void)xmppStream:(XMPPStream *)sender didReceiveError:(id)error{DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}- (void)xmppStreamDidSecure:(XMPPStream *)sender {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);//[settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString *)kCFStreamSSLAllowsAnyRoot];//[settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLLevel];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)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message {}- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);//if (!isXmppConnected) {//DDLogError(@"Unable to connect to server. Check xmppStream.hostName");//}}- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence {DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, [presence fromStr]);}- (void)xmppRoster:(XMPPRoster *)sender didReceiveBuddyRequest:(XMPPPresence *)presence {}- (void)applicationWillResignActive:(UIApplication *)application {    /*     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.     */}- (void)applicationDidEnterBackground:(UIApplication *)application {    /*     Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.      If your application supports background execution, called instead of applicationWillTerminate: when the user quits.     */DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}- (void)applicationWillEnterForeground:(UIApplication *)application {    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);}- (void)applicationDidBecomeActive:(UIApplication *)application {    /*     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.     */}- (void)applicationWillTerminate:(UIApplication *)application {    /*     Called when the application is about to terminate.     See also applicationDidEnterBackground:.     */}#pragma mark -#pragma mark Memory management- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {    /*     Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.     */}- (void)dealloc {[self teardownStream];[xmppStream release];[xmppReconnect release];[myPassword release];    [viewController release];    [window release];    [super dealloc];}@end


////  XmppTest1ViewController.h//  XmppTest1////  Created by liu lavy on 11-10-2.//  Copyright 2011 __MyCompanyName__. All rights reserved.//#import <UIKit/UIKit.h>@interface XmppTest1ViewController : UIViewController {UITextField *fieldJid;UITextField *fieldPwd;}@property (nonatomic, retain) IBOutlet UITextField *fieldJid;@property (nonatomic, retain) IBOutlet UITextField *fieldPwd;-(IBAction) login:(id)sender;-(IBAction) textFieldDownEditing:(id)sender;-(IBAction) backgroundTap:(id)sender;@end


////  XmppTest1ViewController.m//  XmppTest1////  Created by liu lavy on 11-10-2.//  Copyright 2011 __MyCompanyName__. All rights reserved.//#import "XmppTest1ViewController.h"#import "XMPPFramework.h"#import "DDLog.h"#import "XmppTest1AppDelegate.h"#if DEBUGstatic const int ddLogLevel = LOG_LEVEL_VERBOSE;#elsestatic const int ddLogLevel = LOG_LEVEL_INFO;#endif@implementation XmppTest1ViewController@synthesize fieldJid;@synthesize fieldPwd;-(XmppTest1AppDelegate *) appDelegate {return (XmppTest1AppDelegate *)[[UIApplication sharedApplication] delegate];}-(IBAction) login:(id)sender {NSString *myJID = fieldJid.text;NSString *password = fieldPwd.text;if([[self appDelegate] connect:myJID password:password]) {}}-(IBAction) textFieldDownEditing:(id)sender {[sender resignFirstResponder];}-(IBAction) backgroundTap:(id)sender {[fieldJid resignFirstResponder];[fieldPwd resignFirstResponder];}/*// The designated initializer. Override to perform setup that is required before the view is loaded.- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];    if (self) {        // Custom initialization    }    return self;}*//*// Implement loadView to create a view hierarchy programmatically, without using a nib.- (void)loadView {}*/// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.- (void)viewDidLoad {}/*// Override to allow orientations other than the default portrait orientation.- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {    // Return YES for supported orientations    return (interfaceOrientation == UIInterfaceOrientationPortrait);}*/- (void)didReceiveMemoryWarning {// Releases the view if it doesn't have a superview.    [super didReceiveMemoryWarning];// Release any cached data, images, etc that aren't in use.}- (void)viewDidUnload {fieldJid = nil;fieldPwd = nil;}- (void)dealloc {[fieldJid release];[fieldPwd release];    [super dealloc];}@end

当然我也是看XMPPFramework里面的例子学习的,那是个好东西,下一步该学习怎样通过服务器发送消息了。