//首先要配置好環境,Xampp / openfire /spark數組
XmppManager.h文件服務器
#import <Foundation/Foundation.h> #import "XMPPFramework.h" @protocol XmppManagerDelegate<NSObject> - (void)jumpPage; @end @interface XmppManager : NSObject<XMPPStreamDelegate> //創建通訊管道 @property(nonatomic,strong)XMPPStream * xmppStream; //設置代理屬性 @property(nonatomic,assign)id<XmppManagerDelegate>delegate; //好友列表(花名冊) @property(nonatomic,strong)XMPPRoster * roster; @property(nonatomic,strong)XMPPMessageArchiving *xmppMessageArchiving;//消息歸檔 @property(nonatomic,strong)NSManagedObjectContext *messageContext;//管理上下文對象 //單例 + (instancetype)shareXmppManager; //註冊用戶 - (void)registerWithUserName:(NSString *)userName PassWord:(NSString*)passWord; //登錄 - (void)loginWithUserName :(NSString *)userName PassWord:(NSString *)passWord; @end
XmppManager.mapp
#import "XmppManager.h" #import <UIKit/UIKit.h> typedef NS_ENUM(NSInteger, ConncetToServerpopurse) { ConnectToServerpopurseLogin,//登錄 ConnectToServerpopurseRegister//註冊 }; @interface XmppManager ()<XMPPRosterDelegate,UIAlertViewDelegate> //鏈接服務器的目的 @property(nonatomic,assign)ConncetToServerpopurse conncetpopurse; @property(nonatomic,copy)NSString * loginPassword;//登錄密碼 @property(nonatomic,copy)NSString * registerPassword;//註冊密碼 @property(nonatomic,strong)XMPPJID * formJid;//接收jid; @end @implementation XmppManager #pragma mark----單例 + (instancetype)shareXmppManager{ static XmppManager * manager=nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager =[[XmppManager alloc]init]; }); return manager; } -(instancetype)init{ self =[super init]; if (self) { //通訊管道初始化 self.xmppStream =[[XMPPStream alloc]init]; //服務器名稱 域名 self.xmppStream.hostName =kHostName; //端口號 self.xmppStream.hostPort =kHostPort; //添加代理 [self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; //建立管理助手 XMPPRosterCoreDataStorage *rosterStorage =[XMPPRosterCoreDataStorage sharedInstance]; //初始化花名冊 self.roster =[[XMPPRoster alloc]initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_main_queue()]; //設置代理 [self.roster addDelegate:self delegateQueue:dispatch_get_main_queue()]; //激活通訊管道 [self.roster activate:self.xmppStream]; //初始化消息歸檔 XMPPMessageArchivingCoreDataStorage * coredataStorage =[XMPPMessageArchivingCoreDataStorage sharedInstance]; self.xmppMessageArchiving =[[XMPPMessageArchiving alloc]initWithMessageArchivingStorage:coredataStorage dispatchQueue:dispatch_get_main_queue()]; //設置代理 [self.xmppMessageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue() ]; //激活通訊管道 [self.xmppMessageArchiving activate:self.xmppStream]; self.messageContext =coredataStorage.mainThreadManagedObjectContext; } return self; } #pragma mark---註冊 - (void)registerWithUserName:(NSString *)userName PassWord:(NSString *)passWord{ self.conncetpopurse=ConnectToServerpopurseRegister; self.registerPassword=passWord; [self createMyJid:userName]; } #pragma mark ---登錄 - (void)loginWithUserName:(NSString *)userName PassWord:(NSString *)passWord{ self.loginPassword=passWord; self.conncetpopurse=ConnectToServerpopurseLogin; [self createMyJid:userName]; } //建立myJid - (void)createMyJid:(NSString *)userName { //建立地址 XMPPJID XMPPJID * myJid =[XMPPJID jidWithUser:userName domain:kDomin resource:kResource]; self.xmppStream.myJID =myJid; [self connectServer]; } //鏈接服務器 - (void)connectServer { //鏈接服務器 //判斷是否鏈接 if ([self.xmppStream isConnected]) { //斷開鏈接 [self.xmppStream disconnect]; //下線 XMPPPresence * presence =[XMPPPresence presenceWithType:@"unavailabel"]; //發送 [self.xmppStream sendElement:presence]; } //沒有鏈接的話 直接創建鏈接 [self.xmppStream connectWithTimeout:30.f error:nil]; } #pragma mark---xmppStream協議方法 #pragma mark------鏈接成功 -(void)xmppStreamDidConnect:(XMPPStream *)sender{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); switch (self.conncetpopurse) { case 0: //登錄 [self.xmppStream authenticateWithPassword:self.loginPassword error:nil]; break; case 1: //註冊 [self.xmppStream registerWithPassword:self.registerPassword error:nil]; break; default: break; } } #pragma mark -----鏈接失敗 -(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); } #pragma mark----鏈接超時 -(void)xmppStreamConnectDidTimeout:(XMPPStream *)sender{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); } #pragma mark----註冊成功 -(void)xmppStreamDidRegister:(XMPPStream *)sender{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); } #pragma mark-----註冊失敗 -(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); } #pragma mark-------用戶名驗證成功 -(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); XMPPPresence * prence =[XMPPPresence presenceWithType:@"availabel"]; [self.xmppStream sendElement:prence]; [self.delegate jumpPage]; } #pragma mark--------用戶名驗證失敗 -(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{ [self.delegate jumpPage]; NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); } //xmppRosterDelegate協議的方法 #pragma mark ----接收到好友請求 -(void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{ self.formJid =presence.from; UIAlertView *alert =[[UIAlertView alloc]initWithTitle:@"好友請求" message:@"是否贊成好友請求" delegate:self cancelButtonTitle:@"贊成" otherButtonTitles:@"拒絕", nil]; [alert show]; } //UIAlertViewDelegate方法 -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); switch (buttonIndex) { case 0: //贊成請求 [self.roster acceptPresenceSubscriptionRequestFrom:self.formJid andAddToRoster:YES]; break; case 1: //拒絕好友請求 [self.roster rejectPresenceSubscriptionRequestFrom:self.formJid]; break; default: break; } } @end
//登錄界面dom
#import "LoginViewController.h" #import "XmppManager.h" #import "RosterTableViewController.h" @interface LoginViewController ()<XmppManagerDelegate> @property (strong, nonatomic) IBOutlet UITextField *userName; @property (strong, nonatomic) IBOutlet UITextField *password; - (IBAction)loginAction:(UIButton *)sender; - (IBAction)registerAction:(UIButton *)sender; @end @implementation LoginViewController - (void)viewDidLoad { [super viewDidLoad]; [XmppManager shareXmppManager].delegate =self; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ //登錄 - (IBAction)loginAction:(UIButton *)sender { [[XmppManager shareXmppManager] loginWithUserName:self.userName.text PassWord:self.password.text]; } //註冊 - (IBAction)registerAction:(UIButton *)sender { } //實現xmppManagerDelegate代理方法 - (void)jumpPage{ if ([[XmppManager shareXmppManager].xmppStream isAuthenticated]) { RosterTableViewController * roster =[[RosterTableViewController alloc]init]; [self.navigationController pushViewController:roster animated:YES]; }else{ UIAlertView * alert =[[UIAlertView alloc]initWithTitle:@"提示" message:@"用戶名或者密碼錯誤" delegate:self cancelButtonTitle:@"肯定" otherButtonTitles:nil, nil]; [alert show]; } } @end
//註冊界面fetch
#import "RegisterViewController.h" #import "XmppManager.h" @interface RegisterViewController () - (IBAction)registerButton:(UIButton *)sender; - (IBAction)backAction:(UIBarButtonItem *)sender; @property (strong, nonatomic) IBOutlet UITextField *userName; @property (strong, nonatomic) IBOutlet UITextField *passWord; @end @implementation RegisterViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ //註冊 - (IBAction)registerButton:(UIButton *)sender { [[XmppManager shareXmppManager]registerWithUserName:self.userName.text PassWord:self.passWord.text]; [self dismissViewControllerAnimated:YES completion:nil]; } //返回 - (IBAction)backAction:(UIBarButtonItem *)sender { [self dismissViewControllerAnimated:YES completion:nil]; } @end
//好友列表atom
#import "RosterTableViewController.h" #import "ChatTableViewController.h" #import "XmppManager.h" @interface RosterTableViewController ()<XMPPRosterDelegate> @property(nonatomic,strong)NSMutableArray * rosterArray;//存放好友 @end @implementation RosterTableViewController - (void)viewDidLoad { [super viewDidLoad]; //註冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"rosterCell"]; [[XmppManager shareXmppManager].roster addDelegate:self delegateQueue:dispatch_get_main_queue()]; self.navigationItem.title=@"好友列表"; } #pragma mark----開始檢索 -(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); NSLog(@"開始檢索"); } #pragma mark ---結束檢索 -(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{ NSLog(@"function==%s, line==%d",__FUNCTION__,__LINE__); NSLog(@"結束檢索"); } #pragma mark-----獲取到好友 //每次獲取一個 -(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item{ NSString * userName =[[item attributeForName:@"jid"]stringValue]; //拿到一個好友的jid XMPPJID * rosterJid =[XMPPJID jidWithString:userName resource:kResource]; //判斷是否添加過 if ([self.rosterArray containsObject:rosterJid]) { return ; }else{ [self.rosterArray addObject:rosterJid]; } //獲取indexpath NSIndexPath * indexPath =[NSIndexPath indexPathForRow:self.rosterArray.count-1 inSection:0]; [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft]; [self.tableView reloadData]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.rosterArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"rosterCell" forIndexPath:indexPath]; XMPPJID *jid =self.rosterArray[indexPath.row]; cell.textLabel.text=jid.user; return cell; } //懶加載 -(NSMutableArray *)rosterArray{ if (!_rosterArray) { self.rosterArray =[NSMutableArray array]; } return _rosterArray; } -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ ChatTableViewController * chatVC=[[ChatTableViewController alloc]init]; //向聊天界面傳聊天對象的jid XMPPJID *chatToJid =self.rosterArray[indexPath.row]; chatVC.chatToJid =chatToJid; [self.navigationController pushViewController:chatVC animated:YES]; }
消息界面.h文件spa
#import <UIKit/UIKit.h> #import "XMPPFramework.h" #import "XmppManager.h" @interface ChatTableViewController : UITableViewController<XMPPStreamDelegate> @property(nonatomic,strong)XMPPJID * chatToJid;//聊天對象的jid @property(nonatomic,strong)NSManagedObjectContext * messageContext;//管理對象上下文 @end
消息界面.m文件代理
#import "ChatTableViewController.h" @interface ChatTableViewController () @property(nonatomic,strong)NSMutableArray *messageArray;//接收消息的數組 @end @implementation ChatTableViewController - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title =@"消息"; //註冊 [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"chatCell"]; //添加通訊管道代理 [[XmppManager shareXmppManager].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()]; UIBarButtonItem * rightBt=[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(sendmessages)]; self.navigationItem.rightBarButtonItem =rightBt; self.messageContext =[XmppManager shareXmppManager].messageContext; } //發送消息按鈕 - (void)sendmessages{ //建立消息 XMPPMessage * xmppMessage =[[XMPPMessage alloc]initWithType:@"chat" to:self.chatToJid ]; //發送消息 [xmppMessage addBody:@"研發26"]; [[XmppManager shareXmppManager].xmppStream sendElement:xmppMessage]; } #pragma mark -----消息接收成功 -(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{ //刷新界面 [self reloadMessage]; } #pragma mark------消息發送成功 -(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{ //刷新界面 [self reloadMessage]; } //刷新界面 - (void)reloadMessage{ NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; NSEntityDescription *entity = [NSEntityDescription entityForName:@"XMPPMessageArchiving_Message_CoreDataObject" inManagedObjectContext:self.messageContext]; [fetchRequest setEntity:entity]; // Specify criteria for filtering which objects to fetch XMPPStream * stream =[XmppManager shareXmppManager].xmppStream; NSPredicate *predicate = [NSPredicate predicateWithFormat:@"streamBareJidStr =%@ AND bareJidStr = %@",stream.myJID.bare, self.chatToJid.bare]; [fetchRequest setPredicate:predicate]; // Specify how the fetched objects should be sorted NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES]; [fetchRequest setSortDescriptors:[NSArray arrayWithObjects:sortDescriptor, nil]]; NSError *error = nil; NSArray *fetchedObjects = [self.messageContext executeFetchRequest:fetchRequest error:&error]; if (fetchedObjects == nil) { return; } if (self.messageArray.count !=0) { [self.messageArray removeAllObjects]; } [self.messageArray addObjectsFromArray:fetchedObjects]; [self.tableView reloadData]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.messageArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"chatCell" forIndexPath:indexPath]; if (!cell) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"chatCell"]; } cell.detailTextLabel.textAlignment =NSTextAlignmentLeft; XMPPMessageArchiving_Message_CoreDataObject *messageCordata =self.messageArray[indexPath.row]; if (messageCordata.isOutgoing) { //消息是我發 cell.detailTextLabel.hidden =YES; cell.textLabel.hidden=NO; cell.textLabel.text =messageCordata.body; }else{ cell.textLabel.hidden=YES; cell.detailTextLabel.hidden=NO; cell.detailTextLabel.text=messageCordata.body; } return cell; } //懶加載 -(NSMutableArray *)messageArray{ if (!_messageArray) { self.messageArray =[NSMutableArray array]; } return _messageArray; }