-
-
Notifications
You must be signed in to change notification settings - Fork 355
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for "start app on login" as part of packaging #1803
Comments
fwiw i have implemented this feature as part of my briefcase app. while there are a few ways to do it and theoretically the preferred method these days is via Apple's i used the old method, which involves a
If it's helpful here's the contents of my #!/bin/bash
# Create .plist file in ~/Library/LaunchAgents and bootstrap. Output of this script can be seen in /var/log/install.log
set -e
# Arg list: https://discussions.apple.com/thread/2184714?sortBy=best
# $1 is the full path of the .pkg file
# $2 is the path to the installed app, usually just '/Applications/'
# $3 is the mountpoint of the installer disk, usually just '/'
# $4 is root directory of currently booted system, usually just '/'
APP_BASENAME='IllmaticApp'
BUNDLE_ID='com.illmatic.app'
APP_EXECUTABLE_PATH="$2/$APP_BASENAME.app/Contents/Macos/$APP_BASENAME"
INSTALLED_LAUNCH_AGENT_PATH="$HOME/Library/LaunchAgents/$BUNDLE_ID.plist"
# In the env vars accessed by this script $USER = the_actual_user but $UID = 0 (root).
INSTALLING_USER_UID=$(id -u "$USER")
LAUNCHD_DOMAIN="gui/$INSTALLING_USER_UID"
echo "Post installation process started by user $USER..."
echo "-> Checking for and removing existing service..."
INSTALLED_SERVICE=$(launchctl print $LAUNCHD_DOMAIN | grep $BUNDLE_ID | awk '{print $3}')
if [ ! -z $INSTALLED_SERVICE ]; then
echo " -> Existing service found; running launchctl bootout $DOMAIN/$BUNDLE_ID"
launchctl bootout "$DOMAIN/$BUNDLE_ID"
fi
echo "-> Generating .plist at $INSTALLED_LAUNCH_AGENT_PATH"
"$APP_EXECUTABLE_PATH" --generate-plist
echo "-> Running: chown $USER $INSTALLED_LAUNCH_AGENT_PATH"
chown "$USER" "$INSTALLED_LAUNCH_AGENT_PATH"
echo "-> Running: launchctl bootstrap $LAUNCHD_DOMAIN $INSTALLED_LAUNCH_AGENT_PATH"
launchctl bootstrap "$LAUNCHD_DOMAIN" "$INSTALLED_LAUNCH_AGENT_PATH"
echo "Post installation process finished." The def main():
if args.generate_plist:
generate_briefcase_plist()
return and this in import plistlib
from os.path import join, expanduser
from .app_metadata_helper import MAIN_APP_NAME, get_app_name, get_bundle_identifier, installed_executable_path
# Directories
LAUNCHAGENTS_DIR = expanduser(f"~/Library/LaunchAgents")
LAUNCHAGENT_PLIST_PATH = join(LAUNCHAGENTS_DIR, get_bundle_identifier() + '.plist')
APPLICATION_SUPPORT_DIR = expanduser(f"~/Library/Application Support/{MAIN_APP_NAME}")
APPLICATION_LOG_DIR = join(APPLICATION_SUPPORT_DIR, 'log')
def generate_briefcase_plist():
"""Run with briefcase run -u -- --generate-plist"""
build_logfile_path = lambda stream: join(APPLICATION_LOG_DIR, f"{get_app_name()}.{stream}.log")
plist_contents = {
"EnvironmentVariables": {
"PATH": f"{installed_executable_path().parent}:/usr/bin:/bin",
},
"KeepAlive": True,
"Label": get_bundle_identifier(),
"ProgramArguments": [str(installed_executable_path())],
"RunAtLoad": True,
"StandardErrorPath": build_logfile_path("stderr"),
"StandardOutPath": build_logfile_path("stdout"),
"WorkingDirectory": str(installed_executable_path().parent),
}
with open(LAUNCHAGENT_PLIST_PATH, "w") as _plist_file:
_plist_file.write(plistlib.dumps(plist_contents).decode())
print(f"Wrote {get_app_name()} .plist config to '{LAUNCHAGENT_PLIST_PATH}'") And here's the generated <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/Applications/IllmaticApp.app/Contents/MacOS:/usr/bin:/bin</string>
</dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.illmatic.app</string>
<key>ProgramArguments</key>
<array>
<string>/Applications/IllmaticApp.app/Contents/MacOS/IllmaticApp</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StandardErrorPath</key>
<string>/Users/uzor/Library/Application Support/IllmaticApp/log/IllmaticApp.stderr.log</string>
<key>StandardOutPath</key>
<string>/Users/uzor/Library/Application Support/IllmaticApp/log/IllmaticApp.stdout.log</string>
<key>WorkingDirectory</key>
<string>/Applications/IllmaticApp.app/Contents/MacOS</string>
</dict>
</plist> As far as i can tell the main advantage of |
Thanks for those details. There's obviously a couple of details in that literal plist and config script that would need to be templated/configured, but it seems like that should be reasonably straightforward to include in a bundled macOS pkg (once #1781 lands). The question I have about this configuration is how it interacts with individual users. The current state of #1781 only supports global installs; AIUI, login items are specific to individual users. This script seems to be hard-coding the installation of the launch item use of UID 501, and the Also - I don't think we wouldn't necessarily need to ship an extra executable. You can invoke Objective C APIs with ctypes; and although a bundled Briefcase app isn't a "true" Python interpreter, you can control the Python entry point using the |
Sort of... but a system wide startup item is installed the same way. The only differences are that
There's also the
That sounds like it should work - in fact I may try to incorporate that in my app, and if so i will report back - but Apple's documentation is extremely lacking about all this stuff. |
You are correct. FWIW the
I think the answer is "yes" though fwiw Apple's entire approach tends to kind of casually assume single-tenancy machines. EDIT 2024-06-05:
i found that bizarrely |
i just noticed this piece of the official apple docs:
so apparently |
Apparently you can use the |
i changed my situation so that the |
added a couple of lines to the comment above to check for and |
What is the problem or limitation you are having?
Some apps (in particular server and toolbar style apps) need to add themselves to the startup items list. Briefcase should be able to produce apps that can install themselves in the startup item list
Describe the solution you'd like
Apps should have a configuration option so that when an app is installed, it is added to the startup items for the platform - e.g.,
On macOS, this will require the use of a .pkg installer (see #1781)
On Windows, it will require an MSI installer
Linux packages will result in the app being added to systemd/initd.
It might be desirable to add this in a way that the user can opt-in, rather than it being a forced requirement on installation.
Describe alternatives you've considered
None.
Additional context
No response
The text was updated successfully, but these errors were encountered: