关于xmpp的一些东西

时间:2023-01-29 16:10:46


// ======================= 用户   登陆注册 注销  ======================

/**

 *  ====  xmpp 登陆   ====

 

    1. 初始化 XMPPStream

        注意:

            在连接服务器时初始化,

        步骤:  

            1> 创建 XMPPStream对象

            2> 设置代理(注意设置方式不同)

            3> 添加一些需要的xmpp模块,并激活(电子名片,头像,花名册等等)

 

 

    2. 建立连接到服务器(要传一个jid)

        

        步骤:

            1. 设置jid

                1> 根据登陆标识判断是登陆 还是注册

                2> 从单例中获取用户名

                     登陆: 获取账户对象的登陆用户名

                     注册: 获取账户对象的登陆用户名

                3> 拼接jid  jidWithUser

                4> 设置jid

            2. 设置主机地址

            3. 设置主机端口号(不设置的话,默认是5222)

            4. 发起连接 connectWithTimeout方法

 

    XMPPStream 代理方法

    3. 连接成功   xmppStreamDidConnect方法

        注意:

            不管用户名存不存在,连接服务器都会成功,

            1> 如果用户存在,密码正确 会调用xmppStreamDidAuthenticate

            2> 如果用户名不存在会调用-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error

 

        步骤:

            1> 发送密码,判断是登陆还是注册

                登陆:

                    1. LCAccount单例中获取登陆密码

                    2. 发送 authenticateWithPassword方法

                注册:

                    1. LCAccount单例中获取注册密码

                    2. 发送 registerWithPassword方法

 

        2> 登陆成功   xmppStreamDidAuthenticate方法

            1. 发送 "在线"消息 给服务器(默认登陆成功后,是不在线的)(在代理方法中调用)

                -> 好处:可以通知其他好友,上线了

            2. 回调resultBlock

 

        3> 登陆失败   didNotAuthenticate方法

            1. 回调resultBlock

 

        4> 注册成功   xmppStreamDidRegister方法

            1. 回调resultBlock


        5> 注册失败   didNotRegister方法

            1. 回调resultBlock


 */



/**

 *  ====  xmpp  注册   ====

 

    保存block, 删除之前的连接 [_xmppStream disconnect];


    1. 发送注册的 jid给服务器, 建立一个长连接

    2. 连接成功后,发送注册密码(代理方法中实现)

 */



/**

 *  ====  xmpp 注销  ====

 

    1. 发送 "离线消息"给服务器

        // xmpp框架,已经把所有的指令 封装成 对象了

        XMPPPresence *offline = [XMPPPresence presenceWithType:@"unavailable"];

        [_xmppStream sendElement:offline];

 

    2. 断开与服务器的连接

        [_xmppStream disconnect];

    

    3. 把沙盒里的登陆状态修改为NO

        [LCAccount shareAccount].login = NO;

        [[LCAccount shareAccount] saveToSandBox];

 */


// ======================= 好友列表(花名册) ===========================

/**

 *   ====  xmpp 获取好友  ====

 

    注意:

        好友信息存放在沙盒的XMPPRoster.sql数据库里.

        对数据库进行操作.

 

    步骤:

        1. 关联上下文

            NSManagedObjectContext *rosterContext = [XMPPTool sharedXMPPTool].rosterStorage.mainThreadManagedObjectContext;

 

        2. request 请求查询哪张表

            NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPUserCoreDataStorageObject"];

 

        3. 设置查询条件

            (升序排序)

            NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"displayName" ascending:YES];

            request.sortDescriptors = @[sort];

 

            (过滤)对方没有同意添加为好友的, 不显示出来

            NSPredicate *pre = [NSPredicate predicateWithFormat:@"subscription != %@", @"none"];

            request.predicate = pre;

 

        4. 执行请求

            1> 创建结果控制器,接收查找好友的 返回结果对象

            _resultContr = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:rosterContext sectionNameKeyPath:nil cacheName:nil];

            2> 设置代理

            _resultContr.delegate = self;

            3> 执行

            NSError *error = nil;

            [_resultContr performFetch:&error];

 

 

        NSFetchedResultsController代理方法

 

        当数据库内容改变时 ,触发   controllerDidChangeContent方法

            1> 刷新表格,显示最新数据

 

 */


/**

 *  ====   显示好友信息到界面   ==== 

        

    注意:

        默认的情况:不是程序一启动就有头像,第一次的话需要自己从服务器上去获取.

 

    步骤:

        1. 好友的名称

        2. 判断用户是否在线

        3. 显示好友头像

            有头像:

                1> 设置头像

            没有头像:

                1> 从服务器获取头像

                    NSData *imgData = [[XMPPTool sharedXMPPTool].avatar photoDataForJID:user.jid];

                2> 设置头像


 */

/**

 *  ====   添加好友   ====

    注意:

        1. 不能添加自己为好友

        2. 已经存在的好友不能再添加

 

    步骤:

        1. 不能添加自己为好友

 

        2. 已经存在的好友不能再添加

            1> 根据用户jid从数据库中获取 输入的好友是否存在

            BOOL userExists = [[XMPPTool sharedXMPPTool].rosterStorage userExistsWithJID:userJid xmppStream:[XMPPTool sharedXMPPTool].xmppStream];

 

        3. 判断 

            userExists == yes 已经添加

 

        4. 添加好友

            [[XMPPTool sharedXMPPTool].roster subscribePresenceToUser:userJid];

 

    问题:

        xmpp 添加好友现有的openfire中存在的问题:

            添加不存在的好友时,数据库、通讯录里面也显示.

 

        解决1:

            > 服务器可以拦截添加好友的请求,如果服务器当前数据库没有好友, 不要返回信息

 

        解决2:

            > 过滤数据库的查询请求,字段: subscription

            字段类型: none ,对方没有同意添加好友

                    to , 发给对方添加好友请求的

                    form , 别人加你的请求

                    both , 双方互为好友

            > LCContactsViewController结果控制器中, 获取联系人信息时, 添加过滤条件,对方没有同意的好友不显示出来.


 

 */


/**

 *  ====   删除好友   ====

 

    步骤:

    1. 获取要删除的好友 (_resultContr.fetchedObjects查询结果的数组,类似:users)

        XMPPUserCoreDataStorageObject *user = _resultContr.fetchedObjects[indexPath.row];

 

    2.删除好友(使用花名册模块)

        [[XMPPTool sharedXMPPTool].roster removeUser:user.jid];

 

 */


// ========================  实时 聊天 ================================

/**

 *  ====   获取聊天信息  ====

 

    注意:

 

    步骤:

        1. 设置上下文

 

        2. 查询请求

            NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"XMPPMessageArchiving_Message_CoreDataObject"];

 

        3. 查询条件

            1>. 只获取当前登录用户的消息,并且 只获取和当前聊天好友的消息

                NSString *loginJidStr = [XMPPTool sharedXMPPTool].xmppStream.myJID.bare; //当前用户名

                NSPredicate *pre = [NSPredicate predicateWithFormat:@"streamBareJidStr = %@ AND bareJidStr = %@", loginJidStr, self.friendJid.bare]; // sql查询条件

                request.predicate = pre;

 

            2>. 设置时间排序(升序)

                NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"timestamp" ascending:YES];

                request.sortDescriptors = @[sort];

 

        4. 执行

            1>. 请求结果控制器

                _resultContr = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];

            2>. 代理

                _resultContr.delegate = self;

            3>.执行

                NSError *error = nil;

                [_resultContr performFetch:&error];

 

        

        下面的在 cellForRowAtIndexPath:(NSIndexPath *)indexPath方法里面设置


 

        5. 得到结果对象 获取聊天信息

            XMPPMessageArchiving_Message_CoreDataObject *msgObj = _resultContr.fetchedObjects[indexPath.row];

 

            步骤:

            1> 获取原始的xml数据

                XMPPMessage *message = msgObj.message;

 

            2> 获取文件的类型

                NSString *bodyType = [message attributeStringValueForName:@"bodyType"];

 

            3> 判断文件类型  [bodyType isEqualToString:@"image"]

                文本:

                    直接赋值

                    cell.textLabel.text = message.body;

                图片image:

                    1> 获取子节点data数据

                     

                         1). 获取所有的子节点

                         NSArray *child = message.children;

                         2). 返回的数据

                         NSData *data = nil;

                         3). 遍历所有子节点

                         for (XMPPElement *note in child) {

                             // 获取节点的名字,进行判断

                             if ([[note name] isEqual:@"attachment"]) { // 此时说明有文件

                             

                                 // ** 1. 获取文件字符串

                                 NSString *dataStr = [note stringValue];

                                 // ** 2. 字符串 --> data

                                 data = [[NSData alloc] initWithBase64EncodedString:dataStr options:0];

                             }

                         }

                     

                    2> 赋值

                        image = [UIImage imageWithData:imageData];

                 

                音频sound:

                    后续


 */


/**

 *  ====   发送聊天信息   ====

    

    注意:

        把图片转换成字符串(使用base64编码转换)

 

         图片 --> data

            NSData *imgData = UIImagePNGRepresentation(img);

         data --> base64字符串

            NSString *imgStr = [imgData base64EncodedStringWithOptions:0];

 

        上面 = 等价于 = 下面

 

            NSString *base64Str = [data base64EncodedStringWithOptions:0];


    步骤:

        1. 发送文本信息

            1> 向服务器发送聊天数据

                1> 编辑要发送的数据

                    XMPPMessage *msg = [XMPPMessage messageWithType:@"chat" to:self.friendJid];

                    [msg addBody:textField.text];

     

                2> 发送消息

                    [[XMPPTool sharedXMPPTool].xmppStream sendElement:msg];

     

            2> 清空输入框文本

                textField.text = nil;


        2. 发送文件,以发送图片为例

            1> 获取图片

                1). 手机图片库 选取

                    UIImagePickerController *picker = [[UIImagePickerController alloc] init];

                2). 设置图片样式

                    picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;

                3). 设置代理

                    picker.delegate = self;

                4). 跳转

                    [self presentViewController:picker animated:YES completion:nil];

            

 

            2> UIImagePickerController代理   didFinishPickingMediaWithInfo代理方法

 

                 1).获取图片

                     UIImage *img = info[UIImagePickerControllerOriginalImage];

                 

                 2).发送图片

                     1> 编辑要发送的数据

                        XMPPMessage *msg = [XMPPMessage messageWithType:@"chat" to:self.friendJid];

                     

                     2> 设置类型

                        [msg addAttributeWithName:@"bodyType" stringValue:bodyType];

                        [msg addBody:bodyType];

                     

                     3> 把文件转换成字符串(使用base64编码转换)

                        NSString *base64Str = [data base64EncodedStringWithOptions:0];

                     

                     4> 创建节点(定义附件)

                            XMPPElement *attachment = [XMPPElement elementWithName:@"attachment" stringValue:base64Str];

                     5> 添加子节点

                        [msg addChild:attachment];

                     

                     6> 发送消息

                     [[XMPPTool sharedXMPPTool].xmppStream sendElement:msg];

    

        3. 隐藏控制器

            [self dismissViewControllerAnimated:YES completion:nil];

 */

// =========================== 我的信息  电子名片模块 =========================================


/**

 *  ==== 获取 电子名片 信息  ====

 

        注意:

            显示头像和微信号

            从数据库中获取用户信息

 

        步骤:

            1.获取登陆用户的电子名片信息  (内部实现:会去数据库查找, 不需要我们自己写)

                XMPPvCardTemp *myvCard = [XMPPTool sharedXMPPTool].vCard.myvCardTemp;


            2.获取头像,设置头像

                self.iconImage.image = [UIImage imageWithData:myvCard.photo];


            3.微信号(显示用户名)

                self.wcNumL.text = [NSString stringWithFormat:@"微信号:%@",[LCAccount shareAccount].loginUserName];


 */


/**

 *  ====  修改电子名片信息  ====

 

        注意:

        

        1. 修改头像图片  didFinishPickingMediaWithInfo代理方法中

             1> 获取修改后的图片

             UIImage *editImage = info[UIImagePickerControllerEditedImage];

             

             2> 更改cell的头像图片

             self.iconImageV.image = editImage;

             

             3> 移除图片选择控制器

             [self dismissViewControllerAnimated:YES completion:nil];

             

             4> 把新的头像保存到服务器

             [self editvCardViewController:nil didFinishSave:nil];

 

        2. 修改信息

            把数据保存到服务器

             

            1> 获取当前电子名片

                 XMPPvCardTemp *myVCard = [XMPPTool sharedXMPPTool].vCard.myvCardTemp;

             

            2> 重新设置myVCrad的属性

                 myVCard.photo = UIImageJPEGRepresentation(self.iconImageV.image, 1.00); //1.00比例上传图片

                 myVCard.nickname = self.nickNameL.text;

                 myVCard.orgName = self.orgNameL.text;

             

            3> 把数据保存到服务器

                 [[XMPPTool sharedXMPPTool].vCard updateMyvCardTemp:myVCard];

                 内部实现:数据上传是把整个电子名片的数据都重新上传了一次,包括图片


 */





// =========================== 资源管理 =========================================

/**

 *  ====  xmpp 程序退出时释放相应的资源   ====

 

 注意:

  dealloc 方法中调用

 

 步骤:

 1. 移除代理

 [_xmppStream removeDelegate:self];

 

 2. 取消模块

 [_avatar deactivate];

 [_vCard deactivate];

 

 3. 断开连接

 [_xmppStream disconnect];

 

 4. 清空资源

 _xmppStream = nil;

 _avatar = nil;

 _vCard = nil;

 _vCardStorage = nil;

 */





/**

 *   电子名片(vCard)

 

    1> 是一种机制获取电子名片 或者 发送电子名片数据.

    2> 获取电子名片使用XMPPFramework 里面提供的 "电子名片模块 "

    3> 如何使用:  

        > 导入 "电子名片模块头文件

        > 激活 "电子名片模块"

    4> "电子名片模块 "的内部实现:

        > 发送请求,从服务器获取电子名片(个人信息)数据

            <iq type="get" to="lisi@licheng.local"><vCard xmlns="vcard-temp"/></iq>

        > 接收服务器返回的数据把数据缓存到本地的数据库

            为什么mycVard.jid是空的?

            因为服务器返回的电子名片的xml数据中没有JABBERID节点

 */


/**

 *   如何 打开xmpp的日志

 

    1> 打开XMPP/Core/XMPPLogging.h文件67, XMPP_LOGGING_ENABLED 设置为1

    2> 需要配置xmpp日志的启动appdelegate.mdidfinishlauching方法中添加:

        前提导入:DDLog.h  DDTTYLogger.h

        [DDLog addLogger:[DDTTYLogger sharedInstance]];


 */



/**

 *   openfire的二次开发

 

    1> openfire基于java开发获取到源代码,进行二次开发

    2> 每开发一个功能模块最终打包成一个插件

    3> 将插件添加到openfire后台, app就可以实现该插件里面的功能.

 

 */


/**

 *    花名册模块的数据存储原理

    

    1> 沙盒里保存的数据库里的数据只是单个用户的

    2> 如果其他用户登录则数据库里原来用户的数据会被删除

 */


/**

 *    XMPP框架 实时聊天实现

 

    xmpp 提供了 "消息模块" , 来实现实时聊天.

    不管是哪个用户登录实时聊天的数据都保存在同一个数据库的表中

 

    实现:

    1> 接收到好友的聊天数据后把数据保存到数据库

    2> 从数据库中获取显示到表格上


 */


/**

 *  文件发送

    

    图片音频视频文档等.

    xmppios不支持音频等发送需要自己实现.

 

    实现方式:

 

        1> 方式二添加属性 bodyType 确定发送的文件类型

                  添加子节点 attachment

 

         <message type="chat" from="" to="lisi@licheng.local" bodyType="image/text/sound/doc/xls">

         <body>存文本消息</body>

         <attachment>文件内容 转成 字符串 </attachment>  // 自己添加这一行

         </message>

 

        这种方式一定要有body子节点不然没法发送

 

        2> 方式二通过 文件服务器 来实现

 

        -- 1. ios客户端把文件上传到 文件服务器

        -- 2. 文件服务器 返回文件路径给 ios客户端A

        -- 3. ios客户端把文件路径 传递给 openfire服务器

        -- 4. openfire服务器 把文件路径 发送给 ios客户端B

        -- 5. ios客户端通过文件路径  文件服务器 读取文件

 */






/**

 *   电子名片(vCard)

 

    1> 是一种机制获取电子名片 或者 发送电子名片数据.

    2> 获取电子名片使用XMPPFramework 里面提供的 "电子名片模块 "

    3> 如何使用:  

        > 导入 "电子名片模块头文件

        > 激活 "电子名片模块"

    4> "电子名片模块 "的内部实现:

        > 发送请求,从服务器获取电子名片(个人信息)数据

            <iq type="get" to="lisi@licheng.local"><vCard xmlns="vcard-temp"/></iq>

        > 接收服务器返回的数据把数据缓存到本地的数据库

            为什么mycVard.jid是空的?

            因为服务器返回的电子名片的xml数据中没有JABBERID节点

 */


/**

 *   如何 打开xmpp的日志

 

    1> 打开XMPP/Core/XMPPLogging.h文件67, XMPP_LOGGING_ENABLED 设置为1

    2> 需要配置xmpp日志的启动appdelegate.mdidfinishlauching方法中添加:

        前提导入:DDLog.h  DDTTYLogger.h

        [DDLog addLogger:[DDTTYLogger sharedInstance]];


 */



/**

 *   openfire的二次开发

 

    1> openfire基于java开发获取到源代码,进行二次开发

    2> 每开发一个功能模块最终打包成一个插件

    3> 将插件添加到openfire后台, app就可以实现该插件里面的功能.

 

 */


/**

 *    花名册模块的数据存储原理

    

    1> 沙盒里保存的数据库里的数据只是单个用户的

    2> 如果其他用户登录则数据库里原来用户的数据会被删除

 */


/**

 *    XMPP框架 实时聊天实现

 

    xmpp 提供了 "消息模块" , 来实现实时聊天.

    不管是哪个用户登录实时聊天的数据都保存在同一个数据库的表中

 

    实现:

    1> 接收到好友的聊天数据后把数据保存到数据库

    2> 从数据库中获取显示到表格上


 */


/**

 *  文件发送

    

    图片音频视频文档等.

    xmppios不支持音频等发送需要自己实现.

 

    实现方式:

 

        1> 方式二添加属性 bodyType 确定发送的文件类型

                  添加子节点 attachment

 

         <message type="chat" from="" to="lisi@licheng.local" bodyType="image/text/sound/doc/xls">

         <body>存文本消息</body>

         <attachment>文件内容 转成 字符串 </attachment>  // 自己添加这一行

         </message>

 

        这种方式一定要有body子节点不然没法发送

 

        2> 方式二通过 文件服务器 来实现

 

        -- 1. ios客户端把文件上传到 文件服务器

        -- 2. 文件服务器 返回文件路径给 ios客户端A

        -- 3. ios客户端把文件路径 传递给 openfire服务器

        -- 4. openfire服务器 把文件路径 发送给 ios客户端B

        -- 5. ios客户端通过文件路径  文件服务器 读取文件

 */