Launch at startup and Mac App Store - macos

I've read lots of articles about creating helper tools as LSUIElement and then have them added to LoginItems using SMLoginItemSetEnabled.
What I want to know is, am I allowed to add the main app to LoginItems instead of creating a helper? (And the main app run as a LSUIElement shows in the status bar.)
Since the features were all in the helper and the main app is just a launcher, due to sandbox I can't really validate the receipt within the helper, so I can't prevent people from start the helper directly.
And if it's allowed (I have seem such app but not sure how they did it, such as "Flamingo"), how to add it to LoginItems without have it should down when toggle the settings? As SMLoginItemSetEnabled will terminate the app when pass false.
Thanks.

Related

Do I need a helper application to launch my main application at login?

I am creating this macOS application that offers the user the option to launch at login.
I have googled around and found a recipe that everyone is following for centuries, where a helper app is created and then this helper launches at login and from there, launches your main app.
Is that really necessary? Can't the main app launch directly at login?
I don't see any documentation from Apple saying that this scheme is mandatory.
Any thoughts?
It depends:
There is always the option to add the application manually to the Login Items in System Preferences > Users & Groups (no helper app).
Otherwise if the main app is sandboxed the helper app is mandatory.
Otherwise you could add a custom launchd agent which launches the application.

Pros and cons of splitting Cocoa utility app into helper binary + main app binary?

I'm modernizing and sandboxing an old Cocoa utility and considering approaches. The app lives in the menu bar and works in the background, but shows a Dock icon and a configuration window when the icon is clicked.
There are two approaches:
A. A single binary with LSUIElement=YES, using TransformProcessType to show and hide the dock icon as necessary.
B. A helper tool performs the actual app functionality, manages the menu icon and always runs in LSUIElement mode in background. The main app presents the configuration UI and is only launched when necessary.
The app currently does A. I've noticed that many long-running utility apps have separate helper binaries and basically do B. Examples on my Mac include Paste Helper, TimingHelper, Discord Helper, CCC Helper (for Carbon Copy Cloner), 1Password Extension Helper.
I understand that having a separate helper app is conceptually more pure and potentially allows for better separation of sandbox privileges, but it's also harder to implement, so I doubt that's the sole reason why all these apps opted to have a separate helper binary.
So:
What are the pros and cons of A and B, i.e. why do some choose B over A? Is it required to get some functionality these days?
Is it even possible to have a helper tool outlive the main app in a sandboxed Mac App Store app?
What API does one use to make such a helper? The old-style authorisation APIs seem deprecated, and XPC does not seem like it allows a helper app to launch at startup (and even outliving the main app may be hacky)?
I suspect the reason so many developers choose option B is because this arrangement is now baked into macOS via the "Login Items" facility.
In a nutshell, your main application embeds a second (helper) app and that app is configured as a "Login Item". macOS detects this and automatically adds your helper app to the user's login items. You can control this, programmatically, using SMLoginItemSetEnabled(...).
You end up with a regular app users are familiar with, and a helper app that automatically starts at login and can run in the background. I'm also pretty sure this includes a free XPC connection you can take advantage of.
Read all about it in the Adding Login Items section of the infamous Daemons and Services Programming Guide.
I've never done this myself (I currently install background apps as user agents, which I can do because I don't have a sandboxed app), but I did research it for another project and I know a lot of apps do this.
One disadvantage of option A (based on user feedback from my own apps) is that the main app won't act like a regular app. Using the A approach, your users either can't quit the app (because it will need to automatically restart) or you need a way to hide it in the dock, and then there's no (obvious) way to launch it again. It just gets confusing. If you do let your users quit the app, then the background functionality goes away, and that creates other problems.

Xamarin-iOS: host application will not run with share extension

My app setup is a basic new app with default viewController with the default classes for share extension on iOS 11.2.
The host AppDelegate class FinishedLaunching never gets called.
Just shows the launch screen and closes the app.
The sample Xamarin app provided also has the same issue.
Link to the sample app:
Share Extension sample
Any idea whats going wrong?
Do you want to open the app which you created with the share extension, when user clicks the share button to use this share extension? If so, this app should be called Containing App.
But unfortunately, there's no way to do this on iOS8.3+ except Today Extension. From this post we know that:
The intended approach for share extensions is that they handle all of
the necessary work themselves.
Also from the Apple documentation about extension:
An extension’s UI should be simple, restrained, and focused on
facilitating a single task.
Apple doesn't recommend us to open its containing app from extensions, actually it avoids that. If you want to retrieve data in containing app, you can set up an app group so that data can be shared between these two apps.

Set MacOS X menubar app to launch at startup

I have a sandboxed menubar application (no dock icon) that in it's preferences window allows the user to check a checkbox to have the app launch at login. I used to use the LSSharedFileList api, but as this is not allowed anymore for sandboxed apps, I've migrated to using SMLoginItemSetEnabled. What I've found is that although the app will launch at login, as expected, if I go back into the Preferences and uncheck and re-check the launch at login checkbox, I get a second instance of my menubar app launched.
Here's my helper app code (in its app delegate):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSString * path = [[[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent]
stringByDeletingLastPathComponent]
stringByDeletingLastPathComponent]
stringByDeletingLastPathComponent];
[[NSWorkspace sharedWorkspace] launchApplication:path];
[NSApp terminate:nil];
}
Here is the code in my preferences window (main app):
- (IBAction)toggleLoginStatus:(NSButton*)sender{
if(!SMLoginItemSetEnabled((__bridge CFStringRef)#"myAppBundleIdentifier", (BOOL)[sender state])){
NSLog(#"Dagnabit!");
}
}
After the second instance launches, unchecking/re-checking the checkbox does not launch anymore instances. Does anyone have any idea what's going on?
Thanks
I've found the answer. None of the tutorials I looked at mentioned this, but in the docs for SMLoginItemEnabled says this:
The Boolean enabled state of the helper application. This value is
effective only for the currently logged in user. If true, the helper
application will be started immediately (and upon subsequent logins)
and kept running. If false, the helper application will no longer be
kept running.
So I'll have to check if the app is running already before allowing the helper to launch it.
I spent almost two days figuring out this. Finally dropped the idea to support launch at login.
Although it is just a case of Yes or no in the Front end, developer on the other hand has to spent huge amount of time(Adding a helper application and doing all those project settings in both the apps). The process in early days (before sandboxing)was pretty much simpler than it is now.
Also when the application is added to the 'launch at login' list, there is no way to verify because the application is not listed in system preferences -> users -> login items, as it was before sand boxing.
I am also facing a strange problem where I added helper app to the launch at login and then uninstalled the helper, but the activity monitor still shows helper app in the list, after each reboot.
Lets hope apple adds something like LaunchAtLoginController in coming future.

Communicate between helper app and main app in sandbox

I have a status bar application from which I can launch a helper application for preferences. All preferences are stored in NSUserDefaults in the helper app and are read using addSuiteNamed: in the main app.
I would like to notify the main app when preferences are changed in the helper app. What is the best way to do this?
I have tried using NSDistributedNotificationCenter but this is too slow and not very reliable.
RMSharedPreferences by Realmac Software seems to be what I was looking for. It allows communicating between multiple apps and it is very easy to setup and seems to be way more reliable than NSDistributedNotificationCenter.

Resources