美文网首页XMPP
iOS 即时通信系列之XMPP登入、注册、聊天

iOS 即时通信系列之XMPP登入、注册、聊天

作者: DH_Fantasy | 来源:发表于2016-08-01 16:32 被阅读291次

    说明:在即时通信系列XMPP之搭建本地服务器中阐述了通过XAMPP、Openfire工具搭建基于XMPP的服务器端,并使用spark软件进行XMPP客户端的调试。在本文中主要阐述将XMPP添加到工程中,实现iOS中基于XMPP的即时通信。

    项目环境配置

    使用CocoaPods导入XMPP框架,如果不会CocoaPods,点击CocoaPods安装及使用教程,或者手动导入XMPP框架

    创建XMPP管理类

    为了让XMPP不会对工程中其它业务代码具有侵入性,方便我们管理整个关于XMPP的逻辑处理,通常会采用单例模式新建一个专门的管理类,为此,在工程中创建一个继承自NSObject的XMPPManger,为了能够在代码中方便调用XMPPStreamDelegate的方法,让其遵守XMPPStreamDelegate协议。
      XMPP框架中所有的连接、登入、注册、授权、失去连接等操作的回调都是通过XMPPStream来管理,所以XMPPManger必须有一个XMPPStream实例。其它的还包括进行添加好友、删除好友、获取好友列表等功能的XMPPRoster;消息保存组件XMPPMessageArchiving等。

    XMPPManager.h
    @interface XMPPManager : NSObject<XMPPStreamDelegate>
    
    /**
     *  创建全局唯一的管理者对象
     *  @return 返回一个单例对象
     */
    + (XMPPManager *)sharedXMPPManager;
    
    /**
     *  信息管道
     */
    @property (nonatomic,strong)XMPPStream *stream;
    /**
     *  进行添加好友 删除好友 获取好友列表等功能
     */
    @property (nonatomic,strong)XMPPRoster *roster;
    /**
     *  消息保存组件
     */
    @property (nonatomic,strong)XMPPMessageArchiving *messageArchiving;
    /**
     *  消息保存组件的CoreData上下文
     */
    @property (nonatomic,strong)NSManagedObjectContext *managerObjectContext;
    /**
     *  登入
     *
     *  @param userName 账户
     *  @param password 密码
     */
    - (void)loginWithUserName:(NSString *)userName password:(NSString *)password;
    /**
     *  注册
     *
     *  @param userName 账户
     *  @param password 密码
     */
    - (void)registWithUserName:(NSString *)userName password:(NSString *)password;
    
    @end
    
    XMPPManager.m
    //服务器的地址
    static NSString *const kHostName = @"127.0.0.1";
    //端口号
    static UInt16 const kHostPort = 5222;
    
    //连接服务器类型
    typedef NS_ENUM(NSUInteger,ConnectToServerStatus) {
        ConnectToServerStatusLogin,
        ConnectToServerStatusRegist,
    };
    
    @interface XMPPManager ()
    //登入密码
    @property (nonatomic,strong)NSString *loginpassword;
    //注册密码
    @property (nonatomic,strong)NSString *registpassword;
    //是登入还是注册
    @property (nonatomic,assign)ConnectToServerStatus connectToSercerStatus;
    
    @end
    
    @implementation XMPPManager
    
    + (XMPPManager *)sharedXMPPManager{
        static XMPPManager *xmppManager = nil;
        static dispatch_once_t token;
        dispatch_once(&token, ^{
            xmppManager = [[XMPPManager alloc] init];
        });
        return xmppManager;
    }
    
    - (instancetype)init{
        if ([super init]) {
            //设置通信管道属性
            self.stream = [[XMPPStream alloc] init];
            self.stream.hostName = kHostName;
            self.stream.hostPort = kHostPort;
            //设置当前对象为stream的代理
            [self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
            
            //进行好友存储
            XMPPRosterCoreDataStorage *rosterStorage = [XMPPRosterCoreDataStorage sharedInstance];
            self.roster = [[XMPPRoster alloc] initWithRosterStorage:rosterStorage dispatchQueue:dispatch_get_main_queue()];
            //激活
            [self.roster activate:self.stream];
            
            //进行聊天信息存储
            XMPPMessageArchivingCoreDataStorage *messageArchivingStorage = [XMPPMessageArchivingCoreDataStorage sharedInstance];
            self.messageArchiving = [[XMPPMessageArchiving alloc] initWithMessageArchivingStorage:messageArchivingStorage dispatchQueue:dispatch_get_main_queue()];
            [self.messageArchiving activate:self.stream];
            
            self.managerObjectContext = messageArchivingStorage.mainThreadManagedObjectContext;
        }
        return self;
    }
    
    //与服务器建立链接
    -(void)connectToServerWithUser:(NSString *)user{
        //要是正在链接的话那么就先断开连接
        if ([self.stream isConnected]) {
            [self disconnectServer];
        }
        XMPPJID *jid = [XMPPJID jidWithUser:user domain:@"DH_Fantasy" resource:@"iPhone"];
        self.stream.myJID = jid;
        NSError *error = nil;
        [self.stream connectWithTimeout:30.0f error:&error];
        if (nil != error) {
            NSLog(@"%s__%d__链接出错:%@",__FUNCTION__,__LINE__,error);
        }
    }
    
    //与服务器断开链接
    -(void)disconnectServer{
        [self.stream disconnect];
    }
    //登入
    - (void)loginWithUserName:(NSString *)userName password:(NSString *)password{
        self.connectToSercerStatus = ConnectToServerStatusLogin;
        self.loginpassword = password;//将传进来的password传给self.password
        [self connectToServerWithUser:userName];
    }
    //注册
    - (void)registWithUserName:(NSString *)userName password:(NSString *)password{
        self.connectToSercerStatus = ConnectToServerStatusRegist;
        self.registpassword = password;
        [self connectToServerWithUser:userName];
    }
    
    #pragma mark XMPPStreamDelegate
    //与服务器链接成功
    -(void)xmppStreamDidConnect:(XMPPStream *)sender{
    #pragma mark 判断与服务器建立连接是登陆还是注册
        switch (self.connectToSercerStatus) {
            case ConnectToServerStatusLogin:
            {
                NSError *error = nil;
                [self.stream authenticateWithPassword:self.loginpassword error:&error];
                if (nil != error) {
                    NSLog(@"%s__%d__验证出错:%@",__FUNCTION__,__LINE__,error);
                }
                break;
            }
            case ConnectToServerStatusRegist:
            {
                NSError *err = nil;
                [self.stream registerWithPassword:self.registpassword error:&err];
                if (nil != err) {
                    NSLog(@"%s__%d__注册出错:%@",__FUNCTION__,__LINE__,err);
                }
                break;
            }
            default:
                break;
        }
    }
    //与服务器链接失败
    -(void)xmppStreamConnectDidTimeout:(XMPPStream *)sender{
        NSLog(@"😂与服务器链接失败");
    }
    
    - (void)xmppStreamWillConnect:(XMPPStream *)sender {
        NSLog(@"🔌socket正在连接...");
    }
    
    - (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket {
        NSLog(@"🍎socket连接成功");
        // 连接成功之后,由客户端xmpp发送一个stream包给服务器,服务器监听来自客户端的stream包,并返回stream feature包
    }
    
    - (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error {
        NSLog(@"😂xmpp授权失败:%@", error.description);
    }
    
    - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender {
        NSLog(@"🍎xmpp授权成功。");
        // 只有进入到这里,才算是真正的可以聊天了
    }
    
    - (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error {
        NSLog(@"😂xmpp失去连接。");
    }
    
    @end
    

    AppDelegate

    在AppDelegate中主要设置了下进入APP时的登入状态,在一些场景中,某些控制器必须为登入状态才能进入,用NSUserDefaults存储为Bool类型,这为判断是否登入提供了方便。

    AppDelegate.m
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        //设置主窗口并显示
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        
        //设置进入APP为没登入状态
        [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"isLoginStatus"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        //设置好友列表控制器为根视图
        RosterTableViewController *VC = [[RosterTableViewController alloc] init];
        UINavigationController *NC = [[UINavigationController alloc] initWithRootViewController:VC];
        self.window.rootViewController = NC;
        
        return YES;
    }
    

    RosterTableViewController

    RosterTableViewController主要作用就是进行自动登入与显示获取到的好友。

    RosterTableViewController.m
    @interface RosterTableViewController ()
    
    //用于保存获取到的好友
    @property (nonatomic,strong)NSMutableArray *rosterArray;
    
    @end
    
    @implementation RosterTableViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.title = @"好友列表";
        
        self.rosterArray = [[NSMutableArray alloc] init];
        
        //判断之前是否登入过
        if (nil != [[NSUserDefaults standardUserDefaults]objectForKey:@"userName"]) {
            
            //之前登入过,直接读取用户名和密码进行连接
            NSString *userName = [[NSUserDefaults standardUserDefaults]objectForKey:@"userName"];
            NSString *password = [[NSUserDefaults standardUserDefaults]objectForKey:@"password"];
            [[XMPPManager sharedXMPPManager]loginWithUserName:userName password:password];
            [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
            
        }else{
            
            //之前没登入过则进入到登入窗口
            UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
            LoginViewController *loginVC = [storyboard instantiateViewControllerWithIdentifier:@"login"];
            
            [self.navigationController pushViewController:loginVC animated:YES];
        }
        
        [[XMPPManager sharedXMPPManager].roster addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    
    #pragma mark UITableViewDataSource
    - (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:@"cell"];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:@"cell"];
        }
        
        XMPPJID *jid = self.rosterArray[indexPath.row];
        cell.textLabel.text = jid.user;
        
        return cell;
    }
    
    #pragma mark 进入聊天界面
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
        XMPPJID *jid = self.rosterArray[indexPath.row];
        ChatViewController *chat = [[ChatViewController alloc] init];
        chat.chatToJid = jid;
        [self.navigationController pushViewController:chat animated:YES];
    }
    
    #pragma mark XMPPStreamDelegate
    //授权成功
    - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isLoginStatus"];
        
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        //我们验证之后默认的状态是离线的 于是我们想显示在线,需要告诉服务器自己的状态
        XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
        [[XMPPManager sharedXMPPManager].stream sendElement:presence];
    }
    
    //验证失败
    -(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
        NSLog(@"登入验证失败😂");
    }
    
    #pragma mark XMPPRosterDelegate
    //刚开始获取好友列表
    -(void)xmppRosterDidBeginPopulating:(XMPPRoster *)sender{
        NSLog(@"开始获取好友列表");
    }
    
    //正在获取好友列表
    -(void)xmppRoster:(XMPPRoster *)sender didReceiveRosterItem:(DDXMLElement *)item{
        NSLog(@"正在获取好友列表...%@",item);
        NSString *jidStr = [[item attributeForName:@"jid"]stringValue];
        XMPPJID *jid =[XMPPJID jidWithString:jidStr];
        [self.rosterArray addObject:jid];
        
        //将数据添加进数组
        [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.rosterArray.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
    }
    
    //已经完成好友列表获取
    -(void)xmppRosterDidEndPopulating:(XMPPRoster *)sender{
        NSLog(@"已经完成好友列表获取🍅");
    }
    
    
    Friends List.png

    LoginViewController

    LoginViewController中使用XMPPManager单例在登入按钮的点击事件中调用- (void)loginWithUserName:(NSString ***)userName password:(NSString *)password;方法进行登入。

    LoginViewController.m
    @interface LoginViewController ()
    
    //登入账户
    @property (weak, nonatomic) IBOutlet UITextField *userName;
    //登入密码
    @property (weak, nonatomic) IBOutlet UITextField *password;
    
    @end
    
    @implementation LoginViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    
    //登入操作
    - (IBAction)loginAction:(id)sender {
        [[XMPPManager sharedXMPPManager] loginWithUserName:self.userName.text password:self.password.text];
    }
    
    #pragma mark XMPPStreamDelegte
    //验证成功
    - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender{
        //存储账户密码用于下次自动登入
        [[NSUserDefaults standardUserDefaults] setObject:self.userName.text forKey:@"userName"];
        [[NSUserDefaults standardUserDefaults] setObject:self.password.text forKey:@"password"];
        
        //改变APP的登入状态
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isLoginStatus"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        //验证之后默认的状态为离线,需要手动告诉服务器自己的状态
        XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
        [[XMPPManager sharedXMPPManager].stream sendElement:presence];
        
        //返回到根视图
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    
    //验证失败
    -(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{
        NSLog(@"登入验证失败😂");
    }
    
    LoginViewController.png

    RegisterViewController

    注册和登入比较相似,只需在注册按钮的点击事件中使用XMPPManager单例调用- (void)registWithUserName:(NSString *)userName password:(NSString *)password;方法进行注册。

    RegisterViewController.m
    @interface RegisterViewController ()
    
    //注册账户
    @property (weak, nonatomic) IBOutlet UITextField *userName;
    //注册密码
    @property (weak, nonatomic) IBOutlet UITextField *password;
    //密码验证
    @property (weak, nonatomic) IBOutlet UITextField *rePassword;
    
    @end
    
    @implementation RegisterViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    }
    
    - (IBAction)registerAction:(id)sender {
        //简单验证:用户名不为空且密码和密码验证输入一致
        if (![self.userName.text isEqualToString:@""] && [self.rePassword.text isEqualToString:self.password.text]) {
            [[XMPPManager sharedXMPPManager] registWithUserName:self.userName.text password:self.password.text];
        }else{
            UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"注册失败" message:@"" preferredStyle:(UIAlertControllerStyleAlert)];
            
            if ([self.userName.text isEqualToString:@""]) {
                alertController.title = @"账户为空";
                alertController.message = @"请输入账户";
            }
            if (![self.rePassword.text isEqualToString:self.password.text]) {
                alertController.title = @"密码验证错误";
                alertController.message = @"请重新输入密码验证";
            }
            
            UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:(UIAlertActionStyleCancel) handler:^(UIAlertAction * _Nonnull action) {
                [alertController dismissViewControllerAnimated:YES completion:nil];
            }];
            
            [alertController addAction:okAction];
            [self presentViewController:alertController animated:YES completion:nil];
        }
    }
    
    #pragma mark--XMPPStreamDelegate
    //注册成功
    -(void)xmppStreamDidRegister:(XMPPStream *)sender{
        NSLog(@"%s__%d__注册成功",__FUNCTION__,__LINE__);
        
        //存储账户密码用于下次自动登入
        [[NSUserDefaults standardUserDefaults] setObject:self.userName.text forKey:@"userName"];
        [[NSUserDefaults standardUserDefaults] setObject:self.password.text forKey:@"password"];
        
        //改变APP的登入状态
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isLoginStatus"];
        [[NSUserDefaults standardUserDefaults] synchronize];
        
        //验证之后默认的状态为离线,需要手动告诉服务器自己的状态
        XMPPPresence *presence = [XMPPPresence presenceWithType:@"available"];
        [[XMPPManager sharedXMPPManager].stream sendElement:presence];
        
        //注册成功之后返回到登陆界面
        [self.navigationController popToRootViewControllerAnimated:YES];
    }
    //注册失败
    -(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error{
        NSLog(@"%s__%d__注册失败%@",__FUNCTION__,__LINE__,error);
    }
    
    
    RegisterViewController.png

    ChatViewController

    在ChatViewController中需要公开一个属性,用来接收好友列表页面传来的XMPPJID。

    ChatViewController.h
    @interface ChatViewController : UIViewController
    
    @property (nonatomic,strong)XMPPJID *chatToJid;
    
    @end
    
    ChatViewController.m
    @interface ChatViewController ()<UITableViewDataSource,UITableViewDelegate>
    
    //显示消息
    @property (weak, nonatomic) IBOutlet UITableView *messageContent;
    //消息输入框
    @property (weak, nonatomic) IBOutlet UITextView *messageTextView;
    //键盘底部约束
    @property (weak, nonatomic) IBOutlet NSLayoutConstraint *messageTextfieldConstraint;
    //存储消息数据
    @property (nonatomic,strong) NSMutableArray *allMessageArray;
    
    @end
    
    @implementation ChatViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.messageTextView.text = @"";
    
        self.messageContent.delegate = self;
        self.messageContent.dataSource = self;
        
        self.allMessageArray = [[NSMutableArray alloc] init];
        //将历史消息加入到数组
        [self.allMessageArray addObjectsFromArray:[self fromDataBaseFetchResult]];
        
        //监听键盘frame的改变
        [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(kbFrameWillChange:) name:UIKeyboardWillChangeFrameNotification object:nil];
        
        [[XMPPManager sharedXMPPManager].stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
        
        [self reloadMessage];
        
        self.messageContent.separatorStyle = UITableViewCellSeparatorStyleNone;
    }
    
    //消息发送按钮
    - (IBAction)sendMessageAction:(id)sender {
        XMPPMessage *message = [XMPPMessage messageWithType:@"chat" to:self.chatToJid];
        //要发送的消息添加到Body
        [message addBody:self.messageTextView.text];
        //发送消息
        [[XMPPManager sharedXMPPManager].stream sendElement:message];
    }
    
    //键盘即将改变frame
    - (void)kbFrameWillChange:(NSNotification *)noti{
        //获取窗口的高度
        CGFloat windowH = [UIScreen mainScreen].bounds.size.height;
        //键盘结束的frm
        CGRect kbEndFrm = [noti.userInfo [UIKeyboardFrameEndUserInfoKey]CGRectValue];
        //键盘结束的y值
        CGFloat kbEndY = kbEndFrm.origin.y;
        self.messageTextfieldConstraint.constant = windowH - kbEndY;
        
        [self scrollsToBottomAnimated:YES];
    }
    
    - (void)scrollsToBottomAnimated:(BOOL)animated{
        CGFloat offset = self.messageContent.contentSize.height - self.messageTextfieldConstraint.constant - 55;
        if (offset > 0){
            [self.messageContent setContentOffset:CGPointMake(0, offset) animated:animated];
        }
    }
    
    #pragma mark XMPPStreamDelegate
    //发送信息成功
    -(void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message{
        NSLog(@"发送成功🍅");
        [self reloadMessage];//发送信息时刷新一次页面
    }
    
    //发送信息失败
    -(void)xmppStream:(XMPPStream *)sender didFailToSendMessage:(XMPPMessage *)message error:(NSError *)error{
        NSLog(@"发送失败⚠️");
    }
    
    //收到信息
    -(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{
        NSLog(@"收到消息%@",message);
        if ([message isChatMessageWithBody]) {
            [self reloadMessage];//收到信息是刷新一次页面
        }
    }
    
    #pragma mark 加载聊天信息
    -(void)reloadMessage{
        
        //从数据库读取数据
        NSArray *fetchedObjects = [self fromDataBaseFetchResult];
        
        // 清空消息数组里的所有数据
        [self.allMessageArray removeAllObjects];
        // 将新的聊天记录添加到数组中
        [self.allMessageArray addObjectsFromArray:fetchedObjects];
        
        //将信息加载到tableView上
        [self.messageContent reloadData];
        
        //加载时滚动到最底部
        [self scrollToBottomWithAnimated:YES];
    }
    
    //从数据库读取数据
    - (NSArray *)fromDataBaseFetchResult{
        //1.上下文
        NSManagedObjectContext *managerObjectContext =[XMPPManager sharedXMPPManager].managerObjectContext;
        
        //2.创建查询请求
        NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"XMPPMessageArchiving_Message_CoreDataObject"];
        
        //3.设置过滤条件(提取当前用户jid,好友jid)
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bareJidStr == %@ And streamBareJidStr == %@", self.chatToJid.bare,[XMPPManager sharedXMPPManager].stream.myJID.bare];
        fetchRequest.predicate = predicate;
        
        //4.设置排序(时间升序)
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:YES];
        fetchRequest.sortDescriptors = @[sortDescriptor];
        
        //5.执行请求
        NSError *error = nil;
        NSArray *fetchedResult = [managerObjectContext executeFetchRequest:fetchRequest error:&error];
        
        return fetchedResult;
    }
    
    //滚动到最底部
    - (void)scrollToBottomWithAnimated:(BOOL)animated{
        
        if (animated && [self.messageContent numberOfSections] > 0) {
            
            NSInteger lastSectionIndex = [self.messageContent numberOfSections] - 1;
            NSInteger lastRowIndex = [self.messageContent numberOfRowsInSection:lastSectionIndex] - 1;
            
            if (lastRowIndex > 0) {
                
                NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:lastRowIndex inSection:lastSectionIndex];
                [self.messageContent scrollToRowAtIndexPath:lastIndexPath atScrollPosition: UITableViewScrollPositionBottom animated:animated];
            }
        }
    }
    
    #pragma mark UITableViewDataSourceDelegate
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return self.allMessageArray.count;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        if (nil == cell) {
            cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleValue1) reuseIdentifier:@"cell"];
        }
        
        XMPPMessageArchiving_Message_CoreDataObject *chatMessage = self.allMessageArray[indexPath.row];
        
        //判断聊天信息是发出去的 还是接受进来的,在cell上显示不一样的样式
        if (chatMessage.isOutgoing == YES) {
            cell.detailTextLabel.text = chatMessage.body;
            cell.textLabel.text = @"";
        } else {
            cell.textLabel.text = chatMessage.body;
            cell.detailTextLabel.text = @"";
        }
        
        self.messageTextView.text = @"";
        
        return cell;
    }
    
    Use Test_XMPP And Spark Chat.png

    以上就是将XMPP添加到工程,实现基于XMPP的登入、注册、聊天功能,还有一大批别的功能有待探索,之后将进行持续的更新。

    总结

    1.XMPP框架中所有的连接、登入、注册、授权、失去连接等操作的回调都是通过XMPPStream来管理;
    2.使用XMPP开发即时通信,大部分功能都是通过回调XMPPStreamDelegate协议中的方法来实现。


    联系作者:简书·DH_Fantasy 新浪微博·DH_Fantasy
    版权声明:自由转载-非商用-非衍生-保持署名(CC BY-NC-ND 3.0

    相关文章

      网友评论

      本文标题:iOS 即时通信系列之XMPP登入、注册、聊天

      本文链接:https://www.haomeiwen.com/subject/shaxsttx.html