@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 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 | podspec / build.gradle 按版本条件分支,自动适配 0.68-0.70 和 0.71+ |
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,原生构建配置(podspec / build.gradle)已做多版本条件适配。RN 0.71+ 使用 `install_modules_dependencies` / `react-android`;RN 0.68-0.70 使用手动依赖 / `react-native:+`。JS 侧通过 `TurboModuleRegistry.get` + `NativeModules` 双路径获取原生模块,原生模块缺失时自动降级为空实现,不影响纯 JS 能力。
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
 
@@ -70,7 +70,11 @@ if (isRn71Plus) {
70
70
  }
71
71
 
72
72
  android {
73
- namespace "com.rumsdkreactnative"
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
- RumSdkReactnative_kotlinVersion=2.0.21
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
- <manifest xmlns:android="http://schemas.android.com/apk/res/android">
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
- NativeRumSdkReactnativeSpec(reactContext) {
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
- override fun getItem(key: String, promise: Promise) {
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
- override fun setItem(key: String, value: String, promise: Promise) {
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
- override fun removeItem(key: String, promise: Promise) {
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
- override fun clear(promise: Promise) {
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
- override fun getAllKeys(promise: Promise) {
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
- override fun getDeviceInfo(promise: Promise) {
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
- override fun getPendingCrashes(promise: Promise) {
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
- override fun clearCrashReports(crashIds: String, promise: Promise) {
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
- override fun crashedLastRun(promise: Promise) {
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
- override fun updateCrashContext(context: String) {
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
- override fun clearAllCrashReports(promise: Promise) {
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
- override fun cleanupOldCrashes(maxFiles: Double, maxAgeMs: Double, promise: Promise) {
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
- override fun getPendingOomReports(promise: Promise) {
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
- override fun clearOomReports(oomIds: String, promise: Promise) {
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
- override fun updateCollectorsConfig(config: String) {
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
- override fun triggerTestCrash(crashType: String) {
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
- import com.facebook.react.BaseReactPackage
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 : BaseReactPackage() {
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
- - iOS 构建:需 CocoaPods(用于拉取 `KSCrash` 崩溃采集依赖)
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
 
@@ -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
@@ -55,40 +55,40 @@ RCT_EXPORT_MODULE()
55
55
  return defaults;
56
56
  }
57
57
 
58
- - (void)getItem:(NSString *)key
59
- resolve:(RCTPromiseResolveBlock)resolve
60
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)setItem:(NSString *)key
67
- value:(NSString *)value
68
- resolve:(RCTPromiseResolveBlock)resolve
69
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)removeItem:(NSString *)key
76
- resolve:(RCTPromiseResolveBlock)resolve
77
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)clear:(RCTPromiseResolveBlock)resolve
84
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)getAllKeys:(RCTPromiseResolveBlock)resolve
91
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)getDeviceInfo:(RCTPromiseResolveBlock)resolve
101
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)getPendingCrashes:(RCTPromiseResolveBlock)resolve
178
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)clearCrashReports:(NSString *)crashIds
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
- - (void)clearAllCrashReports:(RCTPromiseResolveBlock)resolve
222
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)cleanupOldCrashes:(double)maxFiles
233
- maxAgeMs:(double)maxAgeMs
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
- - (void)crashedLastRun:(RCTPromiseResolveBlock)resolve
246
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)updateCollectorsConfig:(NSString *)config
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
- - (void)getPendingOomReports:(RCTPromiseResolveBlock)resolve
284
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)clearOomReports:(NSString *)oomIds
305
- resolve:(RCTPromiseResolveBlock)resolve
306
- reject:(RCTPromiseRejectBlock)reject
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
- - (void)updateCrashContext:(NSString *)context
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"},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
+ "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"};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};
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arms/rum-reactnative",
3
- "version": "0.1.4-beta.1",
3
+ "version": "0.1.4-beta.2",
4
4
  "description": "RUM SDK For ReactNative",
5
5
  "homepage": "https://help.aliyun.com/zh/arms/user-experience-monitoring/",
6
6
  "main": "./lib/commonjs/index.js",