You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何捕获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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 20:11:09