diff --git a/README.md b/README.md index 6264d72..97fac8d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # XuqmGroup React Native SDK -Modular React Native SDK providing IM, Push, App/Plugin Update, WebView, and License management for XuqmGroup platform applications. +Modular React Native SDK providing IM, Push, App/Plugin Update, WebView, BugCollect, and License management for XuqmGroup platform applications. ## Table of Contents @@ -38,11 +38,12 @@ XuqmGroup-RNSDK/ # @xuqm/rn-sdk (meta-package, private) │ ├── index.ts # Re-exports all sub-packages │ └── sdk.ts # Unified login / logout ├── packages/ -│ ├── common/ @xuqm/rn-common # Init, network, device, token, HTTP, auto-init -│ ├── im/ @xuqm/rn-im # IM messaging (WebSocket/STOMP + WatermelonDB) -│ ├── push/ @xuqm/rn-push # Multi-vendor push registration -│ ├── update/ @xuqm/rn-update # App update check + RN plugin hot-update -│ └── xwebview/ @xuqm/rn-xwebview # Enhanced WebView with JSBridge +│ ├── common/ @xuqm/rn-common # Init, network, device, token, HTTP, auto-init, Metro plugins +│ ├── im/ @xuqm/rn-im # IM messaging (WebSocket/STOMP + WatermelonDB) +│ ├── push/ @xuqm/rn-push # Multi-vendor push registration +│ ├── update/ @xuqm/rn-update # App update check + RN plugin hot-update +│ ├── xwebview/ @xuqm/rn-xwebview # Enhanced WebView with JSBridge +│ └── bugcollect/ @xuqm/rn-bugcollect # Error capture, crash reporting, funnel analytics ``` All packages are at version **0.2.2**. @@ -73,7 +74,7 @@ yarn add @react-native-async-storage/async-storage **Option B -- Individual packages:** ```bash -yarn add @xuqm/rn-common @xuqm/rn-update @xuqm/rn-xwebview +yarn add @xuqm/rn-common @xuqm/rn-update @xuqm/rn-xwebview @xuqm/rn-bugcollect yarn add @react-native-async-storage/async-storage ``` @@ -88,6 +89,9 @@ yarn add react-native-webview react-native-blob-util react-native-svg # Config file decryption (auto-init) yarn add react-native-quick-crypto + +# BugCollect module (if using @xuqm/rn-bugcollect) +yarn add @xuqm/rn-bugcollect ``` --- @@ -96,21 +100,19 @@ yarn add react-native-quick-crypto ### Zero-config initialization (recommended) -Place an encrypted `.xuqmconfig` file (XUQM-CONFIG-V1 format) in your project, then add a Metro alias so the SDK can auto-discover it: +Place the encrypted `.xuqmconfig` file (XUQM-CONFIG-V1 format) downloaded from the tenant platform into `src/assets/config/`, then wrap your Metro config with `withXuqmConfig`: ```js // metro.config.js -const { getDefaultConfig } = require('metro-config'); -module.exports = (async () => { - const config = await getDefaultConfig(__dirname); - config.resolver.extraNodeModules = { - '@xuqm/autoinit-config': './path/to/your.xuqmconfig', - }; - return config; -})(); +const { getDefaultConfig } = require('@react-native/metro-config'); +const { withXuqmConfig } = require('@xuqm/rn-common/metro'); +const baseConfig = getDefaultConfig(__dirname); +module.exports = withXuqmConfig(baseConfig); ``` -That is it. When `@xuqm/rn-common` is imported, it silently calls `XuqmSDK.initWithConfigFile()` using the encrypted file. No explicit init code needed. +That is it. `withXuqmConfig` automatically discovers the config file from `src/assets/config/` (or `src/assets/xuqm/`) and wires up the virtual module. When `@xuqm/rn-common` is imported, it silently calls `XuqmSDK.initWithConfigFile()` using the encrypted file. No explicit init code needed. + +**Compatible fallback:** You can also manually configure a Babel/Metro alias for `@xuqm/autoinit-config` pointing to a `.ts` wrapper file. See `docs/配置文件规范.md` for details. ### Manual initialization @@ -260,6 +262,34 @@ Enhanced WebView with JSBridge for bidirectional communication between RN and we --- +### @xuqm/rn-bugcollect + +Error capture, crash reporting, and funnel analytics. Provides global JS error capture, custom event tracking, and batched async upload to the BugCollect service. + +| Export | Description | +|--------|-------------| +| `BugCollect.setLogLevel(level)` | Set minimum log level (`debug` / `info` / `warn` / `error`) | +| `BugCollect.setEnvironment(env)` | Set environment tag (`development` / `staging` / `production`) | +| `BugCollect.startCapture()` | Enable global JS error and unhandled Promise rejection capture | +| `BugCollect.event(name, properties?)` | Record a custom analytics event | +| `BugCollect.captureError(error, metadata?)` | Report a JS exception | +| `BugCollect.warn(message, metadata?)` | Log a warning | +| `BugCollect.info(message, metadata?)` | Log an info event | +| `BugCollect.defineFunnel(id, steps)` | Define a conversion funnel | +| `BugCollect.getFunnelProgress(funnelId)` | Get client-side funnel progress | +| `BugCollect.flush()` | Immediately flush all pending events | + +**Metro plugin:** `@xuqm/rn-bugcollect/metro` exports `withBugCollect` for automatic SourceMap upload on Release builds. + +```js +const { withBugCollect } = require('@xuqm/rn-bugcollect/metro'); +module.exports = withBugCollect(baseConfig); +``` + +**Config:** `bugCollectApiUrl` and `bugCollectEnabled` are automatically obtained from the platform config (`/api/sdk/config`) after `@xuqm/rn-common` init. No app-level configuration needed. + +--- + ## Development ### Prerequisites @@ -288,7 +318,7 @@ cd packages/common npm publish # Publish all packages (from each package directory) -for pkg in common im push update xwebview; do +for pkg in common im push update xwebview bugcollect; do cd packages/$pkg && npm publish && cd ../.. done ``` diff --git a/docs/架构总览.md b/docs/架构总览.md index e248505..e81b86e 100644 --- a/docs/架构总览.md +++ b/docs/架构总览.md @@ -21,7 +21,7 @@ ├── @xuqm/rn-im → IM 会话 / 消息(peerDep: rn-common) ├── @xuqm/rn-xwebview → WebView UI 组件(peerDep: rn-common) ├── @xuqm/rn-license → 证书授权(peerDep: rn-common) - └── @xuqm/rn-log → 日志 / 追踪(peerDep: rn-common) + └── @xuqm/rn-bugcollect → 错误采集 / Crash 捕获 / 漏斗分析(peerDep: rn-common) ``` ## 依赖关系 @@ -34,7 +34,7 @@ rn-common (核心,无 SDK 内部依赖) ├── rn-im (peerDep rn-common + watermelondb) ├── rn-xwebview (peerDep rn-common + webview + navigation) ├── rn-license (peerDep rn-common + quick-crypto) - └── rn-log (peerDep rn-common) + └── rn-bugcollect(peerDep rn-common) ``` ## 用户状态分发机制 @@ -56,18 +56,21 @@ XuqmSDK.setUserInfo(null) ## 初始化流程 -### 方式 A(自动) +### 方式 A(自动,推荐) ``` -Metro alias → @xuqm/autoinit-config → encrypted .xuqmconfig - ↓ import 时触发 -autoInit.ts → require('@xuqm/autoinit-config') +withXuqmConfig(metroConfig) 自动发现 src/assets/config/*.xuqmconfig + ↓ 生成虚拟模块 @xuqm/autoinit-config +import '@xuqm/rn-common' 时触发 + ↓ autoInit.ts → require('@xuqm/autoinit-config') ↓ 解密(PBKDF2 + AES-256-GCM) initWithConfigFile() → initialize({ appKey, platformUrl }) ↓ HTTP GET -/api/sdk/config → 返回 { apiUrl, imWsUrl, fileServiceUrl, ... } +/api/sdk/config → 返回 { apiUrl, imWsUrl, fileServiceUrl, bugCollectApiUrl, ... } ``` +兼容方式:手动配置 Babel/Metro alias `@xuqm/autoinit-config` → `.ts` 包装文件。 + ### 方式 B(手动) ``` @@ -83,11 +86,11 @@ App 代码调用 XuqmSDK.initialize({ appKey }) ``` App 代码 ↓ 调用 API -子 SDK(update/push/im/license/log) +子 SDK(update/push/im/license/bugcollect) ↓ 使用 apiRequest() rn-common http.ts ↓ 附加 Bearer Token + 处理响应 -平台服务(tenant-service / im-service / push-service / update-service / log-service) +平台服务(tenant-service / im-service / push-service / update-service / bugcollect-service) ``` ## 包发布 @@ -99,7 +102,7 @@ rn-common http.ts cd packages/common && npm publish # 发布所有包 -for pkg in common update push im xwebview license log; do +for pkg in common update push im xwebview license bugcollect; do cd packages/$pkg && npm publish && cd ../.. done ``` diff --git a/docs/配置文件规范.md b/docs/配置文件规范.md index 3cecb7a..afbd1fb 100644 --- a/docs/配置文件规范.md +++ b/docs/配置文件规范.md @@ -75,7 +75,26 @@ XUQM-CONFIG-V1.{base64urlSalt}.{base64urlIV}.{base64urlCiphertext} ### React Native(Metro bundler) -由于 Metro 只能 bundle JS/TS 模块,配置文件使用 `.ts` 扩展名。 +#### 推荐方式:withXuqmConfig Metro 插件 + +将平台下载的 `.xuqmconfig` 加密文件直接放入 `src/assets/config/`(推荐)或 `src/assets/xuqm/`,然后用 `withXuqmConfig` 包裹 Metro 配置: + +**文件位置**:`src/assets/config/config.xuqmconfig`(原始加密文件,无需改名或创建 `.ts` 包装) + +**Metro 配置**(`metro.config.js`): + +```javascript +const { getDefaultConfig } = require('@react-native/metro-config'); +const { withXuqmConfig } = require('@xuqm/rn-common/metro'); +const baseConfig = getDefaultConfig(__dirname); +module.exports = withXuqmConfig(baseConfig); +``` + +`withXuqmConfig` 会自动扫描 `src/assets/config/` 和 `src/assets/xuqm/` 目录,优先查找 `config.xuqmconfig` 或 `config.xuqm`,否则取第一个 `.xuqmconfig` 文件。找到后生成虚拟模块并注入 Metro 解析链,SDK import 时自动读取并初始化。 + +#### 兼容方式:手动 alias + +如果无法使用 Metro 插件,也可以手动配置 alias。由于 Metro 只能 bundle JS/TS 模块,配置文件使用 `.ts` 扩展名。 **文件位置**:`src/assets/xuqm/config.xuqmconfig.ts` diff --git a/packages/bugcollect/README.md b/packages/bugcollect/README.md index b30cfd0..96f5cef 100644 --- a/packages/bugcollect/README.md +++ b/packages/bugcollect/README.md @@ -84,6 +84,26 @@ console.log(progress?.completedSteps) // ['cart_view', 'checkout_start', 'paymen 3. **Fingerprint**:为每个错误生成指纹(基于 message + stack),用于服务端去重聚合 4. **FunnelTracker**:客户端维护漏斗进度,服务端跨 session 聚合 +## Metro 插件(SourceMap 自动上传) + +`@xuqm/rn-bugcollect/metro` 导出 `withBugCollect`,包裹 Metro 配置后,打 Release 包时自动上传 SourceMap: + +```js +// metro.config.js +const { getDefaultConfig } = require('@react-native/metro-config'); +const { withXuqmConfig } = require('@xuqm/rn-common/metro'); +const { withBugCollect } = require('@xuqm/rn-bugcollect/metro'); +const baseConfig = getDefaultConfig(__dirname); +module.exports = withBugCollect(withXuqmConfig(baseConfig)); +``` + +## 导出清单 + +| 导出 | 来源 | 说明 | +|------|------|------| +| `BugCollect` | `@xuqm/rn-bugcollect` | 主对象(setLogLevel / setEnvironment / startCapture / event / captureError / warn / info / defineFunnel / getFunnelProgress / flush) | +| `withBugCollect` | `@xuqm/rn-bugcollect/metro` | Metro 插件,自动上传 SourceMap | + ## 配置 `bugCollectApiUrl` 和 `bugCollectEnabled` 由 `@xuqm/rn-common` 在 init 后从 `/api/sdk/config` 自动获取,无需 App 传入。 diff --git a/packages/common/README.md b/packages/common/README.md index 540d8b9..bc909ce 100644 --- a/packages/common/README.md +++ b/packages/common/README.md @@ -14,17 +14,20 @@ Peer dependencies:`react >= 18`,`react-native >= 0.76`,`axios >= 1.0.0` ### 方式 A — 配置文件自动初始化(推荐) -在宿主项目中配置 Babel alias `@xuqm/autoinit-config` → 加密配置文件: +将平台下载的 `.xuqmconfig` 文件放入 `src/assets/config/`,然后用 `withXuqmConfig` Metro 插件自动发现: ```js // metro.config.js -config.resolver.extraNodeModules = { - '@xuqm/autoinit-config': './path/to/your.xuqmconfig', -}; +const { getDefaultConfig } = require('@react-native/metro-config'); +const { withXuqmConfig } = require('@xuqm/rn-common/metro'); +const baseConfig = getDefaultConfig(__dirname); +module.exports = withXuqmConfig(baseConfig); ``` SDK 在 import 时自动调用 `initWithConfigFile()`,App 无需任何 init 代码。 +**兼容方式**:也可手动配置 Babel alias `@xuqm/autoinit-config` → `.ts` 包装文件。 + ### 方式 B — 手动初始化 ```ts @@ -101,6 +104,12 @@ await XuqmSDK.awaitInitialization() // 等待配置拉取 | `showConfirm(title, msg)` | 显示确认对话框 | | `ScaledImage` | 等比缩放图片组件 | +### Metro 插件 + +| 导出 | 来源 | 说明 | +|------|------|------| +| `withXuqmConfig` | `@xuqm/rn-common/metro` | 自动发现 `.xuqmconfig` 配置文件并注入虚拟模块,推荐方式 | + ### 常量 | 常量 | 说明 |