27 Commits

Author SHA1 Message Date
Christian Tietze 9a894d7992 Consistently use macOS 10.13 as deployment target for 'modern' Xcode (#103) 2024-06-25 02:03:32 +02:00
Sindre Sorhus f326e3d9be Change repo name 2024-05-28 18:38:05 +02:00
Sindre Sorhus 22923d3354 Meta tweaks 2024-03-25 02:35:28 +09:00
Sindre Sorhus 0615d2f292 Tweaks 2024-03-25 02:35:19 +09:00
Dave DeLong cf9770cd43 More robust ONLY_ACTIVE_ARCH comparison (#101) 2024-03-25 02:35:10 +09:00
UeharaYou d811817ce3 Update note for Xcode 15 (#97) 2023-10-07 11:13:34 +07:00
UeharaYou 8e28b5e5a9 Add Xcode 15 note (#96)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2023-07-21 21:28:46 +02:00
Sindre Sorhus 7ad6331f9c Support SMAppService for macOS 13
Fixes #76
2022-11-13 23:48:46 +07:00
Sindre Sorhus d473e16953 Document Xcode 14 requirement
Fixes #81
2022-09-25 12:20:49 +07:00
Sindre Sorhus fe1c59e088 Drop support for macOS 10.12
It’s no longer supported by Xcode.
2022-09-22 23:51:24 +07:00
Sindre Sorhus 05168c04c9 Meta tweaks 2022-09-05 14:02:50 +07:00
Sindre Sorhus e8171b3e38 4.2.0 2021-10-09 16:33:34 +07:00
Ariel Elkin b35bfbde57 Silence SMCopyAllJobDictionaries deprecation warning (#66) 2021-10-09 16:32:27 +07:00
Ariel Elkin b5d8e006bd Add CI (#67)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2021-10-07 21:14:43 +07:00
Sindre Sorhus c34d3c7171 Meta tweaks 2021-08-15 11:33:45 +02:00
Sindre Sorhus afaacda259 Add related package to readme 2021-05-01 18:40:27 +07:00
Sindre Sorhus 6b16bcdf7d 4.1.0 2021-03-20 18:42:16 +07:00
Sindre Sorhus f1cc3b8dd5 Add native Apple Silicon support to the helper app
Fixes #53
2021-03-20 17:36:24 +07:00
Sindre Sorhus b068272af8 Add ITSAppUsesNonExemptEncryption to the helper app
Fixes #55
2021-03-20 16:55:08 +07:00
Sindre Sorhus 389e09faf7 Minor tweaks
Fixes #49
Fixes #51
2021-03-20 16:55:07 +07:00
Zack Sheppard 2badfdd7df Fix notarization issues with build configs not named "Release" (#57)
Co-authored-by: Javi Ramírez <javi.rmrz@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2021-03-20 16:17:12 +07:00
Sindre Sorhus 0f39982b9d 4.0.0 2020-09-17 17:42:51 +02:00
Sindre Sorhus 7f469e4511 Minor tweaks 2020-09-17 17:30:57 +02:00
Sergey Kuryanov c16509926a Swift Package Manager support (#41)
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
2020-09-17 17:29:51 +02:00
Sindre Sorhus 3708ba7f4f Upgrade to Swift 5.3 2020-09-17 00:30:27 +02:00
Sindre Sorhus 08b9b397c8 Cleanup 2020-08-02 14:22:39 +02:00
Sergey Kuryanov f7b255bc96 Add KVO, Combine, and SwiftUI support (#42) 2020-08-02 13:59:03 +02:00
25 changed files with 528 additions and 95 deletions
-4
View File
@@ -1,4 +0,0 @@
github: sindresorhus
open_collective: sindresorhus
patreon: sindresorhus
custom: https://sindresorhus.com/donate
+1
View File
@@ -1,2 +1,3 @@
xcuserdata
project.xcworkspace
.build/
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
+60 -19
View File
@@ -3,10 +3,12 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
D92CFD2224C5D909005B91BE /* Toggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D92CFD2124C5D909005B91BE /* Toggle.swift */; };
D9EF7E1D24BCF9E300A1E9AA /* copy-helper-swiftpm.sh in Resources */ = {isa = PBXBuildFile; fileRef = D9EF7E1C24BCF9E300A1E9AA /* copy-helper-swiftpm.sh */; };
E32E9B681EB87D7B000FEEE9 /* LaunchAtLogin.h in Headers */ = {isa = PBXBuildFile; fileRef = E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */; settings = {ATTRIBUTES = (Public, ); }; };
E32E9B6F1EB87DC5000FEEE9 /* LaunchAtLogin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32E9B6E1EB87DC5000FEEE9 /* LaunchAtLogin.swift */; };
E32E9B771EB87EA3000FEEE9 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = E32E9B761EB87EA3000FEEE9 /* main.swift */; };
@@ -26,6 +28,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
D92CFD2124C5D909005B91BE /* Toggle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Toggle.swift; sourceTree = "<group>"; usesTabs = 1; };
D9EF7E1C24BCF9E300A1E9AA /* copy-helper-swiftpm.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "copy-helper-swiftpm.sh"; sourceTree = "<group>"; };
E32E9B631EB87D7B000FEEE9 /* LaunchAtLogin.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LaunchAtLogin.framework; sourceTree = BUILT_PRODUCTS_DIR; };
E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = LaunchAtLogin.h; sourceTree = "<group>"; usesTabs = 1; };
E32E9B671EB87D7B000FEEE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -34,7 +38,7 @@
E32E9B761EB87EA3000FEEE9 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = main.swift; sourceTree = "<group>"; usesTabs = 1; };
E32E9B7F1EB87EA3000FEEE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E32E9B921EB889AE000FEEE9 /* copy-helper.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; lineEnding = 0; path = "copy-helper.sh"; sourceTree = "<group>"; usesTabs = 1; };
E3A6EB57249009C3004D7101 /* LaunchAtLogin.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = LaunchAtLogin.entitlements; path = LaunchAtLogin/LaunchAtLogin.entitlements; sourceTree = "<group>"; };
E3A6EB57249009C3004D7101 /* LaunchAtLogin.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LaunchAtLogin.entitlements; sourceTree = "<group>"; };
E3B8C38A20C0003300272EC0 /* LaunchAtLoginHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LaunchAtLoginHelper.entitlements; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -56,12 +60,19 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D9CFA59424C0FB5E005BC9E9 /* Sources */ = {
isa = PBXGroup;
children = (
E32E9B651EB87D7B000FEEE9 /* LaunchAtLogin */,
E32E9B751EB87EA3000FEEE9 /* LaunchAtLoginHelper */,
);
path = Sources;
sourceTree = "<group>";
};
E32E9B591EB87D7B000FEEE9 = {
isa = PBXGroup;
children = (
E3A6EB57249009C3004D7101 /* LaunchAtLogin.entitlements */,
E32E9B651EB87D7B000FEEE9 /* LaunchAtLogin */,
E32E9B751EB87EA3000FEEE9 /* LaunchAtLoginHelper */,
D9CFA59424C0FB5E005BC9E9 /* Sources */,
E32E9B641EB87D7B000FEEE9 /* Products */,
);
sourceTree = "<group>";
@@ -79,10 +90,13 @@
E32E9B651EB87D7B000FEEE9 /* LaunchAtLogin */ = {
isa = PBXGroup;
children = (
E32E9B6E1EB87DC5000FEEE9 /* LaunchAtLogin.swift */,
E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */,
D9EF7E1C24BCF9E300A1E9AA /* copy-helper-swiftpm.sh */,
E32E9B921EB889AE000FEEE9 /* copy-helper.sh */,
E32E9B671EB87D7B000FEEE9 /* Info.plist */,
E3A6EB57249009C3004D7101 /* LaunchAtLogin.entitlements */,
E32E9B661EB87D7B000FEEE9 /* LaunchAtLogin.h */,
E32E9B6E1EB87DC5000FEEE9 /* LaunchAtLogin.swift */,
D92CFD2124C5D909005B91BE /* Toggle.swift */,
);
path = LaunchAtLogin;
sourceTree = "<group>";
@@ -153,8 +167,9 @@
E32E9B5A1EB87D7B000FEEE9 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 1020;
LastUpgradeCheck = 1500;
ORGANIZATIONNAME = "Sindre Sorhus";
TargetAttributes = {
E32E9B621EB87D7B000FEEE9 = {
@@ -176,7 +191,7 @@
};
};
buildConfigurationList = E32E9B5D1EB87D7B000FEEE9 /* Build configuration list for PBXProject "LaunchAtLogin" */;
compatibilityVersion = "Xcode 11.0";
compatibilityVersion = "Xcode 15.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -201,6 +216,7 @@
files = (
E32E9B861EB8845E000FEEE9 /* LaunchAtLoginHelper.app in Resources */,
E32E9B931EB889AE000FEEE9 /* copy-helper.sh in Resources */,
D9EF7E1D24BCF9E300A1E9AA /* copy-helper-swiftpm.sh in Resources */,
E3A6EB58249009C3004D7101 /* LaunchAtLogin.entitlements in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -220,6 +236,7 @@
buildActionMask = 2147483647;
files = (
E32E9B6F1EB87DC5000FEEE9 /* LaunchAtLogin.swift in Sources */,
D92CFD2224C5D909005B91BE /* Toggle.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -246,6 +263,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@@ -267,6 +285,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -275,9 +294,11 @@
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
@@ -292,7 +313,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@@ -309,6 +330,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
@@ -330,6 +352,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
@@ -338,9 +361,11 @@
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -349,7 +374,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.12;
MACOSX_DEPLOYMENT_TARGET = 10.13;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -367,20 +392,24 @@
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = LaunchAtLogin/Info.plist;
INFOPLIST_FILE = Sources/LaunchAtLogin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.0.2;
MARKETING_VERSION = 4.2.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLogin;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -397,20 +426,24 @@
CODE_SIGN_IDENTITY = "";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
DEAD_CODE_STRIPPING = YES;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_MODULE_VERIFIER = YES;
FRAMEWORK_VERSION = A;
INFOPLIST_FILE = LaunchAtLogin/Info.plist;
INFOPLIST_FILE = Sources/LaunchAtLogin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 3.0.2;
MARKETING_VERSION = 4.2.0;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLogin;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -421,17 +454,21 @@
E32E9B811EB87EA3000FEEE9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements;
CODE_SIGN_ENTITLEMENTS = Sources/LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = LaunchAtLoginHelper/Info.plist;
INFOPLIST_FILE = Sources/LaunchAtLoginHelper/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MARKETING_VERSION = 1.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLoginHelper;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -442,17 +479,21 @@
E32E9B821EB87EA3000FEEE9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_ENTITLEMENTS = LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements;
CODE_SIGN_ENTITLEMENTS = Sources/LaunchAtLoginHelper/LaunchAtLoginHelper.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
INFOPLIST_FILE = LaunchAtLoginHelper/Info.plist;
INFOPLIST_FILE = Sources/LaunchAtLoginHelper/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = "$(RECOMMENDED_MACOSX_DEPLOYMENT_TARGET)";
MARKETING_VERSION = 1.0.1;
PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.LaunchAtLoginHelper;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1500"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -51,8 +49,6 @@
ReferencedContainer = "container:LaunchAtLogin.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1500"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@@ -38,8 +36,8 @@
ReferencedContainer = "container:LaunchAtLogin.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@@ -61,8 +59,6 @@
ReferencedContainer = "container:LaunchAtLogin.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
-21
View File
@@ -1,21 +0,0 @@
import Foundation
import ServiceManagement
public struct LaunchAtLogin {
private static let id = "\(Bundle.main.bundleIdentifier!)-LaunchAtLoginHelper"
public static var isEnabled: Bool {
get {
guard let jobs = (SMCopyAllJobDictionaries(kSMDomainUserLaunchd).takeRetainedValue() as? [[String: AnyObject]]) else {
return false
}
let job = jobs.first { $0["Label"] as! String == id }
return job?["OnDemand"] as? Bool ?? false
}
set {
SMLoginItemSetEnabled(id as CFString, newValue)
}
}
}
+30
View File
@@ -0,0 +1,30 @@
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "LaunchAtLogin",
platforms: [
.macOS(.v10_13)
],
products: [
.library(
name: "LaunchAtLogin",
targets: ["LaunchAtLogin"]
)
],
targets: [
.target(
name: "LaunchAtLogin",
exclude: [
"Info.plist",
"copy-helper.sh"
],
resources: [
.copy("LaunchAtLogin.entitlements"),
.copy("copy-helper-swiftpm.sh"),
.copy("LaunchAtLoginHelper.zip"),
.copy("LaunchAtLoginHelper-with-runtime.zip")
]
)
]
)
+155
View File
@@ -0,0 +1,155 @@
import Foundation
import ServiceManagement
import Combine
import os.log
private let hasMigratedKey = "LaunchAtLogin__hasMigrated"
public enum LaunchAtLogin {
@available(macOS 11, *)
private static let logger = Logger(subsystem: "com.sindresorhus.LaunchAtLogin", category: "main")
public static let kvo = KVO()
@available(macOS 10.15, *)
public static let observable = Observable()
@available(macOS 10.15, *)
private static let _publisher = CurrentValueSubject<Bool, Never>(isEnabled)
@available(macOS 10.15, *)
public static let publisher = _publisher.eraseToAnyPublisher()
private static let id = "\(Bundle.main.bundleIdentifier!)-LaunchAtLoginHelper"
private static var hasMigrated: Bool {
get { UserDefaults.standard.bool(forKey: hasMigratedKey) }
set {
UserDefaults.standard.set(true, forKey: hasMigratedKey)
}
}
public static func migrateIfNeeded() {
guard
#available(macOS 13, *),
!hasMigrated
else {
return
}
hasMigrated = true
if isEnabledLegacy {
isEnabledModern = true
}
unregisterLegacy()
}
public static var isEnabled: Bool {
get {
if #available(macOS 13, *) {
return isEnabledModern
} else {
return isEnabledLegacy
}
}
set {
if #available(macOS 10.15, *) {
observable.objectWillChange.send()
}
kvo.willChangeValue(for: \.isEnabled)
if #available(macOS 13, *) {
isEnabledModern = newValue
} else {
isEnabledLegacy = newValue
}
kvo.didChangeValue(for: \.isEnabled)
if #available(macOS 10.15, *) {
_publisher.send(newValue)
}
}
}
@available(macOS 13, *)
private static var isEnabledModern: Bool {
get { SMAppService.mainApp.status == .enabled }
set {
do {
if newValue {
if SMAppService.mainApp.status == .enabled {
try? SMAppService.mainApp.unregister()
}
try SMAppService.mainApp.register()
} else {
try SMAppService.mainApp.unregister()
}
} catch {
logger.error("Failed to \(newValue ? "enable" : "disable") launch at login: \(error.localizedDescription)")
}
}
}
private static var isEnabledLegacy: Bool {
get {
guard let jobs = (LaunchAtLogin.self as DeprecationWarningWorkaround.Type).jobsDict else {
return false
}
let job = jobs.first { ($0["Label"] as? String) == id }
return job?["OnDemand"] as? Bool ?? false
}
set {
SMLoginItemSetEnabled(id as CFString, newValue)
}
}
@available(macOS 13, *)
private static func unregisterLegacy() {
isEnabledLegacy = false
try? SMAppService.loginItem(identifier: id).unregister()
}
}
// MARK: - LaunchAtLoginObservable
extension LaunchAtLogin {
@available(macOS 10.15, *)
public final class Observable: ObservableObject {
public var isEnabled: Bool {
get { LaunchAtLogin.isEnabled }
set {
LaunchAtLogin.isEnabled = newValue
}
}
}
}
// MARK: - LaunchAtLoginKVO
extension LaunchAtLogin {
public final class KVO: NSObject {
@objc dynamic public var isEnabled: Bool {
get { LaunchAtLogin.isEnabled }
set {
LaunchAtLogin.isEnabled = newValue
}
}
}
}
private protocol DeprecationWarningWorkaround {
static var jobsDict: [[String: AnyObject]]? { get }
}
extension LaunchAtLogin: DeprecationWarningWorkaround {
// Workaround to silence "'SMCopyAllJobDictionaries' was deprecated in OS X 10.10" warning
// Radar: https://openradar.appspot.com/radar?id=5033815495933952
@available(*, deprecated)
static var jobsDict: [[String: AnyObject]]? {
SMCopyAllJobDictionaries(kSMDomainUserLaunchd)?.takeRetainedValue() as? [[String: AnyObject]]
}
}
Binary file not shown.
+80
View File
@@ -0,0 +1,80 @@
import SwiftUI
@available(macOS 10.15, *)
extension LaunchAtLogin {
/**
This package comes with a `LaunchAtLogin.Toggle` view which is like the built-in `Toggle` but with a predefined binding and label. Clicking the view toggles launch at login for your app.
```
struct ContentView: View {
var body: some View {
LaunchAtLogin.Toggle()
}
}
```
The default label is `"Launch at login"`, but it can be overridden for localization and other needs:
```
struct ContentView: View {
var body: some View {
LaunchAtLogin.Toggle {
Text("Launch at login")
}
}
}
```
*/
public struct Toggle<Label: View>: View {
@ObservedObject private var launchAtLogin = LaunchAtLogin.observable
private let label: Label
/**
Creates a toggle that displays a custom label.
- Parameters:
- label: A view that describes the purpose of the toggle.
*/
public init(@ViewBuilder label: () -> Label) {
self.label = label()
}
public var body: some View {
SwiftUI.Toggle(isOn: $launchAtLogin.isEnabled) { label }
}
}
}
@available(macOS 10.15, *)
extension LaunchAtLogin.Toggle<Text> {
/**
Creates a toggle that generates its label from a localized string key.
This initializer creates a ``Text`` view on your behalf with provided `titleKey`
- Parameters:
- titleKey: The key for the toggle's localized title, that describes the purpose of the toggle.
*/
public init(_ titleKey: LocalizedStringKey) {
label = Text(titleKey)
}
/**
Creates a toggle that generates its label from a string.
This initializer creates a `Text` view on your behalf with the provided `title`.
- Parameters:
- title: A string that describes the purpose of the toggle.
*/
public init(_ title: some StringProtocol) {
label = Text(title)
}
/**
Creates a toggle with the default title of `Launch at login`.
*/
public init() {
self.init("Launch at login")
}
}
+50
View File
@@ -0,0 +1,50 @@
#!/bin/bash
HELPER_CHECKSUM="0a3d09438fb595802d554ce0a7c4ba8e1d2d91d5170362adc965da82e70d74cb"
HELPER_CHECKSUM_RUNTIME="98ef556b490e02f4084a11d8a07c33a880177a9816b355885a11f58c95876d62"
verlte() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
}
if verlte "10.14.4" "$MACOSX_DEPLOYMENT_TARGET"; then
helper_name="LaunchAtLoginHelper"
checksum="$HELPER_CHECKSUM"
else
helper_name="LaunchAtLoginHelper-with-runtime"
checksum="$HELPER_CHECKSUM_RUNTIME"
fi
package_resources_path="$BUILT_PRODUCTS_DIR/LaunchAtLogin_LaunchAtLogin.bundle/Contents/Resources"
helper_path="$package_resources_path/$helper_name.zip"
contents_path="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH"
login_items="$contents_path/Library/LoginItems"
login_helper_path="$login_items/LaunchAtLoginHelper.app"
rm -rf "$login_helper_path"
mkdir -p "$login_items"
# Verify SHA256 checksum of LaunchAtLoginHelper.
zip_checksum="$(shasum -a 256 "$helper_path" | awk '{print $1}')"
if [[ "$zip_checksum" != "$checksum" ]]; then
echo "Wrong checksum of LaunchAtLoginHelper"
exit 1
fi
unzip "$helper_path" -d "$login_items/"
defaults write "$login_helper_path/Contents/Info" CFBundleIdentifier -string "$PRODUCT_BUNDLE_IDENTIFIER-LaunchAtLoginHelper"
if [[ -n $CODE_SIGN_ENTITLEMENTS ]]; then
codesign --force --entitlements="$package_resources_path/LaunchAtLogin.entitlements" --deep --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$login_helper_path"
else
codesign --force --deep --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path"
fi
# If this is being built for multiple architectures, assume it is a release build and we should clean up.
if [[ $ONLY_ACTIVE_ARCH != "YES" ]]; then
rm -rf "$contents_path/Resources/LaunchAtLogin_LaunchAtLogin.bundle"
fi
@@ -16,7 +16,8 @@ else
codesign --force --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path"
fi
if [[ $CONFIGURATION == "Release" ]]; then
# If this is being built for multiple architectures, assume it is a release build and we should clean up.
if [[ $ONLY_ACTIVE_ARCH != "YES" ]]; then
rm -rf "$origin_helper_path"
rm "$(dirname "$origin_helper_path")/copy-helper.sh"
rm "$(dirname "$origin_helper_path")/LaunchAtLogin.entitlements"
@@ -11,17 +11,21 @@
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>1</string>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string>
<key>LSBackgroundOnly</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
<key>NSHumanReadableCopyright</key>
<string>MIT © Sindre Sorhus</string>
<key>LSBackgroundOnly</key>
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
@@ -1,13 +1,12 @@
import Cocoa
import AppKit
final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
let bundleId = Bundle.main.bundleIdentifier!
// TODO: Make this more strict by only replacing at the end
let mainBundleId = bundleId.replacingOccurrences(of: "-LaunchAtLoginHelper", with: "")
let bundleIdentifier = Bundle.main.bundleIdentifier!
let mainBundleIdentifier = bundleIdentifier.replacingOccurrences(of: #"-LaunchAtLoginHelper$"#, with: "", options: .regularExpression)
// Ensure the app is not already running
guard NSRunningApplication.runningApplications(withBundleIdentifier: mainBundleId).isEmpty else {
// Ensures the app is not already running.
guard NSRunningApplication.runningApplications(withBundleIdentifier: mainBundleIdentifier).isEmpty else {
NSApp.terminate(nil)
return
}
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+9
View File
@@ -0,0 +1,9 @@
# Maintaining
## Rebuild helper binaries
1. If it's the non-`with-runtime` ZIP, set the target to macOS 10.14.4 first.
2. Set build configuration to “Release”.
3. Build the binary.
4. Find the binary in “Products” in the sidebar, ZIP it, and overwrite the existing ZIP file in the source directory.
5. Run `shasum -a 256 filename.zip` on the ZIP file and copy the hash into “copy-helper-swiftpm.sh”.
+115 -26
View File
@@ -2,33 +2,52 @@
> Add “Launch at Login” functionality to your macOS app in seconds
It's usually quite a [convoluted and error-prone process](before-after.md) to add this. **No more!**
**If your app targets macOS 13 or later, check out [this modern version](https://github.com/sindresorhus/LaunchAtLogin-Modern) instead.**
It's usually quite a [convoluted and error-prone process](before-after.md) to add this (on macOS 12 and older). **No more!**
This package works with both sandboxed and non-sandboxed apps and it's App Store compatible and used in apps like [Plash](https://github.com/sindresorhus/Plash), [Dato](https://sindresorhus.com/dato), [Lungo](https://sindresorhus.com/lungo), and [Battery Indicator](https://sindresorhus.com/battery-indicator).
**This package uses the new [`SMAppService`](https://developer.apple.com/documentation/servicemanagement/smappservice/3945412-mainapp) on macOS 13+ and [`SMLoginItemSetEnabled`](https://developer.apple.com/documentation/servicemanagement/1501557-smloginitemsetenabled) on older macOS versions.**
### Why should I use this package now that [`SMAppService`](https://developer.apple.com/documentation/servicemanagement/smappservice/3945412-mainapp?changes=latest_minor) exists?
- Backwards compatibility with older macOS versions
- Nicer API
- Included SwiftUI component
## Requirements
- macOS 10.12+
- Xcode 11+
- Swift 5+
macOS 10.13+
## Install
#### Carthage
```
github "sindresorhus/LaunchAtLogin"
```
Add `https://github.com/sindresorhus/LaunchAtLogin-Legacy` in the [“Swift Package Manager” tab in Xcode](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app).
## Usage
Add a new ["Run Script Phase"](http://stackoverflow.com/a/39633955/64949) **below** "Embed Frameworks" in "Build Phases" with the following:
**Skip this step if your app targets macOS 13 or later.**
Add a new [“Run Script Phase”](http://stackoverflow.com/a/39633955/64949) **below** (not into) “Copy Bundle Resources” in “Build Phases” with the following:
```sh
"${PROJECT_DIR}/Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh"
"${BUILT_PRODUCTS_DIR}/LaunchAtLogin_LaunchAtLogin.bundle/Contents/Resources/copy-helper-swiftpm.sh"
```
Use it in your app:
And uncheck “Based on dependency analysis”.
The build phase cannot run with "User Script Sandboxing" enabled. With Xcode 15 or newer where it is enabled by default, disable "User Script Sandboxing" in build settings.
*(It needs some extra works to have our script to comply with the build phase sandbox.)*
*(I would name the run script `Copy “Launch at Login Helper”`)*
### Use it in your app
No need to store any state to UserDefaults.
*Note that the [Mac App Store guidelines](https://developer.apple.com/app-store/review/guidelines/) requires “launch at login” functionality to be enabled in response to a user action. This is usually solved by making it a preference that is disabled by default. Many apps also let the user activate it in a welcome screen.*
#### As static property
```swift
import LaunchAtLogin
@@ -42,13 +61,88 @@ print(LaunchAtLogin.isEnabled)
//=> true
```
No need to store any state to UserDefaults.
#### SwiftUI
*Note that the [Mac App Store guidelines](https://developer.apple.com/app-store/review/guidelines/) requires “launch at login” functionality to be enabled in response to a user action. This is usually solved by making it a preference that is disabled by default. Many apps also let the user activate it in a welcome screen.*
This package comes with a `LaunchAtLogin.Toggle` view which is like the built-in `Toggle` but with a predefined binding and label. Clicking the view toggles “launch at login” for your app.
```swift
struct ContentView: View {
var body: some View {
LaunchAtLogin.Toggle()
}
}
```
The default label is `"Launch at login"`, but it can be overridden for localization and other needs:
```swift
struct ContentView: View {
var body: some View {
LaunchAtLogin.Toggle {
Text("Launch at login")
}
}
}
```
Alternatively, you can use `LaunchAtLogin.observable` as a binding with `@ObservedObject`:
```swift
import SwiftUI
import LaunchAtLogin
struct ContentView: View {
@ObservedObject private var launchAtLogin = LaunchAtLogin.observable
var body: some View {
Toggle("Launch at login", isOn: $launchAtLogin.isEnabled)
}
}
```
#### Combine
Just subscribe to `LaunchAtLogin.publisher`:
```swift
import Combine
import LaunchAtLogin
final class ViewModel {
private var isLaunchAtLoginEnabled = LaunchAtLogin.isEnabled
private var cancellables = Set<AnyCancellable>()
func bind() {
LaunchAtLogin
.publisher
.assign(to: \.isLaunchAtLoginEnabled, on: self)
.store(in: &cancellables)
}
}
```
#### Swift Concurrency
Use [`LaunchAtLogin.publisher.values`](https://developer.apple.com/documentation/combine/publisher/values-1dm9r).
#### Storyboards
Bind the control to the `LaunchAtLogin.kvo` exposed property:
```swift
import Cocoa
import LaunchAtLogin
final class ViewController: NSViewController {
@objc dynamic var launchAtLogin = LaunchAtLogin.kvo
}
```
<img src="storyboard-binding.png" width="445">
## How does it work?
The framework bundles the helper app needed to launch your app and copies it into your app at build time.
On macOS 12 and earlier, the package bundles the helper app needed to launch your app and copies it into your app at build time. On macOS 13 and later, it calls the built-in API.
## FAQ
@@ -64,14 +158,12 @@ rm: […]/Resources/copy-helper.sh: No such file or directory
Command PhaseScriptExecution failed with a nonzero exit code
```
#### The size of my app increased after adding `LaunchAtLogin`
The bundled launcher app is written in Swift and hence needs to embed the Swift runtime libraries. If your project targets macOS 10.14.4 or later, you can avoid embedding the Swift runtime libraries. First, open `./Carthage/Checkouts/LaunchAtLogin/LaunchAtLogin.xcodeproj` and set the deployment target to the same as your app, and then run `$ carthage build`. You'll have to do this each time you update `LaunchAtLogin`.
#### My app doesn't show up in “System Preferences Users & Groups Login Items”
[This is the expected behavior](https://stackoverflow.com/a/15104481/64949), unfortunately.
However, it will show there on macOS 13 and later.
#### My app doesn't launch at login when testing
This is usually caused by having one or more older builds of your app laying around somewhere on the system, and macOS picking one of those instead, which doesn't have the launch helper, and thus fails to start.
@@ -87,19 +179,16 @@ Some helpful Stack Overflow answers:
- https://stackoverflow.com/a/53110832/64949
- https://stackoverflow.com/a/53110852/64949
#### Can you support CocoaPods?
#### I can't see the `LaunchAtLogin.bundle` in my debug build or I get a notarization error for developer ID distribution
CocoaPods used to be supported, but [it did not work well](https://github.com/sindresorhus/LaunchAtLogin/issues/22) and there was no easy way to fix it, so support was dropped. Even though you mainly use CocoaPods, you can still use Carthage just for this package without any problems.
As discussed [here](https://github.com/sindresorhus/LaunchAtLogin-Legacy/issues/50), this package tries to determine if you're making a release or debug build and clean up its install accordingly. If your debug build is missing the bundle or, conversely, your release build has the bundle and it causes a code signing error, that means this has failed.
#### I'm getting a `'SMCopyAllJobDictionaries' was deprecated in OS X 10.10` warning
Apple deprecated that API without providing an alternative. Apple engineers have [stated that it's still the preferred API to use](https://github.com/alexzielenski/StartAtLoginController/issues/12#issuecomment-307525807). I plan to use it as long as it's available. There are workarounds I can implement if Apple ever removes the API, so rest assured, this module will be made to work even then. If you want to see this resolved, submit a [Feedback Assistant](https://feedbackassistant.apple.com) report with [the following text](https://github.com/feedback-assistant/reports/issues/16). There's unfortunately still [no way to suppress warnings in Swift](https://stackoverflow.com/a/32861678/64949).
The script's determination is based on the “Build Active Architecture Only” flag in build settings. If this is set to `YES`, then the script will package LaunchAtLogin for a debug build. You must set this flag to `NO` if you plan on distributing the build with codesigning.
## Related
- [Defaults](https://github.com/sindresorhus/Defaults) - Swifty and modern UserDefaults
- [Preferences](https://github.com/sindresorhus/Preferences) - Add a preferences window to your macOS app in minutes
- [KeyboardShortcuts](https://github.com/sindresorhus/KeyboardShortcuts) - Add user-customizable global keyboard shortcuts to your macOS app
- [DockProgress](https://github.com/sindresorhus/DockProgress) - Show progress in your app's Dock icon
- [create-dmg](https://github.com/sindresorhus/create-dmg) - Create a good-looking DMG for your macOS app in seconds
- [More…](https://github.com/search?q=user%3Asindresorhus+language%3Aswift)
- [More…](https://github.com/search?q=user%3Asindresorhus+language%3Aswift+archived%3Afalse&type=repositories)
Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB