iOS即时通信之XMPP框架的使用及原理简介

2024-05-31 11:18

本文主要是介绍iOS即时通信之XMPP框架的使用及原理简介,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

小公司可以考虑xmpp框架,xmpp内部封装好了异步的socket通信

XMPP是基于XML协议的分散型通讯网络,只要服务器的协议相同,服务器就可以和服务器通信;

XMPP的核心就是XML流传传输协议;

XMPP是C/S 架构;

XMPP中对应的模块会吧数据从服务器拿出来,然后放到本地数据库,我们开发只需要获取本地服务器的数据.




XMPP----------可扩展通讯和标示协议






==================

连接服务器,登录,注册

// 1. 初始化XMPPStream

-(void)setupXMPPStream;



// 2.连接到服务器

-(void)connectToHost;


// 3.连接到服务成功后,再发送密码授权

-(void)sendPwdToHost;



// 4.授权成功后,发送"在线"消息

-(void)sendOnlineToHost;

@end



@implementation WCXMPPTool



singleton_implementation(WCXMPPTool)




#pragma mark  -私有方法

#pragma mark 初始化XMPPStream

-(void)setupXMPPStream{

    

    _xmppStream = [[XMPPStreamalloc]init];

#warning 每一个模块添加后都要激活

    //添加电子名片模块

    _vCardStorage = [XMPPvCardCoreDataStoragesharedInstance];

    _vCard = [[XMPPvCardTempModulealloc]initWithvCardStorage:_vCardStorage];

    

    //激活

    [_vCard activate:_xmppStream];

    

    //添加头像模块

    _avatar = [[XMPPvCardAvatarModulealloc]initWithvCardTempModule:_vCard];

    [_avatar activate:_xmppStream];

    

    

    

    // 设置代理

    [_xmppStreamaddDelegate:selfdelegateQueue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)];

}


#pragma mark 连接到服务器

-(void)connectToHost{

    WCLog(@"开始连接到服务器");

    if (!_xmppStream) {

        [selfsetupXMPPStream];

    }

    

    

    // 设置登录用户JID

    //resource 标识用户登录的客户端 iphone android

    

    // 从单例获取用户名

    NSString *user = nil;

    if (self.isRegisterOperation) {

        user = [WCUserInfo sharedWCUserInfo].registerUser;

    }else{

        user = [WCUserInfo sharedWCUserInfo].user;

    }

    

    XMPPJID *myJID = [XMPPJIDjidWithUser:userdomain:@"teacher.local"resource:@"iphone" ];

    _xmppStream.myJID = myJID;

    

    // 设置服务器域名

    _xmppStream.hostName =@"teacher.local";//不仅可以是域名,还可是IP地址

    

    // 设置端口如果服务器端口是5222,可以省略

    _xmppStream.hostPort =5222;

    

    // 连接

    NSError *err = nil;

    if(![_xmppStreamconnectWithTimeout:XMPPStreamTimeoutNoneerror:&err]){

        WCLog(@"%@",err);

    }

    

}



#pragma mark 连接到服务成功后,再发送密码授权

-(void)sendPwdToHost{

    WCLog(@"再发送密码授权");

    NSError *err = nil;

    

    // 从单例里获取密码

    NSString *pwd = [WCUserInfosharedWCUserInfo].pwd;

    

    [_xmppStreamauthenticateWithPassword:pwderror:&err];

    

    if (err) {

        WCLog(@"%@",err);

    }

}


#pragma mark  授权成功后,发送"在线"消息

-(void)sendOnlineToHost{

    

    WCLog(@"发送在线消息");

    XMPPPresence *presence = [XMPPPresencepresence];

    WCLog(@"%@",presence);

    

    [_xmppStream sendElement:presence];

    

    

}

#pragma mark -XMPPStream的代理

#pragma mark 与主机连接成功

-(void)xmppStreamDidConnect:(XMPPStream *)sender{

    WCLog(@"与主机连接成功");

    

    if (self.isRegisterOperation) {//注册操作,发送注册的密码

        NSString *pwd = [WCUserInfosharedWCUserInfo].registerPwd;

        [_xmppStreamregisterWithPassword:pwderror:nil];

    }else{//登录操作

        // 主机连接成功后,发送密码进行授权

        [selfsendPwdToHost];

    }

    

}

#pragma mark  与主机断开连接

-(void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error{

    // 如果有错误,代表连接失败

    

    // 如果没有错误,表示正常的断开连接(人为断开连接)

    

    

    if(error && _resultBlock){

        _resultBlock(XMPPResultTypeNetErr);

    }

    WCLog(@"与主机断开连接 %@",error);

    

}



#pragma mark 授权成功

-(void)xmppStreamDidAuthenticate:(XMPPStream *)sender{

    WCLog(@"授权成功");

    

    [selfsendOnlineToHost];

    

    // 回调控制器登录成功

    if(_resultBlock){

        _resultBlock(XMPPResultTypeLoginSuccess);

    }

    

    

}



#pragma mark 授权失败

-(void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(DDXMLElement *)error{

    WCLog(@"授权失败 %@",error);

    

    // 判断block有无值,回调给登录控制器

    if (_resultBlock) {

        _resultBlock(XMPPResultTypeLoginFailure);

    }

}


#pragma mark 注册成功

-(void)xmppStreamDidRegister:(XMPPStream *)sender{

    WCLog(@"注册成功");

    if(_resultBlock){

        _resultBlock(XMPPResultTypeRegisterSuccess);

    }

    

}


#pragma mark 注册失败

-(void)xmppStream:(XMPPStream *)sender didNotRegister:(DDXMLElement *)error{

    

    WCLog(@"注册失败 %@",error);

    if(_resultBlock){

        _resultBlock(XMPPResultTypeRegisterFailure);

    }

    

}


#pragma mark -公共方法

-(void)xmppUserlogout{

    // 1." 发送 "离线"消息"

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

    [_xmppStream sendElement:offline];

    

    // 2. 与服务器断开连接

    [_xmppStream disconnect];

    

    // 3. 回到登录界面

//    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Login" bundle:nil];

//    

//    self.window.rootViewController = storyboard.instantiateInitialViewController;

    [UIStoryboardshowInitialVCWithName:@"Login"];

    

    

    //4.更新用户的登录状态

    [WCUserInfosharedWCUserInfo].loginStatus =NO;

    [[WCUserInfosharedWCUserInfo]saveUserInfoToSanbox];

    

}


-(void)xmppUserLogin:(XMPPResultBlock)resultBlock{

    

    // 先把block存起来

    _resultBlock = resultBlock;

    

    //    Domain=XMPPStreamErrorDomain Code=1 "Attempting to connect while already connected or connecting." UserInfo=0x7fd86bf06700 {NSLocalizedDescription=Attempting to connect while already connected or connecting.}

    // 如果以前连接过服务,要断开

    [_xmppStream disconnect];

    

    // 连接主机成功后发送登录密码

    [selfconnectToHost];

}



-(void)xmppUserRegister:(XMPPResultBlock)resultBlock{

    // 先把block存起来

    _resultBlock = resultBlock;

    

    // 如果以前连接过服务,要断开

    [_xmppStream disconnect];

    

    // 连接主机成功后发送注册密码

    [selfconnectToHost];

}


======================

xmpp的一般开发步骤:

1.导入指定模块的头文件

2.创建导入的指定模块的对象

3.设置参数

4.设置代理 (需要代理才设置)

5.激活模块

=================================

0054电子明片(个人资料)的设置:

个人资料功能模块------XMPPVcardTempModule.h

个人资料的存储集合----------XMPPvCardTemp  *myvCardTemp,是XMPPVcardTempModule的一个属性;

个人资料的数据库存储-------XMPPvCardCoreDataStorage.h

 个人资料数据库对象-----------XMPPvCardTempCoreDataStorageObject.h

头像功能模块-----XMPPvCardAVatarModule.h

头像数据存储对象-----XMPPvCardAvatarCoreDataStorageObject.h

@property (nonatomicstrong)XMPPvCardCoreDataStorage *vCardStorage;//电子名片的数据存储

    

@property (nonatomicstrong)XMPPvCardAvatarModule *avatar;//头像模块

 

@property (nonatomicstrong)XMPPvCardTempModule *vCard;//电子名片模块



_xmppStream = [[XMPPStreamalloc]init];

#warning 每一个模块添加后都要激活

    //添加电子名片模块

    _vCardStorage = [XMPPvCardCoreDataStoragesharedInstance];

    _vCard = [[XMPPvCardTempModulealloc]initWithvCardStorage:_vCardStorage];

    

    //激活

    [_vCard activate:_xmppStream];

    

    //添加头像模块

    _avatar = [[XMPPvCardAvatarModulealloc]initWithvCardTempModule:_vCard];

    [_avatar activate:_xmppStream];



    

    //xmpp提供了一个方法,直接获取个人信息(电子面片的功能模块有一个个人信息的集合属性:XMPPvCardTemp *myvCardTemp)

    

   XMPPvCardTemp *myVCard =vCard.myvCardTemp;

    

    // 设置头像

    if(myVCard.photo){

        self.headerView.image = [UIImageimageWithData:myVCard.photo];

    }

    

    // 设置昵称

    self.nickNameLabel.text = myVCard.nickname;

    

    // 设置微信号[用户名]

    

    NSString *user = [WCUserInfosharedWCUserInfo].user;

    self.weixinNumLabel.text = [NSStringstringWithFormat:@"微信号:%@",user];


//更新这个方法内部会实现数据上传到服务器,无需程序自己操作

    [vCardupdateMyvCardTemp:myvCard];



================
心跳检测模块-----XMPPAutoPing.h
自动重连模块--------XMPPReconnect.h;


@property (nonatomicstrong)

XMPPReconnect *reconnect;// 自动连接模块


    //添加自动连接模块

    _reconnect = [[XMPPReconnectalloc]init];

    [_reconnect activate:_xmppStream];


===================================
花名册模块--------XMPPRoster.h
好友实体数据库存储--------XMPPRosterCoreDataStorage.h
好友实体对象-----XMPPUserCoreDataStorageObject.h

@property (nonatomicstrong)XMPPRosterCoreDataStorage *rosterStorage;//花名册数据存储

@property (nonatomicstrong)XMPPRoster *roster;//花名册模块



    //添加花名册模块【获取好友列表】

    _rosterStorage = [[XMPPRosterCoreDataStoragealloc]init];

    _roster = [[XMPPRosteralloc]initWithRosterStorage:_rosterStorage];

    [_roster activate:_xmppStream];



//方法一:    通过上下文  获取好友数据

    // 1.获取对象管理上下文【关联到数据库XMPPRoster.sqlite

    NSManagedObjectContext *context =rosterStorage.mainThreadManagedObjectContext;

    

    

    // 2.FetchRequest【查哪张表】通过实体(相当于表)查找

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

    

    // 3.设置过滤和排序

    // 过滤当前登录用户的好友

    NSString *jid = [WCUserInfosharedWCUserInfo].jid;

    NSPredicate *pre = [NSPredicatepredicateWithFormat:@"streamBareJidStr = %@",jid];

    request.predicate = pre;

    

    //排序

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

    request.sortDescriptors = @[sort];

    

    // 4.执行请求获取数据集合(集合里面的元素都是XMPPUserCoreDataStorageObject类型)

    self.friends = [contextexecuteFetchRequest:requesterror:nil];

    NSLog(@"%@",self.friends);


方法二:通过查询控制器查询获取

<NSFetchedResultsControllerDelegate>协议

{

    NSFetchedResultsController *_resultsContrl;

}

// 1.上下文【关联到数据库XMPPRoster.sqlite

    NSManagedObjectContext *context =rosterStorage.mainThreadManagedObjectContext;

    

    

    // 2.FetchRequest【查哪张表】

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

    

    // 3.设置过滤和排序

    // 过滤当前登录用户的好友

    NSString *jid = [WCUserInfosharedWCUserInfo].jid;

    NSPredicate *pre = [NSPredicatepredicateWithFormat:@"streamBareJidStr = %@",jid];

    request.predicate = pre;

    

    //排序

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

    request.sortDescriptors = @[sort];

    

    // 4.执行请求获取数据,获取好友集合(集合里面的元素都是XMPPUserCoreDataStorageObject类型)

    _resultsContrl = [[NSFetchedResultsControlleralloc]initWithFetchRequest:requestmanagedObjectContext:contextsectionNameKeyPath:nilcacheName:nil];

    

    _resultsContrl.delegate =self;

    

    NSError *err = nil;

    [_resultsContrlperformFetch:&err];



#pragma mark 当数据的内容发生改变后,会调用这个方法

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller{

    WCLog(@"数据发生改变");

    //刷新表格

    [self.tableViewreloadData];

}


-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return_resultsContrl.fetchedObjects.count;

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    staticNSString *ID =@"ContactCell";

    UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:ID];



    // 获取对应好友

    //XMPPUserCoreDataStorageObject *friend =self.friends[indexPath.row];

    XMPPUserCoreDataStorageObject *friend = _resultsContrl.fetchedObjects[indexPath.row];//通过传控制器获取的好友实体对象

    //    sectionNum

    //    “0”- 在线

    //    “1”- 离开

    //    “2”- 离线

    switch ([friend.sectionNumintValue]) {//好友对象的状态

        case 0:

            cell.detailTextLabel.text =@"在线";

            break;

        case 1:

            cell.detailTextLabel.text =@"离开";

            break;

        case 2:

            cell.detailTextLabel.text =@"离线";

            break;

        default:

            break;

    }

    cell.textLabel.text = friend.jidStr;//jid的类型是xxx@aaa.com

    

    return cell;

}


openfire服务器删除好友后,下面这个方法会接收到删除好友的消息后,花名册模块就会吧数据库roster.sqlite相应的好友删除

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller,

// 删除好友,  实现这个方法,cell往左滑就会有个delete

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{

    if (editingStyle ==UITableViewCellEditingStyleDelete) {

        WCLog(@"删除好友");

        XMPPUserCoreDataStorageObject *friend =_resultsContrl.fetchedObjects[indexPath.row];

        

        XMPPJID *freindJid = friend.jid;

        [[WCXMPPTool sharedWCXMPPTool].roster removeUser:freindJid];

    }

}


=============================
在textfield代理方法中

-(BOOL)textFieldShouldReturn:(UITextField *)textField{

    // 添加好友

    

    // 1.获取好友账号

    NSString *user = textField.text;

    WCLog(@"%@",user);

    

    // 判断这个账号是否为手机号码

    if(![textField isTelphoneNum]){

        //提示

        [self showAlert:@"请输入正确的手机号码"];

        return YES;

    }

    

    

    //判断是否添加自己

    if([user isEqualToString:[WCUserInfosharedWCUserInfo].user]){

        

        [self showAlert:@"不能添加自己为好友"];

        return YES;

    }

    NSString *jidStr = [NSStringstringWithFormat:@"%@@%@",user,domain];

    XMPPJID *friendJid = [XMPPJIDjidWithString:jidStr];

    

    

    //判断好友是否已经存在

    if([[WCXMPPToolsharedWCXMPPTool].rosterStorageuserExistsWithJID:friendJidxmppStream:[WCXMPPToolsharedWCXMPPTool].xmppStream]){

        [self showAlert:@"当前好友已经存在"];

        return YES;

    }

    

    

    // 2.发送好友添加的请求

    // 添加好友,xmpp有个叫订阅

  

    [[WCXMPPToolsharedWCXMPPTool].rostersubscribePresenceToUser:friendJid];

    

    return YES;

}


-(void)showAlert:(NSString *)msg{

    

    UIAlertView *alert = [[UIAlertViewalloc]initWithTitle:@"温馨提示"message:msgdelegate:nilcancelButtonTitle:@"谢谢"otherButtonTitles:nil,nil];

    [alert show];

}

@end


====================
聊天消息模块,显示消息,发送消息,发送图片

// 消息模块

消息功能模块-------"XMPPMessageArchiving.h"

消息数据存储------"XMPPMessageArchivingCoreDataStorage.h"

消息实体对象-------XMPPMessageArchiving_Message_CoreDataObject.h

最近联系人实体对象------XMPPMessageArchiving_Contact_CoreDataObject.h


#pragma mark 加载XMPPMessageArchiving数据库的数据显示在表格

-(void)loadMsgs{


    // 上下文

    NSManagedObjectContext *context = [WCXMPPToolsharedWCXMPPTool].msgStorage.mainThreadManagedObjectContext;

    // 请求对象

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

    

    

    // 过滤、排序

    // 1.当前登录用户的JID的消息

    // 2.好友的Jid的消息

    NSPredicate *pre = [NSPredicatepredicateWithFormat:@"streamBareJidStr = %@ AND bareJidStr = %@",[WCUserInfosharedWCUserInfo].jid,self.friendJid.bare];

    NSLog(@"%@",pre);

    request.predicate = pre;

    

    // 时间升序

    NSSortDescriptor *timeSort = [NSSortDescriptorsortDescriptorWithKey:@"timestamp"ascending:YES];

    request.sortDescriptors = @[timeSort];

   

    // 查询

    _resultsContr = [[NSFetchedResultsControlleralloc]initWithFetchRequest:requestmanagedObjectContext:contextsectionNameKeyPath:nilcacheName:nil];

    

    NSError *err = nil;

    // 代理

    _resultsContr.delegate =self;

    

    [_resultsContr performFetch:&err];

    

    NSLog(@"%@",_resultsContr.fetchedObjects);

    if (err) {

        WCLog(@"%@",err);

    }

}


#pragma mark -表格的数据源

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    return_resultsContr.fetchedObjects.count;

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

{

    static NSString *ID =@"ChatCell";

    UITableViewCell *cell = [tableViewdequeueReusableCellWithIdentifier:ID];

    if (!cell) {

        cell = [[UITableViewCellalloc]initWithStyle:UITableViewCellStyleSubtitlereuseIdentifier:ID];

    }

    

    // 获取聊天消息对象

    XMPPMessageArchiving_Message_CoreDataObject *msg = _resultsContr.fetchedObjects[indexPath.row];

    

    

    // 判断是图片还是纯文本

    NSString *chatType = [msg.messageattributeStringValueForName:@"bodyType"];

    if ([chatType isEqualToString:@"image"]) {

        //下图片显示

        [cell.imageViewsd_setImageWithURL:[NSURLURLWithString:msg.body]placeholderImage:[UIImageimageNamed:@"DefaultProfileHead_qq"]];

        cell.textLabel.text =nil;

    }else if([chatTypeisEqualToString:@"text"]){

    

        //显示消息

        if ([msg.outgoingboolValue]) {//自己发

            cell.textLabel.text = msg.body;

        }else{//别人发的

            cell.textLabel.text = msg.body;

        }

        

        cell.imageView.image =nil;

    }

    

    

//    //显示消息

//    if ([msg.outgoing boolValue]) {//自己发

//        cell.textLabel.text = [NSString stringWithFormat:@"Me: %@",msg.body];

//    }else{//别人发的

//        cell.textLabel.text = [NSString stringWithFormat:@"Other: %@",msg.body];

//    }

    

    

    

    return cell;

}



#pragma mark ResultController的代理

-(void)controllerDidChangeContent:(NSFetchedResultsController *)controller{

    // 刷新数据

    [self.tableViewreloadData];

    [selfscrollToTableBottom];

}


#pragma mark TextView的代理

-(void)textViewDidChange:(UITextView *)textView{

    //获取ContentSize

    CGFloat contentH = textView.contentSize.height;

    NSLog(@"textViewcontent的高度 %f",contentH);

    

    // 大于33,超过一行的高度/小于68高度是在三行内

    if (contentH > 33 && contentH < 68 ) {

        self.inputViewHeightConstraint.constant = contentH +18;

    }

    

    NSString *text = textView.text;

    

    

    // 换行就等于点击了的send

    if ([text rangeOfString:@"\n"].length !=0) {

        NSLog(@"发送数据 %@",text);

        

        // 去除换行字符

        text = [text stringByTrimmingCharactersInSet:[NSCharacterSetwhitespaceAndNewlineCharacterSet]];

        

        [selfsendMsgWithText:textbodyType:@"text"];

        //清空数据

        textView.text = nil;

        

        // 发送完消息 inputView的高度改回来

        self.inputViewHeightConstraint.constant =50;

        

    }else{

        NSLog(@"%@",textView.text);


    }

}



#pragma mark 发送聊天消息

-(void)sendMsgWithText:(NSString *)text bodyType:(NSString *)bodyType{

    

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

    

    //text 纯文本

    //image 图片

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

   

    // 设置内容

    [msg addBody:text];

     NSLog(@"%@",msg);

    [[WCXMPPToolsharedWCXMPPTool].xmppStreamsendElement:msg];

}


#pragma mark 滚动到底部

-(void)scrollToTableBottom{

    NSInteger lastRow =_resultsContr.fetchedObjects.count -1;

    

    if (lastRow < 0) {

        //行数如果小于0,不能滚动

        return;

    }

    NSIndexPath *lastPath = [NSIndexPathindexPathForRow:lastRowinSection:0];

    

    [self.tableViewscrollToRowAtIndexPath:lastPathatScrollPosition:UITableViewScrollPositionBottomanimated:YES];

}



#pragma mark 选择图片

-(void)addBtnClick{

    UIImagePickerController *imagePicker = [[UIImagePickerControlleralloc]init];

    imagePicker.sourceType =UIImagePickerControllerSourceTypePhotoLibrary;

    imagePicker.delegate = self;

    [selfpresentViewController:imagePickeranimated:YEScompletion:nil];


}


#pragma mark 选取后图片的回调

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{

    NSLog(@"%@",info);

    // 隐藏图片选择器的窗口

    [selfdismissViewControllerAnimated:YEScompletion:nil];

    

    // 获取图片

    UIImage *image = info[UIImagePickerControllerOriginalImage];

    

    // 把图片发送到文件服务器

    //http post put

    /**

     * put实现文件上传没post那烦锁,而且比POST

     * put的文件上传路径就是下载路径

     

     *文件上传路径http://localhost:8080/imfileserver/Upload/Image/ + "图片名【程序员自已定义】"

     */

    

    // 1.取文件名用户名 +时间(201412111537)年月日时分秒

    NSString *user = [WCUserInfosharedWCUserInfo].user;


    NSDateFormatter *dataFormatter = [[NSDateFormatteralloc]init];

    dataFormatter.dateFormat = @"yyyyMMddHHmmss";

    NSString *timeStr = [dataFormatter stringFromDate:[NSDate date]];

    

    // 针对我的服务,文件名不用加后缀

    NSString *fileName = [user stringByAppendingString:timeStr];

    

    // 2.拼接上传路径

    NSString *uploadUrl = [@"http://localhost:8080/imfileserver/Upload/Image/"stringByAppendingString:fileName];

    

    

    // 3.使用HTTP put上传

#warning 图片上传请使用jpg格式因为我写的服务器只接接收jpg

    [self.httpTooluploadData:UIImageJPEGRepresentation(image,0.75)url:[NSURLURLWithString:uploadUrl]progressBlock:nilcompletion:^(NSError *error) {

       

        if (!error) {

            NSLog(@"上传成功");

            [self sendMsgWithText:uploadUrl bodyType:@"image"];

        }

    }];

    

    

    // 图片发送成功,把图片的URLOpenfire的服务

}


======================

-(void)dealloc{

    [selfteardownXmpp];

}



#pragma mark 释放xmppStream相关的资源

-(void)teardownXmpp{

    

    // 移除代理

    [_xmppStreamremoveDelegate:self];

    

    // 停止模块

    [_reconnect deactivate];

    [_vCarddeactivate];

    [_avatardeactivate];

    [_rosterdeactivate];

    [_msgArchivingdeactivate];

    

    // 断开连接

    [_xmppStream disconnect];

    

    // 清空资源

    _reconnect = nil;

    _vCard = nil;

    _vCardStorage =nil;

    _avatar = nil;

    _roster = nil;

    _rosterStorage =nil;

    _msgArchiving =nil;

    _msgStorage = nil;

    _xmppStream = nil;


}





#pragma mark 接收到好友消息时调用的代理方法

-(void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message{

    WCLog(@"%@",message);

    

    //如果当前程序不在前台,发出一个本地通知

    if([UIApplicationsharedApplication].applicationState !=UIApplicationStateActive){

        WCLog(@"在后台");

        

        //本地通知

        UILocalNotification *localNoti = [[UILocalNotificationalloc] init];

        

        // 设置内容

        localNoti.alertBody = [NSStringstringWithFormat:@"%@\n%@",message.fromStr,message.body];

        

        // 设置通知执行时间

        localNoti.fireDate = [NSDatedate];

        

        //声音

        localNoti.soundName = @"default";

        

        //执行

        [[UIApplicationsharedApplication] scheduleLocalNotification:localNoti];

        

        //{"aps":{'alert':"zhangsan\n have dinner":'sound':'default',badge:'12'}}

    }

}



//好友在线状态改变的代理方法

-(void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence{

    //XMPPPresence 在线 离线

    

    //presence.from 消息是谁发送过来

}




这篇关于iOS即时通信之XMPP框架的使用及原理简介的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017794

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

hdu4407(容斥原理)

题意:给一串数字1,2,......n,两个操作:1、修改第k个数字,2、查询区间[l,r]中与n互质的数之和。 解题思路:咱一看,像线段树,但是如果用线段树做,那么每个区间一定要记录所有的素因子,这样会超内存。然后我就做不来了。后来看了题解,原来是用容斥原理来做的。还记得这道题目吗?求区间[1,r]中与p互质的数的个数,如果不会的话就先去做那题吧。现在这题是求区间[l,r]中与n互质的数的和

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]