如何捕获Cordova原生异常?解决Play Store应用稳定性问题
捕获Cordova原生异常并手动记录的方案
针对你遇到的Sentry无法自动捕获Cordova原生崩溃,但手动调用Sentry.captureException()正常的问题,可以通过在原生层(Android/iOS)实现异常捕获逻辑,再桥接到JS层调用Sentry上报,具体方案如下:
Android 原生异常捕获
步骤1:自定义全局异常处理器
在你的Cordova项目的MainActivity.java中,设置自定义的UncaughtExceptionHandler,捕获未处理的原生异常并传递给JS层:
import android.os.Bundle; import android.util.Log; import org.apache.cordova.CordovaActivity; import java.lang.Thread.UncaughtExceptionHandler; public class MainActivity extends CordovaActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 注册自定义未捕获异常处理器 Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable throwable) { // 格式化异常栈信息 String crashDetails = Log.getStackTraceString(throwable); // 转义字符串避免JS语法错误 String escapedDetails = crashDetails.replace("'", "\\'").replace("\n", "\\n"); // 通过WebView通知JS层 webView.loadUrl("javascript:window.captureNativeCrash('Android原生崩溃:\\n" + escapedDetails + "')"); // 可选:调用系统默认处理器终止应用(根据需求决定是否保留) Thread.getDefaultUncaughtExceptionHandler().uncaughtException(thread, throwable); } }); loadUrl(launchUrl); } }
步骤2:JS层接收并上报
在你的Cordova应用JS代码中,定义全局函数接收原生传递的异常信息,调用Sentry手动上报:
window.captureNativeCrash = function(errorMessage) { // 用Sentry捕获并记录原生异常 Sentry.captureException(new Error(errorMessage)); };
iOS 原生异常捕获
iOS需要同时处理NSException和底层信号(如SIGSEGV、SIGABRT)两种崩溃场景:
步骤1:修改AppDelegate.m
在项目的AppDelegate.m中添加异常和信号处理逻辑:
#import "AppDelegate.h" #import <Cordova/CDVViewController.h> #include <signal.h> #include <execinfo.h> @interface AppDelegate () void handleUncaughtNSException(NSException *exception); void handleNativeSignal(int signal); @end @implementation AppDelegate - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { // 注册未捕获NSException处理器 NSSetUncaughtExceptionHandler(&handleUncaughtNSException); // 注册常见崩溃信号处理器 signal(SIGABRT, handleNativeSignal); signal(SIGSEGV, handleNativeSignal); signal(SIGBUS, handleNativeSignal); signal(SIGILL, handleNativeSignal); signal(SIGFPE, handleNativeSignal); return [super application:application didFinishLaunchingWithOptions:launchOptions]; } // 处理未捕获的NSException void handleUncaughtNSException(NSException *exception) { NSString *crashMsg = [NSString stringWithFormat:@"iOS NSException崩溃: %@\n调用栈:\n%@", exception.reason, [exception.callStackSymbols componentsJoinedByString:@"\n"]]; NSString *escapedMsg = [crashMsg stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; // 获取Cordova视图控制器并通知JS层 CDVViewController *vc = (CDVViewController*)[(AppDelegate*)[[UIApplication sharedApplication] delegate] viewController]; NSString *jsCall = [NSString stringWithFormat:@"window.captureNativeCrash('%@')", escapedMsg]; [vc.webView evaluateJavaScript:jsCall completionHandler:nil]; // 委托系统默认处理器处理 [[NSException defaultHandler] handleException:exception]; } // 处理底层信号崩溃 void handleNativeSignal(int signal) { void *callStack[128]; int frameCount = backtrace(callStack, 128); char **stackSymbols = backtrace_symbols(callStack, frameCount); NSMutableString *stackTrace = [NSMutableString string]; for (int i = 0; i < frameCount; i++) { [stackTrace appendFormat:@"%s\n", stackSymbols[i]]; } free(stackSymbols); NSString *crashMsg = [NSString stringWithFormat:@"iOS信号崩溃(Signal %d):\n%@", signal, stackTrace]; NSString *escapedMsg = [crashMsg stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; CDVViewController *vc = (CDVViewController*)[(AppDelegate*)[[UIApplication sharedApplication] delegate] viewController]; NSString *jsCall = [NSString stringWithFormat:@"window.captureNativeCrash('%@')", escapedMsg]; [vc.webView evaluateJavaScript:jsCall completionHandler:nil]; // 信号崩溃通常无法恢复,终止应用 exit(signal); } @end
步骤2:JS层接收并上报
和Android端共用同一个JS函数即可:
window.captureNativeCrash = function(errorMessage) { Sentry.captureException(new Error(errorMessage)); };
注意事项
- 字符串转义:必须对原生传递的异常信息中的单引号、换行符等特殊字符转义,避免触发JS语法错误。
- 崩溃场景兼容性:部分严重崩溃(如Android的ANR、iOS的内核级崩溃)可能导致WebView无法即时通知JS层,这种情况下可以将异常信息写入本地文件,待应用重启后读取并上报。
- 测试验证:可以在原生代码中主动触发崩溃(如Android中
throw new RuntimeException("Test Crash"),iOS中raise(SIGSEGV, 0)),验证捕获和上报流程是否正常。
内容的提问来源于stack exchange,提问作者lorem_ipsum
相关产品推荐
相关产品推荐

