Taro崩溃排查

142 阅读3分钟

一、SIGSEGV 段错误

React Native 的 JavaScript 代码中,某些语法或操作可能会间接导致 SIGSEGV (段错误) ,尽管 SIGSEGV 通常是原生(Native)层的崩溃(如 C++/Objective-C/Java 代码问题)。但以下 JS 代码行为可能 间接触发原生崩溃


  1. 直接或间接调用 Native 模块时的错误

(1) 调用未注册的 Native 模块

import { NativeModules } from 'react-native';// 如果 MyNonExistentModule 未在原生端注册
NativeModules.MyNonExistentModule.doSomething(); // 可能导致原生崩溃

修复

确保 Native 模块已正确链接(iOS 的 RCT_EXPORT_MODULE() / Android 的 ReactContextBaseJavaModule)。

(2) 错误的参数传递给 Native 方法

NativeModules.MyModule.methodWithObject({ invalid: undefined }); 
// 如果原生端未处理 undefined,可能崩溃

修复

确保参数类型匹配原生端预期(如避免传递 undefinedNaN)。


  1. 滥用 DeviceEventEmitter 或 Native 事件

(1) 过早触发事件(Bridge 未就绪)

import { DeviceEventEmitter } from 'react-native';// 在 App 启动时立即调用,可能 Bridge 未初始化
DeviceEventEmitter.emit('myEvent', { data: 'test' }); 

修复

延迟事件触发(如放到 useEffectcomponentDidMount 中)。

(2) 未移除事件监听导致内存泄漏

DeviceEventEmitter.addListener('event', () => {});// 忘记移除监听,可能导致原生端持有无效回调

修复

在组件卸载时移除监听:

useEffect(() => {const subscription = DeviceEventEmitter.addListener('event', handler);return () => subscription.remove(); // 清理}, []);

  1. 错误的 JSI 或 TurboModules 使用

(1) 直接操作 JSI 对象(高级用法风险)

// 假设某个库内部使用 JSI 直接访问 C++ 内存
const jsiObject = someJsiLibrary.getNativeObject();
jsiObject.invalidMethod(); // 如果 C++ 对象已释放,触发 SIGSEGV

修复

避免直接操作 JSI 对象,除非明确知道生命周期管理。

(2) TurboModules 的异步回调问题

NativeModules.MyTurboModule.methodWithCallback((err, data) => {if (err) throw err; // 如果回调中抛出异常,可能影响原生端});

修复

确保回调中捕获所有异常:

NativeModules.MyTurboModule.methodWithCallback((err, data) => {try {if (err) console.error(err);else console.log(data);} catch (e) {
    console.error('Callback error:', e);}});

  1. 内存密集型操作阻塞 JS 线程

(1) 大数据处理导致 JS 阻塞

const hugeArray = new Array(1e7).fill(0).map(processData); // 主线程卡死// 可能间接导致原生端检测到 ANR(Application Not Responding)

修复

使用 InteractionManagerWeb Worker 分流:
InteractionManager.runAfterInteractions(() => {// 执行耗时任务});

(2) 频繁触发 setState 或 UI 更新

// 快速连续更新状态,可能导致原生 UI 线程过载
for (let i = 0; i < 1000; i++) {setState({ count: i }); // 可能引发原生端布局计算崩溃}

修复

合并状态更新或使用防抖(debounce)。


  1. 第三方 Native 库的误用

(1) 未正确处理库的初始化

import { SomeNativeLib } from 'react-native-native-lib';// 如果库需要在原生端初始化,但未调用
SomeNativeLib.init().catch(console.error); // 未初始化直接调用方法会崩溃

修复

阅读库的文档,确保正确初始化。

(2) 版本不兼容

// 如果 JS 代码调用了新 API,但原生库版本过旧
NativeModules.MyLib.newMethod(); // 原生端不存在此方法

修复

确保 react-native 和第三方库版本兼容。


  1. 其他潜在危险操作

(1) 滥用 eval 或动态执行代码

const dynamicCode = 'NativeModules.MyModule.crash()';eval(dynamicCode); // 可能执行危险操作

修复

避免动态执行代码。

(2) 未捕获的 Promise 异常

async function fetchData() {const res = await someNativeMethod(); // 如果原生端抛出异常
  console.log(res);}fetchData(); // 未捕获异常可能导致 Bridge 不稳定

修复

始终捕获异步错误:

fetchData().catch(e => console.error('Native call failed:', e));

总结表:JS 可能触发 SIGSEGV 的场景

JS 代码行为原生层风险修复方案
调用未注册的 Native 模块访问无效原生方法确保模块已正确链接
传递非法参数到 Native原生端解析崩溃校验参数类型
过早触发 DeviceEventEmitterBridge 未初始化延迟事件触发
未移除事件监听内存泄漏导致野指针组件卸载时清理监听
大数据阻塞 JS 线程原生检测到 ANR使用 InteractionManager 分流任务
第三方库未初始化原生代码未准备好阅读文档,正确初始化库

二、RCTDeviceEventEmitter错误

try-catch