diff --git a/docs-site/docs/rn/index.md b/docs-site/docs/rn/index.md index 69fd688..0d891e6 100644 --- a/docs-site/docs/rn/index.md +++ b/docs-site/docs/rn/index.md @@ -1,209 +1,232 @@ # React Native SDK 概览 -**包名**:`@xuqm/rn-sdk` · **版本**:0.1.0 · **支持**:React Native 0.73+、Expo 50+ +**包名**:`@xuqm/rn-sdk` · **版本**:0.3.0 · **支持**:React Native 0.73+ ## 功能模块 -| 导出 | 功能 | -|------|------| -| `XuqmSDK` | 全局初始化 | -| `ImSDK` | 单聊、群聊、消息收发、历史记录 | -| `UpdateSDK` | App 版本检查、RN Bundle 热更新 | -| `PushSDK` | 设备 Token 上报 | +| 包 | 功能 | +|----|------| +| `@xuqm/rn-common` | 初始化、网络、设备信息(必须) | +| `@xuqm/rn-im` | 单聊、群聊、消息收发、本地 DB | +| `@xuqm/rn-push` | 推送设备 Token 上报 | +| `@xuqm/rn-update` | App 版本检查、RN Bundle 热更新 | +| `@xuqm/rn-sdk` | 以上所有模块的 meta 包(推荐直接使用) | ## 安装 -### 从 Nexus 私有仓库安装 - 在项目根目录创建 `.npmrc`: ``` -@xuqm:registry=https://nexus.xuqinmin.com/repository/npm-hosted/ +@xuqm:registry=https://nexus.xuqinmin.com/repository/npm/ ``` -然后安装: +安装 meta 包(包含全部功能): ```bash -npm install @xuqm/rn-sdk -# 或 yarn add @xuqm/rn-sdk ``` +或按需安装(减小包体积): + +```bash +yarn add @xuqm/rn-common @xuqm/rn-im +``` + ## 快速接入 -### 1. 初始化(一次即可,在 App 启动时调用) +### 1. 初始化(推荐异步方式) ```ts import { XuqmSDK } from '@xuqm/rn-sdk' +// 推荐:从租户平台拉取完整配置 +await XuqmSDK.initialize({ + appId: 'your_app_id', + serverUrl: 'https://your-server.com', + debug: __DEV__, +}) + +// 兼容:同步初始化,不发网络请求,根据 serverUrl 推导 URL XuqmSDK.init({ - appId: 'your_app_id', - appKey: 'your_app_id', - appSecret: 'your_app_secret', - apiBaseUrl: 'https://sentry.xuqinmin.com', - imWsUrl: 'wss://sentry.xuqinmin.com/ws/im', - debug: __DEV__, + appId: 'your_app_id', + serverUrl: 'https://your-server.com', }) ``` +> `initialize` 自动从 `GET /api/sdk/config?appId=` 获取 imWsUrl、fileServiceUrl 等配置,并在网络失败时 fallback 到 serverUrl 推导值。 + ### 2. IM 登录 ```ts import { ImSDK } from '@xuqm/rn-sdk' -await ImSDK.login('user_001', '张三') +// 使用 IM token(由你的业务服务端签发) +await ImSDK.loginWithToken('user_001', 'im_token_from_server', 'xuqm_im') + +// 直接登录(适用于 im-service 直接认证场景) +await ImSDK.login('user_001', '张三', 'https://cdn.example.com/avatar.jpg', 'xuqm_im') ``` -### 3. 监听消息与连接事件 +### 3. 监听消息与连接状态 ```ts import type { ImEventListener } from '@xuqm/rn-sdk' const listener: ImEventListener = { - onConnected() { console.log('WS connected') }, - onDisconnected(reason) { console.log('WS disconnected:', reason) }, - onMessage(msg) { /* 单聊/群聊消息 */ }, - onGroupMessage(msg) { /* 群消息(独立回调) */ }, + onConnected() { console.log('WS 已连接') }, + onDisconnected(reason) { console.log('WS 断开:', reason) }, + onMessage(msg) { /* 收到单聊消息 */ }, + onGroupMessage(msg) { /* 收到群聊消息 */ }, onError(err) { console.error(err) }, } ImSDK.addListener(listener) - -// 组件卸载时移除 -return () => { - ImSDK.removeListener(listener) - ImSDK.disconnect() -} +return () => ImSDK.removeListener(listener) ``` ### 4. 发送消息 ```ts -// 文本 -const sent = await ImSDK.sendMessage('user_002', 'SINGLE', 'TEXT', 'Hello!') +// 文本消息 +const msg = await ImSDK.sendMessage('user_002', 'SINGLE', 'TEXT', 'Hello!') -// 图片(content 为 JSON 字符串) -const sent = await ImSDK.sendMessage('user_002', 'SINGLE', 'IMAGE', JSON.stringify({ - url: 'https://cdn.example.com/img.jpg', - width: 800, height: 600, -})) +// 图片(SDK 自动上传到 file-service) +const msg = await ImSDK.sendImageMessage('user_002', 'SINGLE', localUri, width, height) + +// 视频 +const msg = await ImSDK.sendVideoMessage('user_002', 'SINGLE', localUri, thumbnailUri, durationSeconds) + +// 语音 +const msg = await ImSDK.sendAudioMessage('user_002', 'SINGLE', localUri, durationSeconds) + +// 文件 +const msg = await ImSDK.sendFileMessage('user_002', 'SINGLE', localUri, 'report.pdf', fileSize) ``` -### 5. 撤回消息 +### 5. 拉取历史消息 ```ts -const revoked = await ImSDK.revokeMessage(msg.id) +// 单聊历史(先读本地 DB,再回源服务端) +const history = await ImSDK.fetchHistory('user_002', 0, 30) + +// 群聊历史 +const gHistory = await ImSDK.fetchGroupHistory(groupId, 0, 30) ``` -### 6. 拉取历史 +### 6. 会话列表(响应式) ```ts -// 单聊历史(page=0, size=50) -const history = await ImSDK.fetchHistory('user_002', 0, 50) +// 订阅本地 DB 变更,新消息/已读/静音/置顶都会触发回调 +const unsub = ImSDK.subscribeConversations((convs) => { + setConversations(convs) +}) +return unsub // 组件卸载时调用 -// 群历史 -const gHistory = await ImSDK.fetchGroupHistory(groupId, 0, 50) +// 标记已读 +await ImSDK.markRead('user_002') + +// 置顶/静音 +await ImSDK.setConversationPinned('user_002', 'SINGLE', true) +await ImSDK.setConversationMuted('user_002', 'SINGLE', true) ``` ### 7. 群聊 ```ts -// 创建群(自动将自己加入成员列表) -const group = await ImSDK.createGroup('开发讨论组', ['user_001', 'user_002']) +// 创建群 +const group = await ImSDK.createGroup('讨论组', ['user_001', 'user_002']) -// 订阅群 WebSocket topic +// 订阅群消息 WebSocket topic ImSDK.subscribeGroup(group.id) -// 列出所有群 -const groups = await ImSDK.listGroups() - -// 发群消息 -const sent = await ImSDK.sendMessage(group.id, 'GROUP', 'TEXT', '大家好') +// 群消息撤回 +await ImSDK.revokeMessage(messageId) ``` -### 8. 检查 App 更新 +### 8. 好友管理 + +```ts +await ImSDK.addFriend('user_002') +await ImSDK.removeFriend('user_002') +const friends = await ImSDK.listFriends() +``` + +### 9. 消息搜索 + +```ts +const results = await ImSDK.searchMessages({ + keyword: '关键字', + msgType: 'TEXT', // 可选,过滤消息类型 + startTime: '2026-01-01', // 可选,时间范围 + endTime: '2026-12-31', +}) +``` + +### 10. App 版本更新 ```ts import { UpdateSDK } from '@xuqm/rn-sdk' -const info = await UpdateSDK.checkAppUpdate(1 /* 当前 versionCode */) -if (info) { +// 自动读取原生版本码,无需传参 +const info = await UpdateSDK.checkAppUpdate() +if (info?.needsUpdate) { console.log(info.versionName, info.forceUpdate, info.downloadUrl) } ``` -### 9. RN Bundle 热更新(三步流程) +### 11. RN Bundle 热更新 ```ts -import AsyncStorage from '@react-native-async-storage/async-storage' +// 插件在 bundle 加载时自注册(自动读取 plugin.json) +import meta from './plugin.json' // { moduleId, version } +UpdateSDK.registerPlugin(meta) -// Step 1: 检查是否有新版本 -const bundle = await UpdateSDK.checkRNUpdate('home', '1.0.0') -if (!bundle) return // 已是最新 - -// Step 2: 下载 bundle -const content = await UpdateSDK.downloadBundle(bundle.downloadUrl) - -// Step 3: 缓存,下次启动由 BundleRuntime 加载 -await AsyncStorage.setItem('rn_bundle_home', JSON.stringify({ - version: bundle.version, - md5: bundle.md5, - content, - cachedAt: new Date().toISOString(), -})) +// 检查 → 下载 → 缓存(三步) +const checkInfo = await UpdateSDK.checkRnUpdate('home') +if (checkInfo.needsUpdate) { + const source = await UpdateSDK.downloadRnBundle(checkInfo.downloadUrl) + await UpdateSDK.cacheRnBundle('home', checkInfo.latestVersion, checkInfo.md5, source) +} ``` -> **提示**:运行时替换(热加载)需对接原生 `BundleRuntime`,参考 `ProjectFrameReactNative` 架构文档。 - -## 完整消息类型 - -```ts -type MsgType = - | 'TEXT' | 'IMAGE' | 'VIDEO' | 'AUDIO' | 'FILE' - | 'CUSTOM' | 'LOCATION' | 'NOTIFY' | 'RICH_TEXT' - | 'CALL_AUDIO' | 'CALL_VIDEO' | 'FORWARD' | 'REVOKED' -``` - -每种类型的 `content` 格式: +## 消息类型 content 格式 | MsgType | content | |---------|---------| | `TEXT` | 纯文本字符串 | -| `IMAGE` | `{"url":"...","width":800,"height":600,"thumbnailUrl":"..."}` | -| `VIDEO` | `{"url":"...","duration":30,"thumbnailUrl":"...","size":1048576}` | +| `IMAGE` | `{"url":"...","thumbnailUrl":"...","width":800,"height":600}` | +| `VIDEO` | `{"url":"...","thumbnailUrl":"...","duration":30,"size":1048576}` | | `AUDIO` | `{"url":"...","duration":12,"size":204800}` | | `FILE` | `{"url":"...","name":"report.pdf","size":512000,"mimeType":"application/pdf"}` | -| `LOCATION` | `{"lat":39.9042,"lng":116.4074,"address":"北京市东城区","title":"天安门"}` | +| `LOCATION` | `{"lat":39.9042,"lng":116.4074,"address":"北京市","title":"天安门"}` | | `CUSTOM` | 任意 JSON 字符串 | -| `NOTIFY` | `{"title":"系统通知","content":"服务器维护","level":"INFO"}` | +| `NOTIFY` | `{"title":"系统通知","content":"内容","level":"INFO"}` | | `RICH_TEXT` | `{"html":"加粗内容"}` | -| `CALL_AUDIO` | `{"callId":"uuid","action":"INVITE","callerName":"张三"}` | -| `CALL_VIDEO` | `{"callId":"uuid","action":"INVITE","callerName":"张三"}` | -| `FORWARD` | `{"originalMsgId":"...","originalContent":"原始内容","originalSender":"张三"}` | -| `REVOKED` | 服务端下发,客户端只读 | -## TypeScript 类型定义 +## TypeScript 类型 ```ts interface ImMessage { - id: string - appId: string - fromUserId: string - toId: string - chatType: 'SINGLE' | 'GROUP' - msgType: MsgType - content: string - status: 'SENT' | 'REVOKED' - createdAt: string // ISO 8601 + id: string + appId: string + fromUserId: string + toId: string + chatType: 'SINGLE' | 'GROUP' + msgType: MsgType + content: string + status: 'SENT' | 'DELIVERED' | 'READ' | 'REVOKED' + mentionedUserIds?: string + createdAt: string // ISO 8601 } -interface ImGroup { - id: string - appId: string - name: string - creatorId: string - memberIds: string[] - adminIds: string[] - createdAt: string +interface ConversationData { + targetId: string + chatType: 'SINGLE' | 'GROUP' + lastMsgContent: string + lastMsgType: string + lastMsgTime: number // Unix ms + unreadCount: number + isMuted: boolean + isPinned: boolean } ```