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

如何在Swift中正确设置PLCrashReporter的setCrashCallbacks回调?

Swift完全支持PLCrashReporter的崩溃回调能力,不需要切换到Objective-C实现,你遇到的回调不触发是使用方式错误导致的,具体问题和修复方案如下:

问题原因
  • 回调结构体版本参数错误
    你初始化PLCrashReporterCallbacks时version传了0,该参数必须传入PLCRASHREPORTER_CALLBACKS_VERSION常量,PLCrashReporter会校验版本号,不匹配的回调会被直接忽略。
  • 回调上下文的接口限制
    崩溃发生时处于信号处理的异步安全上下文,NSLog不属于异步安全函数,本身就无法在这个环境下正常输出日志,你用NSLog验证本身就不可行,甚至可能引发二次崩溃导致回调提前终止。
  • 调用顺序适配
    部分版本的PLCrashReporter要求先启用崩溃Reporter,再设置回调,否则回调不会被注册生效。
修复后的实现代码
import CrashReporter

// 明确指定C函数调用约定
@convention(c) func handleSignalForCrashReport(_ siginfo: UnsafeMutablePointer<siginfo_t>?, _ context: UnsafeMutablePointer<ucontext_t>?, _ userInfo: UnsafeMutableRawPointer?) {
    // 用异步安全的write接口输出到stderr,不要用NSLog
    let logStr = "crash rep handleSignalForCrashReport\n"
    guard let data = logStr.data(using: .utf8) else { return }
    data.withUnsafeBytes { buf in
        guard let baseAddr = buf.baseAddress else { return }
        _ = write(STDERR_FILENO, baseAddr, data.count)
    }

    // 你的自定义逻辑,注意只能调用异步安全的C接口,不能使用任何OC/Swift的Foundation方法、申请内存等操作
}

class AppDelegate: UIResponder, UIApplicationDelegate {
    func setupCrashReporter() {
        let config = PLCrashReporterConfig(signalHandlerType: .mach, symbolicationStrategy: .all)
        guard let crashReporter = PLCrashReporter(configuration: config) else {
            NSLog("crash reporter init failed")
            return
        }

        do {
            // 先启用Reporter
            try crashReporter.enableAndReturnError()
            NSLog("crash reporter enabled")
        } catch {
            NSLog("enable crash reporter failed: \(error)")
            return
        }

        // 初始化回调结构体,传入正确的版本号
        var callbacks = PLCrashReporterCallbacks(
            version: UInt16(PLCRASHREPORTER_CALLBACKS_VERSION),
            context: nil,
            handleSignal: handleSignalForCrashReport
        )
        // 启用后再设置回调
        crashReporter.setCrash(&callbacks)

        // 原有 pending crash report 处理逻辑不变
        if crashReporter.hasPendingCrashReport() {
            do {
                let data = try crashReporter.loadPendingCrashReportDataAndReturnError()
                let report = try PLCrashReport(data: data)
                guard let reportText = PLCrashReportTextFormatter.stringValue(for: report, with: PLCrashReportTextFormatiOS) else {
                    NSLog("report text parse failed")
                    return
                }
                NSLog("previous crash report: \(reportText)")
                try crashReporter.purgePendingCrashReportAndReturnError()
            } catch {
                NSLog("load pending report failed: \(error)")
            }
        }
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        setupCrashReporter()
        return true
    }
}
注意事项
  • 崩溃回调内只能执行极简的异步安全逻辑,不要做复杂操作、不要申请内存、不要调用任何Swift/Objective-C的高层API,否则会引发二次崩溃,导致回调逻辑无法完整执行。
  • 验证回调是否触发可以通过直接写文件的方式,或者在Xcode调试环境下触发崩溃,看stderr的输出即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 19:36:01