Finish independent macOS version
This commit is contained in:
@@ -78,6 +78,13 @@ public struct ActiveDashboardView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $errorPresented) {
|
||||
Alert(
|
||||
title: Text("Error"),
|
||||
message: Text(errorMessage),
|
||||
dismissButton: .default(Text("Ok"))
|
||||
)
|
||||
}
|
||||
#if os(iOS)
|
||||
.onChange(of: scenePhase, perform: { newValue in
|
||||
if newValue == .active {
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ExtensionProfile: ObservableObject {
|
||||
|
||||
public static func install() async throws {
|
||||
let manager = NETunnelProviderManager()
|
||||
manager.localizedDescription = "utun interface"
|
||||
manager.localizedDescription = Variant.applicationName
|
||||
let tunnelProtocol = NETunnelProviderProtocol()
|
||||
if Variant.useSystemExtension {
|
||||
tunnelProtocol.providerBundleIdentifier = "\(FilePath.packageName).system"
|
||||
|
||||
@@ -3,7 +3,7 @@ import Libbox
|
||||
|
||||
public class HTTPClient {
|
||||
private static var userAgent: String {
|
||||
var userAgent = FilePath.httpClientName
|
||||
var userAgent = Variant.applicationName
|
||||
userAgent += "/"
|
||||
userAgent += Bundle.main.version
|
||||
userAgent += " (Build "
|
||||
|
||||
@@ -4,24 +4,32 @@
|
||||
|
||||
public class SystemExtension: NSObject, OSSystemExtensionRequestDelegate {
|
||||
private let forceUpdate: Bool
|
||||
private let inBackground: Bool
|
||||
private let semaphore = DispatchSemaphore(value: 0)
|
||||
private var result: OSSystemExtensionRequest.Result?
|
||||
private var properties: [OSSystemExtensionProperties]?
|
||||
private var error: Error?
|
||||
|
||||
private init(forceUpdate: Bool = false) {
|
||||
private init(forceUpdate: Bool = false, inBackground: Bool = false) {
|
||||
self.forceUpdate = forceUpdate
|
||||
self.inBackground = inBackground
|
||||
}
|
||||
|
||||
public func request(_: OSSystemExtensionRequest, actionForReplacingExtension existing: OSSystemExtensionProperties, withExtension ext: OSSystemExtensionProperties) -> OSSystemExtensionRequest.ReplacementAction {
|
||||
if forceUpdate {
|
||||
return .replace
|
||||
}
|
||||
if existing.isAwaitingUserApproval, !inBackground {
|
||||
return .replace
|
||||
}
|
||||
if existing.bundleIdentifier == ext.bundleIdentifier,
|
||||
existing.bundleVersion == ext.bundleVersion
|
||||
existing.bundleVersion == ext.bundleVersion,
|
||||
existing.bundleShortVersion == ext.bundleShortVersion
|
||||
{
|
||||
NSLog("Skip update system extension")
|
||||
return .cancel
|
||||
} else {
|
||||
NSLog("Update system extension")
|
||||
return .replace
|
||||
}
|
||||
}
|
||||
@@ -69,24 +77,26 @@
|
||||
|
||||
public static func isInstalled() async -> Bool {
|
||||
await (try? Task.detached {
|
||||
do {
|
||||
let propList = try SystemExtension().getProperties()
|
||||
if propList.isEmpty {
|
||||
return false
|
||||
}
|
||||
for extensionProp in propList {
|
||||
if !extensionProp.isAwaitingUserApproval, !extensionProp.isUninstalling {
|
||||
return true
|
||||
for _ in 0 ..< 3 {
|
||||
do {
|
||||
let propList = try SystemExtension().getProperties()
|
||||
if propList.isEmpty {
|
||||
return false
|
||||
}
|
||||
for extensionProp in propList {
|
||||
if !extensionProp.isAwaitingUserApproval, !extensionProp.isUninstalling {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
try await Task.sleep(nanoseconds: NSEC_PER_SEC)
|
||||
}
|
||||
} catch {
|
||||
NSLog(error.localizedDescription)
|
||||
}
|
||||
return false
|
||||
}.result.get()) == true
|
||||
}
|
||||
|
||||
public static func install(forceUpdate: Bool = false) async throws -> OSSystemExtensionRequest.Result? {
|
||||
public static func install(forceUpdate: Bool = false, inBackground _: Bool = false) async throws -> OSSystemExtensionRequest.Result? {
|
||||
try await Task.detached {
|
||||
try SystemExtension(forceUpdate: forceUpdate).submitAndWait()
|
||||
}.result.get()
|
||||
|
||||
@@ -2,11 +2,6 @@ import Foundation
|
||||
|
||||
public enum FilePath {
|
||||
public static let packageName = "io.nekohasekai.sfa"
|
||||
#if os(iOS)
|
||||
public static let httpClientName = "SFI"
|
||||
#elseif os(macOS)
|
||||
public static let httpClientName = "SFM"
|
||||
#endif
|
||||
}
|
||||
|
||||
public extension FilePath {
|
||||
|
||||
@@ -6,4 +6,10 @@ public enum Variant {
|
||||
#else
|
||||
public static let useSystemExtension = false
|
||||
#endif
|
||||
|
||||
#if os(iOS)
|
||||
public static let applicationName = "SFI"
|
||||
#elseif os(macOS)
|
||||
public static let applicationName = "SFM"
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -20,33 +20,20 @@ open class ApplicationDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
Task.detached {
|
||||
do {
|
||||
if Variant.useSystemExtension {
|
||||
if await SystemExtension.isInstalled() {
|
||||
if let result = try await SystemExtension.install() {
|
||||
if result == .willCompleteAfterReboot {
|
||||
return
|
||||
}
|
||||
try ProfileUpdateTask.setup()
|
||||
if launchedAsLogInItem {
|
||||
if SharedPreferences.startedByUser {
|
||||
if let profile = try await ExtensionProfile.load() {
|
||||
try await profile.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
try await self.postStart(launchedAsLogInItem)
|
||||
} catch {
|
||||
NSLog("application setup error: \(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func postStart(_ launchedAsLogInItem: Bool) async throws {
|
||||
try ProfileUpdateTask.setup()
|
||||
if launchedAsLogInItem {
|
||||
if SharedPreferences.startedByUser {
|
||||
if let profile = try await ExtensionProfile.load() {
|
||||
try await profile.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func applicationShouldTerminateAfterLastWindowClosed(_: NSApplication) -> Bool {
|
||||
!SharedPreferences.menuBarExtraInBackground
|
||||
}
|
||||
|
||||
+63
-38
@@ -10,9 +10,10 @@ public struct MainView: View {
|
||||
@State private var profileLoading = true
|
||||
@State private var logClient: LogClient!
|
||||
|
||||
@State private var serviceNotificationTitle = ""
|
||||
@State private var serviceNotificationContent = ""
|
||||
@State private var serviceNotificationPresented = false
|
||||
@State private var dialogTitle = ""
|
||||
@State private var dialogContent = ""
|
||||
@State private var dialogAction: (() -> Void)?
|
||||
@State private var dialogPresented = false
|
||||
|
||||
public init() {}
|
||||
public var body: some View {
|
||||
@@ -20,6 +21,7 @@ public struct MainView: View {
|
||||
VStack {
|
||||
SidebarView()
|
||||
}
|
||||
|
||||
.frame(minWidth: 150)
|
||||
} detail: {
|
||||
if profileLoading {
|
||||
@@ -33,45 +35,55 @@ public struct MainView: View {
|
||||
selection.contentView
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $serviceNotificationPresented, content: {
|
||||
Alert(
|
||||
title: Text(serviceNotificationTitle),
|
||||
message: Text(serviceNotificationContent),
|
||||
dismissButton: .default(Text("Ok"))
|
||||
)
|
||||
})
|
||||
#if !DEBUG
|
||||
.onAppear {
|
||||
ServiceNotification.setServiceNotificationListener { notification in
|
||||
serviceNotificationTitle = notification.title
|
||||
serviceNotificationContent = notification.body
|
||||
serviceNotificationPresented = true
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
ServiceNotification.removeServiceNotificationListener()
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigation) {
|
||||
StartStopButton()
|
||||
}
|
||||
}
|
||||
.onChange(of: controlActiveState, perform: { newValue in
|
||||
if newValue != .inactive {
|
||||
Task {
|
||||
await loadProfile()
|
||||
connectLog()
|
||||
if Variant.useSystemExtension {
|
||||
Task.detached {
|
||||
checkApplicationPath()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.onChange(of: selection, perform: { value in
|
||||
if value == .logs {
|
||||
connectLog()
|
||||
#endif
|
||||
.alert(isPresented: $dialogPresented, content: {
|
||||
Alert(
|
||||
title: Text(dialogTitle),
|
||||
message: Text(dialogContent),
|
||||
dismissButton: .default(Text("Ok"), action: dialogAction)
|
||||
)
|
||||
})
|
||||
.onAppear {
|
||||
ServiceNotification.setServiceNotificationListener { notification in
|
||||
dialogTitle = notification.title
|
||||
dialogContent = notification.body
|
||||
dialogAction = nil
|
||||
dialogPresented = true
|
||||
}
|
||||
}
|
||||
})
|
||||
.formStyle(.grouped)
|
||||
.environment(\.selection, $selection)
|
||||
.environment(\.extensionProfile, $extensionProfile)
|
||||
.environment(\.logClient, $logClient)
|
||||
.onDisappear {
|
||||
ServiceNotification.removeServiceNotificationListener()
|
||||
}
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigation) {
|
||||
StartStopButton()
|
||||
}
|
||||
}
|
||||
.onChange(of: controlActiveState, perform: { newValue in
|
||||
if newValue != .inactive {
|
||||
Task {
|
||||
await loadProfile()
|
||||
connectLog()
|
||||
}
|
||||
}
|
||||
})
|
||||
.onChange(of: selection, perform: { value in
|
||||
if value == .logs {
|
||||
connectLog()
|
||||
}
|
||||
})
|
||||
.formStyle(.grouped)
|
||||
.environment(\.selection, $selection)
|
||||
.environment(\.extensionProfile, $extensionProfile)
|
||||
.environment(\.logClient, $logClient)
|
||||
}
|
||||
|
||||
private func loadProfile() async {
|
||||
@@ -99,4 +111,17 @@ public struct MainView: View {
|
||||
logClient.reconnect()
|
||||
}
|
||||
}
|
||||
|
||||
private func checkApplicationPath() {
|
||||
let directoryName = URL(filePath: Bundle.main.bundlePath).deletingLastPathComponent().pathComponents.last
|
||||
if directoryName != "Applications" {
|
||||
dialogTitle = "Wrong application location"
|
||||
dialogContent = "This app needs to be placed under ~/Applications to work."
|
||||
dialogAction = {
|
||||
NSWorkspace.shared.selectFile(Bundle.main.bundlePath, inFileViewerRootedAtPath: "")
|
||||
NSApp.terminate(nil)
|
||||
}
|
||||
dialogPresented = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,7 @@ import SwiftUI
|
||||
|
||||
@main
|
||||
struct Application: App {
|
||||
@NSApplicationDelegateAdaptor private var appDelegate: ApplicationDelegate
|
||||
|
||||
init() {
|
||||
Variant.useSystemExtension = true
|
||||
}
|
||||
@NSApplicationDelegateAdaptor private var appDelegate: IndependentApplicationDelegate
|
||||
|
||||
var body: some Scene {
|
||||
MacApplication()
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import AppKit
|
||||
import Foundation
|
||||
import Library
|
||||
import MacLibrary
|
||||
|
||||
class IndependentApplicationDelegate: ApplicationDelegate {
|
||||
public func applicationWillFinishLaunching(_: Notification) {
|
||||
Variant.useSystemExtension = true
|
||||
Task.detached {
|
||||
if await SystemExtension.isInstalled() {
|
||||
if let result = try await SystemExtension.install() {
|
||||
if result == .willCompleteAfterReboot {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
3A2223582A6E1CC700C50B23 /* MacApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2223572A6E1CC700C50B23 /* MacApplication.swift */; };
|
||||
3A22235A2A6E212A00C50B23 /* SystemExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2223592A6E212A00C50B23 /* SystemExtension.swift */; };
|
||||
3A251C122A52D09700651082 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AAB5E7A2A4C1446009757F1 /* Assets.xcassets */; };
|
||||
3A2EAEED2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */; };
|
||||
3A3AA7FC2A4EFDAE002F78AB /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
|
||||
3A3AA7FF2A4EFDB3002F78AB /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
|
||||
3A3DEBEB2A4FFE2D00373BF4 /* AppIntents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A3DEBE62A4FFA6000373BF4 /* AppIntents.framework */; };
|
||||
@@ -357,6 +358,7 @@
|
||||
3A2223552A6E1BDE00C50B23 /* Variant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Variant.swift; sourceTree = "<group>"; };
|
||||
3A2223572A6E1CC700C50B23 /* MacApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacApplication.swift; sourceTree = "<group>"; };
|
||||
3A2223592A6E212A00C50B23 /* SystemExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemExtension.swift; sourceTree = "<group>"; };
|
||||
3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndependentApplicationDelegate.swift; sourceTree = "<group>"; };
|
||||
3A3DEBE12A4FFA1A00373BF4 /* ExtensionFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ExtensionFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/System/Library/Frameworks/ExtensionFoundation.framework; sourceTree = DEVELOPER_DIR; };
|
||||
3A3DEBE62A4FFA6000373BF4 /* AppIntents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppIntents.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS17.0.sdk/System/Library/Frameworks/AppIntents.framework; sourceTree = DEVELOPER_DIR; };
|
||||
3A44BB662A4DBF7900E4C9F8 /* SFI.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SFI.entitlements; sourceTree = "<group>"; };
|
||||
@@ -768,6 +770,7 @@
|
||||
3AEECC0A2A6DF9CA006A0E0C /* Assets.xcassets */,
|
||||
3AEECC502A6E0074006A0E0C /* SFM.entitlements */,
|
||||
3A2223532A6E1B6700C50B23 /* Info.plist */,
|
||||
3A2EAEEC2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift */,
|
||||
);
|
||||
path = SFM.System;
|
||||
sourceTree = "<group>";
|
||||
@@ -1279,6 +1282,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
3AEECC072A6DF9CA006A0E0C /* Application.swift in Sources */,
|
||||
3A2EAEED2A6F4CBB00D00DE3 /* IndependentApplicationDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1782,7 +1786,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
OTHER_CODE_SIGN_FLAGS = "--deep";
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
|
||||
@@ -1823,7 +1827,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
OTHER_CODE_SIGN_FLAGS = "--deep";
|
||||
OTHER_LDFLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
|
||||
@@ -1847,7 +1851,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 11;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = Z56Z6NYZN2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -1863,7 +1867,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
|
||||
PRODUCT_NAME = "sing-box";
|
||||
@@ -1885,7 +1889,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 11;
|
||||
CURRENT_PROJECT_VERSION = 12;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = Z56Z6NYZN2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -1901,7 +1905,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.3.3;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
OTHER_CODE_SIGN_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
|
||||
PRODUCT_NAME = "sing-box";
|
||||
@@ -2023,7 +2027,6 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = Z56Z6NYZN2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -2039,7 +2042,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.system;
|
||||
PRODUCT_NAME = "$(inherited)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -2059,7 +2062,6 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = Z56Z6NYZN2;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
@@ -2075,7 +2077,7 @@
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.system;
|
||||
PRODUCT_NAME = "$(inherited)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -2108,13 +2110,14 @@
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SFM.System/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "sing-box";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.independent;
|
||||
PRODUCT_NAME = SFM;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@@ -2146,13 +2149,14 @@
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = SFM.System/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = "sing-box";
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.3.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa.independent;
|
||||
PRODUCT_NAME = SFM;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<key>ApplicationLibrary.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>Associations (Playground) 1.xcscheme</key>
|
||||
<dict>
|
||||
@@ -69,7 +69,7 @@
|
||||
<key>MacLibrary.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>5</integer>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
<key>MessageExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
@@ -131,17 +131,17 @@
|
||||
<key>SFM.System.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>5</integer>
|
||||
</dict>
|
||||
<key>SFM.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>4</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>SystemExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>Test.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
||||
Reference in New Issue
Block a user