iOS 即時通訊之xmpp


//
//  ViewController.m
//  XMPP_lesson
//
//  Created by  on 14/8/20.
//  Copyright (c) 2015 Congwang. All rights reserved.
//

#import "ViewController.h"
#import
 "XMPPHelper.h"

@interface ViewController ()<XMPPStreamDelegate>
@property (weak, nonatomic) IBOutlet UITextField *userTF;//用戶名TF
@property (weak, nonatomic) IBOutlet UITextField *passWordTF;//密碼TF

@end

@implementation ViewController
//登陸方法
- (
IBAction)loginAction:(UIButton *)sender {
   
 //發起登陸操作
    [[
XMPPHelper sharedXMPPHelper]loginServerWithUserName:self.userTF.text password:self.passWordTF.text];
}
#pragma mark  --  密碼驗證成功回調方法
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
    [
self performSegueWithIdentifier:@"segue" sender:nil];
}

//註冊方法
- (
IBAction)registerAction:(UIButton *)sender {
    [[
XMPPHelper sharedXMPPHelper] registerServerWithUserName:self.userTF.text password:self.passWordTF.text];
}


- (
void)viewDidLoad {
    [
super viewDidLoad];
   
 //再把當前的對象添加爲xmppStream的代理
    [[
XMPPHelper sharedXMPPHelper].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
   
   
   
   
   
   
 // Do any additional setup after loading the view, typically from a nib.
}

- (
void)didReceiveMemoryWarning {
    [
super didReceiveMemoryWarning];
   
 // Dispose of any resources that can be recreated.
}

@end

//
//  FriendListViewController.m
//  XMPP_lesson
//
//  Created by lanouhn on 15/8/21.
//  Copyright (c) 2015 Congwang. All rights reserved.
//

#import "FriendListViewController.h"
#import
 "XMPPHelper.h"
#import
 "ChatTableViewController.h"
@interface FriendListViewController ()<UITableViewDelegate, UITableViewDataSource, XMPPRosterDelegate, UIAlertViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
//shujvyuan shuxing ,laizhanshixinxi
@property (strong, nonatomic)NSMutableArray *dataSource;
@end

@implementation FriendListViewController
//添加好友
- (
IBAction)addFriend:(UIBarButtonItem *)sender {
   
 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"添加好友" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
   
 //設置alerView的樣式, 帶一個輸入框
    alertView.
alertViewStyle = UIAlertViewStylePlainTextInput;
    [alertView
 show];
   
   
}
#pragma mark - alertView的代理方法
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
   
 //如果點擊的時確定
   
 if (buttonIndex) {
       
 //獲取alertView上面輸入框的值
       
 UITextField *alerTF = [alertView textFieldAtIndex:0];
       
 NSString *userName = alerTF.text;
       
 //封裝成XMPPJID
       
 XMPPJID *friendJID = [XMPPJID jidWithUser:userName domain:kDomin resource:kResource];
       
 //添加好友
        [[
XMPPHelper sharedXMPPHelper].xmppRoster addUser:friendJID withNickname:nil];
       
    }
}




#pragma mark  -- tableView代理方法和dataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
   
   
 return self.dataSource.count;
   
}

- (
NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
   
 return 1;
   
}
- (
UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
   
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
   
 XMPPJID *jid = self.dataSource[indexPath.row];
    cell.
textLabel.text = jid.user;
   
 return cell;
   
   
}
- (
void)viewDidLoad {
    [
super viewDidLoad];
   
 // Do any additional setup after loading the view.
   
 // 初始化數組
   
 self.dataSource = [NSMutableArray array];
   
   
 //添加當前對象爲xmppRoster的代理對象
    [[
XMPPHelper sharedXMPPHelper].xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
   
 //調整視圖的邊距, 這個是ios7之後的方法, ios6不能用
   
 self.edgesForExtendedLayout = UIRectEdgeNone;
}
#pragma mark -- xmppRosterdelegate 的代理方法
//好友花名冊開始檢索好友的代理方法
-(
void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{
   
   
}
//檢索到好友信息的代理方法
- (
void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item{
   
 //xml解析中獲取節點中的屬性
   
 NSString *jidStr = [[item attributeForName:@"jid"] stringValue];
   
 //xml解析獲取節點中的訂閱屬性
   
 NSString *subscriptionStatus = [[item attributeForName:@"subscription"] stringValue];
   
 if ([subscriptionStatus isEqualToString:@"both"]) {
       
 //封裝成JID對象
       
 XMPPJID *friendJID = [XMPPJID jidWithString:jidStr resource:kResource];
       
       
 if ([self.dataSource containsObject:friendJID]) {
           
 return;
        }
       
       
 //插入數據源數組
        [
self.dataSource addObject:friendJID];
       
       
 //再插單元格
        [
self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.dataSource.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
       
 //tableView滾動
        [
self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.dataSource.count - 1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    }
}
//xmppRoster結束檢索
- (
void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{
   
   
}






- (
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.
   
 ChatTableViewController *chatVC = segue.destinationViewController;
   
 //找到點擊的cell
   
 UITableViewCell *cell = sender;
   
 //獲取點擊cell的下標
   
 NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    chatVC.
friendJID = self.dataSource[indexPath.row];

   
   
   
}


@end


//
//  ChatTableViewController.h
//  XMPP_lesson
//
//  Created by lanouhn on 15/8/21.
//  Copyright (c) 2015 Congwang. All rights reserved.
//

#import <UIKit/UIKit.h>
@class XMPPJID;
@interface ChatTableViewController : UITableViewController
//聲明當前聊天好友的JID屬性
@property (nonatomic, strong)XMPPJID *friendJID;
@end

//
//  ChatTableViewController.m
//  XMPP_lesson
//
//  Created by lanouhn on 15/8/21.
//  Copyright (c) 2015 Congwang. All rights reserved.
//

#import "ChatTableViewController.h"
#import
 "XMPPHelper.h"

@interface ChatTableViewController ()<XMPPStreamDelegate>
@property (strong, nonatomic)NSMutableArray *dataSource;
@end

@implementation ChatTableViewController

- (
void)viewDidLoad {
    [
super viewDidLoad];
   
 //添加當前爲xmppStream的代理對象
    [[
XMPPHelper sharedXMPPHelper].xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
   
   
 //初始化數組
   
 self.dataSource = [NSMutableArray array];
   
 //調用檢索本地聊天記錄的方法
    [
self seacherMessageBetweenFriend];
   
   
   
   
}
//檢索本地聊天記錄
- (
void)seacherMessageBetweenFriend{
   
 NSManagedObjectContext *context = [XMPPHelper sharedXMPPHelper].managedContext;
   
   
 //創建查詢請求對象
   
 NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"XMPPMessageArchiving_Message_CoreDataObject"];
   
 //設置檢索條件
   
 //1.創建謂詞
   
 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr == %@ and streamBareJidStr == %@", self.friendJID.bare, [XMPPHelper sharedXMPPHelper].xmppStream.myJID.bare];
    request.
predicate = predicate;
   
 //2.設置排序
   
 NSSortDescriptor *description = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];
    request.
sortDescriptors = @[description];
   
 //執行這個查詢請求
   
 NSArray *resultArray = [context executeFetchRequest:request error:nil];
   
   
 //加入數據源
    [
self.dataSource addObjectsFromArray:resultArray];
   
 //刷新單元格
    [
self.tableView reloadData];
   
   
   
}






//發送消息的方法
- (
IBAction)sendMessage:(UIBarButtonItem *)sender {
   
   
   
 //創建消息對象
   
 XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.friendJID];
   
 //給消息添加內容
    [message
 addBody:@"你懂得http://cl.ttum.pw/htm_data/7/1508/1607032.html"];
   
 //3. *發送消息
    [[
XMPPHelper sharedXMPPHelper].xmppStream sendElement:message];
   
}



- (
void)showNewMessage:(XMPPMessage *)message{
   
 //插入數據源
    [
self.dataSource addObject:message];
   
 //插入單元格
   
 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.dataSource.count - 1 inSection:0];
    [
self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
   
 //tableView
    [
self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}
#pragma mark -- 與聊天相關的xmppStream的代理回調方法
//收到消息的代理回調
- (
void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
   
 //判斷消息發送者
   
 XMPPJID *friendJID = message.from;
   
 if ([self.friendJID isEqualToJID:friendJID]) {
        [
self showNewMessage:message];
    }
   
   
}
//發送消息成功的代理回調方法
- (
void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{
   
    [
self showNewMessage:message];
}

- (
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.dataSource.count;
}


- (
UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
   
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cells" forIndexPath:indexPath];
   
 XMPPMessage *message = self.dataSource[indexPath.row];
   
   
 if ([message isKindOfClass:[XMPPMessage class]]) {
       
 if ([message.from isEqualToJID:self.friendJID]) {
            cell.
textLabel.textColor = [UIColor redColor];
        }
else{
            cell.
textLabel.textColor = [UIColor blackColor];
        }
        cell.
textLabel.text = message.body;
        
 return cell;
    }
   
 else{
       
       
 XMPPMessageArchiving_Message_CoreDataObject *message = self.dataSource[indexPath.row];
       
 //判斷消息是不是登錄用戶發送的(isOutdoing是自己發送的)
       
 if (![message isOutgoing]) {
            cell.
textLabel.textColor = [UIColor redColor];
        }
else{
            cell.
textLabel.textColor = [UIColor blackColor];
        }
        cell.
textLabel.text = message.body;
       
 return cell;

       
    }
    }
   
   
   
   
   
   
   
   
  
  



/*
 // Override to support conditional editing of the table view.
 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the specified item to be editable.
 return YES;
 }
 */


/*
 // Override to support editing the table view.
 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
 if (editingStyle == UITableViewCellEditingStyleDelete) {
 // Delete the row from the data source
 [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
 } else if (editingStyle == UITableViewCellEditingStyleInsert) {
 // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
 }
 }
 */


/*
 // Override to support rearranging the table view.
 - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
 }
 */


/*
 // Override to support conditional rearranging of the table view.
 - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
 // Return NO if you do not want the item to be re-orderable.
 return YES;
 }
 */


/*
 #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.
 }
 */


@end



//
//  XMPPHelper.h
//  XMPP_lesson
//
//  Created by lanouhn on 15/8/20.
//  Copyright (c) 2015 Congwang. All rights reserved.
//

#import <Foundation/Foundation.h>
#import
 "XMPPFramework.h"
@interface XMPPHelper : NSObject<XMPPStreamDelegate, XMPPRosterDelegate>

//通信介質(管道對象), 在整個xmpp框架中非常重要, 所有的服務都是建立在它之上
@property (nonatomic, strong)XMPPStream *xmppStream;
//聲明好友花名冊屬性 (負責所有與好友相關的操作)
@property (nonatomic, strong) XMPPRoster *xmppRoster;
//聲明消息歸檔對象 (這個對象負責消息的歸檔)
@property (nonatomic, strong)XMPPMessageArchiving *messageArchiving;
//聲明被管理對象上下文, 方便外界查詢 (因爲我們要查詢聊天記錄)
@property (strong , nonatomic)NSManagedObjectContext *managedContext;

+ (
XMPPHelper *)sharedXMPPHelper;
//1.登陸方法
- (
void)loginServerWithUserName:(NSString *)userName password:(NSString *)password;

//2.註冊方法
- (
void)registerServerWithUserName:(NSString *)userName password:(NSString *)password;


@end


//
//  XMPPHelper.m
//  XMPP_lesson
//
//  Created by lanouhn on 15/8/20.
//  Copyright (c) 2015 Congwang. All rights reserved.
//

#import "XMPPHelper.h"
#import
 "FriendListViewController.h"

//定義枚舉
typedef NS_ENUM(NSInteger, ThePurposeOfLinkServer)
{
    LoginPurpose =
 0,
    RegisterPurpose =
 1
};

//延展
@interface XMPPHelper ()
//聲明密碼屬性, 用於驗證密碼的驗證
@property (nonatomic, copy)NSString *password;
//聲明枚舉屬性來區分登陸和註冊
@property (nonatomic, assign)ThePurposeOfLinkServer purpose;

@end



@implementation XMPPHelper
//xmpp服務助手
+ (
XMPPHelper *)sharedXMPPHelper{
   
 static XMPPHelper *xmppHelper = nil;
   
 static dispatch_once_t onceToken;
   
 dispatch_once(&onceToken, ^{
        xmppHelper = [[
XMPPHelper alloc] init];
    });
   
 return xmppHelper;
}
//重寫init方法, 在該方法中完成一些xmpp中一些類的基本設置
-(
instancetype)init{
   
 self = [super init];
   
 if (self) {
       
 //1.xmppStream的設置
       
 //1.1創建xmppStream對象
       
 self.xmppStream = [[XMPPStream alloc] init];
       
 //指定xmppStream鏈接的服務器的地址
       
 self.xmppStream.hostName = kHostName;
       
 //指定xmppStream鏈接服務器的端口號
       
 self.xmppStream.hostPort = kHostPort;
       
 //添加xmppStream的代理對象
       
 //1.指定代理對象
       
 //2.指定GCD隊列, 我們選擇主線程
        [
self.xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
       
       
       
 //完成xmppRoster的一些基本配置
       
       
 //1.創建好友存儲對象
       
 XMPPRosterCoreDataStorage *storage = [XMPPRosterCoreDataStorage sharedInstance];
       
 //2.創建好友花名冊管理對象
       
 self.xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:storage dispatchQueue:dispatch_get_main_queue()];
       
 //3.添加代理
        [
self.xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
       
 //4.* 打開xmppRoster服務
        [
self.xmppRoster activate:self.xmppStream];
       
       
 //創建消息存儲對象
       
 XMPPMessageArchivingCoreDataStorage *archivingStorage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
       
 //給數據管理器屬性賦值, 方便外界的訪問
       
 self.managedContext =  archivingStorage.mainThreadManagedObjectContext;
       
 //創建信息歸檔對象
       
 self.messageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:archivingStorage dispatchQueue:dispatch_get_main_queue()];
       
 //添加代理, 不用遵守代理協議
        [
self.messageArchiving addDelegate:self delegateQueue:dispatch_get_main_queue()];
       
 //**啓動該服務
        [
self.messageArchiving activate:self.xmppStream];
       
   
       
       
    }
return self;
   
}

//發起請求方法
- (
void)connectToServer{
   
 if (self.xmppStream.isConnected || self.xmppStream.isConnecting) {
       
 //告訴服務器我們xia線了
       
 //1.創建XMPPPresence對象,unavailable就是xia線了
       
 XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];
       
 //2.發送xia線狀態
        [
self.xmppStream sendElement:presence];
       
 //斷開鏈接
        [
self.xmppStream disconnect];
    }
   
 //發起鏈接請求
    [
self.xmppStream connectWithTimeout:-1 error:nil];
}





/**
 * 
 登陸方法的實現
 */

- (
void)loginServerWithUserName:(NSString *)userName password:(NSString *)password{
   
 //給密碼屬性賦值
   
 self.password = password;
   
 //geimudi meijv fuzhi
   
 self.purpose = LoginPurpose;
   
 // 登陸方法
   
 //1.創建登陸方
   
 XMPPJID *userJID = [XMPPJID jidWithUser:userName domain:kDomin resource:kResource];
   
 //2.告訴xmppStream登陸方是誰
   
 self.xmppStream.myJID = userJID;
   
   
 //發起鏈接請求
    [
self connectToServer];
   
}
/**
 * 
 註冊方法的實現
 */


- (
void)registerServerWithUserName:(NSString *)userName password:(NSString *)password{
   
 //給密碼賦值
   
 self.password = password;
   
 //給目的屬性賦值
   
 self.purpose = RegisterPurpose;
   
   
   
 //註冊第一步
   
 //1.創建註冊方法
   
 XMPPJID *registerUser = [XMPPJID jidWithUser:userName domain:kDomin resource:kResource];
   
 //2.誰在註冊
   
 self.xmppStream.myJID = registerUser;
   
 //3.發起註冊
    [
self connectToServer];
   
}
#pragma mark  -- xmppStream的代理方法
//管道對象將要鏈接的時候出發
- (
void)xmppStreamWillConnect:(XMPPStream *)sender{
   
   
 NSLog(@"%s, %d",__FUNCTION__, __LINE__ );
   
}
//xmppStream基於的socket管道鏈接上的時候觸發
- (
void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket{
   
   
 NSLog(@"%s, %d",__FUNCTION__, __LINE__ );
}
//管道對象已經鏈接上出發的方法
- (
void)xmppStreamDidConnect:(XMPPStream *)sender{
   
   
   
 if (!self.purpose) {
       
 //驗證密碼
        [
self.xmppStream authenticateWithPassword:self.password error:nil];
    }
else{
       
 //註冊賬號
        [
self.xmppStream registerWithPassword:self.password error:nil];
    }
   
 NSLog(@"%s, %d",__FUNCTION__, __LINE__ );
}

//對該賬號進行驗證

//驗證成功的方法
- (
void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
   
 //告訴服務器我們上線了
   
 //1.創建XMPPPresence對象,available就是上線了
   
 XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
   
 //2.發送上線狀態
    [
self.xmppStream sendElement:presence];
   
   
 //提示框
   
 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"登陸成功" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
    [alertView
 show];
   
 NSLog(@"成功");
   
   
   
   
   
   
   
}
//驗證失敗的方法
- (
void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
   
 //提示框
   
 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"登陸失敗" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
    [alertView
 show];
   
 NSLog(@"失敗");
}

//註冊賬號的方法
//註冊成功的方法
- (
void)xmppStreamDidRegister:(XMPPStream *)sender{
   
 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"註冊成功" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
    [alertView
 show];
}
//註冊失敗的方法
- (
void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error{
   
 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"註冊失敗" delegate:nil cancelButtonTitle:@"確定" otherButtonTitles:nil, nil];
    [alertView
 show];
}

#pragma mark -- xmppRoster代理方法
//接收到好友的添加請求
- (
void)xmppRoster:(XMPPRoster *)sender didReceivePresenceSubscriptionRequest:(XMPPPresence *)presence{
   
 //獲取請求添加好友的JID
   
 XMPPJID *friendJID = presence.from;
   
   
 //我們同意添加爲好友
    [
self.xmppRoster acceptPresenceSubscriptionRequestFrom:friendJID andAddToRoster:YES];
   
   
//    //拒絕好友的添加請求
//    [self.xmppRoster rejectPresenceSubscriptionRequestFrom:friendJID];
   
   
   
   
}





@end



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章