LaunchAgents - Howto

If you need your app to launch at startup you can do two things : Add your app to the Login Items or use LaunchAgents.
I mostly use the Login Item but recently I had the need to add a background service that is not listed in the Login Items.

Here is how to do this:

  • First create a plist file like below if you app is called “backgroundservice.app” and your bundle name is “com.mybundlename.test”
    Save the plist as com.mybundlename.test.plist

[code]<?xml version="1.0" encoding="UTF-8"?>

Label com.mybundlename.test RunAtLoad KeepAlive SuccessfulExit ProgramArguments /Applications/backgroundservice.app/Contents/MacOS/backgroundservice [/code]
  • Add the plist file into the user/…/Library/LaunchAgents folder

Now reboot the system. You will notice the app is launched without adding it to the Login Items.
It may be important to know that LaunchAgents are loaded AFTER login items. So Launchagents can take longer to load.

Try this to easily create agents and daemons: http://www.soma-zone.com/LaunchControl/

+1 for LaunchControl.

I am aware of Launchcontrol. But I just was referring how to add a LaunchAgent yourself (from within your own app).

But Launchcontrol is pretty neat to check what you can do with Launchagents.

Here is the how to :

How-to documentation : How-to

And the files : Helper Files and Helper integrator

Helper Integrator is donationware :slight_smile:

I have successfully used Lingon in the past:
http://www.peterborgapps.com/lingon/

Just to make it clear for those who are doing Sandboxed applications, AFAIK the only way is using a system similar to what Valdemar De Sousa has shared.

I use Valdemar de Sousa Helper Integrator http://www.vdsc.eu/files/helperapp.zip and it works like a charm :slight_smile:

[quote=117273:@Valdemar De SOUSA]Here is the how to :

How-to documentation : How-to
And the files : Helper Files and Helper integrator
[/quote]

After using the above example, I’m finding continuously those entries in the console log. How can I remove this helpertest again?

[quote=188849:@Oliver Osswald]After using the above example, I’m finding continuously those entries in the console log. How can I remove this helpertest again?

[/quote]

I forgot to mention it, but after an Apple reviewer rejected the app for keeping unauthorized programs after quit, I just found out Valdemar had forgotten to have the helper quit after it launches the main app. I remember mentioning it to him, though. It should have been corrected.

Here is what I added to the helper code :

[code]Sub LaunchApp()
// this is for Mac where we detect app by Bundle ID
const BundleID = “com.matchsoftware.startmenu”
const nameApp = “StartMenu.app”

dim found as Boolean = false
dim p as new ProcessMBS

p.GetFirstProcess
do
if p.Name = nameApp then
found = true
Return
end if
loop until not p.GetNextProcess

if not found then
// wait some time
DelayMBS 0.1
end if

dim file as FolderItem = LaunchServicesFindApplicationForInfoMBS("", “”, nameApp)

if file<>Nil then

file.Launch("Helper-launched")

end if

quit
End Sub
[/code]

To prevent HelperTest to start over and over, simply delete the executable bundle that contains it. Otherwise the system will find it anywhere it is on the disk.

@Michel: that works for you? Strange. When I quit the helper app it’s simply started again. Here is my code for quitting the helper app:

[code]Protected Sub DeregisterHelperApp(theBundleID as String)

if theBundleID = “” then Return

if ServiceManagementModuleMBS.LoginItemSetEnabled(theBundleID, False) then
'nothing to do
end if

dim theShell as new Shell
theShell.Execute "launchctl list |grep " + theBundleID
if theShell.ErrorCode <> 0 then Return

dim theResult as String = theShell.Result
dim theLines(-1) as String = Split(theResult, EndOfLine.UNIX)

for currentLine as Integer = 0 to UBound(theLines)
dim theData(-1) as String = Split(theLines(currentLine), Chr(9))
if theData <> nil and UBound(theData) = 2 and theData(0) <> “-” then
dim AppPath as String = GetPathFromPID(theData(0))
if InStr(AppPath, “loginitems”) > 0 then
theShell.Execute("launchctl remove " + theData(2))
end if
end if
next

exception exc
theException = new ErrorException(exc, currentMethodName)
End Sub[/code]

I guess this is your own code: GetPathFromPID(theData(0))
Would you be willing to share?

I create a Git repository : https://github.com/Valdemar-VDSC/HelperApp.git

I’m not able to get the example of Valdemar up and running in a sandboxed environment.

I do the following:

  1. I build the Helper-Test.app (fr.vdsc.helpertest)
  2. I build the “My App with Helper.app” (fr.vdsc.helpertest)
  3. I use AppWrapper for Helper-Test.app to codesign, to sandbox and to add a plist entry: UI Element (= true)
  4. I check the sandbox helper app with RB App Checker Lite: it is codesigned and sandboxed: OK
  5. I add the folders /Library/LaunchItems to “My App with Helper” into its contents folder
  6. I move the Helper-Test.app into this new LaunchItems folder.
  7. I use AppWrapper to codesign and sandbox “My App with Helper.app”
  8. Again I use RB App Checker Lite, now to check “My App with Helper.app” : OK
  9. I delete the non-sanboxed files and verify if the helper app is inside of the sandboxed main app: OK
  10. I launch “My App with Helper.app” and click the “Auto start at login” checkbox to switch it on
  11. I log out and in again, the app is NOT starting.
  12. in the console log I find:

[quote]21.05.15 18:05:26.484 My App with Helper[718]: Could not enable login item: fr.vdsc.helpertest: 3: No such process
[/quote]

So this is not running as expected. What is missing?

Here is the missing function:

[code]Private Function GetPathFromPID(thePID as String) As String

if thePID = “” then Return “”
dim theShell as new Shell
theShell.Execute "ps xuwww -p " + thePID
if theShell.ErrorCode <> 0 then Return “”

Return theShell.Result

exception exc
theException = new ErrorException(exc, currentMethodName)
End Function
[/code]

Will try with Git in the next days.

Have you tried with not Sandboxing the apps? Then you could see if Sandboxing makes this process possible or not. Otherwise, I’m doing the same. You shouldn’t have to to log out and in again. The helper app should start immediately.

In my experience with App Wrapper, I did not need to sign the helper. I just signed the app once the helper was placed into it, and App Wrapper signed everything.

From what I understand, at any rate, once set up, the helper always start when the system start, and the setting “start when the system start” only insures that the main app is launched.

Maybe you could put a system.debuglog in the helper and verify in console if indeed it has started. Then if it did, the issue is in the code that verifies the preferences.

[quote=188935:@Oliver Osswald]I’m not able to get the example of Valdemar up and running in a sandboxed environment.

I do the following:

  1. I build the Helper-Test.app (fr.vdsc.helpertest)
  2. I build the “My App with Helper.app” (fr.vdsc.helpertest)
  3. I use AppWrapper for Helper-Test.app to codesign, to sandbox and to add a plist entry: UI Element (= true)
  4. I check the sandbox helper app with RB App Checker Lite: it is codesigned and sandboxed: OK
  5. I add the folders /Library/LaunchItems to “My App with Helper” into its contents folder
  6. I move the Helper-Test.app into this new LaunchItems folder.
  7. I use AppWrapper to codesign and sandbox “My App with Helper.app”
  8. Again I use RB App Checker Lite, now to check “My App with Helper.app” : OK
  9. I delete the non-sanboxed files and verify if the helper app is inside of the sandboxed main app: OK
  10. I launch “My App with Helper.app” and click the “Auto start at login” checkbox to switch it on
  11. I log out and in again, the app is NOT starting.
  12. in the console log I find:

So this is not running as expected. What is missing?[/quote]

Do you use the App Helper Integrator ?
Link to download : https://www.dropbox.com/sh/dbuw58eizik6mam/AAC7d6wLH4JBHqY7cGJzSs1ma?dl=1

@ Valdemar: Thank you! I am also using the version of Helper Integrator which you distributed in Koblenz. But your dropbox link does not provide an app, just a contents folder.

@ Beatrix: Without sandboxing, Valdemars example works as expected. The problem starts with sandboxing.

@ Michel: I also tried both: signing first the helper app (after completing its plist file) and then also signing the main app. Or, just signing the Main app - which I believe is actually signing anything within now. --deep option is no longer optional and AppWrapper is doing automatically, as far as I understand. However, in both cases (signing app+helper or app only), the application fails.

What I am getting now is the following log message in console:

[quote]21.05.15 20:59:46.833 secinitd[258]: fr.vdsc.helpertest[1168]: registration request failed: (0x10, 0x3) Process is not in an inherited sandbox.
[/quote]

“not in an inherited sandbox” - ??? - but I’m using the same Bundle Identifier for both, the main app and its helper: fr.vdsc.helpertest

I also corrected the wrong location in my step 5 (see above) from “/Library/LaunchItems” to “/Library/LoginItems”.

Currently, I am not able to get Valdemar’s example to run in a sandboxed version.

I think I’m stuck and I have to sleep over it. Usually in the early morning hours, I have much better ideas on how to solve an issue…

I compress the file : https://www.dropbox.com/s/v0c0osonmn5igs1/Helper%20integrator.zip?dl=1

So tried again with the latest Integrator, provided by Valdemar on his dropbox.

But again: It works as long as it is not sandboxed, but fails once it is sandboxed.

Console log:

If someone with more knowledge than myself could have a look at code-signed, sandboxed app and check out its plist, then maybe we could find out why this is not working. [My_App_with_Helper.zip]

App Checker is reporting as follows:

Why is this not working? It is supposed to work in a sandbox, right? And I guess it is working for Valdemar, in a sandbox, yes?
So what is the difference to what I am doing here?

I’m using AppWrapper to codesgin and sandbox the test application of Valdemar. Are there any special entitlements necessary for this test application?