import Flutter import MachO import UIKit @main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { application.applicationIconBadgeNumber = 0 NativeCrashRecorder.install() GeneratedPluginRegistrant.register(with: self) // 第三方 SDK(高德/杰理等)初始化时可能装自己的信号处理器把我们顶掉, // 过一会儿再装一次;装的时候会把当时在位的处理器记下来链式调用,两边都不丢。 DispatchQueue.main.asyncAfter(deadline: .now() + 15) { NativeCrashRecorder.install() } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } override func applicationDidBecomeActive(_ application: UIApplication) { application.applicationIconBadgeNumber = 0 super.applicationDidBecomeActive(application) } // 添加URL回调监听 override func application( _ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:] ) -> Bool { print("AppDelegate收到URL回调: \(url.absoluteString)") // 首先尝试让父类处理 if super.application(app, open: url, options: options) { return true } return false } } // MARK: - 原生崩溃记录(2026-09-26) // // 起因:车载香薰对话里 App 两次 SIGSEGV 退出,但这台 iPhone 上**一份系统崩溃报告都没留下** // (「分析数据」里最新的还是 9-21),devicectl 只能看到 "terminated due to signal 11", // 没有调用栈就没法定位。怀疑是某个 SDK 装了信号处理器却没把信号交还系统。 // // 这里在崩溃那一刻把调用栈写进 Documents/logs/native_crash.log(和 App 日志同目录, // devicectl 能直接拉),然后把信号交还给之前在位的处理器 / 系统默认行为,不改变崩溃本身。 // 调用栈是「镜像 + 偏移」形式,拿同一次构建的 dSYM 用 atos 还原成函数名。 // // 信号处理函数里只用 write / backtrace_symbols_fd 这类 async-signal-safe 的调用, // 不分配内存、不碰 Swift 运行时的锁。 private var crashFD: Int32 = -1 /// 调用栈缓冲:安装时就分配好,信号处理里不再申请内存 private let crashFrames = UnsafeMutablePointer.allocate(capacity: 128) private let crashSignals: [Int32] = [SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGTRAP] /// 安装时在位的旧处理器(按信号号索引),崩溃时链式调用 private let previousHandlers = UnsafeMutablePointer.allocate(capacity: 32) private var previousExceptionHandler: (@convention(c) (NSException) -> Void)? private func crashWrite(_ s: StaticString) { guard crashFD >= 0 else { return } _ = s.withUTF8Buffer { write(crashFD, $0.baseAddress, $0.count) } } private func crashWriteInt(_ value: Int) { guard crashFD >= 0 else { return } // 用栈上的元组当缓冲,不走堆分配 var buf: (UInt64, UInt64, UInt64) = (0, 0, 0) withUnsafeMutableBytes(of: &buf) { raw in let p = raw.bindMemory(to: UInt8.self) var v = value < 0 ? -value : value var i = p.count repeat { i -= 1; p[i] = UInt8(48 + v % 10); v /= 10 } while v > 0 && i > 0 if value < 0 && i > 0 { i -= 1; p[i] = 45 } _ = write(crashFD, p.baseAddress! + i, p.count - i) } } private let crashSignalHandler: @convention(c) (Int32) -> Void = { sig in crashWrite("\n=== native crash signal=") crashWriteInt(Int(sig)) crashWrite(" time=") crashWriteInt(Int(time(nil))) crashWrite(" ===\n") let n = backtrace(crashFrames, 128) backtrace_symbols_fd(crashFrames, n, crashFD) crashWrite("=== images ===\n") // 各镜像的加载基址:atos 还原时要用(-l <基址>) let count = _dyld_image_count() for idx in 0.. Void = { e in let text = "\n=== uncaught exception \(Date()) \(e.name.rawValue): \(e.reason ?? "")\n" + e.callStackSymbols.joined(separator: "\n") + "\n" if crashFD >= 0, let d = text.data(using: .utf8) { d.withUnsafeBytes { _ = write(crashFD, $0.baseAddress, d.count) } fsync(crashFD) } previousExceptionHandler?(e) } }