转载自:https://blog.csdn.net/w690333243/article/details/81701548
我目前使用的时Smack 4.4.6版本,根据API变更,进行一定的修改和内容添加,
1、 添加自动重连
2、添加离线信息获取
当前整体工具提供的功能接口如下:
- 连接(自动重连,连接状态监听)
- 注册账户
- 修改密码
- 删除账户
- 获取账户信息
- 获取所有群组
- 添加群组
- 获取指定群组的好友信息
- 获取全部好友信息
- 获取指定好友VCard信息
- 添加好友(无分组、分组)
- 删除好友
- 创建发布订阅节点
- 删除发布订阅节点
- 发布信息
- 订阅主题
- 获取订阅的全部主题
- 获取订阅主题的配置信息
- 获取订阅主题的全部历史信息
- 获取指定主题的全部历史信息
- 向指定用户发送信息
- 获取离线消息(删除记录)
- 添加聊天信息监听(接收、发出)
- 添加文件传输监听
- 创建群聊房间
- 加入群聊房间
- 发送群聊消息
- 添加群聊消息监听
- 退出登录
- 断开连接
带码如下:
import android.util.Log;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.PresenceBuilder;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smackx.filetransfer.FileTransferListener;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.offline.OfflineMessageManager;
import org.jivesoftware.smackx.pubsub.PayloadItem;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.roster.RosterEntry;
import org.jivesoftware.smack.roster.RosterGroup;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smackx.iqregister.AccountManager;
import org.jivesoftware.smackx.pubsub.AccessModel;
import org.jivesoftware.smackx.pubsub.Item;
import org.jivesoftware.smackx.pubsub.LeafNode;
import org.jivesoftware.smackx.pubsub.PubSubManager;
import org.jivesoftware.smackx.pubsub.PublishModel;
import org.jivesoftware.smackx.pubsub.SimplePayload;
import org.jivesoftware.smackx.pubsub.Subscription;
import org.jivesoftware.smackx.pubsub.form.ConfigureForm;
import org.jivesoftware.smackx.pubsub.form.FillableConfigureForm;
import org.jivesoftware.smackx.pubsub.form.FillableSubscribeForm;
import org.jivesoftware.smackx.pubsub.form.SubscribeForm;
import org.jivesoftware.smackx.receipts.DeliveryReceiptManager;
import org.jivesoftware.smackx.receipts.ReceiptReceivedListener;
import org.jivesoftware.smackx.vcardtemp.VCardManager;
import org.jivesoftware.smackx.vcardtemp.packet.VCard;
import org.jivesoftware.smackx.xdata.packet.DataForm;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.Jid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.Localpart;
public class SmackUtil {
private static final String TAG = "smack_util";
private static final int DEFAULT_SERVER_PORT = 5222;
private XMPPTCPConnection connection;
private String userName;
private String serverName;
public SmackUtil(String userName,
String password,
String xmppDomain,
String serverName,
String serverIp,
ConnectionListener connectionListener) {
this.userName = userName;
this.serverName = serverName;
try {
if (connection == null) {
getConnection(userName, password, xmppDomain, serverName, serverIp, connectionListener);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接
*
* @param userName 用户名
* @param password 登录密码
*/
public void getConnection(String userName,
String password,
String xmppDomain,
String serverName,
String serverIp,
ConnectionListener connectionListener ){
try {
XMPPTCPConnectionConfiguration.Builder configBuilder = XMPPTCPConnectionConfiguration.builder();
configBuilder.setUsernameAndPassword(userName, password);
configBuilder.setXmppDomain(xmppDomain);
configBuilder.setHostAddress(InetAddress.getByName(serverIp));
configBuilder.setPort(DEFAULT_SERVER_PORT);
configBuilder.setResource(serverName);
configBuilder.setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.disabled);
connection = new XMPPTCPConnection(configBuilder.build());
if (connectionListener != null) {
connection.addConnectionListener(connectionListener);
}
// 连接服务器
connection.connect();
// 登录服务器
connection.login();
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
ReconnectionManager.setEnabledPerDefault(false);
reconnectionManager.enableAutomaticReconnection();
DeliveryReceiptManager dm = DeliveryReceiptManager.getInstanceFor(connection);
dm.setAutoReceiptMode(DeliveryReceiptManager.AutoReceiptMode.always);
dm.addReceiptReceivedListener(new ReceiptReceivedListener() {
@Override
public void onReceiptReceived(Jid fromJid, Jid toJid, String receiptId, Stanza receipt) {
Log.i(TAG, "onReceiptReceived ; fromJid = " + fromJid.toString() + " ; receiptId = " + receiptId + " ; receipt = " + receipt.toString());
}
});
} catch (Exception e) {
Log.e(TAG, "connect err = " + e.getMessage());
e.printStackTrace();
}
}
/**
* 创建一个新用户
*
* @param userName
* 用户名
* @param password
* 密码
* @param attr
* 用户资料
* @return 注册结果
* @throws Exception 创建用户是异常信息
*/
public boolean registerAccount(String userName,
String password,
Map<String, String> attr) throws Exception {
AccountManager manager = AccountManager.getInstance(connection);
manager.sensitiveOperationOverInsecureConnection(true);
Localpart l_username = Localpart.from(userName);
if (attr == null) {
manager.createAccount(l_username, password);
} else {
manager.createAccount(l_username, password, attr);
}
return true;
}
/**
* 修改当前登陆用户密码
*
* @param password 新密码
* @return 返回修改结果
* @throws Exception 修改密码时异常信息
*/
public boolean changePassword(String password) throws Exception {
AccountManager manager = AccountManager.getInstance(connection);
manager.sensitiveOperationOverInsecureConnection(true);
manager.changePassword(password);
return true;
}
/**
* 删除当前登录用户
*
* @return 删除当前登录用户的结果
* @throws Exception 删除时的异常信息
*/
public boolean deleteAccount() throws Exception {
AccountManager manager = AccountManager.getInstance(connection);
manager.sensitiveOperationOverInsecureConnection(true);
manager.deleteAccount();
return true;
}
/**
* 获取用户属性名称
*
* @return 获取当前登录用户的信息
* @throws Exception 异常
*/
public List<String> getAccountInfo() throws Exception {
AccountManager manager = AccountManager.getInstance(connection);
manager.sensitiveOperationOverInsecureConnection(true);
Set<String> set = manager.getAccountAttributes();
return new ArrayList<>(set);
}
/**
* 获取离线信息记录
* @return 离线信息结果
* @throws Exception 查询时异常信息
*/
public List<Message> getOfflineMessage () throws Exception{
OfflineMessageManager offlineMessageManager = OfflineMessageManager.getInstanceFor(connection);
// 获取离线信息
List<Message> list = offlineMessageManager.getMessages();
// 删除离线信息记录
offlineMessageManager.deleteMessages();
return list;
}
/**
* 获取所有组
*
* @return 群组查询结果
*/
public List<RosterGroup> getGroups() {
Roster roster = Roster.getInstanceFor(connection);
Collection<RosterGroup> rosterGroup = roster.getGroups();
return new ArrayList<>(rosterGroup);
}
/**
* 添加分组
*
* @param groupName 分组名称
* @return 分组结果
*/
public boolean addGroup(String groupName) {
Roster roster = Roster.getInstanceFor(connection);
roster.createGroup(groupName);
return true;
}
/**
* 获取指定分组的好友
*
* @param groupName 群组名称
* @return 群组好友信息
*/
public List<RosterEntry> getEntriesByGroup(String groupName){
Roster roster = Roster.getInstanceFor(connection);
RosterGroup rosterGroup = roster.getGroup(groupName);
Collection<RosterEntry> rosterEntry = rosterGroup.getEntries();
return new ArrayList<>(rosterEntry);
}
/**
* 获取全部好友
*
* @return 获取全部好友信息
*/
public List<RosterEntry> getAllEntries() {
Roster roster = Roster.getInstanceFor(connection);
Collection<RosterEntry> rosterEntry = roster.getEntries();
return new ArrayList<>(rosterEntry);
}
/**
* 获取用户VCard信息
*
* @param userName 用户名称
* @return 返回用户VCard信息
* @throws Exception 异常
*/
public VCard getUserVCard(String userName) throws Exception {
EntityBareJid jid = JidCreate.entityBareFrom(userName + "@" + this.serverName);
return VCardManager.getInstanceFor(connection).loadVCard(jid);
}
/**
* 添加好友 无分组
*
* @param userName 用户账号
* @param name 用户名称
* @return 添加结果
* @throws Exception 异常信息
*/
public boolean addUser(String userName, String name) throws Exception {
Roster roster = Roster.getInstanceFor(connection);
EntityBareJid jid = JidCreate.entityBareFrom(userName + "@" + this.serverName);
roster.createItemAndRequestSubscription(jid, name , null);
return true;
}
/**
* 添加好友 有分组
*
* @param userName 用户账号
* @param name 用户名称
* @param groupName 分组名称
* @return 添加结果
* @throws Exception 异常信息
*/
public boolean addUser(String userName, String name, String groupName) throws Exception {
Roster roster = Roster.getInstanceFor(connection);
EntityBareJid jid = JidCreate.entityBareFrom(userName + "@" + this.serverName);
roster.createItemAndRequestSubscription(jid, name , new String[] { groupName });
return true;
}
/**
* 删除好友
*
* @param userName 用户账号
* @return 删除结果
* @throws Exception 异常信息
*/
public boolean removeUser(String userName) throws Exception {
Roster roster = Roster.getInstanceFor(connection);
EntityBareJid jid = JidCreate.entityBareFrom(userName + "@" + this.serverName);
RosterEntry entry = roster.getEntry(jid);
roster.removeEntry(entry);
return true;
}
/**
* 创建发布订阅节点
*
* @param nodeId 节点ID
* @return 创建结果
* @throws Exception 异常信息
*/
public boolean createPubSubNode(String nodeId) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
// Create the node
LeafNode leaf = mgr.createNode(nodeId);
FillableConfigureForm form = new ConfigureForm(DataForm.builder(DataForm.Type.submit).build()).getFillableForm();
form.setAccessModel(AccessModel.open);
form.setDeliverPayloads(true);
form.setNotifyRetract(true);
form.setPersistentItems(true);
form.setPublishModel(PublishModel.open);
form.setMaxItems(10000000);// 设置最大的持久化消息数量
leaf.sendConfigurationForm(form);
return true;
}
/**
* 创建发布订阅节点
*
* @param nodeId 节点ID
* @param title 标题
* @return 创建结果
* @throws Exception 异常信息
*/
public boolean createPubSubNode(String nodeId, String title) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
// Create the node
LeafNode leaf = mgr.createNode(nodeId);
FillableConfigureForm form = new ConfigureForm(DataForm.builder(DataForm.Type.submit).build()).getFillableForm();
form.setAccessModel(AccessModel.open);
form.setDeliverPayloads(true);
form.setNotifyRetract(true);
form.setPersistentItems(true);
form.setPublishModel(PublishModel.open);
form.setTitle(title);
form.setBodyXSLT(nodeId);
form.setMaxItems(10000000);// 设置最大的持久化消息数量
form.setMaxPayloadSize(1024*12);//最大的有效载荷字节大小
leaf.sendConfigurationForm(form);
return true;
}
/**
* 删除发布订阅节点
* @param nodeId 节点ID
* @return 删除结果
* @throws Exception 异常信息
*/
public boolean deletePubSubNode(String nodeId) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
mgr.deleteNode(nodeId);
return true;
}
/**
* 发布消息
*
* @param nodeId 主题ID
* @param eventId 事件ID
* @param messageType 消息类型:publish(发布)/receipt(回执)/state(状态)
* @param messageLevel 0/1/2
* @param messageSource 消息来源
* @param messageCount 消息数量
* @param packageCount 总包数
* @param packageNumber 当前包数
* @param createTime 创建时间 2018-06-07 09:43:06
* @param messageContent 消息内容
* @return 发布结果
* @throws Exception 异常信息
*/
public boolean publish(String nodeId,
String eventId,
String messageType,
int messageLevel,
String messageSource,
int messageCount,
int packageCount,
int packageNumber,
String createTime,
String messageContent) throws Exception {
if (messageContent.length() > 1024 * 10) {
throw new Exception("消息内容长度超出1024*10,需要进行分包发布");
}
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
LeafNode node = (LeafNode) mgr.getNode(nodeId);
String xml = "<pubmessage xmlns='pub:message'>" +
"<nodeId>" + nodeId + "</nodeId>" +
"<eventId>" + eventId + "</eventId>" +
"<messageType>" + messageType + "</messageType>" +
"<messageLevel>" + messageLevel + "</messageLevel>" +
"<messageSource>" + messageSource + "</messageSource>" +
"<messageCount>" + messageCount + "</messageCount>" +
"<packageCount>" + packageCount + "</packageCount>" +
"<packageNumber>" + packageNumber + "</packageNumber>" +
"<createTime>" + createTime + "</createTime>" +
"<messageContent>" + messageContent + "</messageContent>" +
"</pubmessage>";
// SimplePayload payload = new SimplePayload("pubmessage", "pub:message", xml.toLowerCase());
SimplePayload payload = new SimplePayload("pubmessage");
PayloadItem<SimplePayload> item = new PayloadItem<SimplePayload>(System.currentTimeMillis() + "", payload);
node.publish(item);
return true;
}
/**
* 订阅主题
*
* @param nodeId 主题ID
* @return 订阅结果
* @throws Exception 异常信息
*/
public boolean subscribe(String nodeId) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
// Get the node
LeafNode node = (LeafNode) mgr.getNode(nodeId);
FillableSubscribeForm subscriptionForm = new SubscribeForm(DataForm.builder(DataForm.Type.submit).build()).getFillableForm();
subscriptionForm.setDeliverOn(true);
subscriptionForm.setDigestFrequency(5000);
subscriptionForm.setDigestOn(true);
subscriptionForm.setIncludeBody(true);
List<Subscription> subscriptions = node.getSubscriptions();
boolean flag = true;
for (Subscription s : subscriptions) {
if (s.getJid().toString().toLowerCase().equals(connection.getUser().asEntityBareJidString().toLowerCase())) {// 已订阅过
flag = false;
break;
}
}
if (flag) {// 未订阅,开始订阅
node.subscribe(JidCreate.bareFrom(userName + "@" + this.serverName), subscriptionForm);
// node.subscribe(userName + "@" + this.serverName, subscriptionForm);
}
return true;
}
/**
* 获取订阅的全部主题
*
* @return 查询结果
* @throws Exception 查询异常信息
*/
public List<Subscription> querySubscriptions() throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
return mgr.getSubscriptions();
}
/**
* 获取订阅节点的配置信息
*
* @param nodeId 主题ID
* @return 查询配置结果信息
* @throws Exception 异常信息
*/
public ConfigureForm getConfig(String nodeId) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
LeafNode node = (LeafNode) mgr.getNode(nodeId);
return node.getNodeConfiguration();
}
/**
* 获取订阅主题的全部历史消息
*
* @return 查询结果
* @throws Exception 异常信息
*/
public List<Item> queryHistoryMessage() throws Exception {
List<Item> result = new ArrayList<>();
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
List<Subscription> subs = mgr.getSubscriptions();
if (subs != null && subs.size() > 0) {
for (Subscription sub : subs) {
String nodeId = sub.getNode();
LeafNode node = (LeafNode) mgr.getNode(nodeId);
List<Item> list = node.getItems();
result.addAll(list);
}
}
return result;
}
/**
* 获取指定主题的全部历史消息
*
* @return 查询结果信息
* @throws Exception 异常信息
*/
public List<Item> queryHistoryMessage(String nodeId) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
LeafNode node = (LeafNode) mgr.getNode(nodeId);
List<Item> list = node.getItems();
return new ArrayList<>(list);
}
/**
* 获取指定主题指定数量的历史消息
*
* @param nodeId 主题ID
* @param num 数量
* @return 返回结果
* @throws Exception 异常信息
*/
public List<Item> queryHistoryMessage(String nodeId, int num) throws Exception {
PubSubManager mgr = PubSubManager.getInstanceFor(connection);
LeafNode node = (LeafNode) mgr.getNode(nodeId);
List<Item> list = node.getItems(num);
return new ArrayList<>(list);
}
/**
* 向指定用户发送消息
*
* @param username 用户账号
* @param message 信息内容
* @throws Exception 异常信息
*/
public void sendMessage(String username, String message) throws Exception {
ChatManager chatManager = ChatManager.getInstanceFor(connection);
EntityBareJid jid = JidCreate.entityBareFrom(username + "@" + serverName);
Chat chat = chatManager.chatWith(jid);
Message newMessage = new Message();
newMessage.setBody(message);
chat.send(newMessage);
}
/**
* 添加聊天消息监听
*
* @param incomingListener 接收信息监听器
* @param outgoingListener 发送信息监听器
*/
public void addChatMessageListener(IncomingChatMessageListener incomingListener,
OutgoingChatMessageListener outgoingListener) {
ChatManager chatManager = ChatManager.getInstanceFor(connection);
chatManager.addIncomingListener(incomingListener);
chatManager.addOutgoingListener(outgoingListener);
}
/**
* 添加Stanza 监听器
* @param stanzaListener 监听器
* @param stanzaFilter 过滤器
*/
public void addAsyncStanzaListener (StanzaListener stanzaListener, StanzaFilter stanzaFilter) {
connection.addAsyncStanzaListener(stanzaListener, stanzaFilter);
}
/**
* 添加文件传输监听器
* @param transferListener 监听器
*/
public void addFileTransferListener(FileTransferListener transferListener) {
FileTransferManager fileTransferManager = FileTransferManager.getInstanceFor(connection);
fileTransferManager.addFileTransferListener(transferListener);
}
/**
* 创建群聊聊天室
*
* @param roomName 聊天室名字
* @param nickName 创建者在聊天室中的昵称
* @param password 聊天室密码
* @return 群聊房间
*/
public MultiUserChat createChatRoom(String roomName, String nickName, String password) throws Exception {
MultiUserChat muc;
try {
EntityBareJid jid = JidCreate.entityBareFrom(roomName + "@conference." + serverName);
// 创建一个MultiUserChat
muc = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(jid);
Resourcepart r = Resourcepart.from(nickName);
// 创建聊天室
MultiUserChat.MucCreateConfigFormHandle isCreated = muc.createOrJoin(r);
Log.i(TAG, "muc create result = " + (isCreated != null));
// 获得聊天室的配置表单
Form form = muc.getConfigurationForm();
FillableForm answerForm = form.getFillableForm();
answerForm.setAnswer("muc#roomconfig_moderatedroom", "1");
// 设置聊天室的新拥有者
List<String> owners = new ArrayList<>();
owners.add(connection.getUser().asEntityBareJidString());// 用户JID
answerForm.setAnswer("muc#roomconfig_roomowners", owners);
// 设置聊天室是持久聊天室,即将要被保存下来
answerForm.setAnswer("muc#roomconfig_persistentroom", true);
// 房间仅对成员开放
answerForm.setAnswer("muc#roomconfig_membersonly", false);
// 允许占有者邀请其他人
answerForm.setAnswer("muc#roomconfig_allowinvites", true);
if (password != null && password.length() != 0) {
// 进入是否需要密码
answerForm.setAnswer("muc#roomconfig_passwordprotectedroom", true);
// 设置进入密码
answerForm.setAnswer("muc#roomconfig_roomsecret", password);
}
// 能够发现占有者真实 JID 的角色
// answerForm.setAnswer("muc#roomconfig_whois", "anyone");
// 登录房间对话
answerForm.setAnswer("muc#roomconfig_enablelogging", true);
// 仅允许注册的昵称登录
answerForm.setAnswer("x-muc#roomconfig_reservednick", true);
// 允许使用者修改昵称
answerForm.setAnswer("x-muc#roomconfig_canchangenick", false);
// 允许用户注册房间
answerForm.setAnswer("x-muc#roomconfig_registration", false);
// 发送已完成的表单(有默认值)到服务器来配置聊天室
muc.sendConfigurationForm(answerForm);
} catch (XMPPException e) {
e.printStackTrace();
return null;
}
return muc;
}
/**
* 加入聊天室
*
* @param roomName 房间名称
* @param nickname 昵称
* @param password 密码
* @throws Exception 异常
*/
public MultiUserChat joinMultiUserChat(String roomName, String nickname, String password) throws Exception {
EntityBareJid jid = JidCreate.entityBareFrom(roomName + "@conference." + serverName);
// 创建一个MultiUserChat
MultiUserChat muc = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(jid);
// 聊天室服务将会决定要接受的历史记录数量
Resourcepart r = Resourcepart.from(nickname);
muc.join(r);
return muc;
}
/**
* 聊天室发送消息
*
* @param roomName 房间名称
* @param msg 信息内容
* @throws Exception 发送异常
*/
public void sendMessageMultiUserChat(String roomName, String msg) throws Exception {
EntityBareJid jid = JidCreate.entityBareFrom(roomName + "@conference." + serverName);
// 创建一个MultiUserChat
MultiUserChat muc = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(jid);
muc.sendMessage(msg);
}
/**
* 获取MultiUserChat
*
* @param roomName 房间名称
* @return 群聊房间
* @throws Exception 异常信息
*/
public MultiUserChat getMultiUserChat(String roomName) throws Exception {
EntityBareJid jid = JidCreate.entityBareFrom(roomName + "@conference." + serverName);
// 创建一个MultiUserChat
MultiUserChat muc = MultiUserChatManager.getInstanceFor(connection).getMultiUserChat(jid);
return muc;
}
/**
* 添加聊天室消息监听
*
* @param roomName 房间名称
* @param messageListener 消息监听器
* @throws Exception 异常信息
*/
public void addMultiUserChatMessageListener(String roomName, MessageListener messageListener) throws Exception {
MultiUserChat muc = getMultiUserChat(roomName);
muc.addMessageListener(messageListener);
}
/**
* 退出登录
* @throws Exception 异常信息
*/
public void logout() throws Exception {
connection.sendStanza(PresenceBuilder.buildPresence().ofType(Presence.Type.unavailable).build());
}
/**
* 断开连接
*/
public void close() {
connection.disconnect();
}
}