I have an application that spawns subprocesses. These subprocesses require XPCServices, that are in the same application bundle.
My main application has its executable in
my.app/Contents/MacOS/my
My XPC service sits in my.app/Contents/XPCServices/com.my.service.xpc
When the subprocess resides in my.app/Contents/Resources/mysubprocess, and the application is being launched, my subprocess can't connect to the XPC service (why not?), but it doesn't show up in the Dock.
If on the other hand the subprocess is in my.app/Contents/MacOS/mysubprocess the subprocess successfully connects to my XPC service (the main application doesn't need anything from this XPC service), the subprocess suddenly gets an own bouncing icon in the Dock. I guess OS X detects if something is being launched from within *.app/Contents/MacOS/* and sees it as application.
I obviously need it to work that way, that the subprocess can connect to the XPC service, but that the subprocess stays hidden and doesn't appear in the Dock. I've tried registering LSUIElement and LSBackgroundOnly at runtime to my user defaults, but that didn't do the trick. If i write LSUIElement into the user defaults, my main application doesn't get a main menu, which is also undesired (but in case of LSUIElement being NO absolutely correct behaviour).
Basically I have two questions:
When I move my subprocess binary outside of my.app/Contents/MacOS/ it can't locate the XPCServices. I find that kinda odd, because the relative path to the service stays the same, if the subprocess would be in my.app/Contents/Resources/. I also checked [NSBundle mainBundle] while debugging my subprocess and it had a valid path, even when it was in the Resources folder. Is there a way to somehow tell my subprocess where it should look for my XPC service?
The other approach would be that I can prevent the subprocess of bouncing in the Dock. My main application needs its icon and menu. So is there a way to specify at runtime that the subprocess won't launch a Dock icon, even if it's in the my.app/Contents/MacOS/ folder?
Thank You
According to the Apple Developer docs, XPC services that you as a developer can write must reside in your app’s bundle in My.app/Contents/XPC Services. Your app can only connect to XPC services that reside there and those XPC services can only be connected to from the app whose bundle they reside in.
(Note that the XPC services Apple ships in its system frameworks work a bit differently: /System/Library/PrivateFrameworks/WebKit2.framework contains XPC services that are used by any process that use the WebKit2 framework. But then again, the framework connects to that XPC service, not your app itself.)
That is probably the reason why you can’t connect to the XPC service if your subprocess’ binary is not in My.app/Contents/MacOS/. I’m not sure, but that you can connect to the XPC service from an arbitrary binary that resides in MacOS almost sounds like a bug. But I think it’s not because XPC services only work if the code signature is OK and placing an arbitrary binary in the MacOS directory would break that code signature.
As for the dock icon: How are you spawning the subprocess? Using NSTask? Does the regular app itself use the XPC service? If not, is there any reason why the subprocess isn’t an app itself? That way the XPC service could be inside the subprocess’ /Contents/XPC Services directory and everything should work OK.
Edit: Another solution that comes to mind: Don’t use XPC, but a separate process that talks via Distributed Objects to your subprocesses. Because that doesn’t require any special folder structure or something like that, you can place all auxiliary binaries wherever you want and can therefore avoid the Dock icon bouncing issue.
Related
I am creating a plug-in in Objective-C to a third-party macOS app. I want to register and handle url scheme (like myscheme://somedatahere) and file types - for example, when a user double click on a file our plug-in should be notified.
As my product is just a plug-in to a third-party app, the code has no access to the app's NSApplication instance nor to its events. As such, I need to create a helper app and bundle it inside the plug-in bundle/package to register and handle that. Please let me know if these presumptions are incorrect.
The plug-in bundle is being installed inside the Library/Application Support (the user typically downloads the plug-in into the Downloads folder, double click it and then the host app's handler copies the plug-in into the Application Support folder). The app handling urls and file types will be placed inside the plug-in bundle. The location was chosen by the host app.
I have several uncertainties I failed to find answers for:
How does the macOS finds apps capable of handling a particular url scheme and file types?
Does macOS finds it somewhat automatically or should I call something?
If it is found automatically, will it work even if the app is located inside a plug-in package outside of the Applications directory?
You can find the answers you are looking for the in the Launch Services documentation.
If you check the section "Application Registration", you will see that:
A built-in background tool, run whenever the system is booted or a new user logs in, automatically searches the Applications folders in the system, network, local, and user domains and registers any new applications it finds there.
The Finder automatically registers all applications as it becomes aware of them, such as when they are dragged onto the user’s disk or when the user navigates to a folder containing them.
So, if your helper app is installed into /Library/Application Support by the user manually dragging-and-dropping, it looks like Launch Services will see it and register the URL scheme.
Otherwise, the documentation continues to cover the manual case:
In spite of these automatic registration utilities, it may sometimes be necessary to register an application explicitly with Launch Services. For example, although developers are encouraged to package their applications so that they can be installed by simply dragging them onto the user’s disk, some applications may require more elaborate custom installer software. In such cases, the installer should call one of the Launch Services registration functions LSRegisterFSRef or LSRegisterURL to register the application explicitly.
I have a application inside which i have kept other applications.I want to launch other application in root privilege through main application.As we know AuthorizationExecuteWithPrivileges() has been deprecated, so that i have created a privileged helper tool. I am using Main application to install this helper tool through SMJobBless() function , and communicate through XPC mechanism. Every thing is working fine, Main application sending message(Path of application to be launch) to helper tool that is already running in root mode. The helper tool is able to launch that application provided in path, but the problem is, launched application doesn't have root privilege. Can anyone tell me how i can use this helper tool to launch another application in root privilege.Or is there any other mechanism to achieve it, i will ever thankful for this.
I am working on a Finder Sync Extension for OS X and want to use a background XPC service.
I can start in the main app and have it launch the XPC and run correctly but nothing happens when I attempt to access it from the Finder Sync. both the finder sync and the XPC are their own bundles so that may be the reason why. What I am wanting is for the finder sync to talk to the XPC about the status of the files and the main app to talk to both the finder sync and XPC about the list of folders to watch.
Has anyone had any luck with this? Is there a better way for a on demand background service? Is it possible to talk between two XPC services?
Working with some Apple Engineers they realized this was a problem and suggested using a LoginItem until a better solution is in place.
So, it is sort of an XPC service, just one that constantly runs. XPC communication is available to both extension and host app.
It works, although it is not the most ideal solution. I recommend the apple sample project that deals with XPC login items for an example of how to get this working.
I implemented MainApp <-> FinderSyncExtension communication via CFMessagePorts. See my question and answer for some details:
How should Finder Sync Extension and Main App communicate?
You can't communicate directly between the container application and the extension, but you can do it indirectly using shared resources. I did exactly what you have done which is completely incorrect. I hope you store the file status in the database, if not store it and then share the database between the container application and the extension. I know, why do you want to use XPCService as it is in the Apple's FinderSync Doc. (Actually for the performance reason, Create a NSXPCService to the extension and from the XPCService, access the shared database)
For more information about sharing database:
http://blog.sam-oakley.co.uk/post/92323630293/sharing-core-data-between-app-and-extension-in-ios-8
Hope this helps you,
I had stubbornly ignored utahwithak's answer and tried to get it to work anyway. I eventually had to ask a similar question on Apple Developer Forums and finally received a definitive answer on why connecting the Finder Sync Extension to an embedded XPC service is not a viable system design.
Essentially:
Finder Sync Extension essentially behaves like a third party app in that it does not have the same scope as the host app to be able to establish an XPC connection with the embedded XPC service.
utahwithak's answer is correct in that in order to allow the Finder Sync Extension to communicate with the XPC service, it needs to be an XPC login item. However there are some caveats to this:
This seems to be an accidental feature. Not sure if it's something that might eventually be fixed/removed
The XPC will have to be always running even if it doesn't need to, by virtue of being an login item
If it's a login item, the user will need to explicitly opt in for this feature and be able to opt out.
Source:
Establishing an NSXPCConnection from a Finder Sync Extension to an XPC Service
I have created an application that exposes a OSX service for certain file by adding an NSService entry into my applications info.plist (as in http://www.macosxautomation.com/services/learn/), but I find that upon installing my application on a new machine the service doesn't show up quickly in the finder right click context menu.
I know that this is because pasteboard services hasn't re-indexed the /Applications folder and "discovered" the newly installed service.
I also know that I can force a re-index and discovery by manually running /System/Library/CoreServices/pbs.
The question here is what is the best way to ensure that my service shows up as quickly as possible for users who are installing my application for the first time.
I could execute a system call to "/System/Library/CoreServices/pbs" when my application starts up --If the user immediately starts my application--, but that only partly solves the problem (in addition I wonder if there is a better Cocoa API based way of doing this).
If my application is generally only accessed via the context menu, a user will never think to go out and start the application in the first place. They will only think it is broken when the context menu isn't there.
I am not distributing my application with an installer. I am simply providing a bundle that can be dragged and dropped into /Applications (as I believe Apple usually suggests).
Is there a way to expedite the process of service discovery when doing an installation in this fashion, so that there isn't any period of time where the user is without the newly installed service?
As a side note, it appears that the problem may not exist in 10.8 (or at least be as pronounced). Apple may have made this indexing happen more quickly in their most recent release.
I've actually ended up using
system("killall pbs;/System/Library/CoreServices/pbs -flush");
in one of my apps, just as you describe, though it's a long time ago, when 10.5 was in question as well.
You might want to try this function, however:
void NSUpdateDynamicServices(void)
which according to the documentation acts just like flushing pbs, but is a cleaner solution.
Also, if (according to your description), the app is nothing but a service, consider making it a really just a service - see (Installing the Service)
To build a standalone service, use the extension .service and store it in Library/Services.
I have a dynamic library, I intent to inject in running application & newly launched applications.
I can inject it in running applications with the help of a process running with root user permissions.
Now I am trying that library should get loaded as soon as application is launched. I know one such library capable of doing this called, application enhancer. I am looking for similar behavior.
Does anyone has an Idea how can this be achieved?
Look at SIMBL agent code. It adds a observer to application launch notification and then injects. You can follow the same approach.