Reputation: 14983
I'm currently developing an OS X Application which should run in the background. This app should be able to request some information by displaying an input GUI for the user.
Possibilities:
Right now I'm using a single application being an Agent by setting the "Application is Agent (UIElement)" key in the info.plist to true. It displays an item in the system status bar and can show my preferences view (being possible with the activateIgnoringOtherApps
method of the appDelegate
).
Using an Agent works, but the problem is, that any window launched by this application counts as one of itself. So cmd-q-ing the window quits the whole app. And using this activateIgnoringOtherApps
method doesn't seem very legit.
So another possibility I tried was to use a sub-project. On build, the app copies the .app file from the sub-project to the Resources of the containing project. Now those applications are totally separate and cmd-q-ing just quits the configuration view app. But there are some problems with this method: Because the apps are separate, they cannot interchange data at all. Also debugging is annoying and only partially possible.
Another method I considered was using an App Extension. This would solve the problem with the data exchange, because App Extensions and it's containing Applications can have a shared data container. But there would be other problems, also hitting cmd-q would probably quit the app that calls the extension.
Then I read about XPC services, which is probably the right way to do it. XPC I believe should be able to transfer data from app to app.
Also there are "App Bundles" (also used by Extensions) where multiple apps can share the same data. I did not try out this method yet.
So basically my question is:
What is the recommended way to run a background application, being able to request data from the user with a GUI?
Requirements:
Do not want:
Any help would be appreciated
Thank you
UPDATE:
So I read a lot about XPC and it's possibilities. There is a great modern article on objc.io by Daniel Eggert with an example.
I think I'm going with this way:
When the main app gets a request to show the configuration window, it will first start the GUI app (which won't show the GUI just yet). Then it will create a bidirectional XPC connection to the just opened app, using an anonymous Listener. When the user is done entering the input, the GUI app sends the input over the XPC connection back to the main app.
But I have no idea how to do this. I only managed to create a connection to an XPC Service. I'd really like an example project using a bidirectional connection, because I just cannot figure it out (I'll continue to try though).
Upvotes: 1
Views: 1481
Reputation: 27631
an OS X Application which should run in the background
This is a 'daemon' application and can be either a Launch Daemon or Launch Agent.
A Launch Daemon application is started when the system starts up and only one exists. In contrast, a Launch Agent exists for each session and begins when a user logs in.
A daemon application should not and cannot display UI. However, in order to achieve your requirements, the daemon can use IPC, such as XPC, TcpIP, local sockets or any other desired method to communicate to a second application, which provides the required UI to the user and relays that back to the daemon, as required.
No cheaty methods, I'd like to use the recommended way
If a method works and is secure, it wouldn't be defined as 'cheating'. As for a recommended method, Apple suggests XPC as an easy method of IPC (communicating between two applications), but it's not wrong to use another IPC mechanism.
As for using activateIgnoringOtherApps, if your GUI is an alert to the user and needs to be handled by the user, without delay, I don't see a problem with using this here. Alternatively, the GUI application can be a Launch Agent, which is set to restart if quit.
Finally, you may be able to create a daemon with a XPC Helper application to handle the GUI, though it's not something I've tried.
Upvotes: 2
Reputation: 4282
Publishing to App Store is whole different story and I don't know about that.
I think, straightforward way to do is your sub-project
type.
There is NSConnection
. It's a kind of IPC/RPC mechanism. Different processes can interact almost seamlessly via Objective-C method calls.
One create `NSConnection' objects and vend services, the other connect to the vended services and acquire remote objects with which the other can do usual Obj-C message sending (function calls).
For debugging concerns, preventing Cmd-Q is really cheaty. We must assure user can quit out program without hassle. So, running an another background process is safest and most legit way, I think.
Upvotes: 1