fix(macos): Avoid Bundle.module crash in DeviceModelCatalog
Bundle.module is a SwiftPM-generated computed property that calls fatalError() when the resource bundle isn't found. This happens in packaged .app bundles where SwiftPM's expected bundle paths differ from the actual layout. The fix uses manual bundle lookup (similar to ClawdbotKitResources.swift and Textual's Bundle.textual) to search known locations without crashing. This addresses the same class of issue fixed in Textual 0.3.1: https://github.com/gonzalezreal/textual/pull/21
This commit is contained in:
parent
343882d45c
commit
a7e4a26d3d
@ -123,17 +123,51 @@ enum DeviceModelCatalog {
|
|||||||
|
|
||||||
private static func locateResourceBundle() -> Bundle? {
|
private static func locateResourceBundle() -> Bundle? {
|
||||||
// Prefer main bundle (packaged app), then module bundle (SwiftPM/tests).
|
// Prefer main bundle (packaged app), then module bundle (SwiftPM/tests).
|
||||||
// Accessing Bundle.module in the packaged app can crash if the bundle isn't where SwiftPM expects it.
|
|
||||||
if let bundle = self.bundleIfContainsDeviceModels(Bundle.main) {
|
if let bundle = self.bundleIfContainsDeviceModels(Bundle.main) {
|
||||||
return bundle
|
return bundle
|
||||||
}
|
}
|
||||||
|
|
||||||
if let bundle = self.bundleIfContainsDeviceModels(Bundle.module) {
|
// Try to locate the module bundle manually to avoid fatalError from Bundle.module
|
||||||
return bundle
|
// when the bundle isn't where SwiftPM expects it (e.g., in packaged .app bundles).
|
||||||
|
if let bundle = locateModuleBundleSafely() {
|
||||||
|
if let checked = self.bundleIfContainsDeviceModels(bundle) {
|
||||||
|
return checked
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static func locateModuleBundleSafely() -> Bundle? {
|
||||||
|
let bundleName = "Clawdbot_Clawdbot"
|
||||||
|
|
||||||
|
let candidates: [URL?] = [
|
||||||
|
Bundle.main.resourceURL,
|
||||||
|
Bundle.main.bundleURL,
|
||||||
|
Bundle(for: BundleLocator.self).resourceURL,
|
||||||
|
Bundle(for: BundleLocator.self).bundleURL,
|
||||||
|
]
|
||||||
|
|
||||||
|
for candidate in candidates {
|
||||||
|
guard let baseURL = candidate else { continue }
|
||||||
|
|
||||||
|
// Direct path
|
||||||
|
let directURL = baseURL.appendingPathComponent("\(bundleName).bundle")
|
||||||
|
if let bundle = Bundle(url: directURL) {
|
||||||
|
return bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inside Resources/
|
||||||
|
let resourcesURL = baseURL
|
||||||
|
.appendingPathComponent("Resources")
|
||||||
|
.appendingPathComponent("\(bundleName).bundle")
|
||||||
|
if let bundle = Bundle(url: resourcesURL) {
|
||||||
|
return bundle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
private static func bundleIfContainsDeviceModels(_ bundle: Bundle) -> Bundle? {
|
private static func bundleIfContainsDeviceModels(_ bundle: Bundle) -> Bundle? {
|
||||||
if bundle.url(
|
if bundle.url(
|
||||||
forResource: "ios-device-identifiers",
|
forResource: "ios-device-identifiers",
|
||||||
@ -186,3 +220,6 @@ enum DeviceModelCatalog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helper class for bundle lookup via Bundle(for:)
|
||||||
|
private final class BundleLocator {}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user