Set MacOS X menubar app to launch at startup - cocoa

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.

Related

AXIsProcessTrustedWithOptions doesn't return true even when the app is ticked in accessibility

As this question answered, I use AXIsProcessTrustedWithOptions with no option to test if my app has been enabled in the accessibility panel. If not, prompt the window to let users to enable it. There is button bound to this test call as well, so users don't need to close the UI and reopen it.
But sometimes, even after a user enables the app, AXIsProcessTrustedWithOptions still returns false. When I check the sqlite database, it shows my app as "kTCCServiceAccessibility|com.abc.def|0|1|1||". The first 1 digit indicates it has been allowed apparently. But the api call still returns false. At this point, if I close the UI, the app is unticked in the accessibility panel which causes a loop so users can never pass this step.
Another thing is this app is actually a version 2 of the previous app. But the user did replace the bundle with the v2 one. Not sure if this is related.
Any idea why this would happen?
NSDictionary *options = #{(id)kAXTrustedCheckOptionPrompt: #NO};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
if (!accessibilityEnabled) {
NSString *urlString = #"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];
}
Update: In Xcode, Signing & Capabilities, make sure you have selected a Team and Signing Certificate.
Original answer:
I experienced this when developing an app on macOS 10.14.5 in Xcode trying both AXIsProcessTrusted and AXIsProcessTrustedWithOptions .
After wasting a lot of time trying all sorts of things, including different options for AXIsProcessTrustedWithOptions, logging out/in, rebooting, praying, and crying, I eventually shut down my machine and powered it back on in frustration. Then it worked. Hopefully nobody else has this same experience.

OS X: Launching app from dock is a no-op if app is already running headless (via NSApplicationActivationPolicyProhibited)

My app can run with a UI and run headless, chosen via a command-line argument. (I don't want to build two separate apps.) When running headless, I'm calling:
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
during app initialization, and don't show any windows.
This all works fine, and I can run the app headed (via the dock) and headless (via another app passing the command-line argument) at the same time. The little dot shows up next to the dock icon only for the headed app. Good. The problem happens if the headless app is launched first. In that state (no dot in the dock), any clicking on the app icon (or launching via Spotlight or the Finder) does nothing, or sometimes brings up "You can’t open the application “Foo” because it is not responding." Presumably the OS thinks the app is already running headed, and is trying to activate it. Is there a way to convince it to ignore that background app and launch a new instance?
Quitting the background app allows the app to launch normally again from the dock.
I don't want to set LSBackgroundOnly in the plist, because that would require two separate apps unless I changed the setActivationPolicy to NSApplicationActivationPolicyRegular in the case of the headed app. But I've read that doing that causes various other bugs, like the menu bar not always showing up.
Any ideas?
I'm on OS 10.10.5 (the oldest OS I need to support). Thanks for any help!
Update: I just noticed that when clicking on the dock and it appears to do nothing, if there are no app windows open I can see that it actually unhides my app's main window (which was created hidden) but doesn't bring it to the front (presumably it notices that NSApplicationActivationPolicyProhibited is set, though that wasn't enough to prevent it from showing the window!).
Update 2: At this point, I'd settle for a way to notify the user that the reason the app isn't launching is that they need to quit the other app that has sublaunched the headless process. Of course this code would need to be in the headless app, since the headed doesn't even launch.
It looks like you can call setActivationPolicy from applicationShouldHandleReopen and set the policy back to NSApplicationActivationPolicyRegular at that time. I made a test app with the following code and it seems to behave as you describe you would like it to above (although I've only run it on 10.11.5):
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) {
if NSUserDefaults.standardUserDefaults().stringForKey("background") == "true" {
NSApp.setActivationPolicy(.Prohibited)
print("launched in background")
}
}
func applicationShouldHandleReopen(sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
NSApp.setActivationPolicy(.Regular)
return true
}
}

User preferences are not saved from XPC service

In my main app bundle I have supporting XPC service included. App is sandboxed and everything works quite fine, except that when I call [[NSUserDefaults standardUserDefault] setObject:forKey:] method and than - synchronize method from the XPC service app, preferences are not written and data cannot be retrieved next time I need it.
I didn't find anything related to this problem in Apple's documentation, except that the sandboxed app cannot access preferences of other apps. That's all right, I don't need it. XPC service has its own container in ~/Library/Containers, where it should be able to store its own data, I'd suppose. But obviously it's not the case for some reason.
I probably missed something, but cannot find what. Is there anything special which needs to be done (adding some entitlement or so) in order to make this work?
Thanks for any tips.
I believe you'll need to use Group Containers to share the preferences and I have achieved something similar (a non-UI LSUIElement app sharing preferences with its conventional Preferences app countpart) using RMSharedPreferences.

Launch at startup and Mac App Store

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.

How does Reminders launch the app?

I am having a few problems getting my Windows Phone 7 app-specific Reminders to work properly - the app re-closes after a fraction of a second after starting to show the splash-screen.
In order to debug this, I'd like to know how a Reminder launches an app, which events are fired and so on.
For what it might be worth - here is what I found out.
A Reminder restarts the app, triggering the Launching-event in App.xaml.cs. That is - you need to re-load anything you need to make the app work from Isolated Storage or the web
When the Launching event is done with, the app goes straight to the requested view - skipping any loading-page you might have made for your app. Again, remember to load whatever resources you need from Isolated Storage.
Then the app fires the view's constructor, before OnNavigatedTo and Loaded goes off.

Resources