@arms/rum-reactnative 0.1.4-beta.1 → 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 +3 -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 +39 -17
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +9 -2
- package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +7 -1
- package/docs//346/216/245/345/205/245ReactNative/345/272/224/347/224/250.md +2 -1
- package/ios/RumSdkReactnative.h +11 -1
- package/ios/RumSdkReactnative.mm +40 -34
- package/lib/commonjs/utils/platform.js +1 -1
- package/lib/module/utils/platform.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -420,6 +420,7 @@ SDK 仅持久化一个键 `_arms_uid`(匿名用户 UID),用于跨冷启动
|
|
|
420
420
|
1. **必须重新构建原生工程**:新增了 TurboModule 方法,升级或首次接入后需要重新执行 iOS 的 `pod install`、Android 的 Gradle Sync;Expo 工程请执行 `expo prebuild --clean` 后再编译,否则会报 protocol method 缺失。
|
|
421
421
|
2. **隔离命名空间,不污染宿主 App**:iOS 走独立 `NSUserDefaults` suite、Android 走独立 prefs 文件,与宿主 App 自身的偏好数据互不干扰;用户卸载 / 抹机时会一并清除。
|
|
422
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)。
|
|
423
424
|
|
|
424
425
|
## 版本要求
|
|
425
426
|
|
|
@@ -427,7 +428,7 @@ SDK 的 peerDependencies 声明为 `react-native: >=0.68.0`,原生构建配置
|
|
|
427
428
|
|
|
428
429
|
| 功能点 | 关键依赖 / API | 最低 RN 版本 | 说明 |
|
|
429
430
|
|--------|--------------|-------------|------|
|
|
430
|
-
| **原生崩溃采集** | TurboModule + codegen | 0.68 |
|
|
431
|
+
| **原生崩溃采集** | TurboModule + codegen | 0.68 | 自动适配 0.68-0.70 旧桥导出与 0.71+ Spec 协议/interop;RN ≤0.70 Android 前置条件见注意事项 4 |
|
|
431
432
|
| NDK 崩溃采集(C/C++) | CMake + NDK `externalNativeBuild` | 0.68 | 随原生崩溃采集一起启用 |
|
|
432
433
|
| iOS 崩溃采集(KSCrash) | KSCrash 2.5.1(CocoaPods 源码依赖,已锁定版本) | 0.68 | `pod install` 时自动编译 |
|
|
433
434
|
| **OOM 采集(iOS)** | TurboModule + KSCrash + 状态快照持久化 | 0.68 | 仅 iOS,默认关闭(`collectors.oom` 显式开启);Android 为空实现 |
|
|
@@ -446,7 +447,7 @@ SDK 的 peerDependencies 声明为 `react-native: >=0.68.0`,原生构建配置
|
|
|
446
447
|
| **自监控(Self-Monitoring)** | `fetch` 上报 Protobuf 至 `/rum/monitor` | 0.68 | 纯 JS 实现 |
|
|
447
448
|
| **Expo 集成** | Expo Config Plugin | Expo SDK 49+(RN 0.72+) | 仅配置透传,零运行时依赖 |
|
|
448
449
|
|
|
449
|
-
> **总结**: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 条)。
|
|
450
451
|
|
|
451
452
|
## 相关文档
|
|
452
453
|
|
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)
|
|
@@ -429,7 +447,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
429
447
|
* 已由 CrashHandler 崩溃链路捕获,系统低内存杀进程检测不在本期范围。
|
|
430
448
|
* 空实现仅为满足 TurboModule Spec 双端对齐。
|
|
431
449
|
*/
|
|
432
|
-
|
|
450
|
+
@ReactMethod
|
|
451
|
+
fun getPendingOomReports(promise: Promise) {
|
|
433
452
|
try {
|
|
434
453
|
promise.resolve("[]")
|
|
435
454
|
} catch (e: Throwable) {
|
|
@@ -438,7 +457,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
438
457
|
}
|
|
439
458
|
|
|
440
459
|
/** 清除 OOM 报告文件:Android 无 OOM 文件,no-op */
|
|
441
|
-
|
|
460
|
+
@ReactMethod
|
|
461
|
+
fun clearOomReports(oomIds: String, promise: Promise) {
|
|
442
462
|
try {
|
|
443
463
|
promise.resolve(null)
|
|
444
464
|
} catch (e: Throwable) {
|
|
@@ -447,7 +467,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
447
467
|
}
|
|
448
468
|
|
|
449
469
|
/** 同步 JS 侧采集器配置(如 oom 开关):Android 无 OOM 能力,接受但忽略 */
|
|
450
|
-
|
|
470
|
+
@ReactMethod
|
|
471
|
+
fun updateCollectorsConfig(config: String) {
|
|
451
472
|
// no-op
|
|
452
473
|
}
|
|
453
474
|
|
|
@@ -457,7 +478,8 @@ class RumSdkReactnativeModule(reactContext: ReactApplicationContext) :
|
|
|
457
478
|
|
|
458
479
|
private external fun nativeTriggerCrash(type: Int)
|
|
459
480
|
|
|
460
|
-
|
|
481
|
+
@ReactMethod
|
|
482
|
+
fun triggerTestCrash(crashType: String) {
|
|
461
483
|
when (crashType) {
|
|
462
484
|
// TurboModule 架构下,@ReactMethod void 方法中抛出的 Java 异常会被 C++ 层
|
|
463
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
|
)
|
|
@@ -6,7 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
### v0.1.4(2026年09月)
|
|
8
8
|
|
|
9
|
-
iOS 看门狗终止(OOM
|
|
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,详见接入文档前提条件)
|
|
10
16
|
|
|
11
17
|
#### v0.1.4-beta.1(2026年09月23日)
|
|
12
18
|
|
|
@@ -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
|
|
package/ios/RumSdkReactnative.h
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
// codegen 产物存在性分支(RN 版本兼容,见 dev-docs/RN 0.68-0.70 兼容性打通方案.md):
|
|
2
|
+
// - RN 0.71+(新旧架构均生成 React-Codegen 产物):实现 codegen Spec 协议,
|
|
3
|
+
// 方法经 JSI/TurboModule 绑定导出;
|
|
4
|
+
// - RN 0.68-0.70 默认旧架构(codegen 不运行、无 Spec 产物):回退普通
|
|
5
|
+
// RCTBridgeModule,方法经 .mm 中 RCT_EXPORT_METHOD 方法表导出,
|
|
6
|
+
// JS 侧经 NativeModules 路径调用(TurboModuleRegistry.get 未命中时自动降级)。
|
|
7
|
+
#if __has_include(<RumSdkReactnativeSpec/RumSdkReactnativeSpec.h>)
|
|
1
8
|
#import <RumSdkReactnativeSpec/RumSdkReactnativeSpec.h>
|
|
2
|
-
|
|
3
9
|
@interface RumSdkReactnative : NSObject <NativeRumSdkReactnativeSpec>
|
|
10
|
+
#else
|
|
11
|
+
#import <React/RCTBridgeModule.h>
|
|
12
|
+
@interface RumSdkReactnative : NSObject <RCTBridgeModule>
|
|
13
|
+
#endif
|
|
4
14
|
|
|
5
15
|
@end
|
package/ios/RumSdkReactnative.mm
CHANGED
|
@@ -55,40 +55,40 @@ RCT_EXPORT_MODULE()
|
|
|
55
55
|
return defaults;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
RCT_EXPORT_METHOD(getItem:(NSString *)key
|
|
59
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
60
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
61
61
|
{
|
|
62
62
|
NSString *value = [[self defaults] stringForKey:key];
|
|
63
63
|
resolve(value ?: [NSNull null]);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
RCT_EXPORT_METHOD(setItem:(NSString *)key
|
|
67
|
+
value:(NSString *)value
|
|
68
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
69
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
70
70
|
{
|
|
71
71
|
[[self defaults] setObject:value forKey:key];
|
|
72
72
|
resolve(nil);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
RCT_EXPORT_METHOD(removeItem:(NSString *)key
|
|
76
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
77
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
78
78
|
{
|
|
79
79
|
[[self defaults] removeObjectForKey:key];
|
|
80
80
|
resolve(nil);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
RCT_EXPORT_METHOD(clear:(RCTPromiseResolveBlock)resolve
|
|
84
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
85
85
|
{
|
|
86
86
|
[[self defaults] removePersistentDomainForName:kRumSdkDefaultsSuiteName];
|
|
87
87
|
resolve(nil);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
RCT_EXPORT_METHOD(getAllKeys:(RCTPromiseResolveBlock)resolve
|
|
91
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
92
92
|
{
|
|
93
93
|
NSDictionary<NSString *, id> *suite =
|
|
94
94
|
[[self defaults] persistentDomainForName:kRumSdkDefaultsSuiteName];
|
|
@@ -97,8 +97,8 @@ RCT_EXPORT_MODULE()
|
|
|
97
97
|
|
|
98
98
|
// MARK: - Device Info
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve
|
|
101
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
102
102
|
{
|
|
103
103
|
@try {
|
|
104
104
|
NSMutableDictionary *info = [NSMutableDictionary dictionary];
|
|
@@ -166,16 +166,22 @@ RCT_EXPORT_MODULE()
|
|
|
166
166
|
|
|
167
167
|
// MARK: - TurboModule
|
|
168
168
|
|
|
169
|
+
// RN 0.71+ 才生成 codegen 产物;RN 0.68-0.70 旧架构无 Spec,方法缺席即可——
|
|
170
|
+
// 模块经 RCT_EXPORT_METHOD 方法表走旧桥(JS 侧 NativeModules 路径)。
|
|
171
|
+
// 守卫条件与 .h 一致:Spec.h 为 umbrella 头,NativeRumSdkReactnativeSpecJSI
|
|
172
|
+
// 类定义内联其中(codegen 产物中不存在 RumSdkReactnativeSpec/…SpecJSI.h 路径)
|
|
173
|
+
#if __has_include(<RumSdkReactnativeSpec/RumSdkReactnativeSpec.h>)
|
|
169
174
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
170
175
|
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
171
176
|
{
|
|
172
177
|
return std::make_shared<facebook::react::NativeRumSdkReactnativeSpecJSI>(params);
|
|
173
178
|
}
|
|
179
|
+
#endif
|
|
174
180
|
|
|
175
181
|
// MARK: - Crash Reporting
|
|
176
182
|
|
|
177
|
-
|
|
178
|
-
|
|
183
|
+
RCT_EXPORT_METHOD(getPendingCrashes:(RCTPromiseResolveBlock)resolve
|
|
184
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
179
185
|
{
|
|
180
186
|
@try {
|
|
181
187
|
NSArray<NSDictionary *> *reports = [RumCrashReporter pendingCrashReports];
|
|
@@ -195,9 +201,9 @@ RCT_EXPORT_MODULE()
|
|
|
195
201
|
}
|
|
196
202
|
}
|
|
197
203
|
|
|
198
|
-
|
|
204
|
+
RCT_EXPORT_METHOD(clearCrashReports:(NSString *)crashIds
|
|
199
205
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
200
|
-
reject:(RCTPromiseRejectBlock)reject
|
|
206
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
201
207
|
{
|
|
202
208
|
@try {
|
|
203
209
|
NSArray *ids = @[];
|
|
@@ -218,8 +224,8 @@ RCT_EXPORT_MODULE()
|
|
|
218
224
|
}
|
|
219
225
|
}
|
|
220
226
|
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
RCT_EXPORT_METHOD(clearAllCrashReports:(RCTPromiseResolveBlock)resolve
|
|
228
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
223
229
|
{
|
|
224
230
|
@try {
|
|
225
231
|
[RumCrashReporter clearAllCrashReports];
|
|
@@ -229,10 +235,10 @@ RCT_EXPORT_MODULE()
|
|
|
229
235
|
}
|
|
230
236
|
}
|
|
231
237
|
|
|
232
|
-
|
|
233
|
-
|
|
238
|
+
RCT_EXPORT_METHOD(cleanupOldCrashes:(double)maxFiles
|
|
239
|
+
maxAgeMs:(double)maxAgeMs
|
|
234
240
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
235
|
-
reject:(RCTPromiseRejectBlock)reject
|
|
241
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
236
242
|
{
|
|
237
243
|
@try {
|
|
238
244
|
[RumCrashReporter cleanupOldCrashesWithMaxFiles:(NSInteger)maxFiles maxAgeMs:maxAgeMs];
|
|
@@ -242,15 +248,15 @@ RCT_EXPORT_MODULE()
|
|
|
242
248
|
}
|
|
243
249
|
}
|
|
244
250
|
|
|
245
|
-
|
|
246
|
-
|
|
251
|
+
RCT_EXPORT_METHOD(crashedLastRun:(RCTPromiseResolveBlock)resolve
|
|
252
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
247
253
|
{
|
|
248
254
|
resolve(@([RumCrashReporter crashedLastRun]));
|
|
249
255
|
}
|
|
250
256
|
|
|
251
257
|
// MARK: - OOM (Watchdog Termination) Reporting
|
|
252
258
|
|
|
253
|
-
|
|
259
|
+
RCT_EXPORT_METHOD(updateCollectorsConfig:(NSString *)config)
|
|
254
260
|
{
|
|
255
261
|
@try {
|
|
256
262
|
// 解析 config JSON(如 {"oom": true})。仅 oom == true 时安装 OOM 状态记录器
|
|
@@ -280,8 +286,8 @@ RCT_EXPORT_MODULE()
|
|
|
280
286
|
}
|
|
281
287
|
}
|
|
282
288
|
|
|
283
|
-
|
|
284
|
-
|
|
289
|
+
RCT_EXPORT_METHOD(getPendingOomReports:(RCTPromiseResolveBlock)resolve
|
|
290
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
285
291
|
{
|
|
286
292
|
@try {
|
|
287
293
|
NSArray<NSDictionary *> *reports = [RumAppStateRecorder pendingOomReports];
|
|
@@ -301,9 +307,9 @@ RCT_EXPORT_MODULE()
|
|
|
301
307
|
}
|
|
302
308
|
}
|
|
303
309
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
310
|
+
RCT_EXPORT_METHOD(clearOomReports:(NSString *)oomIds
|
|
311
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
312
|
+
reject:(RCTPromiseRejectBlock)reject)
|
|
307
313
|
{
|
|
308
314
|
@try {
|
|
309
315
|
NSArray *ids = @[];
|
|
@@ -324,7 +330,7 @@ RCT_EXPORT_MODULE()
|
|
|
324
330
|
}
|
|
325
331
|
}
|
|
326
332
|
|
|
327
|
-
|
|
333
|
+
RCT_EXPORT_METHOD(updateCrashContext:(NSString *)context)
|
|
328
334
|
{
|
|
329
335
|
[RumCrashReporter updateCrashContext:context];
|
|
330
336
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.appName=exports.VERSION=void 0,exports.clearStorage=clearStorage,exports.fixAttrs=void 0,exports.getAllStorageKeys=getAllStorageKeys,exports.getStorage=getStorage,exports.removeStorage=removeStorage,exports.setStorage=setStorage;var _rumCore=require("@arms/rum-core"),_reactNative=require("react-native"),_NativeRumSdkReactnative=_interopRequireDefault(require("../NativeRumSdkReactnative"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const _pkg={version:"0.1.4-beta.
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.appName=exports.VERSION=void 0,exports.clearStorage=clearStorage,exports.fixAttrs=void 0,exports.getAllStorageKeys=getAllStorageKeys,exports.getStorage=getStorage,exports.removeStorage=removeStorage,exports.setStorage=setStorage;var _rumCore=require("@arms/rum-core"),_reactNative=require("react-native"),_NativeRumSdkReactnative=_interopRequireDefault(require("../NativeRumSdkReactnative"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const _pkg={version:"0.1.4-beta.2"},VERSION=exports.VERSION=_pkg.version,appName=exports.appName="react-native";function getReactNativeVersion(){try{return require("react-native/package.json").version??""}catch{const e=_reactNative.Platform.constants?.reactNativeVersion;return e?`${e.major}.${e.minor}.${e.patch}`:""}}function getStorage(e){return _NativeRumSdkReactnative.default.getItem(e)}function setStorage(e,t){return _NativeRumSdkReactnative.default.setItem(e,t)}function removeStorage(e){return _NativeRumSdkReactnative.default.removeItem(e)}function clearStorage(){return _NativeRumSdkReactnative.default.clear()}function getAllStorageKeys(){return _NativeRumSdkReactnative.default.getAllKeys()}async function fetchDeviceInfo(){try{return await _NativeRumSdkReactnative.default.getDeviceInfo()}catch(e){return console.warn("[rum] getDeviceInfo failed, falling back to JS defaults",e),{os_type:"ios"===_reactNative.Platform.OS?"iOS":"Android",os_version:String(_reactNative.Platform.Version??"")}}}let _cachedDeviceInfo=null;function getDeviceInfo(){return _cachedDeviceInfo||(_cachedDeviceInfo=fetchDeviceInfo()),_cachedDeviceInfo}const fixAttrs=async function(e){if(!e)return;const t=await getDeviceInfo(),r={id:t.device_id,type:t.device_type,brand:t.device_brand,model:t.device_model,name:t.device_name},a=getReactNativeVersion(),i={type:t.os_type??("ios"===_reactNative.Platform.OS?"iOS":"Android"),version:t.os_version??String(_reactNative.Platform.Version??""),container:appName,container_version:a||void 0};let o;if(t.viewport_width&&t.viewport_height)o={width:t.viewport_width,height:t.viewport_height};else try{const e=_reactNative.Dimensions.get("screen");o={width:Math.round(e.width),height:Math.round(e.height)}}catch{}return e.app.type=_rumCore.AppType.reactnative,e.app.package=e.app.package??t.app_package,e.app.version=e.app.version??t.app_version,e._v=VERSION,e.device={...r,...e.device},e.os={...i,...e.os},o&&(e.viewport={...e.viewport,...o}),e};exports.fixAttrs=fixAttrs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";import{AppType}from"@arms/rum-core";import{Dimensions,Platform}from"react-native";import NativeRumSdkReactnative from"../NativeRumSdkReactnative.js";const _pkg={version:"0.1.4-beta.
|
|
1
|
+
"use strict";import{AppType}from"@arms/rum-core";import{Dimensions,Platform}from"react-native";import NativeRumSdkReactnative from"../NativeRumSdkReactnative.js";const _pkg={version:"0.1.4-beta.2"};export const VERSION=_pkg.version;export const appName="react-native";function getReactNativeVersion(){try{return require("react-native/package.json").version??""}catch{const e=Platform.constants?.reactNativeVersion;return e?`${e.major}.${e.minor}.${e.patch}`:""}}export function getStorage(e){return NativeRumSdkReactnative.getItem(e)}export function setStorage(e,t){return NativeRumSdkReactnative.setItem(e,t)}export function removeStorage(e){return NativeRumSdkReactnative.removeItem(e)}export function clearStorage(){return NativeRumSdkReactnative.clear()}export function getAllStorageKeys(){return NativeRumSdkReactnative.getAllKeys()}async function fetchDeviceInfo(){try{return await NativeRumSdkReactnative.getDeviceInfo()}catch(e){return console.warn("[rum] getDeviceInfo failed, falling back to JS defaults",e),{os_type:"ios"===Platform.OS?"iOS":"Android",os_version:String(Platform.Version??"")}}}let _cachedDeviceInfo=null;function getDeviceInfo(){return _cachedDeviceInfo||(_cachedDeviceInfo=fetchDeviceInfo()),_cachedDeviceInfo}export const fixAttrs=async function(e){if(!e)return;const t=await getDeviceInfo(),i={id:t.device_id,type:t.device_type,brand:t.device_brand,model:t.device_model,name:t.device_name},r=getReactNativeVersion(),n={type:t.os_type??("ios"===Platform.OS?"iOS":"Android"),version:t.os_version??String(Platform.Version??""),container:appName,container_version:r||void 0};let a;if(t.viewport_width&&t.viewport_height)a={width:t.viewport_width,height:t.viewport_height};else try{const e=Dimensions.get("screen");a={width:Math.round(e.width),height:Math.round(e.height)}}catch{}return e.app.type=AppType.reactnative,e.app.package=e.app.package??t.app_package,e.app.version=e.app.version??t.app_version,e._v=VERSION,e.device={...i,...e.device},e.os={...n,...e.os},a&&(e.viewport={...e.viewport,...a}),e};
|
package/package.json
CHANGED