# React Native SDK 接入指南

**包名**：`@xuqm/rn-sdk` · **版本**：0.2.x（内部基础包，业务方不直接引用）

> **注意**：`rn-sdk` 作为内部基础包存在，业务方正常接入时使用 `@xuqm/rn-common` 和各业务模块即可。

---

## 功能模块

| 包 | 功能 |
|----|------|
| `@xuqm/rn-common` | 初始化、网络、设备信息，可独立使用 |
| `@xuqm/rn-im` | 单聊、群聊、消息收发、本地 DB（WatermelonDB）|
| `@xuqm/rn-push` | 推送设备 Token 上报 |
| `@xuqm/rn-update` | App 版本检查、RN Bundle 热更新 |
| `@xuqm/rn-license` | 设备授权注册与验证（License SDK）|
| `@xuqm/rn-sdk` | 内部基础包，随 IM / Push / Update 自动安装，不建议业务方直接引用 |

---

## 安装

在项目根目录创建 `.npmrc`：

```
@xuqm:registry=https://nexus.xuqinmin.com/repository/npm-hosted/
```

只使用基础能力时，直接安装 `rn-common`，不会带入 IM / Push / Update：

```bash
yarn add @xuqm/rn-common
```

按需安装模块时，`rn-im` / `rn-push` / `rn-update` 都会自动带上 `rn-common` 和 `rn-sdk`：

```bash
yarn add @xuqm/rn-common @xuqm/rn-im
```

`rn-sdk` 不作为业务方直接安装入口；它会随着 `rn-im` / `rn-push` / `rn-update` 自动进入依赖树。

---

## 快速接入（当前 v0.2.x）

### 1. 初始化

初始化只需传入 `appKey`，平台地址由 SDK 内置，开发者无需额外配置。

```ts
import { XuqmSDK } from '@xuqm/rn-common'

// App 入口（如 App.tsx 的顶层）
await XuqmSDK.initialize({
  appKey:   'your_app_key',
  logLevel: __DEV__ ? 'debug' : 'warn',
})
```

> SDK 内部自动处理服务器地址、IM 实时连接、文件服务等配置，开发者无需关心。

### 2. 统一登录

```ts
import { XuqmSDK } from '@xuqm/rn-common'
import { ImSDK } from '@xuqm/rn-im'

// 登录只需要 userId + userSig
// nickname / avatar 不再通过登录接口传入
await XuqmSDK.login({
  userId: 'user_001',
  userSig: 'your_user_sig_jwt',
})

// 如果集成了 rn-im，XuqmSDK.login 会自动触发 ImSDK 连接
// 业务侧无需单独调用 ImSDK.login
```

### 3. 消息收发

```ts
// 监听实时消息
ImSDK.addEventListener('message', (msg) => {
  console.log('收到消息:', msg.msgType, msg.content)
})

// 发送文本消息
const msg = await ImSDK.sendMessage(
  'user_002',   // toId
  'SINGLE',     // chatType: 'SINGLE' | 'GROUP'
  'TEXT',       // msgType
  'Hello!'      // content
)

// 发送图片（自动上传到 file-service）
const msg = await ImSDK.sendImageMessage(
  'user_002', 'SINGLE',
  '/path/to/image.jpg',  // 本地 URI
  800, 600               // 宽高（可选）
)

// 获取历史消息（单聊）
const history = await ImSDK.fetchHistory('user_002', page, size)

// 获取群历史消息
const groupHistory = await ImSDK.fetchGroupHistory('group_xxx', page, size)
```

### 4. 会话列表

```ts
// 订阅会话变化
const unsub = ImSDK.subscribeConversations((conversations) => {
  // conversations: ConversationData[]
  console.log(conversations)
})

// 置顶会话
await ImSDK.setConversationPinned('user_002', 'SINGLE', true)

// 免打扰
await ImSDK.setConversationMuted('group_xxx', 'GROUP', true)

// 标记已读
await ImSDK.markRead('user_002')
```

### 5. 群组管理

```ts
// 创建群组
const group = await ImSDK.createGroup('项目讨论', ['user_002', 'user_003'])

// 群组列表（仅返回当前用户所在的群）
const groups = await ImSDK.listGroups()

// 添加成员
await ImSDK.addGroupMember('group_xxx', 'user_004')

// 移除成员（需要管理员权限）
await ImSDK.removeGroupMember('group_xxx', 'user_004')

// 退出群聊
await ImSDK.leaveGroup('group_xxx')
```

### 6. 好友关系

```ts
// 好友列表
const friends = await ImSDK.listFriends()

// 添加好友（双向）
await ImSDK.addFriend('user_002')

// 删除好友（双向）
await ImSDK.removeFriend('user_002')
```

### 7. 消息搜索（本地）

```ts
import { ImSDK } from '@xuqm/rn-im'
import type { MessageSearchParams } from '@xuqm/rn-im'

const params: MessageSearchParams = {
  keyword: '会议',        // 关键词搜索
  toId: 'user_002',      // 限定会话（可选）
  chatType: 'SINGLE',    // 限定类型（可选）
  msgTypes: ['TEXT'],    // 限定消息类型（可选）
  limit: 20,
}
const results = await ImSDK.searchMessages(params)
```

### 8. 推送 SDK

登录成功后 SDK **自动**注册设备 Token，业务侧无需手动调用。

如需自定义 Push 行为，可引入 `@xuqm/rn-push`：

```ts
import { PushSDK } from '@xuqm/rn-push'

// 手动设置接收推送开关
await PushSDK.setReceivePush(false)
```

### 9. 版本更新 SDK

```ts
import { UpdateSDK } from '@xuqm/rn-update'

// 检查 App 原生更新
const appUpdate = await UpdateSDK.checkAppUpdate()
if (appUpdate?.needsUpdate) {
  console.log('新版本:', appUpdate.versionName)
  // Linking.openURL(appUpdate.downloadUrl)
}

// 检查 RN Bundle 热更新
const rnUpdate = await UpdateSDK.checkRnUpdate('your_module_id')
if (rnUpdate?.needsUpdate) {
  await UpdateSDK.downloadAndApplyBundle(rnUpdate)
}
```

### 10. 断开连接

```ts
ImSDK.disconnect()
```

---

## TypeScript 类型参考

```ts
// 消息
interface ImMessage {
  id:         string
  fromId:     string
  toId:       string
  chatType:   'SINGLE' | 'GROUP'
  msgType:    'TEXT' | 'IMAGE' | 'AUDIO' | 'VIDEO' | 'FILE' |
              'LOCATION' | 'NOTIFY' | 'CUSTOM' | 'RICH_TEXT' |
              'CALL_AUDIO' | 'CALL_VIDEO' | 'FORWARD' | 'REVOKED'
  content:    string    // JSON 字符串，结构按 msgType 不同
  status:     'SENDING' | 'SENT' | 'DELIVERED' | 'READ' | 'FAILED' | 'REVOKED'
  createdAt:  number    // Unix 毫秒
}

// 会话
interface ConversationData {
  targetId:       string
  chatType:       'SINGLE' | 'GROUP'
  lastMsgContent: string
  lastMsgType:    string
  lastMsgTime:    number
  unreadCount:    number
  isMuted:        boolean
  isPinned:       boolean
}

// 群组
interface ImGroup {
  id:         string
  name:       string
  creatorId:  string
  memberIds:  string    // JSON 数组字符串
  adminIds:   string
  createdAt:  number
}
```

---

## 当前接入

当前接入方式如下：

```ts
// 初始化
await XuqmSDK.initialize({ appKey: 'xxx' }) // 平台地址内置，无需传入

// IM 登录（UserSig 由业务服务端签发）
const userSig = await yourServer.getUserSig(userId)
await ImSDK.login(userId, userSig)

// dbName 自动由 appKey + userId 派生，无需传入
```

---

## 常见问题

**Q: 如何获取 appKey？**
在 [平台控制台](https://dev.xuqinmin.com) 注册账号后，创建应用即可获得 AppKey。

**Q: 为什么不需要传平台地址参数？**
XuqmGroup 是托管平台，服务地址统一管理，与腾讯云 IM 等平台的设计一致，开发者只需关心业务逻辑。

**Q: UserSig 是什么？**
UserSig 是您的业务服务端用 AppSecret 为用户签发的安全凭证。当前项目的 IM 登录不做过期功能，只校验 `userId + UserSig` 是否匹配。AppSecret 绝不下发到客户端。

**Q: 本地消息存储在哪里？**
使用 WatermelonDB（SQLite），按 `appKey + userId` 自动隔离，多账号切换安全。
