21 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
18 changed files with 194 additions and 82 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/
+30 -7
View File
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
@@ -167,8 +167,9 @@
E32E9B5A1EB87D7B000FEEE9 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 1200;
LastUpgradeCheck = 1500;
ORGANIZATIONNAME = "Sindre Sorhus";
TargetAttributes = {
E32E9B621EB87D7B000FEEE9 = {
@@ -190,7 +191,7 @@
};
};
buildConfigurationList = E32E9B5D1EB87D7B000FEEE9 /* Build configuration list for PBXProject "LaunchAtLogin" */;
compatibilityVersion = "Xcode 12.0";
compatibilityVersion = "Xcode 15.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -262,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";
@@ -292,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;
@@ -309,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;
@@ -326,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";
@@ -356,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;
@@ -367,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;
@@ -385,11 +392,13 @@
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 = Sources/LaunchAtLogin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -398,7 +407,9 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 4.0.0;
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 = "";
@@ -415,11 +426,13 @@
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 = Sources/LaunchAtLogin/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
@@ -428,7 +441,9 @@
"@executable_path/../Frameworks",
"@loader_path/Frameworks",
);
MARKETING_VERSION = 4.0.0;
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 = "";
@@ -443,6 +458,8 @@
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 = Sources/LaunchAtLoginHelper/Info.plist;
@@ -450,6 +467,8 @@
"$(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 = "";
@@ -464,6 +483,8 @@
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 = Sources/LaunchAtLoginHelper/Info.plist;
@@ -471,6 +492,8 @@
"$(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 = "1200"
LastUpgradeVersion = "1500"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
LastUpgradeVersion = "1500"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
+2 -2
View File
@@ -1,10 +1,10 @@
// swift-tools-version:5.3
// swift-tools-version:5.9
import PackageDescription
let package = Package(
name: "LaunchAtLogin",
platforms: [
.macOS(.v10_12)
.macOS(.v10_13)
],
products: [
.library(
+97 -9
View File
@@ -1,29 +1,57 @@
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 var _publisher = CurrentValueSubject<Bool, Never>(isEnabled)
private static let _publisher = CurrentValueSubject<Bool, Never>(isEnabled)
@available(macOS 10.15, *)
public static var publisher = _publisher.eraseToAnyPublisher()
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 {
guard let jobs = (SMCopyAllJobDictionaries(kSMDomainUserLaunchd).takeRetainedValue() as? [[String: AnyObject]]) else {
return false
if #available(macOS 13, *) {
return isEnabledModern
} else {
return isEnabledLegacy
}
let job = jobs.first { $0["Label"] as! String == id }
return job?["OnDemand"] as? Bool ?? false
}
set {
if #available(macOS 10.15, *) {
@@ -31,7 +59,13 @@ public enum LaunchAtLogin {
}
kvo.willChangeValue(for: \.isEnabled)
SMLoginItemSetEnabled(id as CFString, newValue)
if #available(macOS 13, *) {
isEnabledModern = newValue
} else {
isEnabledLegacy = newValue
}
kvo.didChangeValue(for: \.isEnabled)
if #available(macOS 10.15, *) {
@@ -39,6 +73,47 @@ public enum LaunchAtLogin {
}
}
}
@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
@@ -65,3 +140,16 @@ extension LaunchAtLogin {
}
}
}
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.
+3 -3
View File
@@ -25,7 +25,7 @@ extension LaunchAtLogin {
}
```
*/
public struct Toggle<Label>: View where Label: View {
public struct Toggle<Label: View>: View {
@ObservedObject private var launchAtLogin = LaunchAtLogin.observable
private let label: Label
@@ -46,7 +46,7 @@ extension LaunchAtLogin {
}
@available(macOS 10.15, *)
extension LaunchAtLogin.Toggle where Label == Text {
extension LaunchAtLogin.Toggle<Text> {
/**
Creates a toggle that generates its label from a localized string key.
@@ -67,7 +67,7 @@ extension LaunchAtLogin.Toggle where Label == Text {
- Parameters:
- title: A string that describes the purpose of the toggle.
*/
public init<S>(_ title: S) where S: StringProtocol {
public init(_ title: some StringProtocol) {
label = Text(title)
}
+6 -5
View File
@@ -1,7 +1,7 @@
#!/bin/bash
HELPER_CHECKSUM="6eaaced9173120f82ef98452b2d8cb3705c12db39d4286c70c4f5bb6b67a5e43"
HELPER_CHECKSUM_RUNTIME="c5a48f5ba681088aa7922b79f2f1b55a1a006904b8de378790eb0e8b0ac66234"
HELPER_CHECKSUM="0a3d09438fb595802d554ce0a7c4ba8e1d2d91d5170362adc965da82e70d74cb"
HELPER_CHECKSUM_RUNTIME="98ef556b490e02f4084a11d8a07c33a880177a9816b355885a11f58c95876d62"
verlte() {
[ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
@@ -39,11 +39,12 @@ 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" --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$login_helper_path"
codesign --force --entitlements="$package_resources_path/LaunchAtLogin.entitlements" --deep --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$login_helper_path"
else
codesign --force --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path"
codesign --force --deep --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 "$contents_path/Resources/LaunchAtLogin_LaunchAtLogin.bundle"
fi
+2 -1
View File
@@ -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"
+5 -3
View File
@@ -11,11 +11,13 @@
<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>
+5 -6
View File
@@ -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”.
+31 -39
View File
@@ -2,49 +2,44 @@
> 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 12+
- Swift 5.3+
macOS 10.13+
## Install
#### Swift Package Manager
Xcode 12+ required.
```
.package(url: "https://github.com/sindresorhus/LaunchAtLogin", from: "4.0.0")
```
#### Carthage
*Warning: Carthage is not recommended. Support for it will be removed at some point in the future.*
```
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.**
#### Swift Package Manager
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
"${BUILT_PRODUCTS_DIR}/LaunchAtLogin_LaunchAtLogin.bundle/Contents/Resources/copy-helper-swiftpm.sh"
```
#### Carthage
And uncheck “Based on dependency analysis”.
```sh
"${PROJECT_DIR}/Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh"
```
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
@@ -126,6 +121,10 @@ final class ViewModel {
}
```
#### 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:
@@ -143,7 +142,7 @@ final class ViewController: NSViewController {
## 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
@@ -159,16 +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` when using Carthage
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`.
This is not a problem when using Swift Package Manager.
#### 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.
@@ -184,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