主题
Android Java/XML 接入
本页默认使用 Java、CompletableFuture、Listener 和 XML/ViewBinding,现有 MVP、MVVM 或传统 Activity/Fragment 工程可以直接接入,不要求改成 Kotlin Coroutine 或 Jetpack Compose。
完成本页后,你会连接一个测试账号、监听数据变化并向另一个账号发送文字消息。
不想从空白项目开始时,直接运行 platforms/android/demo-java。该工程 只有 Java + XML 业务代码,已经包含 Repository、ViewModel、会话列表、聊天页和 应用自带矢量图标。
bash
cd platforms/android
JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" \
ANDROID_HOME="$HOME/Library/Android/sdk" \
./gradlew :demo-java:assembleDebug -Pxhim.skipNativeBuild=truexhim.skipNativeBuild=true 只用于单独检查 Java 源码;真实运行时必须消费完整 Maven AAR,或用包含目标 ABI Core/JNI 的正式构建。
text
准备 Server 和测试账号
-> 添加 Maven 依赖
-> 连接当前账号
-> 注册 Listener
-> 发送第一条消息
-> 验证登出和换号1. 准备接入信息
向服务端负责人领取 Server URL、App ID、当前用户 ID 和一个对端用户 ID。 正式环境还需要应用自己的后台提供短期 XHIM 凭证。客户端不保存管理员密钥, 也不需要自行管理 WebSocket 或 SDK 数据库。
2. 安装
Groovy build.gradle:
groovy
dependencies {
implementation "com.xihansoftware.xhim:xhim-sdk:<version>"
}Kotlin DSL 项目也可以保留 Java 业务源码:
kotlin
dependencies {
implementation("com.xihansoftware.xhim:xhim-sdk:<version>")
}xhim-sdk 不依赖 Compose。只有宿主已经使用 Compose 界面时才加 xhim-ui-compose。Minimum SDK 为 API 24,建议 JDK 17 与 Android Gradle Plugin 8.x 的稳定版组合。
3. Development 连接
Development Server 明确启用免密登录时:
java
import com.xihansoftware.xhim.XHIMJavaClient;
import java.util.concurrent.CompletableFuture;
CompletableFuture<XHIMJavaClient> connecting =
XHIMJavaClient.connectDevelopment(
getApplicationContext(),
"https://im.customer.example",
"alice");
connecting.thenAccept(client -> repository.attach(client))
.exceptionally(error -> {
repository.reportConnectionError(error);
return null;
});Production 不使用 Development Login。让已有业务账号 Repository 提供 当前用户凭证:
java
XHIMJavaClient.connectWithCredentialProvider(
getApplicationContext(),
BuildConfig.XHIM_SERVER_URL,
businessSession.currentUserId(),
() -> accountRepository.fetchXHIMCredentialBlocking()
).thenAccept(repository::attach);Credential Provider 会在 SDK IO 线程调用。它不能访问 Activity/View, 不能保存明文 Token,也不能向 UI 打印凭证。
4. Repository 中订阅事件
java
import java.io.Closeable;
import java.util.concurrent.Executor;
final class XHIMRepository implements Closeable {
private final Executor mainExecutor;
private XHIMJavaClient client;
private Closeable events;
XHIMRepository(Executor mainExecutor) {
this.mainExecutor = mainExecutor;
}
void attach(XHIMJavaClient connected) {
client = connected;
events = connected.addEventListener(event -> {
// 收到变化后,按事件中的会话或模块重新查询数据。
}, mainExecutor);
}
@Override public void close() throws Exception {
if (events != null) events.close();
if (client != null) client.close();
}
}SDK 不强制 UI 线程框架。传给 addEventListener 的 Executor 决定 事件交付线程。Activity 可以使用 ContextCompat.getMainExecutor(...), 单元测试可以传直接 Executor。
5. 发送文字并刷新消息
java
import java.util.UUID;
String clientMessageId = UUID.randomUUID().toString();
client.sendText(conversationId, draft, clientMessageId)
.thenCompose(receipt -> client.messages(conversationId))
.thenAcceptAsync(page -> viewModel.replaceMessages(page), mainExecutor)
.exceptionally(error -> {
viewModel.showStableError(error);
return null;
});sendText 完成只表示本地可靠 Outbox 已受理。最终发送状态通过 messages(...) 查询;不要用回调 payload 在页面另维护一份消息库。
6. 已读、Presence 和 Typing
java
client.markConversationRead(conversationId, throughServerSequence);
client.publishPresence(XHIMPresenceStatus.ONLINE);
client.publishTyping(conversationId, true);
// 输入框清空、发送成功或页面离开时清除 Typing。
client.publishTyping(conversationId, false);7. 编辑、撤回与历史消息
常用逻辑只组合 CompletableFuture,不需要在 Activity 中手写 Coroutine 或 JNI 回调:
java
String mutationId = UUID.randomUUID().toString();
client.recall(conversationId, serverMessageId, mutationId, messageRevision)
.thenAccept(recalled -> viewModel.replaceMessage(recalled))
.exceptionally(error -> {
viewModel.showStableError(error);
return null;
});
client.getMessageHistory(conversationId)
.thenAccept(page -> viewModel.prependHistory(page));mutationId 只用于同一次逻辑操作的精确重试; messageRevision 使用最后一次权威消息快照中的 revision。
8. 好友与群组
java
client.friendships()
.thenAccept(page -> contactRepository.replace(page.getItems()));
client.groups()
.thenAccept(page -> groupRepository.replace(page.getItems()));
client.changeGroupMembers(
conversationId,
List.of("bob"),
List.of(),
groupRevision,
UUID.randomUUID().toString())
.thenAccept(change -> groupRepository.apply(change));好友、群成员和用户资料都返回不可变模型。列表与搜索的 cursor 是不透明字节;业务层原样传回 SDK,不自行解码。
9. 取消、异常和关闭
java
CompletableFuture<XHIMMessagePage> request = client.messages(conversationId);
// Fragment/ViewModel 销毁时停止等待。
request.cancel(true);
request.exceptionally(error -> {
Throwable cause = error instanceof java.util.concurrent.CompletionException
? error.getCause()
: error;
// cause 为 XHIMException 时按 stableCode 分支,不解析 message。
return null;
});
client.shutdown();CompletableFuture.cancel(...)会把取消请求传给 SDK;- UI 不应根据异常 message 分支,而应使用
XHIMException.stableCode; close()只做本地资源释放;正常账号退出先调logout();- Application 退出或账号容器销毁时调
shutdown()/close()。
10. Java 常用方法
| 模块 | Java 入口 |
|---|---|
| 连接 | connectDevelopment / connectWithAccessToken / connectWithCredentialProvider |
| 会话 | conversations / searchConversations / directConversation / clearConversation / hideConversation / markConversationRead / markAllConversationsRead / totalUnreadCount / setLocalDraft |
| 消息 | sendText / sendMessage / editText / recall / message / messages / messagesAfter / messageContext / getMessageHistory / searchMessages / deleteMessageForSelf / retryMessage / cancelMessage |
| 用户 | currentUserProfile / userProfiles / resolveUserByPhone / updateCurrentUserProfile / publishPresence / publishTyping |
| 好友 | friendRequests / friendships / searchFriendships / sendFriendRequest / resolveFriendRequest / deleteFriendship / setFriendRemark / setFriendPinned / blocks / setBlock |
| 群组 | groups / groupMembers / searchGroups / searchGroupMembers / createGroup / changeGroupMembers / leaveGroup / dismissGroup |
| 推送与设备 | registerPushDevice / disablePushDevice / listDeviceSessions / revokeDeviceSession |
| 生命周期 | state / diagnostics / deviceSessionPolicy / compatibility / sessionIdentity / notifyNetworkAvailable / updateCredential / logout / shutdown |
每个独立 API 页只有在 Java 入口真实存在时,才展示“Android · Java”。没有 Java 高层入口的能力会明确标为当前版本不支持,不要求应用调用 Kotlin 字节码接口。