@arms/rum-reactnative 0.1.3-beta.4 → 0.1.3-beta.5

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
@@ -427,7 +427,7 @@ SDK 的 peerDependencies 声明为 `react-native: >=0.68.0`,原生构建配置
427
427
  |--------|--------------|-------------|------|
428
428
  | **原生崩溃采集** | TurboModule + codegen | 0.68 | podspec / build.gradle 按版本条件分支,自动适配 0.68-0.70 和 0.71+ |
429
429
  | NDK 崩溃采集(C/C++) | CMake + NDK `externalNativeBuild` | 0.68 | 随原生崩溃采集一起启用 |
430
- | iOS 崩溃采集(KSCrash) | KSCrash ~2.0(CocoaPods 源码依赖) | 0.68 | `pod install` 时自动编译 |
430
+ | iOS 崩溃采集(KSCrash) | KSCrash 2.5.1(CocoaPods 源码依赖,已锁定版本) | 0.68 | `pod install` 时自动编译 |
431
431
  | **JS 异常采集** | `ErrorUtils.setGlobalHandler` | 0.68 | 全版本可用 |
432
432
  | Hermes Promise rejection | `HermesInternal.enablePromiseRejectionTracker` | 0.70(推荐) | Hermes 为默认引擎时完整支持 |
433
433
  | JSC Promise rejection 兜底 | `globalThis.onunhandledrejection` | 0.68 | 非 Hermes 引擎有降级方案 |
@@ -25,7 +25,9 @@ Pod::Spec.new do |s|
25
25
 
26
26
  # KSCrash 通过 CocoaPods 源码依赖引入。KSCrash 不发布官方 XCFramework,
27
27
  # 故不自行预编译,直接由宿主工程 `pod install` 时源码编译。
28
- s.dependency "KSCrash", "~> 2.0"
28
+ # 锁定到已验证版本 2.5.1:避免 `~> 2.0` 浮动解析到未经测试的新版本,在不同
29
+ # iOS(尤其新系统如 iOS 26)上源码编译引入不可控行为。升级须重新回归验证后再改此处。
30
+ s.dependency "KSCrash", "2.5.1"
29
31
 
30
32
  if defined?(install_modules_dependencies)
31
33
  # RN 0.71+ 使用 install_modules_dependencies 自动解析 React 依赖
@@ -11,6 +11,8 @@
11
11
  #import <dlfcn.h>
12
12
  #import <signal.h>
13
13
  #import <stdlib.h>
14
+ #import <string.h>
15
+ #import <mach-o/dyld.h>
14
16
 
15
17
  #import "fishhook.h"
16
18
 
@@ -53,6 +55,37 @@ static void RumCrashReporterEarlyLoad(void) {
53
55
  gRumCrashLoaded = 1;
54
56
  }
55
57
 
58
+ #pragma mark - Detox detection
59
+
60
+ /**
61
+ * 检测当前进程是否运行在 Detox(E2E 测试)环境下。
62
+ *
63
+ * 仅当检测到 Detox 时,才需要用 fishhook 把被 Detox swizzle 的 sigaction 重绑回
64
+ * libsystem 的真实实现(详见 +install 内注释)。生产环境不存在 Detox,应跳过该
65
+ * 全局运行时符号重绑:rebind_symbols 会遍历进程内所有已加载镜像、对命中的
66
+ * __DATA_CONST 符号指针页执行 vm_protect + 改写,属高侵入操作,可能扰动其他库
67
+ * (如图片解码)后台线程的内存布局与调度时序。参见
68
+ * docs/iOS 26 图片解码崩溃排查说明.md。
69
+ *
70
+ * 采用双重信号,兼容 Detox “链接进 App” 与 “DYLD_INSERT_LIBRARIES 注入” 两种集成:
71
+ * 1) Detox 框架注册的 Objective-C 主类 "Detox" 是否存在;
72
+ * 2) 已加载的 dyld 镜像路径中是否包含 "Detox"(覆盖注入了框架但主类名不同的情形)。
73
+ * 本函数在普通线程(RN 模块 init)调用,非信号处理器上下文,可安全使用 Foundation/dyld API。
74
+ */
75
+ static BOOL RumIsDetoxRuntimePresent(void) {
76
+ if (NSClassFromString(@"Detox") != nil) {
77
+ return YES;
78
+ }
79
+ uint32_t imageCount = _dyld_image_count();
80
+ for (uint32_t i = 0; i < imageCount; i++) {
81
+ const char *imageName = _dyld_get_image_name(i);
82
+ if (imageName != NULL && strstr(imageName, "Detox") != NULL) {
83
+ return YES;
84
+ }
85
+ }
86
+ return NO;
87
+ }
88
+
56
89
  #pragma mark - Helpers
57
90
 
58
91
  @interface RumCrashReporter ()
@@ -129,28 +162,32 @@ static void RumCrashReporterEarlyLoad(void) {
129
162
  config.userInfoJSON = @{ kRumCrashUserInfoContextKey: currentContext };
130
163
  }
131
164
 
132
- // Detox(如果注入)通过 fishhook swizzle 了 sigaction,会静默丢弃后续对
133
- // SIGABRT/SIGSEGV 等致命信号的 sigaction 调用。KSCrash 的 signal monitor
134
- // 调用 sigaction 安装自己的 handler 时就会被丢弃,导致 KSCrash 无法捕获
135
- // 信号类崩溃。
136
- // 这里在 KSCrash install 之前用 fishhook 把 sigaction 的 lazy pointer
137
- // 重绑回 libsystem 的真实函数(dlsym 返回的是真实函数地址,不受 fishhook
138
- // 影响)。重绑后 KSCrash 的 sigaction 调用会真正生效,其 signal handler
139
- // 会覆盖 Detox 的 handler。崩溃发生时 KSCrash 先写报告,再 uninstall +
140
- // raise(sig) 触发 Detox 的 handler(KSCrash 在 uninstall 时恢复了 previous
141
- // handler),Detox 仍能感知崩溃并通知测试 runner。
142
- static int (*real_sigaction)(int, const struct sigaction * __restrict,
143
- struct sigaction * __restrict) = NULL;
144
- if (real_sigaction == NULL) {
145
- real_sigaction = (int (*)(int, const struct sigaction * __restrict,
146
- struct sigaction * __restrict))
147
- dlsym(RTLD_DEFAULT, "sigaction");
148
- }
149
- if (real_sigaction != NULL) {
150
- struct rebinding rebindings[] = {
151
- {"sigaction", (void *)real_sigaction, NULL},
152
- };
153
- rebind_symbols(rebindings, sizeof(rebindings) / sizeof(rebindings[0]));
165
+ // 【仅在 Detox(E2E)环境下执行】Detox 会通过 fishhook swizzle sigaction,
166
+ // 静默丢弃后续对 SIGABRT/SIGSEGV 等致命信号的 sigaction 调用,导致 KSCrash
167
+ // 的 signal monitor 无法安装 handler、捕获不到信号类崩溃。此时在 KSCrash
168
+ // install 之前用 fishhook 把 sigaction 的 lazy pointer 重绑回 libsystem 的
169
+ // 真实函数(dlsym 返回真实地址,不受 fishhook 影响),KSCrash 的 sigaction
170
+ // 调用即可生效,其 signal handler 会覆盖 Detox 的 handler;崩溃时 KSCrash
171
+ // 先写报告,再 uninstall + raise(sig) 触发 Detox 的 handler(uninstall 已
172
+ // 恢复 previous handler),Detox 仍能感知崩溃并通知测试 runner。
173
+ //
174
+ // 生产环境无 Detox 的 sigaction swizzle,无需重绑;rebind_symbols 的高侵入
175
+ // 全局改写可能扰动其他库后台线程(如 SDWebImage 图片解码)的内存/时序,
176
+ // 故用 RumIsDetoxRuntimePresent() 将其收敛为仅测试环境执行。
177
+ if (RumIsDetoxRuntimePresent()) {
178
+ static int (*real_sigaction)(int, const struct sigaction * __restrict,
179
+ struct sigaction * __restrict) = NULL;
180
+ if (real_sigaction == NULL) {
181
+ real_sigaction = (int (*)(int, const struct sigaction * __restrict,
182
+ struct sigaction * __restrict))
183
+ dlsym(RTLD_DEFAULT, "sigaction");
184
+ }
185
+ if (real_sigaction != NULL) {
186
+ struct rebinding rebindings[] = {
187
+ {"sigaction", (void *)real_sigaction, NULL},
188
+ };
189
+ rebind_symbols(rebindings, sizeof(rebindings) / sizeof(rebindings[0]));
190
+ }
154
191
  }
155
192
 
156
193
  NSError *error = nil;
@@ -14,7 +14,7 @@ var _rumCore = require("@arms/rum-core");
14
14
  var _reactNative = require("react-native");
15
15
  var _NativeRumSdkReactnative = _interopRequireDefault(require("../NativeRumSdkReactnative"));
16
16
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
17
- const _pkg = {"version":"0.1.3-beta.4"};
17
+ const _pkg = {"version":"0.1.3-beta.5"};
18
18
  const VERSION = exports.VERSION = _pkg.version;
19
19
 
20
20
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -3,7 +3,7 @@
3
3
  import { AppType } from '@arms/rum-core';
4
4
  import { Dimensions, Platform } from 'react-native';
5
5
  import NativeRumSdkReactnative from "../NativeRumSdkReactnative.js";
6
- const _pkg = {"version":"0.1.3-beta.4"};
6
+ const _pkg = {"version":"0.1.3-beta.5"};
7
7
  export const VERSION = _pkg.version;
8
8
 
9
9
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arms/rum-reactnative",
3
- "version": "0.1.3-beta.4",
3
+ "version": "0.1.3-beta.5",
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",