Android IM 即时通讯应用开发实战:基于 Smack 与 Openfire
Android IM 开发指南,基于 Smack 客户端库与 Openfire 服务端搭建。涵盖服务器环境配置、Gradle 依赖引入、XMPP 连接建立、用户注册登录流程、消息收发实现及离线消息处理。重点展示连接监听、自动重连机制及在线状态管理,提供完整的 Java 代码示例,帮助开发者快速构建即时通讯功能模块。

Android IM 开发指南,基于 Smack 客户端库与 Openfire 服务端搭建。涵盖服务器环境配置、Gradle 依赖引入、XMPP 连接建立、用户注册登录流程、消息收发实现及离线消息处理。重点展示连接监听、自动重连机制及在线状态管理,提供完整的 Java 代码示例,帮助开发者快速构建即时通讯功能模块。

准备一台 Linux 或 Windows 服务器,或在本地运行 Docker/虚拟机。
Openfire 是一个基于 XMPP 协议的即时通讯服务器。虽然可以通过宝塔面板等工具管理 Tomcat,但 Openfire 通常作为独立服务运行。
http://<服务器 IP>:9090 进行初始配置。im.example.com。注意:确保服务器防火墙开放 5222 (XMPP Client)、7070 (Admin Console) 等端口。
在项目的 build.gradle (Module: app) 中添加 Smack 相关依赖:
// 即时通讯客户端 smack
implementation 'org.igniterealtime.smack:smack-android-extensions:4.4.4'
implementation 'org.igniterealtime.smack:smack-tcp:4.4.4'
implementation 'org.igniterealtime.smack:smack-core:4.4.4'
在 AndroidManifest.xml 中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
使用 XMPPTCPConnectionConfiguration 构建连接配置。
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import java.net.InetAddress;
public class XmppConfig {
public static XMPPTCPConnection createConnection(String host, String domain) throws Exception {
XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
.setXmppDomain(domain) // 设置主机名,即 Openfire 配置的 Domain
.setHostAddress(InetAddress.getByName(host)) // 设置服务器 IP 地址
.setHost(domain) // 同上
.setPort(5222) // XMPP 默认端口
.setConnectTimeout(600000) // 设置连接超时时间 (毫秒)
.setSecurityMode(XMPPTCPConnectionConfiguration.SecurityMode.disabled) // 测试环境可禁用 SSL
.setCompressionEnabled(true) // 开启压缩,节省流量
.setSendPresence(false) // 发送状态通知
.allowEmptyOrNullUsernames() // 允许用户名是空或 NULL
.build();
XMPPTCPConnection connection = new XMPPTCPConnection(config);
connection.setUseStreamManagement(true); // 开启流管理
connection.setUseStreamManagementResumption(true);
return connection;
}
}
根据用户是否已注册,执行不同的逻辑。
import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.iq.register.RegisterManager;
import org.jivesoftware.smackx.iq.register.provider.Register;
import org.jivesoftware.smackx.xdata.DataForm;
import org.jivesoftware.smackx.xdata.field.Field;
// 初始化连接后执行
XMPPTCPConnection connection = XmppConfig.createConnection("192.168.1.100", "im.example.com");
connection.connect();
// 判断是否需要注册
AccountManager accountManager = AccountManager.getInstance(connection);
accountManager.sensitiveOperationOverInsecureConnectionDefault(true);
try {
if (!accountManager.supportsRegistration()) {
// 如果服务器不支持注册,直接尝试登录
connection.login("user_id", "password");
} else {
// 尝试创建账号
HashMap<String, String> attributes = new HashMap<>();
attributes.put("name", "此处填账号名称即用户名");
accountManager.createAccount("user_id", "password", attributes);
connection.login("user_id", "password");
}
} catch (XMPPException e) {
e.printStackTrace();
// 处理登录失败逻辑
}
使用 ChatManager 监听聊天会话。
import org.jivesoftware.smack.chat.Chat;
import org.jivesoftware.smack.chat.ChatManager;
import org.jivesoftware.smack.chat.ChatMessageListener;
import org.jivesoftware.smack.filter.StanzaTypeFilter;
ChatManager cm = ChatManager.getInstanceFor(connection);
cm.addChatListener((chat, createdLocally) -> {
if (!createdLocally) { // 仅处理对方发来的消息
chat.addMessageListener((chatInstance, message) -> {
String body = message.getBody();
// 在主线程更新 UI 显示消息
runOnUiThread(() -> {
// updateUI(message);
});
});
}
});
创建聊天会话并发送文本消息。
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.MUCService; // 如需群聊需引入
ChatManager cm = ChatManager.getInstanceFor(connection);
String targetJid = "[email protected]"; // 目标用户 ID + 域名
Chat chat = cm.createChat(targetJid);
Message message = new Message();
message.setBody("此处填文本消息内容");
chat.sendMessage(message);
当用户离线时,服务器会保存消息。重新上线后可获取。
import org.jivesoftware.smackx.offline.OfflineMessageManager;
OfflineMessageManager offlineManager = OfflineMessageManager.getInstanceFor(connection);
List<Message> messages = offlineManager.getMessages();
for (Message msg : messages) {
// 处理历史离线消息
}
设置并发布当前用户的 Presence 状态。
import org.jivesoftware.smack.packet.Presence;
Presence userState = new Presence(Presence.Type.available);
userState.setStatus("online");
connection.sendStanza(userState);
监控连接生命周期,处理断线重连。
import org.jivesoftware.smack.ConnectionListener;
connection.addConnectionListener(new ConnectionListener() {
@Override
public void connected(XMPPConnection connection, boolean resumed) {
// 连接成功回调
}
@Override
public void authenticated(XMPPConnection connection, boolean resumed) {
// 认证成功回调
}
@Override
public void connectionClosed() {
// 连接正常关闭
}
@Override
public void connectionClosedOnError(Exception e) {
// 异常关闭
}
});
启用 Smack 内置的重连管理器。
import org.jivesoftware.smack.ReconnectionManager;
ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(connection);
reconnectionManager.enableAutomaticReconnection();
reconnectionManager.setReconnectionPolicy(ReconnectionManager.ReconnectionPolicy.FIXED_DELAY);
reconnectionManager.setFixedDelay(5); // 每间隔 5 秒重连一次
SecurityMode.require),避免明文传输密码。connection.disconnect() 释放资源。本文详细介绍了基于 Smack 和 Openfire 构建 Android 即时通讯应用的核心流程。从服务器部署到客户端连接、消息收发及异常处理,涵盖了 IM 开发的关键环节。开发者可根据实际需求扩展群聊、文件传输等功能。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online