本文:openfire:4.0.1,Smack:4.1.6
OpenFire与Smack下载:http://www.igniterealtime.org/index.jsp
SmackAPI:http://www.igniterealtime.org/projects/index.jsp
Smack开发指南:http://www.igniterealtime.org/builds/smack/docs/latest/documentation/
Smack源码(GitHub地址):https://github.com/igniterealtime/Smack
Smack开发指南写的很简单只描述了一些基本功能,本文记录我在开发过程中遇到的开发指南上没有的问题。
XMPP官网:http://www.xmpp.org/
Android怎么导入Smack的jar包(请参考Android部分):https://github.com/igniterealtime/Smack/wiki/Smack-4.1-Readme-and-Upgrade-Guide
这里有一个老外回答的怎么在Android上使用Smack:http://stackoverflow.com/questions/26965506/how-to-use-smack-4-1-in-android
两个对学习XMPP有帮助的博客:
1、http://blog.csdn.net/lnb333666/article/list/1
2、http://blog.csdn.net/h7870181?viewmode=contents
这两个博主都是基于ASmack开发的,我是基于Smack开发的不过有很多代码通用,很有借鉴意义。
1、登录后立马获取Roster一般是获取不到的,你可以这么做:
mRoster.addRosterLoadedListener(new RosterLoadedListener() {
@Override
public void onRosterLoaded(Roster arg0) {
getAllRoster();
}
});
监听所有Roster加载完成后进行获取。
2、添加好友:
private void addUser(String userId){
if(userId.indexOf("@你服务器的域名或IP")==-1){
userId=userId+"@你服务器的域名或IP";
}
mRoster.addRosterListener(new RosterListener(){
@Override
public void entriesAdded(Collection<String> arg0) {
}
@Override
public void entriesDeleted(Collection<String> arg0) {
}
@Override
public void entriesUpdated(Collection<String> arg0) {
}
@Override
public void presenceChanged(Presence arg0) {
}
});
try {
mRoster.createEntry(userId, userId, new String[]{"好友分组名"});
} catch (NotLoggedInException e) {
e.printStackTrace();
} catch (NoResponseException e) {
e.printStackTrace();
} catch (XMPPErrorException e) {
e.printStackTrace();
} catch (NotConnectedException e) {
e.printStackTrace();
}
}
3、监听别人对你添加好友(也可以监听别人是否响应你的添加请求,在4.1.6PacketListener和PacketTypeFilter提示以过期):
public void addSubscriptionListener() {
PacketTypeFilter packetFilter = new PacketTypeFilter(Presence.class);
PacketListener subscribeListener = new PacketListener(){
@Override
public void processPacket(Stanza stanza) throws NotConnectedException {
Looper.prepare();
final Presence presence = (Presence)stanza;
if (presence.getType().equals(Presence.Type.subscribe)) {
Toast.makeText(MainActivity.this, stanza.getFrom()+"请求添加你为好友",
Toast.LENGTH_SHORT).show();
} else if (presence.getType().equals(Presence.Type.unsubscribe)) {
Toast.makeText(MainActivity.this, stanza.getFrom()+"删除了你",
Toast.LENGTH_SHORT).show();
}
Looper.loop();
}
};
mXMPPTCPConnection.addPacketListener(subscribeListener, packetFilter);
}
4、添加好友分组:
public static boolean addGroup(Roster roster, String groupName) {
try {
roster.createGroup(groupName);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
5、获取账户所有属性信息:
/**
* 获取账户所有属性信息
* @return
*/
public Set getAccountAttributes() {
if(isConnected()) {
try {
return AccountManager.getInstance(connection).getAccountAttributes();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
throw new NullPointerException("服务器连接失败,请先连接服务器");
}
6、删除好友:
/* 删除好友*
* @param roster
* @param userName
* @return
*/
public static boolean removeUser(Roster roster, String userName) {
try {
if (userName.contains("@")) {
userName = userName.split("@")[0];
}
RosterEntry entry = roster.getEntry(userName);
System.out.println("删除好友:" + userName);
System.out.println("User." + roster.getEntry(userName) == null);
roster.removeEntry(entry);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
7、获取所有会议服务器与服务器中的群聊(获取所有群聊):
private void getChatGroups() {
try {
Collection<HostedRoom> hostrooms = multiUserChatManager.getHostedRooms("124.128.194.106");
for (HostedRoom entry : hostrooms) {
List<DiscoverItems.Item> listDiscoverItems = new ArrayList<DiscoverItems.Item>();
// 获得与XMPPConnection相关的ServiceDiscoveryManager
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager
.getInstanceFor(MainActivity.mXMPPTCPConnection);
// 获得指定XMPP实体的项目
// 这个例子获得与在线目录服务相关的项目
try {
DiscoverItems discoItems = discoManager.discoverItems(entry.getJid());
// 获得被查询的XMPP实体的要查看的项目
List<DiscoverItems.Item> listItems = discoItems.getItems();
// 显示远端XMPP实体的项目
for(DiscoverItems.Item item:listItems){
GroupInfo groupInfo=new GroupInfo();
groupInfo.setName(item.getName());
groupInfo.setService(entry.getJid());
groupInfo.setEntityId(item.getEntityID());
groupInfo.setAction(item.getAction());
groupInfo.setNode(item.getNode());
mList.add(groupInfo);
}
setListAdapter();
} catch (XMPPException e) {
e.printStackTrace();
}
}
} catch (XMPPException e) {
e.printStackTrace();
} catch (NoResponseException e1) {
e1.printStackTrace();
} catch (NotConnectedException e1) {
e1.printStackTrace();
}
}
8、加入群聊:
try {
MultiUserChat multiUserChat=multiUserChatManager
.getMultiUserChat(editText.getText().toString());
multiUserChat.join("nickname");
} catch (NoResponseException e) {
e.printStackTrace();
} catch (XMPPErrorException e) {
e.printStackTrace();
} catch (NotConnectedException e) {
e.printStackTrace();
}
9、获取离线消息:
获取好友的离线消息:
private void getOfflineMessage(){
new Thread(){
@Override
public void run() {
offlineMsgList.clear();
//使用OfflineMessageManager需要先“离线状态登录”然后获取离线消息
XMPPTCPConnectionConfiguration configuration=XMPPTCPConnectionConfiguration.builder()
.setServiceName("124.128.194.106")
.setHost("124.128.194.106")
.setPort(5222)
.setUsernameAndPassword("15606416093", "1111111a")
.setSendPresence(isPresence)
.setSecurityMode(SecurityMode.disabled)
.setConnectTimeout(15*1000)
.setCompressionEnabled(false)
.build();
mXMPPTCPConnection=new XMPPTCPConnection(configuration);
mXMPPTCPConnection.addConnectionListener(new ConnectionListener() {
@Override
public void reconnectionSuccessful() {
}
@Override
public void reconnectionFailed(Exception arg0) {
}
@Override
public void reconnectingIn(int arg0) {
}
@Override
public void connectionClosedOnError(Exception arg0) {
}
@Override
public void connectionClosed() {
}
@Override
public void connected(XMPPConnection arg0) {
try {
// mXMPPTCPConnection.setPacketReplyTimeout(30*1000);
mXMPPTCPConnection.login();
OfflineMessageManager offlineManager = new OfflineMessageManager(
MainActivity.mXMPPTCPConnection);
// offlineManager.supportsFlexibleRetrieval();
Log.i("离线消息数量: ", "" + offlineManager.getMessageCount());
List<org.jivesoftware.smack.packet.Message> messageList = offlineManager.getMessages();
for(org.jivesoftware.smack.packet.Message message:messageList){
Log.i("收到离线消息", "Received from 【" + message.getFrom()
+ "】 message: " + message.getBody());
if (message != null && message.getBody() != null
&& !message.getBody().equals("null")) {
offlineMsgList.add(message.getFrom().split("/")[0]+"###"
+message.getBody());
}
}
offlineManager.deleteMessages();// 通知服务器删除离线消息
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void authenticated(XMPPConnection arg0, boolean arg1) {
Log.d("jinru", "jinru authenticated offline message");
}
});
try {
mXMPPTCPConnection.connect();
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (XMPPException e) {
e.printStackTrace();
}
}
}.start();
}
群离线消息,貌似Smack不提供获取群离线消息需要插件。
10、监听收到的消息(无论是群还是个人,不知道为什么我使用ChatManagerListener或者ChatMessageListener都不能收到消息),我干脆监听Packet了:
PacketTypeFilter packetTypeFilter=new PacketTypeFilter(Message.class);
mXMPPTCPConnection.addPacketListener(new PacketListener() {
@Override
public void processPacket(Stanza stanza) throws NotConnectedException {
Message message=(Message)stanza;
}
}, packetTypeFilter);
11、发送群消息:
MultiUserChat multiUserChat=multiUserChatManager.getMultiUserChat(user)
Message message=multiUserChat.createMessage();
message.setBody(editText.getText().toString());
multiUserChat.sendMessage(message);
12、发送文件:
初始化:
ServiceDiscoveryManager sdManager= ServiceDiscoveryManager
.getInstanceFor(mXMPPTCPConnection);
sdManager.addFeature("http://jabber.org/protocol/disco#info");
sdManager.addFeature("jabber:iq:privacy");
fileTransferManager = FileTransferManager.getInstanceFor(MainActivity.mXMPPTCPConnection);
//监听好友发文件给你
fileTransferManager.addFileTransferListener(new FileTransferListener() {
@Override
public void fileTransferRequest(FileTransferRequest request) {
File file=new File(file_save_path);
IncomingFileTransfer incomingFileTransfer=request.accept();
try {
incomingFileTransfer.recieveFile(file);
} catch (SmackException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
发送文件:
new SendFileTask().execute("/sdcard/123456.jpg",userId);//图片路径,和文件发送给谁的user
public class SendFileTask extends AsyncTask<String, Integer, Integer>{
private final static String TAG="SendFileTask";
@Override
protected Integer doInBackground(String... params) {
if (params.length < 2) {
Log.d(TAG,"parameter invalide");
return Integer.valueOf(-1);
}
String img_path=params[0];
String toId=params[1]+"/Spark"; //resource必须要加,不加报不是一个完整的userId错误。
Log.d(TAG,"img_path:"+img_path+","+toId);
if(fileTransferManager==null)
{
Log.d(TAG, "get FileTransferManager failed");
return -1 ;
}
File filetosend= new File(img_path);
if(filetosend.exists()==false)
{
Log.d(TAG,"file:"+img_path+" is not exist");
return -1;
}
Log.d(TAG,"to user:"+toId);
OutgoingFileTransfer oft=fileTransferManager.createOutgoingFileTransfer(toId);//创建一个输出文件传输对象
try {
oft.sendFile(filetosend, "recv img");
while(!oft.isDone())
{
if (oft.getStatus().equals(FileTransfer.Status.error))
{
Log.e(TAG, "send failed");
}
else
{
Log.i(TAG, "status:" + oft.getStatus() + "|progress:" + oft.getProgress());//打印进度
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} catch (SmackException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return 0;
}
}
13、创建群聊:
private void createGroupChat(){
try {
MultiUserChat multiUserChat=multiUserChatManager
.getMultiUserChat("自定义的群ID");
multiUserChat.create("群聊的名字");
// 获得聊天室的配置表单
Form form = multiUserChat.getConfigurationForm();
// 根据原始表单创建一个要提交的新表单。
Form submitForm = form.createAnswerForm();
// 向要提交的表单添加默认答复
// for (List<FormField> fields = form.getFields(); fields.hasNext();) {
// FormField field = (FormField) fields.next();
// if (!FormField.TYPE_HIDDEN.equals(field.getType())
// && field.getVariable() != null) {
// // 设置默认值作为答复
// submitForm.setDefaultAnswer(field.getVariable());
// }
// }
for(FormField formField:form.getFields()){
if(!formField.getType().equals(Type.hidden)&&formField.getVariable()!=null){
submitForm.setDefaultAnswer(formField.getVariable());
}
}
// 设置聊天室的新拥有者
// List owners = new ArrayList();
// owners.add("liaonaibo2\\40slook.cc");
// owners.add("liaonaibo1\\40slook.cc");
// submitForm.setAnswer("muc#roomconfig_roomowners", owners);
// 设置聊天室是持久聊天室,即将要被保存下来
submitForm.setAnswer("muc#roomconfig_persistentroom", true);
// 房间仅对成员开放
submitForm.setAnswer("muc#roomconfig_membersonly", false);
// 允许占有者邀请其他人
submitForm.setAnswer("muc#roomconfig_allowinvites", true);
// 能够发现占有者真实 JID 的角色
// submitForm.setAnswer("muc#roomconfig_whois", "anyone");
// 登录房间对话
submitForm.setAnswer("muc#roomconfig_enablelogging", true);
// 仅允许注册的昵称登录
submitForm.setAnswer("x-muc#roomconfig_reservednick", true);
// 允许使用者修改昵称
submitForm.setAnswer("x-muc#roomconfig_canchangenick", false);
// 允许用户注册房间
submitForm.setAnswer("x-muc#roomconfig_registration", false);
// 发送已完成的表单(有默认值)到服务器来配置聊天室
multiUserChat.sendConfigurationForm(submitForm);
multiUserChat.join("用户加入群聊的昵称");
multiUserChat.grantOwnership("用户的ID(完整登录名)");
//邀请用户进入群聊
multiUserChat.invite("用户ID", "邀请语");
} catch (NoResponseException e) {
e.printStackTrace();
} catch (XMPPErrorException e) {
e.printStackTrace();
} catch (SmackException e) {
e.printStackTrace();
}
}
14、监听加入群聊的邀请:
multiUserChatManager.addInvitationListener(new InvitationListener() {
@Override
public void invitationReceived(XMPPConnection conn, MultiUserChat multiUserChat,
String room, String inviter, String reason,,Message message) {
}
});