您的位置:首页 > 移动开发 > Android开发

在 Android 的 IM 应用中使用 asmack 库实现用户头像的传输(基于VCard协议)

2014-03-20 18:30 603 查看
转载自:/article/7289568.html

根据 XMPP 的 XEP 标准协议规范,实现 avatar 头像传输与存储的功能主要有三种实现方式,分别对应于协议规范:

+ 【XEP-0153】vCard-BasedAvatars
http://xmpp.org/extensions/xep-0153.html
+ 【XEP-0084】UserAvatar
http://xmpp.org/extensions/xep-0084.html

+ 【XEP-0008】IQ-BasedAvatars http://xmpp.org/extensions/xep-0008.html

其中

+ XEP-0153是通过将 avatar 头像存储在 vcard 的 XML 报文中实现的,这个也是 openfire 和 spark 中支持的方式;

在 openfire 中的 vcard 的实现都在 org.jivesoftware.openfire.vcard 包中,其中:

- 用户的 vcard 的存储实现在类 DefaultVCardProvider 中处理了 vcard 的查询,删除,更新,新增等 DB 操作;

- 在VCardManager 中实现对 vcard 的缓存与管理(包括新增,删除,更新,以及查询);

这种实现方式比较直接,在服务端就是将用户的 vcard(XML格式)信息一起存储在表(ofVcard)中,示例:

<vCard xmlns="vcard-temp">

<N>

<FAMILY/>

<GIVEN/>

<MIDDLE/>

</N>

<ORG>

<ORGNAME/>

<ORGUNIT/>

</ORG>

<FN/>

<URL/>

<TITLE/>

<NICKNAME/>

<PHOTO><TYPE>image/jpeg</TYPE><BINVAL>/9j/4AAQSkZJRgABAQEAYABgAAD......YlFFFM4T//2Q==</BINVAL></PHOTO>

<EMAIL>

<HOME/>

<INTERNET/>

<PREF/>

<USERID/>

</EMAIL>

<TEL><PAGER/><WORK/><NUMBER/>

</TEL>

<TEL><CELL/><WORK/><NUMBER/>

</TEL>

<TEL><VOICE/><WORK/><NUMBER/>

</TEL>

<TEL><FAX/><WORK/><NUMBER/>

</TEL>

<TEL><PAGER/><HOME/><NUMBER/>

</TEL>

<TEL><CELL/><HOME/><NUMBER/>

</TEL>

<TEL><VOICE/><HOME/><NUMBER/>

</TEL>

<TEL><FAX/><HOME/><NUMBER/>

</TEL>

<ADR><WORK/><PCODE/>

<REGION/>

<STREET/>

<CTRY/>

<LOCALITY/>

</ADR>

<ADR><HOME/><PCODE/>

<REGION/>

<STREET/>

<CTRY/>

<LOCALITY/>

</ADR>

</vCard>

+ XEP-0008的 IQ-Based Avatars 实现方式现在已不被推荐,用官方协议来说:

WARNING: Consideration of this document has been Deferred by the XMPP Standards Foundation. Implementation of the protocol described herein is not recommended

+ XEP-0084 User Avatar
是通过基于 pubsub 协议的基础上实现用户 头像 的发布(publish) 与 其他用户的订阅(subscribe);这也是 beem 的实现方式(beem 中也提供了直接通过 url 的方式下载头像);

在 User Avatar 的协议中定义了两个 pubsub 节点,分别为:

- metadata 节点:主要包括 avatar 的状态信息;

- data 节点:就是 avatar 的数据;

该协议也指出可以通过 HTTP 协议方式访问 avatar 的存储;

按照官方协议说法,该协议的实现方式可能要替代其他两种实现方式:

It is intended that this specification will supersede both IQ-Based Avatars [6]and vCard-Based Avatars [7] once the PEP subset of XMPP publish-subscribe isimplemented and deployed widely enough.

针对 user avatar 方式的实现,针对 publisher 与 subscriber 至少需要完成如下功能:

- Publishing avatar data

- Updating metadata about the current avatar

- Disabling avatars

- Discovering avatar availability

- Receiving notification of avatar changes

- Retrieving avatar data via pubsub

- Retrieving avatar data via HTTP

上面只是对实现avatar相关XEP协议做一个初步的了解,我这里的实例仍然“偷懒”采用了VCard方式实现。

协议参考: http://xmpp.org/extensions/xep-0054.html
Smack 中的 VCard API
参考: http://www.igniterealtime.org/builds/smack/docs/latest/javadoc/
1,设置用户blue的VCard中的头像avatar信息:
a)首先确认ProviderManager已经加入vcard-temp,如下代码:
ProviderManager pm = ProviderManager.getInstance();

// Private Data Storage

pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());

// Roster Exchange

pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());

// Message Events

pm.addExtensionProvider("x", "jabber:x:event", new MessageEventProvider());

// Delayed Delivery

pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());

// Version

try {

pm.addIQProvider("query", "jabber:iq:version",

Class.forName("org.jivesoftware.smackx.packet.Version"));

} catch (ClassNotFoundException e) {

// Not sure what's happening here.

}

// VCard

pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());

// Offline Message Requests

pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());

b)设置用户选择的头像(其中还附带演示了设置用户blue的其他信息,如FirstName,LastName,以及NickName),如下示例代码:
public class SetVCardTask extends AsyncTask<Uri, Integer, Long>

{

@Override

protected Long doInBackground(Uri... params)

{

if (params.length < 1) {

return Long.valueOf(-1);

}

Uri uriFile = params[0]; //
需要传输的头像文件


ByteArrayOutputStream baos = new ByteArrayOutputStream();

FileInputStream fis;

try

{

String[] proj = { MediaStore.Images.Media.DATA };

Cursor actualimagecursor = managedQuery(uriFile,proj,null,null,null);

int actual_image_column_index

= actualimagecursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);

actualimagecursor.moveToFirst();

String filePath = actualimagecursor.getString(actual_image_column_index);

fis = new FileInputStream(new File(filePath));

byte[] buf = new byte[1024];

int n;

while (-1 != (n = fis.read(buf)))

{

baos.write(buf, 0, n);

}

}

catch (Exception e)

{

e.printStackTrace();

}

byte[] bbytes = baos.toByteArray();

// 设置和更新用户信息

VCard vCard = new VCard();

vCard.setFirstName("Steven");

vCard.setLastName("Hu");

vCard.setNickName("安静的疯子");

vCard.setAvatar(bbytes);

try

{

vCard.save(MainHelloIM.getInstance().getConnection());

}

catch (XMPPException e)

{

e.printStackTrace();

}

return Long.valueOf(0);

}

}

c)最终在服务端的数据库中可以看到如下数据(其中可以看到用户昵称也都设置成功了):



d)通过spark登录成功后,可以看到头像已经更新如下:



2,查看用户blue的VCard信息
a)首先确认ProviderManager已经加入vcard-temp,同上;
b)采用异步任务来获取用户blue的VCard信息中的昵称
public class GetVCardTask extends AsyncTask<String, Integer, Long>

{

@Override

protected Long doInBackground(String... params)

{

if (params.length < 1) {

return Long.valueOf(-1);

}

// 获取用户 params[0]
的 vcard
信息


try

{

// load(Connection connection, String user)

vcard.load(MainHelloIM.getInstance().getConnection(), params[0]);
Log.d(TAG, "nickname: " + vcard.getNickName());

}

catch (XMPPException e)

{

e.printStackTrace();

return Long.valueOf(-2);

}

return Long.valueOf(0);

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐