前言
上一篇博客中我们说到如何通过XMPPFramework中的代理方法来获取到好友节点数据信息,但是我们发现节点信息能展示的只有JID,所以今天我们就说一下在XMPPFramework如何设置名片信息以及如何获取自己的和好友的名片信息.
XMPP中的电子名片简介(来自网络...)
在Extensions中有XEP-0054扩展,提供了一种可以通过XMPP发送电子名片的机制。
- vCard,也叫Versitcard,vCard的常用文件扩展名是.vcf。在XMPPFramework中通过XMPPvCardTemp和XMPPvCardCoreDataStorage两个类来实现。
- vCard是电子名片的文件格式标准,一般附加在电子邮件之后,但也可以用于其它场合,比如在因特网上相互交换。
这里我要说一下在XMPPFramework中电子名片的几个相关的类.其中,XMPPv CardTempModule这个类使用做电子名片的读取和存储,XMPPvCardCoreDataStorage用来做电子名片的本地存储,XMPPvCardAvatarModule是用来做头像的存储和读取的,XMPPvCardTemp则是电子名片.
这里我要说一下关于XMPPvCardTemp相关的属性,XMPPvCardTemp是电子名片类.用户的电子名片就是XMPPvCardTemp对象.这里我就把几个常用的属性列举出来.当然了,我们可以自己对其中一些属性进行存储修改,我们只要知道我们在哪一个属性存储了什么数据即可,比如我们让nickname(标准化姓名)存储一个地址字符串,然后取出来nickname的时候,我们知道是nickname存储的是什么即可.灵活运用XMPPvCardTemp的各种属性.
//头像图片属性
@property (nonatomic, strong) NSData *photo;
//标准化名称
@property (nonatomic, strong) NSString *nickname;
//地址数组
@property (nonatomic, strong) NSArray *addresses;
//公司名称
@property (nonatomic, strong) NSString *orgName;
//部门数组
@property (nonatomic, strong) NSArray *orgUnits;
//职位
@property (nonatomic, strong) NSString *title;
//邮件地址数组
@property (nonatomic, strong) NSArray *emailAddresses;
//备注
@property (nonatomic, strong) NSString *note;
</br>
XMPPFramework中电子名片相关的方法说明
下面是XMPPFramework中与电子名片相关的方法(下述的所有方法都在在X MPPvCardTempModule类中).
注意:❗️❗️❗️最后一个是代理方法,我们调用前两个方法在获取到电子名片数据之后,会调起最后的那个代理方法.
//到服务器上请求联系人名片信息
- (void)fetchvCardTempForJID:(XMPPJID *)jid;
//请求联系人的名片,如果数据库有就不请求,没有就发送名片请求
- (void)fetchvCardTempForJID:(XMPPJID *)jid ignoreStorage:(BOOL)ignoreStorage;
//获取联系人的名片,如果数据库有就返回,没有返回空,并到服务器上抓取
- (XMPPvCardTemp *)vCardTempForJID:(XMPPJID *)jid shouldFetch:(BOOL)shouldFetch;
//更新自己的名片信息
- (void)updateMyvCardTemp:(XMPPvCardTemp *)vCardTemp;
//获取到联系人的名片信息的回调
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp forJID:(XMPPJID *)jid
电子名片的业务流程
上面我们对电子名片进行了简单的介绍,那么接下来我们就SDChat这个Demo中的电子名片的获取以及设置来进行业务流程说明.流程分为三大部分.(PS:高清图片过大,请下载再进行查看.)
不管是做什么,我们都需要先在SDXmppManager激活对应的模块.在SDXmppManager我们要声明三个属性,分别是电子名片本地存储类属性XMPPvCardCoreDataStorage电子名片读取存储属性XMPPvCardTempModule 以及电子名片的头像模块XMPPvCardAvatarModule.
@property(nonatomic,strong)XMPPvCardTempModule *vCardTempModule;
@property(nonatomic,strong)XMPPvCardCoreDataStorage *vCardCoreDataStorage;
@property(nonatomic,strong)XMPPvCardAvatarModule *vCardAvatarModule
然后在SDXmppManager的初始化过程中对三个属性对象进行初始化并且激活电子名片模块以及头像模块.
self.vCardCoreDataStorage = [XMPPvCardCoreDataStorage sharedInstance];
self.vCardTempModule = [[XMPPvCardTempModule alloc]initWithvCardStorage:self.vCardCoreDataStorage];
[self.vCardTempModule activate:self.stream];
[self.vCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
self.vCardAvatarModule = [[XMPPvCardAvatarModule alloc]initWithvCardTempModule:self.vCardTempModule];
[self.vCardAvatarModule activate:self.stream];
[self.vCardAvatarModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
用户注册过程中的电子名片设置
用户在注册过程中就可能需要设置电子名片,我们在SDXmppManager单例的初始化过程中完成电子名片模块激活之后,在SDRegisterVC这个类中,我们注册完成之后,在注册成功之后,我们在注册成功的代理方法(-(void)xmppStreamDidRegister:(XMPPStream *)sender
)中登录注册的账号密码(我觉得应该可以直接上传的,但是我怕出现问题,就让登录之后在上传电子名片数据,大家可以自行测试).代码如下所示.
-(void)xmppStreamDidRegister:(XMPPStream *)sender{
[[SDXmppManager defaulManager] loginWithUserName:self.loginName.text AndPassWord:self.passWord.text];
}
当登录成功之后,我们在登录成功的代理方法(- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
)中新建一个XMPPvCardTemp对象并上传工作,代码如下所示.
XMPPvCardTemp *myCard = [XMPPvCardTemp vCardTemp];
myCard.nickname = self.userName.text;
[[SDXmppManager defaulManager].vCardTempModule updateMyvCardTemp:myCard];
同时弹出头像设置页面跳转的弹窗.
UIAlertController *alertView = [UIAlertController alertControllerWithTitle:@"设置头像" message:@"设置属于自己的头像" preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self)temp = self;
UIAlertAction *action = [UIAlertAction actionWithTitle:@"好的,没问题" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[temp.navigationController pushViewController:[SDRegisterHeaderVC new] animated:YES];
}];
[alertView addAction:action];
[self presentViewController:alertView animated:YES completion:nil];
进入头像设置页面之后,我们可以默认给用户一张图片,当用户不进行设置的时候,默认上传的头像图片就是默认图片,这里我就随意找了一张图片,然后我们给UIImageView对象添加一个轻点手势.让用户点击图片的时候可以切换图像.
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(clickHeaderView)];
[self.headerView addGestureRecognizer:tap];
self.headerView.userInteractionEnabled = YES;
我们在点击事件中添加打开系统的图库以及系统的相机的方法并且添加代理方法,如果不知道如何打开系统相机或者相册,可以查看华山论剑之浅谈iOS调用大乱斗(电话,短信,浏览器,相机,相册).那么我们就可以通过代理方法来获取到我们的图片,代理方法如下所示.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
在代理方法中,我们需要注意一个问题,如果我们依照华山论剑之浅谈iOS调用大乱斗(电话,短信,浏览器,相机,相册)来获取图片的话可能获取图片是变形的,我们需要把从info字典中获取图片的key值UIImagePickerControllerOriginalImage
换成UIImagePickerControllerEditedImage
;
UIImage* image = [info objectForKey:@"UIImagePickerControllerEditedImage"];
我们把图片保存在SDRegisterHeaderVC的属性对象headerImg当中,然后在用户点击"完成"时候,我们就会调用SDXmppManager获取到当前登录账号的d电子名片对象.
XMPPvCardTemp *vCard = [SDXmppManager defaulManager].vCardTempModule.myvCardTemp;
然后我们把进行压缩,修改图片的尺寸,(注意:❗️❗️❗️图片过大的时候,可能会出现图片上传失败的情况,所以我们把它进行图片的修改),这里我提供了一个图片修改的方法并且用它对我们的头像图片进行了尺寸修改.
- (UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize{
UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height));
[image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)];
UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return reSizeImage;
}
UIImage *headerimage = [self reSizeImage:self.headerImg toSize:CGSizeMake(100, 100)];
修改完图片的尺寸之后,我们就对头像图片进行二级制文件的文件转换(这里只拿PNG格式图片作说明,具体还有JPEG格式的,请查看Demo源码),然后把头像文件更新到Openfire服务器中.代码如下所示.
data = UIImagePNGRepresentation(headerimage);
vCard.photo = data;
[[SDXmppManager defaulManager].vCardTempModule updateMyvCardTemp:vCard];
最后,我们关闭与服务器之间的连接,跳转到登录界面.
[self dismissViewControllerAnimated:YES completion:nil];
[[SDXmppManager defaulManager] disconnectWithServer];
用户登录之后电子名片的获取(过程在SDContactsVC中实现)
上面我们说到如何在用户的注册过程中对用户的电子名片进行设置,那么我们在登录完成之后如何获取用户的头像,名称以及好友的用户头像,名称呢?我们先用代理方法来实现获取电子名片的方法.
首先,我们需要在联系人界面初始化方法中添加电子名片的相关代理.如下所示.
[[SDXmppManager defaulManager].vCardAvatarModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
[[SDXmppManager defaulManager].vCardTempModule addDelegate:self delegateQueue:dispatch_get_main_queue()];
紧接着,我们在获取每一个好友节点的代理方法中获取到好友节点所对应的JID信息,然后我们使用SDXmppManager中的vCardTempModule调起- (void)fetchvCardTempForJID:(XMPPJID *)jid ignoreStorage:(BOOL)ignoreStorage
方法就可以调起代理方法来.代码如下所示.
[[SDXmppManager defaulManager].vCardTempModule fetchvCardTempForJID:jid ignoreStorage:YES];
然后,我们通过下述代理方法的回调,我们可以获取到JID以及对应的电子名片信息.
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule
didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp
forJID:(XMPPJID *)jid
不过,这里不但能获取到好友的数据,而且登录者的电子名片也可以通过这个代理方法进行获取,所以我们要判断区分.如果是登录者的JID,那么我们把获取到电子信息名片存储到SDUser这个单例当中方便其他位置获取,如果是好友的JID,那么我们就遍历我们的好友节点数组,然后通过比对JID信息,把对应的电子名片添加到Model中去,然后刷新当前的好友列表页面 .整体的代码如下所示.
if ([jid.user isEqual:[SDUser defaulUser].jid.user]) {
[SDUser defaulUser].vCard = vCardTemp;
[self.userInformationView reloadAllData];
}else{
for (NSString * key in self.contactsPinyinDic) {
NSMutableArray *array = [NSMutableArray arrayWithArray:self.contactsPinyinDic[key]];
for (SDContactModel *model in array) {
if ([model.jid isEqual:jid]) {
model.vCard =vCardTemp;
}
}
}
//刷新页面
[self networkingWithContactsArray];
}
上述的是通过代理方法来实现好友以及登陆者本身的电子名片获取.下面我们看一下如何通过XMPPvCardTempModule这个类来进行电子名片的获取.
首先,我们还是在获取每一个好友节点的代理方法中获取到好友节点所对应的JID信息,然后我们使用SDXmppManager中的vCardTempModule调起- (XMPPvCardTemp *)vCardTempForJID:(XMPPJID *)jid shouldFetch:(BOOL)shouldFetch;
这个方法来.直接获取到好友本身的电子名片信息,代码如下所示/
XMPPvCardTemp *vCard = [[SDXmppManager defaulManager].vCardTempModule vCardTempForJID:jid shouldFetch:YES];
那么,我们如何直接获取登陆者本身的电子名片数据呢?我们直接使用SDXmppManager就可以直接获取到登陆者本身电子名片本身.
XMPPvCardTemp *myCard = [SDXmppManager defaulManager].vCardTempModule.myvCardTemp;
NSString *userName = [NSString stringWithFormat:@" 昵称: %@",myCard.nickname];
NSData *imgData = myCard.photo;
骚栋前期也是直接获取电子名片数据的,不过这样直接获取电子名片数据是有一定弊端的,那就是获取服务器中电子名片数据是有一定时间的,如果在页面刷新之前还没有获取到数据的话,那么在页面上数据像是就为空了,所以建议使用代理回调方法来进行好友数据的获取.(SDChat中两种方法都是有所保留的.)
登录之后设置电子名片流程
用户在登录之后,跟注册过程类似,也是可以设置对应的电子名片数据的.首先我们获取到登录者的电子名片,如下所示.
XMPPvCardTemp *myCard = [SDXmppManager defaulManager].vCardTempModule.myvCardTemp;
然后,我们修改电子名片中的属性.这里拿名称来举例说明.
myCard.nickname = textField.text;
最后,我们上传到服务器上进行更新.
[[SDXmppManager defaulManager].vCardTempModule updateMyvCardTemp:myCard];
不过这里需要注意的是代理方法的回调问题,我们如何知道我们的好友已经进行了头像的更改或者说是电子名片的修改呢?这就需要实现两个代理方法,一个是我们上面说到获取到好友节点的电子名片回调方法,另外一个就是获得好友节点的头像更改的代理回调方法,两个方法如下所示.(前提,我们先要在初始化过程中设置代理)
//获取到好友节点的电子名片回调方法
- (void)xmppvCardTempModule:(XMPPvCardTempModule *)vCardTempModule
didReceivevCardTemp:(XMPPvCardTemp *)vCardTemp
forJID:(XMPPJID *)jid
//获得好友节点的头像更改的代理回调方法
- (void)xmppvCardAvatarModule:(XMPPvCardAvatarModule *)vCardTempModule
didReceivePhoto:(UIImage *)photo
forJID:(XMPPJID *)jid
在方法中,我们需要区别处理,我们当获取到登录者本身的电子名片的修改该怎么办,我们收到联系人中电子名片又该如何操作,需要我们根据实际情况来进行处理.
好了上述就是电子名片的相关这是获取和设置,当我们完成之后,我们就可以等到下面的界面了,相比于只展示JID确实是美观了许多呢~~
结束
上面基本就是XMPPFramework中电子名片的相关技术点了,如果任何童鞋有疑问,欢迎提出,骚栋非常欢迎各位童鞋前来交流.下一篇我准备写写XMPPFramework中逻辑最多的好友添加和删除模块,希望大家持续关注骚栋,谢谢.最后把SDChat的传送门送给大家.大家可以对照着Demo来看本篇博客.