Smack是一个用于和XMPP服务器通讯的类库,由此能够实现即时通信和聊天。java
XMPPConnection connection = new XMPPConnection("jabber.org"); connection.login("mtucker", "password"); connection.createChat("jsmith@jivesoftware.com").sendMessage("Howdy!");
Smack的惟一必要条件是JDK 1.2 或更高版本。smack.jar文件已包含一个XML解析器,不须要其它第三方类库。编程
XMPPConnection类用来创建到XMPP服务器的链接。要创建SSL链接,要使用SSLXMPPConnection类。服务器
下面是创建链接的例子:并发
// 创建一个到jabber.org服务器的链接。 XMPPConnection conn1 = new XMPPConnection("jabber.org"); // 经过一个特殊的端口创建一个到jabber.org服务器的链接。 XMPPConnection conn2 = new XMPPConnection("jabber.org", 5222); // 创建一个到jabber.org服务器的SSL链接。 XMPPConnection connection = new SSLXMPPConnection("jabber.org");
一旦您创建了一个链接,您必须经过方法XMPPConnection.login(String username, String password)使用用户名和密码登录
框架
若是登录成功,您能够经过建立新的Chat或GroupChat对象和其它用户聊天。 异步
Roster可以让您跟踪其它用户的有效性(存在)ide
您能够经过使用像“朋友”和“同事”这样的组来组织用户,这样您能够发现每一个用户是否在线。this
使用XMPPConnection.getRoster()这个方法获得Roster。编码
经过Roster类您能够找到全部Roster登录、他们所属的组以及每一个登录当前的存在状态。 spa
从客户端以XML格式发送到XMPP服务器的每一个消息被称为一个“packet”。
org.jivesoftware.smack.packet包中包含了一些类,这些类封装了XMPP所容许的三个不一样的基本packet类型(message, presence, 和 IQ)。
像Chat和GroupChat这样的类提供了更高类别的构造可以自动地建立和发送packet,可是您也能够直接建立和发送packet。
下面是一个经过改变您的presence来让别人知道您已无效,已经"out fishing"了:
// 建立一个新的presence. 传入false以指示咱们已经无效了 Presence presence = new Presence(Presence.Type.UNAVAILABLE); presence.setStatus("Gone fishing"); // 发送packet (假设已经有了一个名为"con"的XMPPConnection实例). con.sendPacket(presence);
Smack提供两种方法读取收到的packet:
往复地发送消息处于即时通信的核心地位。
两个类辅助发送和接收消息:
Chat和 GroupCha类都是使用 org.jivesoftware.smack.packet.Message packet类来发送消息。
在某种特定状况下,您可能不肯意使用高级的Chat和GroupChat类而直接发送和监听消息。
一个chat在两个用户之间建立一个消息线程(经过线程ID)。
下面这段代码演示了怎样和用户建立一个新的Chat并向他们发送一条文本消息:
// 假设咱们已经建立了一个名为"connection"的XMPPConnection。 Chat newChat = connection.createChat("jsmith@jivesoftware.com"); newChat.sendMessage("Howdy!");
Chat.sendMessage(String)方法能够方便地建立一个Message对象,用字符串参数设置消息正文,而后发送消息。
在必定状况下您可能但愿在发送消息前设置额外的值,使用Chat.createMessage()和 Chat.sendMessage(Message)方法,以下面代码片断所示:
// 假设咱们已经建立了一个名为"connection"的XMPPConnection。 Chat newChat = connection.createChat("jsmith@jivesoftware.com"); Message newMessage = newChat.createMessage(); newMessage.setBody("Howdy!"); message.setProperty("favoriteColor", "red"); newChat.sendMessage(newMessage);
Chat对象可以让您很容易监听其它聊天参与者的回复。
下面这段代码演示的功能相似鹦鹉学舌--它将回复对方输入的一切消息。
// 假设咱们已经建立了一个名为"connection"的XMPPConnection。 Chat newChat = connection.createChat("jsmith@jivesoftware.com"); newMessage.setBody("Hi, I'm an annoying parrot-bot! Type something back to me."); while (true) { // 等待用户发送给咱们的下一条消息。 Message message = newChat.nextMessage(); // 将对方发送过来的消息原样发送给他。 newChat.sendMessage(message.getBody()); }
以上这段代码使用了这个Chat.nextMessage() 方法获得下一条消息,它将等待不肯定什么时候到来的另外一条消息。
固然也有其它的方法用于等待特定时间段到来的新消息,或者您能够添加一个监听器,它将在每次有消息到来时通知您。
经过GroupChat链接到服务器上的聊天室,您能够在一群人中发送和接收消息。但在您发送或接收消息以前,您必须用一个昵称加入聊天室。
下面这段代码演示了链接到一个聊天室并发送一条消息:
// 假设咱们已经建立了一个名为"connection"的XMPPConnection。 GroupChat newGroupChat = connection.createGroupChat("test@jivesoftware.com"); // 用昵称"jsmith"加入这处群。 newGroupChat.join("jsmith"); // 向聊天室中的其它人发送一条消息。 newGroupChat.sendMessage("Howdy!");
一般,在群中发送和接收消息和在Chat类中很是类似。
同时还提供了用于获得聊天室中其它人的列表的方法。
Smack提供灵活的框架来经过两种构造处理收到的 packet:
packet监听器用于事件样式的编程,而packet收集器有一个能够作轮询和阻塞操做的packet的结果队列。
因此,当您想对一个有可能随时到来的packet采起一些操做时,使用packet监听器;而当您想等待一个特别的packet到来时,使用packet收集器。
您可使用XMPPConnection实例建立packet收集器和监听器。
org.jivesoftware.smack.filter.PacketFilter 接口决定哪一个特别的将会被传递到PacketCollector或PacketListener。
org.jivesoftware.smack.filter package包中有许多预约义的过滤器。
下面的代码片断演示注册了一个packet收集器和一个packet 监听器:
// 建立一个packet过滤器来监听来自一个特定用户的新的消息 //咱们可使用一个AndFilter来结合其它两个过滤器。 PacketFilter filter = new AndFilter(new PacketTypeFilter(Message.class), new FromContainsFilter("mary@jivesoftware.com")); // 假设咱们已经建立了一个名为"connection"的XMPPConnection。 // 首先,用咱们建立的过滤器注册一个packet收集器。 PacketCollector myCollector = connection.createPacketCollector(filter); // 一般,您应该用收集器来些什么,像等待新的packet。 // 接下来,建立一个packet监听器。咱们能够简便地使用匿名内部类。 PacketListener myListener = new PacketListener() { public void processPacket(Packet packet) { // 在这里用收到的packet作些什么。 } }; // 注册这个监听器。 connection.addPacketListener(myListener, filter);
Smack包括丰富的packet 过滤器集,固然您能够经过实现PacketFilter接口建立本身的过滤器。
默认的过滤器集包括:
Smack提供一个有效的机制,能够向packet附加任意属性。
每一个属性有一个String名字,这是一个java简单类型值(int, long, float, double, boolean)and a value that is a Java primitive () 或者任何序列化对象(java对象可序列化当它实现了Serializable接口)。
全部主要对象支持属性,如Message对象。
下面的代码显示如何设置属性:
Message message = chat.createMessage(); // 添加一个Color对象做为属性。 message.setProperty("favoriteColor", new Color(0, 0, 255)); // 添加一个int做为属性。 message.setProperty("favoriteNumber", 4); chat.sendMessage(message);
使用以下代码得到这些属性:
Message message = chat.nextMessage(); // 得到一个Color对象属性。 Color favoriteColor = (Color)message.getProperty("favoriteColor"); // 得到一个intg属性,注意属性做为对象返回,咱们必须把值转换为Integer,而后转换为int。 int favoriteNumber = ((Integer)message.getProperty("favoriteNumber")).intValue();
使用对象做为属性值是一个很是强大和容易的交换数据的方式。
然而,应该牢记以下:
当前用于发送属性数据XML格式还不规范,因此极可能难以被不使用Smack的客户端识别。
XML犹以下面所示(附清晰的注释):
<!--某块中的全部属性。 --> <properties xmlns="http://www.jivesoftware.com/xmlns/xmpp/properties"> <!-- 首选,一个名为"prop1"的integer型值。--> <property> <name>prop1</name> <value type="integer">123</value> <property> <!-- 其次,一个序列化的Java对象,而后从二进制数据转换到base-64编码的文本。 --> <property> <name>blah2</name> <value type="java-object">adf612fna9nab</value> <property> </properties>
前支持的类型有:integer, long, float, double, boolean, string, 和java对象。
roster能让您跟踪其它用户的有效性(存在)。您能够经过使用像“朋友”和“同事”这样的组来组织用户。
其它IM系统如朋友列表,联系列表引用roster。
一个roster实例经过XMPPConnection.getRoster()方法得到,但仅当成功登录服务器以后对可用。
在roster中每一个用户用一个RosterEntry表示,它包括:
下面的代码片断打印roster中的全部登录:
Roster roster = con.getRoster(); for (Iterator i=roster.getEntries(); i.hasNext(); ) { System.out.println(i.next()); }
也可能用方法得到单个登录,未定义登录列表,或者得到一个或全部roster组。
roster中的每一个登录有presence与之关联。
Roster.getPresence(String user)方法能够返回一个用户Presence的对象,若是用户不在线或您没有预订用户的presence将会返回null。
注意:通常而言,presence预订通常受用户是否在roster中的约束,但这并不适应全部状况。
一个用户能够有在线或离线两种presence。
当用户在线时,他们的可能包含外延信息,如他们正在作什么,他们是否愿意被打扰等等。参考Presence类以得到更多细节信息。
roster类的典型应用就是显示组的树型视图和含有当前presence值的登录。
presence信息极可能常常变化,roster登录也可能常常改变或被删除。
为了监听roster和presence数据的变化,应该使用RosterListener。
下面的代码片断注册了一个roster的RosterListener,它可以在标准输出中打印任何presence的变化。
一个标准的客户端可使用相似的代码用变化的信息来更新roster用户界面。
final Roster roster = con.getRoster(); roster.addRosterListener(new RosterListener() { public void rosterModified() { // 这个例子中忽略这个事件。 } public void presenceChanged(String user) { // 若是presence无效,将会打印"null", // 这对本例来讲很不错。 System.out.println("Presence changed: " + roster.getPresence(user)); } });
roster和presence使用一种基于许可的模式,用户只有在被许可的状况下才能被添加到别人的roster中。
这样能够保护用户的隐私由于只有经核准的其它用户才能查看他们的 presence信息。
所以,只有当其它用户接受您的请求时您才能添加新的roster登录。
若是一个用户请求presence预订,所以他们能够把您添加到他们的roster中,您必须接受或拒绝该请求。
Smack经过如下三种方式中的一种处理presence预订请求:
经过Roster.setSubscriptionMode(int subscriptionMode)方法设置对请求的处理方式。
简易客户端一般使用一种自动方式处理预订请求,而复杂客户端应该手动处理方式,请最终用户接受或拒绝请求。
若是使用手动方式,应该注册一个PacketListener以监听Presence.Type.SUBSCRIBE类型的Presence packet。
Privacy是用户阻挡其它个别用户的通讯的方法。在XMPP中它经过操做隐私列表完成。
经过下面的用例服务器端隐私列表可以成功完成:
API实现有三个主公共类:
1.正确从头开始,客户端能够得到他的/她的存储在服务器上的隐私列表:
// 为当前链接建立一个隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 从新得到服务器隐私列表。 PrivacyList[] lists = privacyManager.getPrivacyLists();
正在客户端可以显示服务器的每一个PrivacyItem和每一个列表是不是活动的,默认或没有。客户端是一个隐私变化的监听器。
2.要向服务器添加一个新列表,客户端能够像这样执行:
// 设置列表的名称 String listName = "newList"; // 建立PrivacyItem的列表,PrivacyItem将会容许或拒绝某些隐私方面。 String user = "tybalt@example.com"; String groupName = "enemies"; ArrayList privacyItems = new ArrayList(); PrivacyItem item = new PrivacyItem(PrivacyRule.JID, true, 1); item.setValue(user); privacyItems.add(item); item = new PrivacyItem(PrivacyRule.SUBSCRIPTION, true, 2); item.setValue(PrivacyRule.SUBSCRIPTION_BOTH); privacyItems.add(item); item = new PrivacyItem(PrivacyRule.GROUP, false, 3); item.setValue(groupName); item.setFilterMessage(true); privacyItems.add(item); // 得到当前链接的隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 建立新列表。 privacyManager.createPrivacyList(listName, Arrays.asList(privacyItems));
3.修改一个已存的列表,客户端代码可能像这样:
// 设置列表名称 String listName = "existingList"; //得到当前链接的隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 向服务器发送新列表。 privacyManager.updatePrivacyList(listName, items);
注意items在例2中定义而且必须包含列表中的全部元素(not the "delta")。
4.删除一个已存在的列表,客户端能够像这样执行:
// 设置列表名称 String listName = "existingList"; // 得到当前链接的隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 删除列表。 privacyManager.deletePrivacyList(listName);
5.放弃活动列表的使用,客户端能够像这样执行:
// 得到当前链接的隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 放弃活动列表的使用。 privacyManager.declineActiveList();
6.放弃默认列表的使用,客户端能够像这样执行:
// 得到当前链接的隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 放弃默认列表的使用。 privacyManager.declineDefaultList();
为了处理隐私变化,客户端应该监听管理器的更新。
当一个列表更改时管理器通知每一个已添加的监听器。
监听必须实现PrivacyListListener接口。当隐私列表被修改时客户端可能须要做出反应。
PrivacyListManager让您添加监听器,它将在列表被改变时得知通知。监听器应该实现PrivacyListListener接口
最重要的通知是updatedPrivacyList,它当隐私列表改变它的隐私项目时被执行。
当执行以下代码监听器能获得通知:
// 得到当前链接的隐私管理器。 PrivacyListManager privacyManager = PrivacyListManager.getInstanceFor(myConnection); // 为了获得通知添加监听器(this) privacyManager.addListener(this);