@arms/rum-reactnative 0.1.3-beta.5 → 0.1.4-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/android/build.gradle +12 -1
- package/android/gradle.properties +3 -1
- package/android/src/main/AndroidManifest.xml +4 -1
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +67 -14
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +9 -2
- package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +25 -0
- package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +20 -0
- package/docs//346/216/245/345/205/245ReactNative/345/272/224/347/224/250.md +2 -1
- package/ios/RumAppStateRecorder.h +69 -0
- package/ios/RumAppStateRecorder.mm +547 -0
- package/ios/RumCrashReporter.h +32 -0
- package/ios/RumCrashReporter.mm +97 -11
- package/ios/RumSdkReactnative.h +11 -1
- package/ios/RumSdkReactnative.mm +115 -29
- package/lib/commonjs/NativeRumSdkReactnative.js +1 -54
- package/lib/commonjs/collector/action/index.js +1 -108
- package/lib/commonjs/collector/exception/crash.js +1 -148
- package/lib/commonjs/collector/exception/index.js +1 -238
- package/lib/commonjs/collector/exception/oom.js +1 -0
- package/lib/commonjs/collector/index.js +1 -42
- package/lib/commonjs/collector/resource/api.js +1 -292
- package/lib/commonjs/collector/view/perf.js +1 -79
- package/lib/commonjs/collector/view/pv.js +1 -88
- package/lib/commonjs/expoConfigPlugin.js +1 -37
- package/lib/commonjs/index.js +1 -29
- package/lib/commonjs/plugin.js +1 -47
- package/lib/commonjs/processor/default-processor.js +1 -27
- package/lib/commonjs/processor/session-processor.js +1 -47
- package/lib/commonjs/reporter/index.js +1 -148
- package/lib/commonjs/reporter/monitor-reporter.js +1 -43
- package/lib/commonjs/shell.js +1 -91
- package/lib/commonjs/types/client.js +1 -6
- package/lib/commonjs/types/crash.js +1 -37
- package/lib/commonjs/types/index.js +1 -2
- package/lib/commonjs/types/oom.js +1 -0
- package/lib/commonjs/utils/action.js +1 -305
- package/lib/commonjs/utils/api.js +1 -84
- package/lib/commonjs/utils/base.js +1 -95
- package/lib/commonjs/utils/crash.js +1 -149
- package/lib/commonjs/utils/platform.js +1 -162
- package/lib/commonjs/utils/session.js +1 -158
- package/lib/commonjs/utils/url.js +1 -59
- package/lib/commonjs/utils/view.js +1 -93
- package/lib/module/NativeRumSdkReactnative.js +1 -51
- package/lib/module/collector/action/index.js +1 -103
- package/lib/module/collector/exception/crash.js +1 -143
- package/lib/module/collector/exception/index.js +1 -233
- package/lib/module/collector/exception/oom.js +1 -0
- package/lib/module/collector/index.js +1 -8
- package/lib/module/collector/resource/api.js +1 -287
- package/lib/module/collector/view/perf.js +1 -79
- package/lib/module/collector/view/pv.js +1 -83
- package/lib/module/expoConfigPlugin.js +1 -33
- package/lib/module/index.js +1 -7
- package/lib/module/plugin.js +1 -42
- package/lib/module/processor/default-processor.js +1 -22
- package/lib/module/processor/session-processor.js +1 -42
- package/lib/module/reporter/index.js +1 -144
- package/lib/module/reporter/monitor-reporter.js +1 -38
- package/lib/module/shell.js +1 -84
- package/lib/module/types/client.js +1 -4
- package/lib/module/types/crash.js +1 -33
- package/lib/module/types/index.js +1 -2
- package/lib/module/types/oom.js +1 -0
- package/lib/module/utils/action.js +1 -299
- package/lib/module/utils/api.js +1 -76
- package/lib/module/utils/base.js +1 -90
- package/lib/module/utils/crash.js +1 -144
- package/lib/module/utils/platform.js +1 -150
- package/lib/module/utils/session.js +1 -154
- package/lib/module/utils/url.js +1 -54
- package/lib/module/utils/view.js +1 -88
- package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +10 -0
- package/lib/typescript/commonjs/src/collector/exception/oom.d.ts +34 -0
- package/lib/typescript/commonjs/src/collector/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/shell.d.ts +1 -1
- package/lib/typescript/commonjs/src/types/client.d.ts +27 -0
- package/lib/typescript/commonjs/src/types/oom.d.ts +58 -0
- package/lib/typescript/commonjs/src/utils/crash.d.ts +13 -0
- package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +10 -0
- package/lib/typescript/module/src/collector/exception/oom.d.ts +34 -0
- package/lib/typescript/module/src/collector/index.d.ts +1 -0
- package/lib/typescript/module/src/shell.d.ts +1 -1
- package/lib/typescript/module/src/types/client.d.ts +27 -0
- package/lib/typescript/module/src/types/oom.d.ts +58 -0
- package/lib/typescript/module/src/utils/crash.d.ts +13 -0
- package/package.json +1 -2
- package/src/NativeRumSdkReactnative.ts +18 -0
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
## 功能特性
|
|
6
6
|
|
|
7
7
|
- **原生崩溃采集** — 自动捕获 iOS(KSCrash)与 Android(Java + NDK)原生崩溃,支持堆栈双侧截断与数据体积优化
|
|
8
|
+
- **OOM采集(iOS)** — 看门狗终止(Watchdog Termination / FOOM)的事后推断上报,默认关闭,需显式开启
|
|
8
9
|
- **API性能监控** — 自动拦截 XMLHttpRequest / fetch 请求,采集耗时、状态码等指标
|
|
9
10
|
- **JS错误捕获** — 自动捕获 JavaScript 运行时异常
|
|
10
11
|
- **控制台错误监听** — 监听 `console.error` 输出
|
|
@@ -81,6 +82,7 @@ armsRum.init({
|
|
|
81
82
|
| api | boolean \| object | `true` | API请求监控(XMLHttpRequest / fetch) |
|
|
82
83
|
| jsError | boolean \| object | `true` | JavaScript运行时错误捕获 |
|
|
83
84
|
| consoleError | boolean \| object | `true` | `console.error`监听 |
|
|
85
|
+
| oom | boolean | `false` | OOM(iOS 看门狗终止推断)采集,仅 iOS 前台场景,需显式开启,详见[配置参考](docs/ReactNative%20SDK配置参考.md) |
|
|
84
86
|
|
|
85
87
|
### sessionConfig Session配置
|
|
86
88
|
|
|
@@ -418,6 +420,7 @@ SDK 仅持久化一个键 `_arms_uid`(匿名用户 UID),用于跨冷启动
|
|
|
418
420
|
1. **必须重新构建原生工程**:新增了 TurboModule 方法,升级或首次接入后需要重新执行 iOS 的 `pod install`、Android 的 Gradle Sync;Expo 工程请执行 `expo prebuild --clean` 后再编译,否则会报 protocol method 缺失。
|
|
419
421
|
2. **隔离命名空间,不污染宿主 App**:iOS 走独立 `NSUserDefaults` suite、Android 走独立 prefs 文件,与宿主 App 自身的偏好数据互不干扰;用户卸载 / 抹机时会一并清除。
|
|
420
422
|
3. **从旧版本(依赖 AsyncStorage)升级会重置一次 UID**:原 AsyncStorage 中的 `_arms_uid` 不会自动迁移到新存储,老用户首次升级后会被分配新 UID(仅影响一次 UV 统计的连续性,不影响功能与后续使用)。如对历史 UID 连续性有强诉求,请提 issue。
|
|
423
|
+
4. **RN 0.68-0.70 的 Android 宿主前置条件**:宿主工程 `android/build.gradle` 的 buildscript 需存在 `kotlin-gradle-plugin` classpath,且 Kotlin 版本 **≥ 1.8.0**(RN 0.70 模板默认 1.6.x,无法读取 SDK 依赖的 kotlin-stdlib 1.8 metadata,需手动提升)。AGP 无需改动——SDK 构建脚本对 AGP <7.3 自动回退 AndroidManifest package 属性。iOS 侧无额外配置,`pod install` 即可(0.68-0.70 自动走旧桥导出路径)。因含原生代码,**Expo Go 不可用**(需 `expo prebuild` 或 EAS Build)。
|
|
421
424
|
|
|
422
425
|
## 版本要求
|
|
423
426
|
|
|
@@ -425,9 +428,10 @@ SDK 的 peerDependencies 声明为 `react-native: >=0.68.0`,原生构建配置
|
|
|
425
428
|
|
|
426
429
|
| 功能点 | 关键依赖 / API | 最低 RN 版本 | 说明 |
|
|
427
430
|
|--------|--------------|-------------|------|
|
|
428
|
-
| **原生崩溃采集** | TurboModule + codegen | 0.68 |
|
|
431
|
+
| **原生崩溃采集** | TurboModule + codegen | 0.68 | 自动适配 0.68-0.70 旧桥导出与 0.71+ Spec 协议/interop;RN ≤0.70 Android 前置条件见注意事项 4 |
|
|
429
432
|
| NDK 崩溃采集(C/C++) | CMake + NDK `externalNativeBuild` | 0.68 | 随原生崩溃采集一起启用 |
|
|
430
433
|
| iOS 崩溃采集(KSCrash) | KSCrash 2.5.1(CocoaPods 源码依赖,已锁定版本) | 0.68 | `pod install` 时自动编译 |
|
|
434
|
+
| **OOM 采集(iOS)** | TurboModule + KSCrash + 状态快照持久化 | 0.68 | 仅 iOS,默认关闭(`collectors.oom` 显式开启);Android 为空实现 |
|
|
431
435
|
| **JS 异常采集** | `ErrorUtils.setGlobalHandler` | 0.68 | 全版本可用 |
|
|
432
436
|
| Hermes Promise rejection | `HermesInternal.enablePromiseRejectionTracker` | 0.70(推荐) | Hermes 为默认引擎时完整支持 |
|
|
433
437
|
| JSC Promise rejection 兜底 | `globalThis.onunhandledrejection` | 0.68 | 非 Hermes 引擎有降级方案 |
|
|
@@ -443,8 +447,11 @@ SDK 的 peerDependencies 声明为 `react-native: >=0.68.0`,原生构建配置
|
|
|
443
447
|
| **自监控(Self-Monitoring)** | `fetch` 上报 Protobuf 至 `/rum/monitor` | 0.68 | 纯 JS 实现 |
|
|
444
448
|
| **Expo 集成** | Expo Config Plugin | Expo SDK 49+(RN 0.72+) | 仅配置透传,零运行时依赖 |
|
|
445
449
|
|
|
446
|
-
> **总结**:SDK 声明支持 RN ≥ 0.68
|
|
450
|
+
> **总结**:SDK 声明支持 RN ≥ 0.68。iOS 经 `__has_include` 条件协议 + `RCT_EXPORT_METHOD` 旧桥导出、Android 经 `@ReactMethod` 方法表 + `namespace` DSL 条件守卫,原生能力在 0.68-0.70(旧桥路径)与 0.71+(TurboModule 协议 / interop)均可用;构建层 RN 0.71+ 使用 `install_modules_dependencies` / `react-android`,0.68-0.70 使用手动依赖 / `react-native:+`。JS 侧通过 `TurboModuleRegistry.get` + `NativeModules` 双路径获取原生模块,原生模块缺失时自动降级为空实现,不影响纯 JS 能力。RN ≤0.70 的 Android 宿主需满足 Kotlin ≥1.8 前置条件(见「升级 / 接入注意事项」第 4 条)。
|
|
447
451
|
|
|
448
452
|
## 相关文档
|
|
449
453
|
|
|
454
|
+
- [接入ReactNative应用](docs/接入ReactNative应用.md)
|
|
455
|
+
- [ReactNative SDK配置参考](docs/ReactNative%20SDK配置参考.md)
|
|
456
|
+
- [SDK 版本说明](docs/SDK%20版本说明.md)
|
|
450
457
|
- [ARMS用户体验监控文档](https://help.aliyun.com/zh/arms/user-experience-monitoring/)
|
package/android/build.gradle
CHANGED
|
@@ -70,7 +70,11 @@ if (isRn71Plus) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
android {
|
|
73
|
-
namespace
|
|
73
|
+
// AGP 7.3+ 才支持 namespace DSL(RN 0.70 模板默认 AGP 7.2.1);低版本回退
|
|
74
|
+
// AndroidManifest.xml 的 package 属性(RN 0.68-0.70 兼容,见 dev-docs 打通方案 A1)
|
|
75
|
+
if (android.hasProperty("namespace")) {
|
|
76
|
+
namespace "com.rumsdkreactnative"
|
|
77
|
+
}
|
|
74
78
|
|
|
75
79
|
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
76
80
|
|
|
@@ -109,6 +113,13 @@ android {
|
|
|
109
113
|
}
|
|
110
114
|
}
|
|
111
115
|
|
|
116
|
+
// CMake 显式链接 c++_shared 与 react-android 携带的同名 so 在 androidTest 变体
|
|
117
|
+
// 合并时冲突(mergeAndroidTestNativeLibs 报 2 files found)。两者为同一 STL,取任一
|
|
118
|
+
// 均可,pickFirst 去重(库模块自身声明,宿主无需额外配置)。
|
|
119
|
+
packagingOptions {
|
|
120
|
+
pickFirst "**/libc++_shared.so"
|
|
121
|
+
}
|
|
122
|
+
|
|
112
123
|
lintOptions {
|
|
113
124
|
disable "GradleCompatible"
|
|
114
125
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
# 默认 1.8.0:stdlib metadata 可被 1.8+ 编译器读取(向上兼容),覆盖 RN 0.68-0.70
|
|
2
|
+
# 手动配置场景与 0.71+ 默认工具链;宿主 rootProject.ext.kotlinVersion 定义时优先跟随宿主
|
|
3
|
+
RumSdkReactnative_kotlinVersion=1.8.0
|
|
2
4
|
RumSdkReactnative_minSdkVersion=24
|
|
3
5
|
RumSdkReactnative_targetSdkVersion=34
|
|
4
6
|
RumSdkReactnative_compileSdkVersion=35
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
<
|
|
1
|
+
<!-- package 属性:AGP <7.3(RN 0.68-0.70)下的包名来源;AGP 7.3+ 由 build.gradle
|
|
2
|
+
条件 namespace 取代(该属性被忽略,仅 deprecation warning,属预期) -->
|
|
3
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
4
|
+
package="com.rumsdkreactnative">
|
|
2
5
|
<application>
|
|
3
6
|
<!--
|
|
4
7
|
崩溃处理器自启动:通过 ContentProvider 在 Application.onCreate() 之前安装
|
|
@@ -10,6 +10,8 @@ import android.view.WindowManager
|
|
|
10
10
|
import com.facebook.react.bridge.Arguments
|
|
11
11
|
import com.facebook.react.bridge.Promise
|
|
12
12
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
13
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
14
|
+
import com.facebook.react.bridge.ReactMethod
|
|
13
15
|
import com.facebook.react.module.annotations.ReactModule
|
|
14
16
|
import com.rumsdkreactnative.crash.CrashContextManager
|
|
15
17
|
import com.rumsdkreactnative.crash.CrashHandler
|
|
@@ -17,9 +19,13 @@ import org.json.JSONArray
|
|
|
17
19
|
import org.json.JSONObject
|
|
18
20
|
import java.io.File
|
|
19
21
|
|
|
22
|
+
// 不继承 codegen 生成的 Spec 基类(RN ≤0.70 不运行 codegen、无此产物,见
|
|
23
|
+
// dev-docs/RN 0.68-0.70 兼容性打通方案.md A2):直接继承 ReactContextBaseJavaModule,
|
|
24
|
+
// 方法经 @ReactMethod 导出(RN 0.71+ 经 TurboModule interop 调用);
|
|
25
|
+
// 代价是失去 codegen 对 TS Spec 与原生签名一致性的编译期校验,签名变更需人工同步 Spec
|
|
20
26
|
@ReactModule(name = RumSdkReactnativeModule.NAME)
|
|
21
27
|
class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
22
|
-
|
|
28
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
23
29
|
|
|
24
30
|
private val prefs: SharedPreferences =
|
|
25
31
|
migratePrefs(reactContext).also {
|
|
@@ -36,7 +42,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
36
42
|
|
|
37
43
|
// region Storage
|
|
38
44
|
|
|
39
|
-
|
|
45
|
+
@ReactMethod
|
|
46
|
+
fun getItem(key: String, promise: Promise) {
|
|
40
47
|
try {
|
|
41
48
|
promise.resolve(prefs.getString(key, null))
|
|
42
49
|
} catch (e: Throwable) {
|
|
@@ -44,7 +51,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
@ReactMethod
|
|
55
|
+
fun setItem(key: String, value: String, promise: Promise) {
|
|
48
56
|
try {
|
|
49
57
|
prefs.edit().putString(key, value).apply()
|
|
50
58
|
promise.resolve(null)
|
|
@@ -53,7 +61,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
53
61
|
}
|
|
54
62
|
}
|
|
55
63
|
|
|
56
|
-
|
|
64
|
+
@ReactMethod
|
|
65
|
+
fun removeItem(key: String, promise: Promise) {
|
|
57
66
|
try {
|
|
58
67
|
prefs.edit().remove(key).apply()
|
|
59
68
|
promise.resolve(null)
|
|
@@ -62,7 +71,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
62
71
|
}
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
|
|
74
|
+
@ReactMethod
|
|
75
|
+
fun clear(promise: Promise) {
|
|
66
76
|
try {
|
|
67
77
|
prefs.edit().clear().apply()
|
|
68
78
|
promise.resolve(null)
|
|
@@ -71,7 +81,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
71
81
|
}
|
|
72
82
|
}
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
@ReactMethod
|
|
85
|
+
fun getAllKeys(promise: Promise) {
|
|
75
86
|
try {
|
|
76
87
|
val array = Arguments.createArray()
|
|
77
88
|
for (key in prefs.all.keys) {
|
|
@@ -87,7 +98,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
87
98
|
|
|
88
99
|
// region Device Info
|
|
89
100
|
|
|
90
|
-
|
|
101
|
+
@ReactMethod
|
|
102
|
+
fun getDeviceInfo(promise: Promise) {
|
|
91
103
|
try {
|
|
92
104
|
val ctx = reactApplicationContext
|
|
93
105
|
val map = Arguments.createMap()
|
|
@@ -170,7 +182,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
170
182
|
* 崩溃文件命名:crash_{timestamp}_{id}.json(Java)或 crash_native_{timestamp}_{pid}.json(NDK)
|
|
171
183
|
* 注意:排除 context 文件(.rum_crash_context)和临时文件
|
|
172
184
|
*/
|
|
173
|
-
|
|
185
|
+
@ReactMethod
|
|
186
|
+
fun getPendingCrashes(promise: Promise) {
|
|
174
187
|
try {
|
|
175
188
|
val arr = JSONArray()
|
|
176
189
|
if (crashDir.exists() && crashDir.isDirectory) {
|
|
@@ -244,7 +257,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
244
257
|
/**
|
|
245
258
|
* 解析 crashIds JSON array,按 crash_id 删除对应文件。
|
|
246
259
|
*/
|
|
247
|
-
|
|
260
|
+
@ReactMethod
|
|
261
|
+
fun clearCrashReports(crashIds: String, promise: Promise) {
|
|
248
262
|
try {
|
|
249
263
|
val ids = HashSet<String>()
|
|
250
264
|
if (crashIds.isNotEmpty()) {
|
|
@@ -307,7 +321,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
307
321
|
}
|
|
308
322
|
|
|
309
323
|
/** 上次运行是否发生过崩溃:crashDir 中存在崩溃报告文件即认为发生过 */
|
|
310
|
-
|
|
324
|
+
@ReactMethod
|
|
325
|
+
fun crashedLastRun(promise: Promise) {
|
|
311
326
|
try {
|
|
312
327
|
val crashed = crashDir.exists() &&
|
|
313
328
|
(crashDir.listFiles()?.any { it.isFile && isCrashReportFile(it.name) } ?: false)
|
|
@@ -318,7 +333,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
318
333
|
}
|
|
319
334
|
|
|
320
335
|
/** 更新崩溃上下文快照(session/view 变更时调用) */
|
|
321
|
-
|
|
336
|
+
@ReactMethod
|
|
337
|
+
fun updateCrashContext(context: String) {
|
|
322
338
|
try {
|
|
323
339
|
crashContextManager.updateContext(context)
|
|
324
340
|
} catch (_: Throwable) {
|
|
@@ -327,7 +343,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
327
343
|
}
|
|
328
344
|
|
|
329
345
|
/** 清除所有崩溃报告文件(用于清理无 crash_id 的旧版 NDK 文件) */
|
|
330
|
-
|
|
346
|
+
@ReactMethod
|
|
347
|
+
fun clearAllCrashReports(promise: Promise) {
|
|
331
348
|
try {
|
|
332
349
|
if (crashDir.exists() && crashDir.isDirectory) {
|
|
333
350
|
val files = crashDir.listFiles { f -> isCrashReportFile(f.name) }
|
|
@@ -346,7 +363,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
346
363
|
}
|
|
347
364
|
|
|
348
365
|
/** 清理过期和超限的崩溃文件 */
|
|
349
|
-
|
|
366
|
+
@ReactMethod
|
|
367
|
+
fun cleanupOldCrashes(maxFiles: Double, maxAgeMs: Double, promise: Promise) {
|
|
350
368
|
try {
|
|
351
369
|
if (!crashDir.exists() || !crashDir.isDirectory) {
|
|
352
370
|
promise.resolve(null)
|
|
@@ -422,11 +440,46 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
422
440
|
|
|
423
441
|
// endregion
|
|
424
442
|
|
|
443
|
+
// region OOM (iOS-only watchdog termination, no-op on Android)
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Android 无 OOM(看门狗终止推断)能力(D2):Java OutOfMemoryError
|
|
447
|
+
* 已由 CrashHandler 崩溃链路捕获,系统低内存杀进程检测不在本期范围。
|
|
448
|
+
* 空实现仅为满足 TurboModule Spec 双端对齐。
|
|
449
|
+
*/
|
|
450
|
+
@ReactMethod
|
|
451
|
+
fun getPendingOomReports(promise: Promise) {
|
|
452
|
+
try {
|
|
453
|
+
promise.resolve("[]")
|
|
454
|
+
} catch (e: Throwable) {
|
|
455
|
+
promise.reject(ERR_CRASH, e)
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/** 清除 OOM 报告文件:Android 无 OOM 文件,no-op */
|
|
460
|
+
@ReactMethod
|
|
461
|
+
fun clearOomReports(oomIds: String, promise: Promise) {
|
|
462
|
+
try {
|
|
463
|
+
promise.resolve(null)
|
|
464
|
+
} catch (e: Throwable) {
|
|
465
|
+
promise.reject(ERR_CRASH, e)
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/** 同步 JS 侧采集器配置(如 oom 开关):Android 无 OOM 能力,接受但忽略 */
|
|
470
|
+
@ReactMethod
|
|
471
|
+
fun updateCollectorsConfig(config: String) {
|
|
472
|
+
// no-op
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// endregion
|
|
476
|
+
|
|
425
477
|
// region Test Crash
|
|
426
478
|
|
|
427
479
|
private external fun nativeTriggerCrash(type: Int)
|
|
428
480
|
|
|
429
|
-
|
|
481
|
+
@ReactMethod
|
|
482
|
+
fun triggerTestCrash(crashType: String) {
|
|
430
483
|
when (crashType) {
|
|
431
484
|
// TurboModule 架构下,@ReactMethod void 方法中抛出的 Java 异常会被 C++ 层
|
|
432
485
|
// 拦截并转换为 JS 异常,不会到达 Thread.getDefaultUncaughtExceptionHandler()。
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
package com.rumsdkreactnative
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// 基类用 TurboReactPackage 而非 BaseReactPackage(见 dev-docs/RN 0.68-0.70 兼容性打通方案
|
|
4
|
+
// 方案 A4):BaseReactPackage 为 RN 0.74 新增类,RN 0.68-0.73 宿主下编译失败;
|
|
5
|
+
// TurboReactPackage 自 RN 0.68 起存在(0.76+ 标记 deprecated 但仍可用,仅为警告)。
|
|
6
|
+
// 两者抽象方法签名一致(getModule / getReactModuleInfoProvider)。
|
|
7
|
+
import com.facebook.react.TurboReactPackage
|
|
4
8
|
import com.facebook.react.bridge.NativeModule
|
|
5
9
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
10
|
import com.facebook.react.module.model.ReactModuleInfo
|
|
7
11
|
import com.facebook.react.module.model.ReactModuleInfoProvider
|
|
8
12
|
import java.util.HashMap
|
|
9
13
|
|
|
10
|
-
class RumSdkReactnativePackage :
|
|
14
|
+
class RumSdkReactnativePackage : TurboReactPackage() {
|
|
11
15
|
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
|
|
12
16
|
return if (name == RumSdkReactnativeModule.NAME) {
|
|
13
17
|
RumSdkReactnativeModule(reactContext)
|
|
@@ -19,11 +23,14 @@ class RumSdkReactnativePackage : BaseReactPackage() {
|
|
|
19
23
|
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
|
|
20
24
|
return ReactModuleInfoProvider {
|
|
21
25
|
val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
|
|
26
|
+
// 7 参构造(含 hasConstants):RN ≤0.72 仅提供此签名;0.73+ 保留为 deprecated
|
|
27
|
+
// 兼容构造(hasConstants 被忽略),故 0.68-0.79+ 全版本可编译。模块无 constants,传 false。
|
|
22
28
|
moduleInfos[RumSdkReactnativeModule.NAME] = ReactModuleInfo(
|
|
23
29
|
RumSdkReactnativeModule.NAME,
|
|
24
30
|
RumSdkReactnativeModule.NAME,
|
|
25
31
|
false, // canOverrideExistingModule
|
|
26
32
|
false, // needsEagerInit
|
|
33
|
+
false, // hasConstants(RN ≤0.72 必填,0.73+ 忽略)
|
|
27
34
|
false, // isCxxModule
|
|
28
35
|
true // isTurboModule
|
|
29
36
|
)
|
|
@@ -104,6 +104,7 @@ Collector是RUM SDK用于收集React Native应用监控数据的最小单元。
|
|
|
104
104
|
| api | boolean \| object | 监听API请求(XMLHttpRequest / fetch) | 否 | true |
|
|
105
105
|
| jsError | boolean \| object | 监听JS错误 | 否 | true |
|
|
106
106
|
| consoleError | boolean \| object | 监听Console错误 | 否 | true |
|
|
107
|
+
| oom | boolean | OOM(iOS看门狗终止推断)采集,详细说明请参见[oom配置](#oom-配置) | 否 | false |
|
|
107
108
|
|
|
108
109
|
### 示例
|
|
109
110
|
|
|
@@ -131,6 +132,30 @@ armsRum.init({
|
|
|
131
132
|
});
|
|
132
133
|
```
|
|
133
134
|
|
|
135
|
+
## oom 配置
|
|
136
|
+
|
|
137
|
+
iOS看门狗终止(Watchdog Termination / FOOM,前台 OOM)的事后推断采集。App在前台被系统看门狗终止时无任何信号可捕获,表现为无提示"闪退",现有崩溃管线天然采集不到;开启本能力后,SDK在运行期持续持久化 App 状态快照,下次冷启动时用排除法推断上次是否发生看门狗终止,并通过标准 exception 事件链路上报(`type='crash'` + `subtype='oom'`,name 为 `WatchdogTermination`)。
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
armsRum.init({
|
|
141
|
+
endpoint: '<your-endpoint>',
|
|
142
|
+
collectors: {
|
|
143
|
+
oom: true,
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**能力范围与限制**:
|
|
149
|
+
|
|
150
|
+
- 仅支持 iOS,且仅覆盖**前台激活状态**被杀的推断(后台被杀不判定不上报);Android 无此能力(Java `OutOfMemoryError` 已由崩溃采集链路捕获)
|
|
151
|
+
- 启发式推断存在精度上限:无堆栈(`stack` 为空),`timestamp` 为估算值,事件通过 `snapshots.estimated: true` 结构化标记推断性质
|
|
152
|
+
- 每次启动最多上报 1 条 OOM 事件;首次安装后被杀、调试器附加期间被杀、设备重启等场景不判定(业界同类能力同款排除条件)
|
|
153
|
+
- 判定依据为上次会话持久化的状态快照,需重新构建原生 App(如 `expo run:ios` / `pod install` + 重新编译)后生效
|
|
154
|
+
|
|
155
|
+
> **注意**:
|
|
156
|
+
> - `oom` 默认为 `false`,需显式开启(`oom: true`);其开关方向与崩溃采集相反(崩溃采集默认开启,配置 `crash: false` 才关闭)。
|
|
157
|
+
> - 建议与崩溃采集同时开启(保持 `crash` 默认开启即可)。崩溃采集关闭时,原生崩溃监控仍会安装、KSCrash 崩溃报告照常写入但不会被读取和清理;残留的陈旧报告会使紧跟崩溃之后的 OOM 判定让位崩溃链路(防双报,预期行为),整体方向保守——OOM 倾向被抑制(漏判方向),而非误报增多。
|
|
158
|
+
|
|
134
159
|
## tracing 链路追踪配置
|
|
135
160
|
|
|
136
161
|
支持布尔值开关或详细配置对象:
|
|
@@ -4,6 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
## 版本列表
|
|
6
6
|
|
|
7
|
+
### v0.1.4(2026年09月)
|
|
8
|
+
|
|
9
|
+
iOS 看门狗终止(OOM)推断采集、RN 0.68-0.70 原生兼容打通与发布产物混淆修复。
|
|
10
|
+
|
|
11
|
+
#### v0.1.4-beta.2(2026年09月23日)
|
|
12
|
+
|
|
13
|
+
打通 RN 0.68-0.70 原生兼容。
|
|
14
|
+
|
|
15
|
+
- iOS/Android 崩溃采集与 OOM 在低版本旧架构可用(Android 宿主需 Kotlin ≥1.8,详见接入文档前提条件)
|
|
16
|
+
|
|
17
|
+
#### v0.1.4-beta.1(2026年09月23日)
|
|
18
|
+
|
|
19
|
+
新增 iOS 看门狗终止(OOM)事后推断采集。
|
|
20
|
+
|
|
21
|
+
- 新增 iOS OOM 采集,默认关闭需显式开启
|
|
22
|
+
- 崩溃与 OOM 配置独立,判定互斥防双报
|
|
23
|
+
- OOM 事件英文证据式表述,estimated 标记推断性质
|
|
24
|
+
- 锁定 KSCrash 依赖版本
|
|
25
|
+
- 修复发布流程,生产产物启用代码混淆压缩
|
|
26
|
+
|
|
7
27
|
### v0.1.3(2026年07月)
|
|
8
28
|
|
|
9
29
|
原生崩溃采集安全加固与自监控系统集成。
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
- Node.js >= 18
|
|
23
23
|
- npm或yarn包管理工具
|
|
24
24
|
- Android 构建:需安装 NDK 与 CMake(由宿主工程的 `ndkVersion` 决定,SDK 不强制特定版本)
|
|
25
|
-
-
|
|
25
|
+
- **RN 0.68-0.70 的 Android 工程额外要求**:宿主 `android/build.gradle` 的 buildscript 需声明 `kotlin-gradle-plugin` classpath,且 Kotlin 版本 **≥ 1.8.0**(RN 0.70 模板默认 1.6.x,与 SDK 依赖的 kotlin-stdlib 1.8 metadata 不兼容,需手动提升);AGP 7.2 及以下无需改动,SDK 构建脚本自动回退 AndroidManifest package 属性
|
|
26
|
+
- iOS 构建:需 CocoaPods(用于拉取 `KSCrash` 崩溃采集依赖);RN 0.68-0.70 无需额外配置,`pod install` 后自动走旧桥导出路径
|
|
26
27
|
|
|
27
28
|
### 安装步骤
|
|
28
29
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* RumAppStateRecorder
|
|
7
|
+
*
|
|
8
|
+
* iOS 看门狗终止(OOM)事后推断采集(P1 阶段,方案见
|
|
9
|
+
* dev-docs/OOM采集调研与实施方案.md 4.2 节)。负责:
|
|
10
|
+
* - 运行期持久化 App 状态快照(app_state.json):生命周期通知驱动、仅状态变化时写
|
|
11
|
+
* - 下次启动时按 10 项排除条件判定上次是否发生看门狗终止(判定逻辑纯函数化,见下)
|
|
12
|
+
* - 判定通过时构造 oom_{timestamp}_{uuid}.json 事件文件,交由 JS 侧回捞上报
|
|
13
|
+
* (原生落盘、JS 回捞,保持 Ack 删文件链路的可靠性)
|
|
14
|
+
*
|
|
15
|
+
* 与 RumCrashReporter 的职责边界:RumCrashReporter 管信号/崩溃(KSCrash),
|
|
16
|
+
* 本类管状态记录与 OOM 推断,不使用信号处理器、不与 KSCrash 冲突。
|
|
17
|
+
* 判定逻辑(RumWatchdogTerminationLogic)与本类同文件实现。
|
|
18
|
+
*/
|
|
19
|
+
@interface RumAppStateRecorder : NSObject
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 安装 OOM 采集(幂等,dispatch_once 保证判定只执行一次)。
|
|
23
|
+
*
|
|
24
|
+
* 驱动方:RumSdkReactnative.updateCollectorsConfig——JS 侧 OomCollector 在
|
|
25
|
+
* SDK init 且 collectors.oom === true 时调用 updateCollectorsConfig("{\"oom\":true}")
|
|
26
|
+
* 触发;未开启时本方法不会被调用:不安装 Recorder、不执行判定、不产生
|
|
27
|
+
* 任何 OOM 相关 I/O(D6 默认关闭)。
|
|
28
|
+
*
|
|
29
|
+
* 上次会话是否开启由 app_state.json 的存在性隐式承载(上次未开启则无快照,
|
|
30
|
+
* 判定条件①不通过,不会误判),无需独立的开关持久化。
|
|
31
|
+
*/
|
|
32
|
+
+ (void)setup;
|
|
33
|
+
|
|
34
|
+
/** 获取待上报的 OOM 事件(已解析为字典数组,逐文件处理,不一次性全量读入拼接) */
|
|
35
|
+
+ (NSArray<NSDictionary *> *)pendingOomReports;
|
|
36
|
+
|
|
37
|
+
/** 按 oomId 删除已上报的 OOM 事件文件 */
|
|
38
|
+
+ (void)clearOomReportsWithIds:(NSArray<NSString *> *)oomIds;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 看门狗终止判定(纯函数化:输入上次快照 + 当前环境 + 崩溃证据,输出是否判定,
|
|
42
|
+
* 便于后续经桥伪造输入测试或 XCTest)。
|
|
43
|
+
*
|
|
44
|
+
* 10 项排除条件全部满足才判定(方案 4.2.2,D5/D7 硬约束):
|
|
45
|
+
* ① 存在上次快照;② 非模拟器;③ appVersion 未变;④ osVersion 未变;
|
|
46
|
+
* ⑤ systemBootTime 未变;⑥ vendorId 一致且非空;⑦ 上次非调试态;
|
|
47
|
+
* ⑧ 上次非正常终止;⑨ 上次前台激活(D5 前台限定);
|
|
48
|
+
* ⑩ 上次运行内无崩溃证据(crashed_last_run.flag 不存在 且 KSCrash reportStore
|
|
49
|
+
* 无晚于上次快照 updatedAt 的 pending 报告——时间范围限定排除陈旧报告,
|
|
50
|
+
* D7 判定层互斥)。
|
|
51
|
+
*
|
|
52
|
+
* @param previousState 上次会话的 app_state.json 快照(不存在时传 nil)
|
|
53
|
+
* @param currentState 本次会话采集的当前环境快照
|
|
54
|
+
* @param flagExists crashed_last_run.flag 是否存在
|
|
55
|
+
* @param hasPendingReports 上次运行内是否存在待处理崩溃报告(调用方对 KSCrash
|
|
56
|
+
* pending 报告施加时间范围限定后传入:仅最新报告时间戳
|
|
57
|
+
* 晚于上次快照 updatedAt 时为 YES,陈旧报告不计入)
|
|
58
|
+
* @param isSimulator 是否运行在模拟器(生产路径由 TARGET_OS_SIMULATOR
|
|
59
|
+
* 编译宏求值;参数化便于模拟器上运行的测试伪造真机分支)
|
|
60
|
+
*/
|
|
61
|
+
+ (BOOL)evaluateWatchdogTerminationFromPreviousState:(nullable NSDictionary *)previousState
|
|
62
|
+
currentState:(NSDictionary *)currentState
|
|
63
|
+
crashedLastRunFlagExists:(BOOL)flagExists
|
|
64
|
+
hasPendingCrashReports:(BOOL)hasPendingReports
|
|
65
|
+
runningOnSimulator:(BOOL)isSimulator;
|
|
66
|
+
|
|
67
|
+
@end
|
|
68
|
+
|
|
69
|
+
NS_ASSUME_NONNULL_END
|