@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.
Files changed (89) hide show
  1. package/README.md +9 -2
  2. package/android/build.gradle +12 -1
  3. package/android/gradle.properties +3 -1
  4. package/android/src/main/AndroidManifest.xml +4 -1
  5. package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +67 -14
  6. package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativePackage.kt +9 -2
  7. package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +25 -0
  8. package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +20 -0
  9. package/docs//346/216/245/345/205/245ReactNative/345/272/224/347/224/250.md +2 -1
  10. package/ios/RumAppStateRecorder.h +69 -0
  11. package/ios/RumAppStateRecorder.mm +547 -0
  12. package/ios/RumCrashReporter.h +32 -0
  13. package/ios/RumCrashReporter.mm +97 -11
  14. package/ios/RumSdkReactnative.h +11 -1
  15. package/ios/RumSdkReactnative.mm +115 -29
  16. package/lib/commonjs/NativeRumSdkReactnative.js +1 -54
  17. package/lib/commonjs/collector/action/index.js +1 -108
  18. package/lib/commonjs/collector/exception/crash.js +1 -148
  19. package/lib/commonjs/collector/exception/index.js +1 -238
  20. package/lib/commonjs/collector/exception/oom.js +1 -0
  21. package/lib/commonjs/collector/index.js +1 -42
  22. package/lib/commonjs/collector/resource/api.js +1 -292
  23. package/lib/commonjs/collector/view/perf.js +1 -79
  24. package/lib/commonjs/collector/view/pv.js +1 -88
  25. package/lib/commonjs/expoConfigPlugin.js +1 -37
  26. package/lib/commonjs/index.js +1 -29
  27. package/lib/commonjs/plugin.js +1 -47
  28. package/lib/commonjs/processor/default-processor.js +1 -27
  29. package/lib/commonjs/processor/session-processor.js +1 -47
  30. package/lib/commonjs/reporter/index.js +1 -148
  31. package/lib/commonjs/reporter/monitor-reporter.js +1 -43
  32. package/lib/commonjs/shell.js +1 -91
  33. package/lib/commonjs/types/client.js +1 -6
  34. package/lib/commonjs/types/crash.js +1 -37
  35. package/lib/commonjs/types/index.js +1 -2
  36. package/lib/commonjs/types/oom.js +1 -0
  37. package/lib/commonjs/utils/action.js +1 -305
  38. package/lib/commonjs/utils/api.js +1 -84
  39. package/lib/commonjs/utils/base.js +1 -95
  40. package/lib/commonjs/utils/crash.js +1 -149
  41. package/lib/commonjs/utils/platform.js +1 -162
  42. package/lib/commonjs/utils/session.js +1 -158
  43. package/lib/commonjs/utils/url.js +1 -59
  44. package/lib/commonjs/utils/view.js +1 -93
  45. package/lib/module/NativeRumSdkReactnative.js +1 -51
  46. package/lib/module/collector/action/index.js +1 -103
  47. package/lib/module/collector/exception/crash.js +1 -143
  48. package/lib/module/collector/exception/index.js +1 -233
  49. package/lib/module/collector/exception/oom.js +1 -0
  50. package/lib/module/collector/index.js +1 -8
  51. package/lib/module/collector/resource/api.js +1 -287
  52. package/lib/module/collector/view/perf.js +1 -79
  53. package/lib/module/collector/view/pv.js +1 -83
  54. package/lib/module/expoConfigPlugin.js +1 -33
  55. package/lib/module/index.js +1 -7
  56. package/lib/module/plugin.js +1 -42
  57. package/lib/module/processor/default-processor.js +1 -22
  58. package/lib/module/processor/session-processor.js +1 -42
  59. package/lib/module/reporter/index.js +1 -144
  60. package/lib/module/reporter/monitor-reporter.js +1 -38
  61. package/lib/module/shell.js +1 -84
  62. package/lib/module/types/client.js +1 -4
  63. package/lib/module/types/crash.js +1 -33
  64. package/lib/module/types/index.js +1 -2
  65. package/lib/module/types/oom.js +1 -0
  66. package/lib/module/utils/action.js +1 -299
  67. package/lib/module/utils/api.js +1 -76
  68. package/lib/module/utils/base.js +1 -90
  69. package/lib/module/utils/crash.js +1 -144
  70. package/lib/module/utils/platform.js +1 -150
  71. package/lib/module/utils/session.js +1 -154
  72. package/lib/module/utils/url.js +1 -54
  73. package/lib/module/utils/view.js +1 -88
  74. package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +10 -0
  75. package/lib/typescript/commonjs/src/collector/exception/oom.d.ts +34 -0
  76. package/lib/typescript/commonjs/src/collector/index.d.ts +1 -0
  77. package/lib/typescript/commonjs/src/shell.d.ts +1 -1
  78. package/lib/typescript/commonjs/src/types/client.d.ts +27 -0
  79. package/lib/typescript/commonjs/src/types/oom.d.ts +58 -0
  80. package/lib/typescript/commonjs/src/utils/crash.d.ts +13 -0
  81. package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +10 -0
  82. package/lib/typescript/module/src/collector/exception/oom.d.ts +34 -0
  83. package/lib/typescript/module/src/collector/index.d.ts +1 -0
  84. package/lib/typescript/module/src/shell.d.ts +1 -1
  85. package/lib/typescript/module/src/types/client.d.ts +27 -0
  86. package/lib/typescript/module/src/types/oom.d.ts +58 -0
  87. package/lib/typescript/module/src/utils/crash.d.ts +13 -0
  88. package/package.json +1 -2
  89. package/src/NativeRumSdkReactnative.ts +18 -0
@@ -29,14 +29,6 @@ static NSString *const kRumCrashedLastRunFlagName = @"crashed_last_run.flag";
29
29
  /** 旧版目录名(用于升级迁移) */
30
30
  static NSString *const kLegacyCrashDirName = @"ARMSCrashReporter";
31
31
 
32
- /** Forward-declare private class methods used by the constructor */
33
- @interface RumCrashReporter (Private)
34
- + (NSString *)crashDir;
35
- + (NSString *)contextPath;
36
- + (id)readJSONFileAtPath:(NSString *)path;
37
- + (void)atomicWriteJSONObject:(id)obj toPath:(NSString *)path;
38
- @end
39
-
40
32
  #pragma mark - Early constructor
41
33
 
42
34
  /**
@@ -224,9 +216,9 @@ static BOOL RumIsDetoxRuntimePresent(void) {
224
216
  // 优先读 flag file —— KSCrash.crashedLastLaunch 在 reports 被清理后会被重置,
225
217
  // 而 SDK 会在 app 启动早期就处理 pending 文件,因此直接读 KSCrash 会导致
226
218
  // 用户在 UI 上查询时永远得到 NO。
227
- NSString *flagPath = [[self crashDir]
228
- stringByAppendingPathComponent:kRumCrashedLastRunFlagName];
229
- if ([[NSFileManager defaultManager] fileExistsAtPath:flagPath]) {
219
+ // flag 生命周期由 install 全权管理(每次启动按 KSCrash.crashedLastLaunch
220
+ // 重写/删除),OOM 判定只读不清除,本启动内查询结果稳定。
221
+ if ([self crashedLastRunFlagExists]) {
230
222
  return YES;
231
223
  }
232
224
  @try {
@@ -426,6 +418,100 @@ static BOOL RumIsDetoxRuntimePresent(void) {
426
418
  }
427
419
  }
428
420
 
421
+ #pragma mark - OOM support
422
+
423
+ + (NSDictionary *)currentCrashContext {
424
+ id obj = [self readJSONFileAtPath:[self contextPath]];
425
+ return [obj isKindOfClass:[NSDictionary class]] ? (NSDictionary *)obj : @{};
426
+ }
427
+
428
+ + (BOOL)crashedLastRunFlagExists {
429
+ NSString *flagPath = [[self crashDir]
430
+ stringByAppendingPathComponent:kRumCrashedLastRunFlagName];
431
+ return [[NSFileManager defaultManager] fileExistsAtPath:flagPath];
432
+ }
433
+
434
+ + (BOOL)hasPendingCrashReports {
435
+ // 轻量检查(只看 reportIDs 数量,不解析报告内容),供 OOM 判定层互斥使用
436
+ @try {
437
+ KSCrashReportStore *store = [KSCrash sharedInstance].reportStore;
438
+ return store != nil && store.reportIDs.count > 0;
439
+ } @catch (...) {
440
+ return NO;
441
+ }
442
+ }
443
+
444
+ + (BOOL)hasPendingCrashReportsAfterEpochMs:(long long)epochMs {
445
+ // 条件⑩时间范围限定:仅当上次运行内产生了崩溃(最新 pending 报告时间戳晚于
446
+ // 上次 app_state.json 的 updatedAt)才抑制 OOM 判定;早于该时间的陈旧报告
447
+ // (离线堆积、crash 关闭时遗留——crash 关闭时 KSCrash 报告只写不删,唯一
448
+ // 清理入口 cleanupOldCrashes 在 CrashCollector.setup 链内)不抑制。
449
+ // 时间戳不可得或比较异常时返回 YES(保守兜底,维持抑制)。
450
+ @try {
451
+ KSCrashReportStore *store = [KSCrash sharedInstance].reportStore;
452
+ if (store == nil) {
453
+ return NO;
454
+ }
455
+ NSArray<NSNumber *> *reportIDs = store.reportIDs;
456
+ if (reportIDs.count == 0) {
457
+ return NO;
458
+ }
459
+ // 基准时刻不可得(epochMs <= 0):退化为"任一 pending 报告即抑制"(原语义)
460
+ if (epochMs <= 0) {
461
+ return YES;
462
+ }
463
+ // 取最新 pending 报告时间戳;单份解析失败按当前时间计(保守视为新鲜崩溃)
464
+ double now = [[NSDate date] timeIntervalSince1970] * 1000.0;
465
+ double newest = 0;
466
+ for (NSNumber *reportID in reportIDs) {
467
+ @autoreleasepool {
468
+ KSCrashReportDictionary *report = [store reportForID:[reportID longLongValue]];
469
+ NSDictionary *raw = report ? report.value : nil;
470
+ double ts = [self crashReportTimestampMsFromRaw:raw fallback:now];
471
+ if (ts > newest) {
472
+ newest = ts;
473
+ }
474
+ }
475
+ }
476
+ return newest > (double)epochMs;
477
+ } @catch (NSException *e) {
478
+ NSLog(@"[RumCrashReporter] hasPendingCrashReportsAfterEpochMs exception: %@", e);
479
+ return YES;
480
+ }
481
+ }
482
+
483
+ /** 解析 KSCrash raw 报告 report.timestamp(ISO8601 字符串或秒级 NSNumber)为毫秒,不可得时返回 fallback(解析模式与 cleanupOldCrashesWithMaxFiles 一致) */
484
+ + (double)crashReportTimestampMsFromRaw:(NSDictionary *)raw fallback:(double)fallback {
485
+ NSDictionary *reportMeta = [raw isKindOfClass:[NSDictionary class]] ? raw[@"report"] : nil;
486
+ if (![reportMeta isKindOfClass:[NSDictionary class]]) {
487
+ return fallback;
488
+ }
489
+ id t = reportMeta[@"timestamp"];
490
+ if ([t isKindOfClass:[NSString class]]) {
491
+ NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
492
+ fmt.locale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
493
+ NSArray<NSString *> *formats = @[
494
+ @"yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
495
+ @"yyyy-MM-dd'T'HH:mm:ss.SSSZ",
496
+ @"yyyy-MM-dd'T'HH:mm:ss'Z'",
497
+ @"yyyy-MM-dd'T'HH:mm:ssXXX"
498
+ ];
499
+ for (NSString *format in formats) {
500
+ fmt.dateFormat = format;
501
+ NSDate *d = [fmt dateFromString:(NSString *)t];
502
+ if (d != nil) {
503
+ return [d timeIntervalSince1970] * 1000.0;
504
+ }
505
+ }
506
+ return fallback;
507
+ }
508
+ if ([t isKindOfClass:[NSNumber class]]) {
509
+ // 已是数值(秒级),转毫秒
510
+ return [(NSNumber *)t doubleValue] * 1000.0;
511
+ }
512
+ return fallback;
513
+ }
514
+
429
515
  #pragma mark - Context
430
516
 
431
517
  + (void)updateCrashContext:(NSString *)context {
@@ -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
@@ -1,5 +1,6 @@
1
1
  #import "RumSdkReactnative.h"
2
2
  #import "RumCrashReporter.h"
3
+ #import "RumAppStateRecorder.h"
3
4
  #import <UIKit/UIKit.h>
4
5
  #import <sys/utsname.h>
5
6
  #import <signal.h>
@@ -15,7 +16,10 @@ RCT_EXPORT_MODULE()
15
16
  - (instancetype)init
16
17
  {
17
18
  if ((self = [super init])) {
18
- // 模块实例化时安装崩溃监控(dispatch_once 内部保证幂等)
19
+ // 模块实例化时安装崩溃监控(dispatch_once 内部保证幂等)。
20
+ // OOM(看门狗终止)采集不在此时安装:由 updateCollectorsConfig 驱动
21
+ // (JS 侧 OomCollector 在 collectors.oom === true 时调用),未调用即
22
+ // 未开启,不产生任何 OOM 相关 I/O
19
23
  [RumCrashReporter install];
20
24
  }
21
25
  return self;
@@ -51,40 +55,40 @@ RCT_EXPORT_MODULE()
51
55
  return defaults;
52
56
  }
53
57
 
54
- - (void)getItem:(NSString *)key
55
- resolve:(RCTPromiseResolveBlock)resolve
56
- reject:(RCTPromiseRejectBlock)reject
58
+ RCT_EXPORT_METHOD(getItem:(NSString *)key
59
+ resolve:(RCTPromiseResolveBlock)resolve
60
+ reject:(RCTPromiseRejectBlock)reject)
57
61
  {
58
62
  NSString *value = [[self defaults] stringForKey:key];
59
63
  resolve(value ?: [NSNull null]);
60
64
  }
61
65
 
62
- - (void)setItem:(NSString *)key
63
- value:(NSString *)value
64
- resolve:(RCTPromiseResolveBlock)resolve
65
- reject:(RCTPromiseRejectBlock)reject
66
+ RCT_EXPORT_METHOD(setItem:(NSString *)key
67
+ value:(NSString *)value
68
+ resolve:(RCTPromiseResolveBlock)resolve
69
+ reject:(RCTPromiseRejectBlock)reject)
66
70
  {
67
71
  [[self defaults] setObject:value forKey:key];
68
72
  resolve(nil);
69
73
  }
70
74
 
71
- - (void)removeItem:(NSString *)key
72
- resolve:(RCTPromiseResolveBlock)resolve
73
- reject:(RCTPromiseRejectBlock)reject
75
+ RCT_EXPORT_METHOD(removeItem:(NSString *)key
76
+ resolve:(RCTPromiseResolveBlock)resolve
77
+ reject:(RCTPromiseRejectBlock)reject)
74
78
  {
75
79
  [[self defaults] removeObjectForKey:key];
76
80
  resolve(nil);
77
81
  }
78
82
 
79
- - (void)clear:(RCTPromiseResolveBlock)resolve
80
- reject:(RCTPromiseRejectBlock)reject
83
+ RCT_EXPORT_METHOD(clear:(RCTPromiseResolveBlock)resolve
84
+ reject:(RCTPromiseRejectBlock)reject)
81
85
  {
82
86
  [[self defaults] removePersistentDomainForName:kRumSdkDefaultsSuiteName];
83
87
  resolve(nil);
84
88
  }
85
89
 
86
- - (void)getAllKeys:(RCTPromiseResolveBlock)resolve
87
- reject:(RCTPromiseRejectBlock)reject
90
+ RCT_EXPORT_METHOD(getAllKeys:(RCTPromiseResolveBlock)resolve
91
+ reject:(RCTPromiseRejectBlock)reject)
88
92
  {
89
93
  NSDictionary<NSString *, id> *suite =
90
94
  [[self defaults] persistentDomainForName:kRumSdkDefaultsSuiteName];
@@ -93,8 +97,8 @@ RCT_EXPORT_MODULE()
93
97
 
94
98
  // MARK: - Device Info
95
99
 
96
- - (void)getDeviceInfo:(RCTPromiseResolveBlock)resolve
97
- reject:(RCTPromiseRejectBlock)reject
100
+ RCT_EXPORT_METHOD(getDeviceInfo:(RCTPromiseResolveBlock)resolve
101
+ reject:(RCTPromiseRejectBlock)reject)
98
102
  {
99
103
  @try {
100
104
  NSMutableDictionary *info = [NSMutableDictionary dictionary];
@@ -162,16 +166,22 @@ RCT_EXPORT_MODULE()
162
166
 
163
167
  // MARK: - TurboModule
164
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>)
165
174
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
166
175
  (const facebook::react::ObjCTurboModule::InitParams &)params
167
176
  {
168
177
  return std::make_shared<facebook::react::NativeRumSdkReactnativeSpecJSI>(params);
169
178
  }
179
+ #endif
170
180
 
171
181
  // MARK: - Crash Reporting
172
182
 
173
- - (void)getPendingCrashes:(RCTPromiseResolveBlock)resolve
174
- reject:(RCTPromiseRejectBlock)reject
183
+ RCT_EXPORT_METHOD(getPendingCrashes:(RCTPromiseResolveBlock)resolve
184
+ reject:(RCTPromiseRejectBlock)reject)
175
185
  {
176
186
  @try {
177
187
  NSArray<NSDictionary *> *reports = [RumCrashReporter pendingCrashReports];
@@ -191,9 +201,9 @@ RCT_EXPORT_MODULE()
191
201
  }
192
202
  }
193
203
 
194
- - (void)clearCrashReports:(NSString *)crashIds
204
+ RCT_EXPORT_METHOD(clearCrashReports:(NSString *)crashIds
195
205
  resolve:(RCTPromiseResolveBlock)resolve
196
- reject:(RCTPromiseRejectBlock)reject
206
+ reject:(RCTPromiseRejectBlock)reject)
197
207
  {
198
208
  @try {
199
209
  NSArray *ids = @[];
@@ -214,8 +224,8 @@ RCT_EXPORT_MODULE()
214
224
  }
215
225
  }
216
226
 
217
- - (void)clearAllCrashReports:(RCTPromiseResolveBlock)resolve
218
- reject:(RCTPromiseRejectBlock)reject
227
+ RCT_EXPORT_METHOD(clearAllCrashReports:(RCTPromiseResolveBlock)resolve
228
+ reject:(RCTPromiseRejectBlock)reject)
219
229
  {
220
230
  @try {
221
231
  [RumCrashReporter clearAllCrashReports];
@@ -225,10 +235,10 @@ RCT_EXPORT_MODULE()
225
235
  }
226
236
  }
227
237
 
228
- - (void)cleanupOldCrashes:(double)maxFiles
229
- maxAgeMs:(double)maxAgeMs
238
+ RCT_EXPORT_METHOD(cleanupOldCrashes:(double)maxFiles
239
+ maxAgeMs:(double)maxAgeMs
230
240
  resolve:(RCTPromiseResolveBlock)resolve
231
- reject:(RCTPromiseRejectBlock)reject
241
+ reject:(RCTPromiseRejectBlock)reject)
232
242
  {
233
243
  @try {
234
244
  [RumCrashReporter cleanupOldCrashesWithMaxFiles:(NSInteger)maxFiles maxAgeMs:maxAgeMs];
@@ -238,13 +248,89 @@ RCT_EXPORT_MODULE()
238
248
  }
239
249
  }
240
250
 
241
- - (void)crashedLastRun:(RCTPromiseResolveBlock)resolve
242
- reject:(RCTPromiseRejectBlock)reject
251
+ RCT_EXPORT_METHOD(crashedLastRun:(RCTPromiseResolveBlock)resolve
252
+ reject:(RCTPromiseRejectBlock)reject)
243
253
  {
244
254
  resolve(@([RumCrashReporter crashedLastRun]));
245
255
  }
246
256
 
247
- - (void)updateCrashContext:(NSString *)context
257
+ // MARK: - OOM (Watchdog Termination) Reporting
258
+
259
+ RCT_EXPORT_METHOD(updateCollectorsConfig:(NSString *)config)
260
+ {
261
+ @try {
262
+ // 解析 config JSON(如 {"oom": true})。仅 oom == true 时安装 OOM 状态记录器
263
+ // 并执行上次启动的看门狗终止判定(setup 内部 dispatch_once 幂等,重复调用
264
+ // 不重复判定/安装);false/缺省/解析失败 = no-op,不安装、不判定、不产生
265
+ // 任何 OOM 相关 I/O(D6 默认关闭)
266
+ BOOL oomEnabled = NO;
267
+ if (config.length > 0) {
268
+ NSData *data = [config dataUsingEncoding:NSUTF8StringEncoding];
269
+ id parsed = data ? [NSJSONSerialization JSONObjectWithData:data
270
+ options:0
271
+ error:nil]
272
+ : nil;
273
+ if ([parsed isKindOfClass:[NSDictionary class]]) {
274
+ id oom = [(NSDictionary *)parsed objectForKey:@"oom"];
275
+ if ([oom isKindOfClass:[NSNumber class]]) {
276
+ oomEnabled = [(NSNumber *)oom boolValue];
277
+ }
278
+ }
279
+ }
280
+ if (oomEnabled) {
281
+ [RumAppStateRecorder setup];
282
+ }
283
+ } @catch (NSException *exception) {
284
+ // void 返回的 codegen 方法无 reject 通道,静默降级(对齐 JS 侧 try-catch 兜底)
285
+ NSLog(@"[RumSdkReactnative] updateCollectorsConfig exception: %@", exception);
286
+ }
287
+ }
288
+
289
+ RCT_EXPORT_METHOD(getPendingOomReports:(RCTPromiseResolveBlock)resolve
290
+ reject:(RCTPromiseRejectBlock)reject)
291
+ {
292
+ @try {
293
+ NSArray<NSDictionary *> *reports = [RumAppStateRecorder pendingOomReports];
294
+ NSError *error = nil;
295
+ NSData *jsonData = [NSJSONSerialization dataWithJSONObject:reports
296
+ options:0
297
+ error:&error];
298
+ if (jsonData == nil) {
299
+ resolve(@"[]");
300
+ return;
301
+ }
302
+ NSString *jsonString = [[NSString alloc] initWithData:jsonData
303
+ encoding:NSUTF8StringEncoding];
304
+ resolve(jsonString ?: @"[]");
305
+ } @catch (NSException *exception) {
306
+ reject(@"RUM_OOM_GET_PENDING_ERROR", exception.reason, nil);
307
+ }
308
+ }
309
+
310
+ RCT_EXPORT_METHOD(clearOomReports:(NSString *)oomIds
311
+ resolve:(RCTPromiseResolveBlock)resolve
312
+ reject:(RCTPromiseRejectBlock)reject)
313
+ {
314
+ @try {
315
+ NSArray *ids = @[];
316
+ if (oomIds.length > 0) {
317
+ NSData *data = [oomIds dataUsingEncoding:NSUTF8StringEncoding];
318
+ id parsed = data ? [NSJSONSerialization JSONObjectWithData:data
319
+ options:0
320
+ error:nil]
321
+ : nil;
322
+ if ([parsed isKindOfClass:[NSArray class]]) {
323
+ ids = (NSArray *)parsed;
324
+ }
325
+ }
326
+ [RumAppStateRecorder clearOomReportsWithIds:ids];
327
+ resolve(nil);
328
+ } @catch (NSException *exception) {
329
+ reject(@"RUM_OOM_CLEAR_ERROR", exception.reason, nil);
330
+ }
331
+ }
332
+
333
+ RCT_EXPORT_METHOD(updateCrashContext:(NSString *)context)
248
334
  {
249
335
  [RumCrashReporter updateCrashContext:context];
250
336
  }
@@ -1,54 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _reactNative = require("react-native");
8
- /**
9
- * 原生设备信息,对应存储模型中的公共属性:
10
- * - device.* (id / type / brand / model / name)
11
- * - os.* (type / version / container / container_version)
12
- * - app.package
13
- * - viewport.width / viewport.height
14
- */
15
-
16
- /**
17
- * 获取原生模块。
18
- *
19
- * 优先使用 TurboModuleRegistry(RN 0.68+ TurboModule 架构),
20
- * 若未找到则降级到 Legacy Bridge 的 NativeModules(RN 0.68-0.70 未开启 New Arch 时),
21
- * 若均不可用则返回一组空实现兜底。
22
- *
23
- * 使用非强制的 `TurboModuleRegistry.get`(而非 `getEnforcing`),避免在原生
24
- * 二进制未注册该模块时于「模块加载阶段」直接抛异常——那会连锁导致整个 JS
25
- * bundle 评估失败(表现为所有路由丢失 default export、App 白屏)。
26
- *
27
- * 当原生模块缺失时(通常是新增原生代码后未重新编译原生 App,只重跑了 Metro),
28
- * 返回一组空实现兜底:崩溃采集与原生设备信息降级为不可用,但 PV / 行为 / API /
29
- * JS 异常等纯 JS 能力不受影响。需重新构建原生工程(如 `expo run:ios` /
30
- * `pod install` + 重新编译)后崩溃采集才会真正生效。
31
- */
32
- const nativeModule = _reactNative.TurboModuleRegistry.get('RumSdkReactnative') ?? _reactNative.NativeModules.RumSdkReactnative;
33
- if (!nativeModule) {
34
- console.warn("[rum] Native module 'RumSdkReactnative' not found in the native binary. " + 'Crash reporting and native device info are disabled. ' + 'Rebuild the native app (e.g. `expo run:ios` / `expo run:android`, ' + 'or `pod install` + rebuild) so the module gets registered.');
35
- }
36
-
37
- /** 原生模块缺失时的空实现,保证调用方不会因缺方法而抛错。 */
38
- const fallback = {
39
- getItem: async () => null,
40
- setItem: async () => {},
41
- removeItem: async () => {},
42
- clear: async () => {},
43
- getAllKeys: async () => [],
44
- getDeviceInfo: async () => ({}),
45
- getPendingCrashes: async () => '[]',
46
- clearCrashReports: async () => {},
47
- clearAllCrashReports: async () => {},
48
- cleanupOldCrashes: async () => {},
49
- crashedLastRun: async () => false,
50
- updateCrashContext: () => {},
51
- triggerTestCrash: () => {}
52
- };
53
- var _default = exports.default = nativeModule ?? fallback;
54
- //# sourceMappingURL=NativeRumSdkReactnative.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _reactNative=require("react-native");const nativeModule=_reactNative.TurboModuleRegistry.get("RumSdkReactnative")??_reactNative.NativeModules.RumSdkReactnative;nativeModule||console.warn("[rum] Native module 'RumSdkReactnative' not found in the native binary. Crash reporting and native device info are disabled. Rebuild the native app (e.g. `expo run:ios` / `expo run:android`, or `pod install` + rebuild) so the module gets registered.");const fallback={getItem:async()=>null,setItem:async()=>{},removeItem:async()=>{},clear:async()=>{},getAllKeys:async()=>[],getDeviceInfo:async()=>({}),getPendingCrashes:async()=>"[]",clearCrashReports:async()=>{},clearAllCrashReports:async()=>{},cleanupOldCrashes:async()=>{},crashedLastRun:async()=>!1,updateCrashContext:()=>{},triggerTestCrash:()=>{},getPendingOomReports:async()=>"[]",clearOomReports:async()=>{},updateCollectorsConfig:()=>{}};var _default=exports.default=nativeModule??fallback;
@@ -1,108 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
- var _rumCore = require("@arms/rum-core");
8
- var _view = require("../../utils/view");
9
- var _action = require("../../utils/action");
10
- class ActionCollector {
11
- name = 'action-collector';
12
- DELAY_TIME = 300;
13
- events = ['tap'];
14
- setup(ctx, sendEvent) {
15
- const {
16
- collectors = {}
17
- } = ctx.getConfig();
18
- if (collectors.action === false) {
19
- return;
20
- }
21
- this.ctx = ctx;
22
- this.sendEvent = sendEvent;
23
- // 开启 React Native 触摸自动采集,并监听标准化的 tap 事件
24
- (0, _action.startTrackingActions)();
25
- (0, _action.addActionListener)(this.onEvent);
26
- }
27
- onEvent = e => {
28
- if (e && this.events.includes(e.type) && e.target) {
29
- const {
30
- target,
31
- currentTarget,
32
- type
33
- } = e;
34
- const {
35
- dataset,
36
- id
37
- } = target;
38
- if (!id) return;
39
- if (currentTarget && id !== currentTarget.id) return;
40
- let view;
41
- if (this.ctx) {
42
- view = (0, _view.getCurView)(this.ctx);
43
- }
44
- const event = {
45
- event_type: _rumCore.RumEventType.ACTION,
46
- type,
47
- name: e.name || id,
48
- target_name: e.targetName,
49
- duration: e.duration,
50
- position: e.position,
51
- target: this.buildTarget(target),
52
- snapshots: dataset && Object.keys(dataset).length ? JSON.stringify(dataset).slice(0, 1000) : undefined,
53
- times: 1,
54
- view
55
- };
56
- clearTimeout(this.timer);
57
- if (this.lastEvent && this.lastActionId === id) {
58
- // 同一元素的连续点击:仅累加次数
59
- // @ts-ignore
60
- this.lastEvent.times += 1;
61
- } else {
62
- // 切换到不同元素:立即上报上一个,再记录新事件
63
- if (this.lastEvent) {
64
- this.sendAction();
65
- }
66
- this.lastEvent = event;
67
- this.lastActionId = id;
68
- }
69
- this.timer = setTimeout(this.sendAction, this.DELAY_TIME);
70
- }
71
- };
72
-
73
- /**
74
- * 组装热力图相关的 target 信息(selector/宽高/可交互性/可信度)。
75
- * 当没有任何字段时返回 undefined,避免上报空对象。
76
- */
77
- buildTarget(target) {
78
- const {
79
- selector,
80
- width,
81
- height,
82
- reaction,
83
- trust
84
- } = target;
85
- if (selector === undefined && width === undefined && height === undefined && reaction === undefined && trust === undefined) {
86
- return undefined;
87
- }
88
- return {
89
- selector,
90
- width,
91
- height,
92
- reaction,
93
- trust
94
- };
95
- }
96
- sendAction = () => {
97
- // @ts-ignore
98
- this.sendEvent(this.lastEvent);
99
- this.lastEvent = undefined;
100
- this.lastActionId = undefined;
101
- };
102
- destroy() {
103
- (0, _action.removeActionListener)(this.onEvent);
104
- (0, _action.stopTrackingActions)();
105
- }
106
- }
107
- exports.default = ActionCollector;
108
- //# sourceMappingURL=index.js.map
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=void 0;var _rumCore=require("@arms/rum-core"),_view=require("../../utils/view"),_action=require("../../utils/action");class ActionCollector{name="action-collector";DELAY_TIME=300;events=["tap"];setup(t,e){const{collectors:i={}}=t.getConfig();!1!==i.action&&(this.ctx=t,this.sendEvent=e,(0,_action.startTrackingActions)(),(0,_action.addActionListener)(this.onEvent))}onEvent=t=>{if(t&&this.events.includes(t.type)&&t.target){const{target:e,currentTarget:i,type:s}=t,{dataset:n,id:o}=e;if(!o)return;if(i&&o!==i.id)return;let r;this.ctx&&(r=(0,_view.getCurView)(this.ctx));const a={event_type:_rumCore.RumEventType.ACTION,type:s,name:t.name||o,target_name:t.targetName,duration:t.duration,position:t.position,target:this.buildTarget(e),snapshots:n&&Object.keys(n).length?JSON.stringify(n).slice(0,1e3):void 0,times:1,view:r};clearTimeout(this.timer),this.lastEvent&&this.lastActionId===o?this.lastEvent.times+=1:(this.lastEvent&&this.sendAction(),this.lastEvent=a,this.lastActionId=o),this.timer=setTimeout(this.sendAction,this.DELAY_TIME)}};buildTarget(t){const{selector:e,width:i,height:s,reaction:n,trust:o}=t;if(void 0!==e||void 0!==i||void 0!==s||void 0!==n||void 0!==o)return{selector:e,width:i,height:s,reaction:n,trust:o}}sendAction=()=>{this.sendEvent(this.lastEvent),this.lastEvent=void 0,this.lastActionId=void 0};destroy(){(0,_action.removeActionListener)(this.onEvent),(0,_action.stopTrackingActions)()}}exports.default=ActionCollector;