Refactor to eliminate hardcoded identifiers

Read package identifier and app group ID from Info.plist at runtime
via AppConfiguration. This enables SFM.System to use TeamID-prefixed
app group format required by macOS Sequoia, fixing the privacy prompt
when accessing app group data.
This commit is contained in:
世界
2026-01-03 02:46:52 +08:00
parent 64e2ece819
commit 81d6827334
21 changed files with 118 additions and 41 deletions
+1 -1
View File
@@ -115,7 +115,7 @@ public struct TypedProfile: Transferable, Codable {
}
public extension UTType {
static var profile: UTType { .init(exportedAs: "io.nekohasekai.sfavt.profile") }
static var profile: UTType { .init(exportedAs: AppConfiguration.profileUTType) }
}
#if !os(tvOS)
+3 -3
View File
@@ -4,7 +4,7 @@ import NetworkExtension
@MainActor
public class ExtensionProfile: ObservableObject {
public static let controlKind = "io.nekohasekai.sfavt.widget.ServiceToggle"
public static let controlKind = AppConfiguration.widgetControlKind
private let manager: NEVPNManager
private var connection: NEVPNConnection
@@ -162,9 +162,9 @@ public class ExtensionProfile: ObservableObject {
manager.localizedDescription = Variant.applicationName
let tunnelProtocol = NETunnelProviderProtocol()
if Variant.useSystemExtension {
tunnelProtocol.providerBundleIdentifier = "\(FilePath.packageName).system"
tunnelProtocol.providerBundleIdentifier = AppConfiguration.systemExtensionBundleID
} else {
tunnelProtocol.providerBundleIdentifier = "\(FilePath.packageName).extension"
tunnelProtocol.providerBundleIdentifier = AppConfiguration.extensionBundleID
}
tunnelProtocol.serverAddress = "sing-box"
manager.protocolConfiguration = tunnelProtocol
+25
View File
@@ -0,0 +1,25 @@
import Foundation
public enum AppConfiguration {
public static let packageName: String = {
guard let value = Bundle.main.object(forInfoDictionaryKey: "BasePackageIdentifier") as? String else {
fatalError("Missing BasePackageIdentifier in Info.plist")
}
return value
}()
public static let appGroupID: String = {
guard let value = Bundle.main.object(forInfoDictionaryKey: "AppGroupIdentifier") as? String else {
fatalError("Missing AppGroupIdentifier in Info.plist")
}
return value
}()
public static var extensionBundleID: String { "\(packageName).extension" }
public static var systemExtensionBundleID: String { "\(packageName).system" }
public static var fileProviderDomainID: String { "\(packageName).workingdir" }
public static var widgetControlKind: String { "\(packageName).widget.ServiceToggle" }
public static var profileUTType: String { "\(packageName).profile" }
public static var backgroundTaskID: String { "\(packageName).update_profiles" }
public static var iCloudContainerID: String { "iCloud.\(packageName)" }
}
+12 -15
View File
@@ -1,32 +1,29 @@
import Foundation
public enum FilePath {
public static let packageName = "io.nekohasekai.sfavt"
}
public static let packageName = AppConfiguration.packageName
public static let groupName = AppConfiguration.appGroupID
public extension FilePath {
static let groupName = "group.\(packageName)"
private static let defaultSharedDirectory: URL! = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: FilePath.groupName)
private static let defaultSharedDirectory: URL! = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupName)
#if os(iOS)
static let sharedDirectory = defaultSharedDirectory!
public static let sharedDirectory = defaultSharedDirectory!
#elseif os(tvOS)
static let sharedDirectory = defaultSharedDirectory
public static let sharedDirectory = defaultSharedDirectory
.appendingPathComponent("Library", isDirectory: true)
.appendingPathComponent("Caches", isDirectory: true)
#elseif os(macOS)
static var sharedDirectory: URL! = defaultSharedDirectory
public static var sharedDirectory: URL! = defaultSharedDirectory
#endif
#if os(iOS)
static let cacheDirectory = sharedDirectory
public static let cacheDirectory = sharedDirectory
.appendingPathComponent("Library", isDirectory: true)
.appendingPathComponent("Caches", isDirectory: true)
#elseif os(tvOS)
static let cacheDirectory = sharedDirectory
public static let cacheDirectory = sharedDirectory
#elseif os(macOS)
static var cacheDirectory: URL {
public static var cacheDirectory: URL {
sharedDirectory
.appendingPathComponent("Library", isDirectory: true)
.appendingPathComponent("Caches", isDirectory: true)
@@ -34,15 +31,15 @@ public extension FilePath {
#endif
#if os(macOS)
static var workingDirectory: URL {
public static var workingDirectory: URL {
cacheDirectory.appendingPathComponent("Working", isDirectory: true)
}
#else
static let workingDirectory = cacheDirectory.appendingPathComponent("Working", isDirectory: true)
public static let workingDirectory = cacheDirectory.appendingPathComponent("Working", isDirectory: true)
#endif
static var iCloudDirectory = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents", isDirectory: true) ?? URL(string: "stub")!
public static var iCloudDirectory = FileManager.default.url(forUbiquityContainerIdentifier: nil)?.appendingPathComponent("Documents", isDirectory: true) ?? URL(string: "stub")!
}
public extension URL {