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

如何在Crashlytics非致命错误报告中覆盖库与文件名?

Crashlytics适配依赖注入式日志封装的解决方案

针对封装Logger接口后,Crashlytics上报错误时仅显示LoggerImpl栈帧的问题,有以下几种可行方案:

方案一:手动包装Error并注入原始调用栈

利用NSError的NSStackTraceKey字段,在Logger实现中捕获并清理掉自身的栈帧,将原始错误的调用栈传递给Crashlytics:

final class LoggerImpl: Logger {
    func log(error: Error) {
        // 获取当前调用栈,移除LoggerImpl相关的栈帧
        var stackTrace = Thread.callStackSymbols
        while let topFrame = stackTrace.first, topFrame.contains("LoggerImpl.log(error:)") {
            stackTrace.removeFirst()
        }
        
        // 包装原始错误,注入清理后的调用栈
        let wrappedUserInfo: [String: Any] = [
            NSUnderlyingErrorKey: error,
            NSStackTraceKey: stackTrace
        ]
        let wrappedError = NSError(
            domain: error._domain,
            code: error._code,
            userInfo: wrappedUserInfo
        )
        
        Crashlytics.crashlytics().record(error: wrappedError)
    }
}

Crashlytics会识别NSStackTraceKey字段,自动展示原始错误的调用栈,而非LoggerImpl的位置。

方案二:使用自定义异常上报API

直接调用Crashlytics的recordCustomExceptionName方法,传入自定义的堆栈帧数组,完全绕过默认的栈帧捕获逻辑:

import Crashlytics

final class LoggerImpl: Logger {
    func log(error: Error) {
        // 获取调用栈地址,移除LoggerImpl及当前方法的栈帧(根据实际调用深度调整移除数量)
        var stackAddresses = Thread.callStackReturnAddresses
        stackAddresses.removeFirst(2)
        
        // 转换为Crashlytics要求的CLSStackFrame数组
        let crashFrames = stackAddresses.map { CLSStackFrame(address: $0) }
        
        // 上报自定义异常
        Crashlytics.crashlytics().recordCustomExceptionName(
            error._domain,
            reason: error.localizedDescription,
            frameArray: crashFrames
        )
    }
}

这种方式能直接控制上报的堆栈内容,确保错误来源的准确性。

方案三:扩展Error自动捕获堆栈

通过扩展Error类型,让业务模块可以便捷地传递带原始栈帧的错误(需业务侧配合调用):

extension Error {
    func withOriginalStackTrace() -> NSError {
        var userInfo = self._userInfo ?? [:]
        userInfo[NSStackTraceKey] = Thread.callStackSymbols
        return NSError(
            domain: self._domain,
            code: self._code,
            userInfo: userInfo
        )
    }
}

业务侧调用示例:

do {
    try someRiskyOperation()
} catch {
    logger.log(error: error.withOriginalStackTrace())
}

内容的提问来源于stack exchange,提问作者Jacob Bartlett

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:46:28