@arms/rum-reactnative
v0.1.3-beta.4
Published
RUM SDK For ReactNative
Downloads
898
Readme
@arms/rum-reactnative
阿里云ARMS用户体验监控React Native SDK,用于在React Native应用中采集前端性能、异常及用户行为数据,并上报至ARMS控制台。
功能特性
- 原生崩溃采集 — 自动捕获 iOS(KSCrash)与 Android(Java + NDK)原生崩溃,支持堆栈双侧截断与数据体积优化
- API性能监控 — 自动拦截 XMLHttpRequest / fetch 请求,采集耗时、状态码等指标
- JS错误捕获 — 自动捕获 JavaScript 运行时异常
- 控制台错误监听 — 监听
console.error输出 - 链路追踪 — 支持多种传播协议的分布式链路追踪
- 页面导航追踪 — 集成 React Navigation,自动追踪页面切换
- 自定义事件上报 — 支持自定义业务数据、异常、资源、视图等事件上报
- Session管理 — 自动管理用户会话,支持采样率和超时配置
安装
npm install @arms/rum-reactnative自
0.1.3起,SDK 内置原生持久化实现(iOSNSUserDefaults/ AndroidSharedPreferences),不再依赖@react-native-async-storage/async-storage,无需额外安装。详见下方 存储说明。
SDK 包含原生崩溃采集模块(iOS:ObjC++ + KSCrash;Android:C/C++ + CMake),安装后必须重新构建原生工程,否则会报 TurboModule 方法缺失:
- iOS(bare workflow):
cd ios && pod install,再在 Xcode 重新 Build。 - Android(bare workflow):Gradle Sync 后重新 Build。
- Expo:
expo prebuild --clean后再expo run:ios/expo run:android。
原生编译环境:Android 需安装 NDK 与 CMake(可在 Android Studio 的 SDK Manager 中安装),iOS 需 CocoaPods(
pod install时自动拉取并编译 KSCrash)。由于崩溃采集模块以源码方式编译,首次构建耗时会略有增加,后续增量构建不受影响。
快速开始
在应用入口处初始化SDK:
import armsRum from '@arms/rum-reactnative';
armsRum.init({
endpoint: '<your-endpoint>'
});说明:
endpoint可在ARMS控制台创建应用后获取;
配置项
基础配置
| 配置项 | 类型 | 必填 | 默认值 | 说明 |
|-------|------|------|-------|------|
| endpoint | string | 是 | - | 数据上报地址 |
| env | string | 否 | 'prod' | 环境:'prod' | 'gray' | 'pre' | 'daily' | 'local' |
| version | string | 否 | - | 应用版本号 |
| user | object | 否 | - | 用户信息配置 |
| collectors | object | 否 | - | 采集器配置 |
| tracing | boolean | object | 否 | false | 链路追踪配置 |
| filters | object | 否 | - | 事件过滤配置 |
| properties | object | 否 | - | 全局自定义属性 |
| reportConfig | object | 否 | - | 上报配置 |
| sessionConfig | object | 否 | - | Session配置 |
| beforeReport | function | 否 | - | 上报前钩子函数 |
| parseViewName | function | 否 | - | 自定义解析页面名称 |
| parseResourceName | function | 否 | - | 自定义解析资源名称 |
| evaluateApi | function | 否 | - | 自定义API事件解析 |
user 用户配置
| 字段 | 类型 | 说明 | |------|------|------| | name | string | 用户名称(建议关联业务账号) | | tags | string | 用户标签 |
注意:
user.id由SDK自动生成并维护,不可自行设置。
collectors 采集器配置
| 采集器 | 类型 | 默认值 | 说明 |
|--------|------|-------|------|
| api | boolean | object | true | API请求监控(XMLHttpRequest / fetch) |
| jsError | boolean | object | true | JavaScript运行时错误捕获 |
| consoleError | boolean | object | true | console.error监听 |
sessionConfig Session配置
| 字段 | 类型 | 默认值 | 说明 |
|------|------|-------|------|
| sampleRate | number | 1 | 采样率,范围 [0, 1],0.5 表示 50% 采样 |
| maxDuration | number | 86400000 | Session最大持续时间(毫秒),默认24小时 |
| overtime | number | 3600000 | Session超时时间(毫秒),默认1小时无活动则过期 |
reportConfig 上报配置
| 字段 | 类型 | 默认值 | 说明 |
|------|------|-------|------|
| flushTime | number | 3000 | 上报时间间隔(ms),范围 [0, 10000],0 表示立即上报 |
| maxEventCount | number | 20 | 单次上报最大事件数,范围 [1, 100] |
tracing 链路追踪
支持布尔值开关或详细配置对象:
tracing: {
enable: true,
sample: 0.1, // 10% 采样
propagatorTypes: ['tracecontext', 'b3'],
allowedUrls: [
{ match: 'https://api.example.com/', propagatorTypes: ['tracecontext'] }
]
}支持的传播协议:
| 协议 | 说明 |
|------|------|
| tracecontext | W3C Trace Context |
| b3 | Zipkin B3 单头传播 |
| b3multi | Zipkin B3 多头传播 |
| jaeger | Jaeger |
| sw8 | SkyWalking |
filters 事件过滤
filters: {
resource: ['https://cdn.example.com/', /localhost/i],
exception: [/^Script error/, (msg) => msg.includes('ignore')],
view: ['/internal/']
}过滤规则支持以下类型:
| 类型 | 说明 |
|------|------|
| 字符串 | 前缀匹配,匹配到则过滤 |
| 正则表达式 | 正则匹配,匹配到则过滤 |
| 函数 | 返回 true 表示过滤该事件 |
API方法
armsRum.init(config)
初始化SDK,应在应用启动时调用。调用后SDK将根据配置自动开始数据采集和上报。
armsRum.setConfig(key, value) / armsRum.setConfig(config)
动态更新SDK配置。
// 单个配置更新
armsRum.setConfig('version', '1.2.0');
// 批量配置更新
armsRum.setConfig({
version: '1.2.0',
env: 'pre',
});armsRum.getConfig()
获取当前SDK配置对象。
事件上报
| 方法 | 说明 |
|------|------|
| armsRum.sendCustom(payload) | 上报自定义业务数据 |
| armsRum.sendException(payload \| Error) | 上报自定义异常 |
| armsRum.sendResource(payload) | 上报自定义资源事件 |
| armsRum.sendView(payload) | 上报自定义视图事件 |
| armsRum.sendEvent(payload) | 上报自定义事件 |
页面导航追踪
| 方法 | 说明 |
|------|------|
| armsRum.startTrackingViews(navigationRef) | 启动页面追踪 |
| armsRum.stopTrackingViews() | 停止页面追踪 |
高级用法
React Navigation 集成
方式一:onReady 回调模式
import React, { useRef } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import armsRum from '@arms/rum-reactnative';
export default function App() {
const navigationRef = useRef(null);
return (
<NavigationContainer
ref={navigationRef}
onReady={() => {
armsRum.startTrackingViews(navigationRef.current);
}}
>
{/* 路由配置 */}
</NavigationContainer>
);
}方式二:Hook 模式(推荐)
import React, { useEffect } from 'react';
import { useNavigationContainerRef } from '@react-navigation/native';
import armsRum from '@arms/rum-reactnative';
export default function App() {
const navigationContainerRef = useNavigationContainerRef();
useEffect(() => {
armsRum.startTrackingViews(navigationContainerRef.current);
}, []);
return (
<NavigationContainer ref={navigationContainerRef}>
{/* 路由配置 */}
</NavigationContainer>
);
}Expo 接入
SDK 提供一个零依赖的 Expo config plugin,便于在 Expo 工程中通过 app.config 声明 SDK 配置,避免在 JS 入口硬编码 endpoint。
在 app.config.ts 中:
const config = {
expo: {
plugins: [
['@arms/rum-reactnative', { endpoint: '<your-endpoint>', env: 'prod' }],
],
},
};
export default config;随后照常 expo prebuild / EAS Build。运行时通过 Constants.expoConfig?.extra?.rumSdk 读取该配置:
import { Constants } from 'expo-constants';
import armsRum from '@arms/rum-reactnative';
const cfg = (Constants.expoConfig?.extra as any)?.rumSdk;
armsRum.init({ endpoint: cfg?.endpoint, env: cfg?.env });即便不使用 config plugin,Expo 工程在
npm install后执行expo prebuild --clean即可由 autolinking 自动接入原生模块;plugin 仅提供配置透传的便利。
原生代码集成方式
SDK 的原生崩溃采集层通过源码编译集成,不预编译二进制随 npm 包发布:
- iOS:KSCrash 通过 CocoaPods 源码依赖(
s.dependency "KSCrash")引入,pod install时自动编译。 - Android:
librum_crash.so由宿主工程 Gradle 通过externalNativeBuild(CMake)在构建时编译,需 NDK / CMake(RN 工程通常已具备)。
原生模块会在宿主工程构建时自动编译,无需额外的预编译产物或手动步骤。
自定义API解析(evaluateApi)
当默认的API事件解析逻辑不满足需求时,可通过 evaluateApi 自定义解析。函数接收以下参数:
- request — 请求信息
- response — 响应信息
- error — 错误信息
- xhr — 原始XHR对象
返回值为 IApiBaseAttr 对象:
armsRum.init({
endpoint: '<your-endpoint>',
evaluateApi: async (request, response, error) => {
return {
name: '/api/list',
success: error ? 0 : 1,
duration: 100,
snapshots: JSON.stringify({ params: 'page=1' }),
};
}
});自定义事件上报示例
// 自定义业务事件
armsRum.sendCustom({
name: 'order_placed',
properties: { order_id: 'ORD-12345', amount: 99.99 }
});
// 手动上报异常
try {
// 业务逻辑
} catch (error) {
armsRum.sendException(error);
}beforeReport 钩子
在事件上报前进行修改或过滤:
armsRum.init({
beforeReport(event) {
// 返回修改后的event,返回 false 则丢弃该事件
return event;
}
});完整配置示例
import armsRum from '@arms/rum-reactnative';
armsRum.init({
// 基础配置
endpoint: '<your-endpoint>',
env: 'prod',
version: '1.0.0',
// 用户配置
user: {
name: 'zhangsan',
tags: 'vip',
},
// 采集器配置
collectors: {
api: true,
jsError: true,
consoleError: true,
},
// 链路追踪
tracing: {
enable: true,
sample: 0.1,
propagatorTypes: ['tracecontext'],
allowedUrls: [
{ match: 'https://api.example.com/', propagatorTypes: ['tracecontext'] }
],
},
// 事件过滤
filters: {
resource: ['https://cdn.example.com/'],
exception: [/^Script error/],
},
// 全局自定义属性
properties: {
channel: 'appstore',
},
// 上报配置
reportConfig: {
flushTime: 5000,
maxEventCount: 30,
},
// Session配置
sessionConfig: {
sampleRate: 1,
maxDuration: 86400000,
overtime: 3600000,
},
// 上报前钩子
beforeReport(event) {
return event;
},
});存储说明
SDK 仅持久化一个键 _arms_uid(匿名用户 UID),用于跨冷启动保持 UV 稳定。底层采用各平台原生轻量级 KV 存储:
| 平台 | 实现 | 命名空间 |
|------|------|----------|
| iOS | NSUserDefaults(独立 suite) | com.aliyun.arms.rum.reactnative |
| Android | SharedPreferences(独立 prefs 文件) | com.aliyun.arms.rum.reactnative |
原生存储 API
原生模块提供以下能力(全部为异步 Promise,且仅作用于上表的独立命名空间,不会读写宿主 App 的偏好数据):
| 方法 | 返回 | 说明 |
|------|------|------|
| getItem(key) | Promise<string \| null> | 读取字符串值,不存在返回 null |
| setItem(key, value) | Promise<void> | 写入字符串值 |
| removeItem(key) | Promise<void> | 删除指定 key |
| clear() | Promise<void> | 清空 SDK 命名空间下的所有 key |
| getAllKeys() | Promise<string[]> | 列出 SDK 命名空间下的所有 key |
该原生模块主要服务于 SDK 内部,不属于公开 API;如有定制场景需要直接调用,可从
@arms/rum-reactnative内部模块引入,未来版本可能调整签名。
升级 / 接入注意事项
- 必须重新构建原生工程:新增了 TurboModule 方法,升级或首次接入后需要重新执行 iOS 的
pod install、Android 的 Gradle Sync;Expo 工程请执行expo prebuild --clean后再编译,否则会报 protocol method 缺失。 - 隔离命名空间,不污染宿主 App:iOS 走独立
NSUserDefaultssuite、Android 走独立 prefs 文件,与宿主 App 自身的偏好数据互不干扰;用户卸载 / 抹机时会一并清除。 - 从旧版本(依赖 AsyncStorage)升级会重置一次 UID:原 AsyncStorage 中的
_arms_uid不会自动迁移到新存储,老用户首次升级后会被分配新 UID(仅影响一次 UV 统计的连续性,不影响功能与后续使用)。如对历史 UID 连续性有强诉求,请提 issue。
版本要求
SDK 的 peerDependencies 声明为 react-native: >=0.68.0,原生构建配置已做多版本条件适配,不同功能点的实际要求如下:
| 功能点 | 关键依赖 / API | 最低 RN 版本 | 说明 |
|--------|--------------|-------------|------|
| 原生崩溃采集 | TurboModule + codegen | 0.68 | podspec / build.gradle 按版本条件分支,自动适配 0.68-0.70 和 0.71+ |
| NDK 崩溃采集(C/C++) | CMake + NDK externalNativeBuild | 0.68 | 随原生崩溃采集一起启用 |
| iOS 崩溃采集(KSCrash) | KSCrash ~2.0(CocoaPods 源码依赖) | 0.68 | pod install 时自动编译 |
| JS 异常采集 | ErrorUtils.setGlobalHandler | 0.68 | 全版本可用 |
| Hermes Promise rejection | HermesInternal.enablePromiseRejectionTracker | 0.70(推荐) | Hermes 为默认引擎时完整支持 |
| JSC Promise rejection 兜底 | globalThis.onunhandledrejection | 0.68 | 非 Hermes 引擎有降级方案 |
| console.error 监听 | interceptFunction(console, 'error') | 0.68 | 全版本可用 |
| API 性能监控 | XMLHttpRequest.prototype 拦截 | 0.68 | 全版本可用 |
| fetch 拦截 | globalThis.fetch patch | 0.68 | 当前已注释,仅启用 XHR 拦截 |
| 分布式链路追踪 | tracecontext / b3 / jaeger / sw8 | 0.68 | 纯 JS 实现,无原生依赖 |
| 页面导航追踪(PV) | React Navigation addListener('state') | 0.68 | 兼容 React Navigation v5 / v6 |
| 用户行为采集(Action) | patch React.createElement | 0.68 | 经典 JSX 运行时 |
| Pressable 组件支持 | RN.Pressable | 0.68 | Pressable 在 0.63 引入,下限受 peerDependencies 约束 |
| automatic JSX runtime patch | react/jsx-runtime 的 jsx / jsxs / jsxDEV | 0.73(推荐) | automatic runtime 在 RN 0.73+ 为默认 |
| 设备信息采集 | Platform.OS / Dimensions.get() | 0.68 | 全版本可用,原生桥失败有 JS 降级 |
| 自监控(Self-Monitoring) | fetch 上报 Protobuf 至 /rum/monitor | 0.68 | 纯 JS 实现 |
| Expo 集成 | Expo Config Plugin | Expo SDK 49+(RN 0.72+) | 仅配置透传,零运行时依赖 |
总结:SDK 声明支持 RN ≥ 0.68,原生构建配置(podspec / build.gradle)已做多版本条件适配。RN 0.71+ 使用
install_modules_dependencies/react-android;RN 0.68-0.70 使用手动依赖 /react-native:+。JS 侧通过TurboModuleRegistry.get+NativeModules双路径获取原生模块,原生模块缺失时自动降级为空实现,不影响纯 JS 能力。
