# Android IM 接入

基于 `sdk-im` 模块实现即时通讯功能。

---

## 初始化详情

在 `Application.onCreate()` 中完成初始化，只需传入 `appKey`：

```kotlin
import com.xuqm.sdk.XuqmSDK
import com.xuqm.sdk.core.LogLevel

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        XuqmSDK.initialize(
            context = this,
            appKey = "your_app_key",
            logLevel = LogLevel.WARN,  // 可选：DEBUG / INFO / WARN / ERROR
        )
    }
}
```

> 服务器地址由 SDK 内置，**无需传 `serverUrl`**。

---

## 登录鉴权（UserSig）

`userSig` 由业务服务端签发。登录只需 `userId + userSig`：

```kotlin
import androidx.lifecycle.lifecycleScope
import com.xuqm.sdk.XuqmSDK
import kotlinx.coroutines.launch

lifecycleScope.launch {
    XuqmSDK.login(
        userId = "user_001",
        userSig = "your_user_sig_jwt",
    )
}
```

> 登录成功后，IM 模块会自动连接，Push 模块会自动注册设备 Token。

---

## 单聊消息收发

### 监听实时消息

```kotlin
import com.xuqm.sdk.im.ImSDK
import com.xuqm.sdk.im.listener.ImEventListener
import com.xuqm.sdk.im.model.ImMessage

ImSDK.addListener(object : ImEventListener {
    override fun onConnected() { /* IM 已连接 */ }
    override fun onMessage(msg: ImMessage) { /* 单聊消息 */ }
    override fun onGroupMessage(msg: ImMessage) { /* 群聊消息 */ }
    override fun onRead(msg: ImMessage) { /* 对方已读回执 */ }
    override fun onRevoke(msg: ImMessage) { /* 消息被撤回 */ }
    override fun onDisconnected(reason: String?) { /* 断线处理 */ }
    override fun onError(error: String) { /* 错误回调 */ }
})
```

### 发送文本消息

```kotlin
ImSDK.sendTextMessage(
    toId = "user_002",
    chatType = "SINGLE",
    content = "Hello!",
)
```

### 发送多媒体消息

```kotlin
// 图片（需先调用 FileSDK 上传）
ImSDK.sendImageMessage(
    toId = "user_002",
    chatType = "SINGLE",
    file = uploadResult,
    width = 800,
    height = 600,
)

// 视频
ImSDK.sendVideoMessage(
    toId = "user_002",
    chatType = "SINGLE",
    file = uploadResult,
    width = 1920,
    height = 1080,
    durationMs = 15_000,
)

// 语音
ImSDK.sendAudioMessage(
    toId = "user_002",
    chatType = "SINGLE",
    file = uploadResult,
    durationMs = 5_000,
)

// 文件
ImSDK.sendFileMessage(
    toId = "user_002",
    chatType = "SINGLE",
    file = uploadResult,
)

// 位置
ImSDK.sendLocationMessage(
    toId = "user_002",
    chatType = "SINGLE",
    latitude = 31.2304,
    longitude = 121.4737,
    title = "上海",
    address = "上海市黄浦区",
)
```

### 获取历史消息

```kotlin
lifecycleScope.launch {
    val history = ImSDK.fetchHistory("user_002", page = 0, size = 20)
    // 带筛选的历史消息
    val filtered = ImSDK.fetchHistoryWithFilters(
        toId = "user_002",
        page = 0,
        size = 20,
        msgType = "TEXT",
        keyword = "会议",
    )
}
```

### 撤回与编辑

```kotlin
lifecycleScope.launch {
    ImSDK.revokeMessage(messageId)
    ImSDK.editMessage(messageId, "新内容")
}
```

---

## 群聊

### 创建群组

```kotlin
lifecycleScope.launch {
    val group = ImSDK.createGroup(
        name = "项目讨论",
        memberIds = listOf("user_002", "user_003"),
        groupType = "WORK",  // 可选：WORK / PUBLIC / PRIVATE
    )
}
```

### 订阅群消息

```kotlin
ImSDK.subscribeGroup("group_xxx")
```

### 发送群消息

```kotlin
ImSDK.sendTextMessage(
    toId = "group_xxx",
    chatType = "GROUP",
    content = "大家好",
)
```

### 群成员管理

```kotlin
lifecycleScope.launch {
    // 添加成员
    ImSDK.addGroupMember("group_xxx", "user_004")
    // 移除成员
    ImSDK.removeGroupMember("group_xxx", "user_004")
    // 批量添加/移除
    ImSDK.batchAddGroupMembers("group_xxx", listOf("user_005", "user_006"))
    ImSDK.batchRemoveGroupMembers("group_xxx", listOf("user_005", "user_006"))
    // 设置角色
    ImSDK.setGroupRole("group_xxx", "user_004", "ADMIN")
    // 禁言
    ImSDK.muteGroupMember("group_xxx", "user_004", minutes = 60)
    // 转让群主
    ImSDK.transferGroupOwner("group_xxx", "user_002")
    // 退出群聊
    ImSDK.leaveGroup("group_xxx")
    // 解散群聊
    ImSDK.dismissGroup("group_xxx")
}
```

### 群信息查询

```kotlin
lifecycleScope.launch {
    val groups = ImSDK.listGroups()
    val publicGroups = ImSDK.listPublicGroups(keyword = "项目")
    val group = ImSDK.getGroupInfo("group_xxx")
    val members = ImSDK.listGroupMembers("group_xxx")
    val history = ImSDK.fetchGroupHistory("group_xxx", page = 0, size = 20)
}
```

---

## 好友管理

```kotlin
lifecycleScope.launch {
    // 好友列表
    val friends = ImSDK.listFriends()
    // 添加好友
    ImSDK.addFriend("user_002")
    // 删除好友
    ImSDK.removeFriend("user_002")
    // 批量操作
    ImSDK.batchAddFriends(listOf("user_002", "user_003"))
    ImSDK.batchRemoveFriends(listOf("user_002", "user_003"))
    // 好友分组
    ImSDK.setFriendGroup("user_002", "同事")
    val groups = ImSDK.listFriendGroups()
    // 好友请求
    ImSDK.sendFriendRequest("user_002", remark = "你好")
    val requests = ImSDK.listFriendRequests(direction = "incoming")
    ImSDK.acceptFriendRequest("request_id")
    ImSDK.rejectFriendRequest("request_id")
    // 黑名单
    ImSDK.addToBlacklist("user_002")
    ImSDK.removeFromBlacklist("user_002")
    val check = ImSDK.checkBlacklist("user_002")
}
```

---

## 会话列表

```kotlin
lifecycleScope.launch {
    val conversations = ImSDK.listConversations()
    // 置顶
    ImSDK.setConversationPinned("user_002", "SINGLE", true)
    // 免打扰
    ImSDK.setConversationMuted("user_002", "SINGLE", true)
    // 标记已读
    ImSDK.markRead("user_002", "SINGLE")
    // 草稿
    ImSDK.setDraft("user_002", "SINGLE", "草稿内容")
    // 删除会话
    ImSDK.deleteConversation("user_002", "SINGLE")
    // 总未读数
    val totalUnread = ImSDK.getTotalUnreadCount()
}
```

---

## 离线消息同步

```kotlin
lifecycleScope.launch {
    // 查询离线消息数量
    val count = ImSDK.offlineMessageCount()
    // 同步离线消息
    val offlineMessages = ImSDK.syncOfflineMessages()
}
```

---

## 连接状态监听

```kotlin
lifecycleScope.launch {
    ImSDK.connectionState.collect { state ->
        when (state) {
            is ImConnectionState.Connected -> { /* 已连接 */ }
            is ImConnectionState.Connecting -> { /* 连接中 */ }
            is ImConnectionState.Disconnected -> { /* 已断开：state.reason */ }
        }
    }
}
```

---

## 消息类型

| MsgType | 说明 | content 结构 |
|---------|------|-------------|
| `TEXT` | 纯文本 | `String` |
| `IMAGE` | 图片 | `{url, width, height, thumbnailUrl?}` |
| `VIDEO` | 视频 | `{url, duration, thumbnailUrl, size}` |
| `AUDIO` | 语音 | `{url, duration, size}` |
| `FILE` | 文件 | `{url, name, size, mimeType}` |
| `LOCATION` | 位置 | `{lat, lng, address, title}` |
| `CUSTOM` | 自定义 | 任意 JSON |
| `NOTIFY` | 系统通知 | `{title, content}` |
| `RICH_TEXT` | 富文本 | `{html}` |
| `CALL_AUDIO` | 语音通话信令 | `{action}` |
| `CALL_VIDEO` | 视频通话信令 | `{action}` |
| `FORWARD` | 转发 | `{originalSender, originalContent}` |
| `QUOTE` | 引用 | `{quotedMsgId, quotedContent, text}` |
| `MERGE` | 合并转发 | `{title, msgList}` |
| `REVOKED` | 撤回 | 系统内部填充 |
