thanks Quinn, especially for the magic incantation for launchctl (I had read the enormous man page, but couldn't figure out how to do the needful). There is no service published containing my company ID. My extension's main attempts to make an XPC listener using NSXPCListener *listener = [NSXPCListener serviceListener];
So it looks like the OS didn't do whatever it needs to do to publish a service. Which points to missing required entries in my plist.
My app is not sandboxed.
Post
Replies
Boosts
Views
Activity
I managed to get direct app to camera extension communication working, but I'm not sure I'm doing it right. The gist is this:
You make a launch daemon which acts as a helper. The code lives in your app bundle, but the process started by launchd on your behalf will run as root. The helper makes a XPC listener on a Mach port with a global name, which can be found by your app and by the camera extension. You use the helper as a kind of mailbox to let the extension know where to find the app. This approach is mentioned at various places on this forum and elsewhere on the Internet, but never in great detail.
In your app, find and connect to the helper. This is similar to connecting to a bundled XPC service, only you use initWithMachServiceName instead of initWithServiceName. Then make an anonymous listener, get its endpoint, and send that endpoint as a parameter to your helper. Store it in the helper.
In your extension, find and connect to the helper, exactly the same way you do so from the app. Make an XPC call into the helper to fetch the endpoint which the app stored (in the reply block of your call). I don't know how to deal with synchronization issues here, I guess there is a slim chance that the extension could fetch the endpoint value at a time when it is in the process of being written by the app.
Now, in the extension, build a connection around the endpoint you just received, with initWithListenerEndpoint.
From the extension, make a call into your app - this will cause your app's listener:shouldAcceptNewConnection to be called and you have established a direct communication between the extension and the app, which of course can be used in both directions.
There are a myriad of small things you have to get right - matching protocols at each end, allowing the extension to break out of its sandbox to look up a Mach service name with a properly formatted com.apple.security.temporary-exception.mach-lookup.global-name entitlement, ensuring the name of the service is prefixed by one of the app groups, the helper bundle ID has to be the same as its Mach service name etc etc.
Also, I might be doing something wrong and making it all too complicated. The Camera Extension is nicely self-contained. All the app code has to do is ask to activate it. But the helper requires an installer, and it has to be at a known location so that the launchd plist can find it. Which restricts you to putting your app in /Applications, or to doing some heroics to write a plist with the correct absolute path to the bundle at run-time, and then somehow installing this newly-generated plist, all of which is very far from drag-and-drops simplicity.
Also, the camera extension isn't replaced when you install a new one. _cmiodalassistants will stubbornly hang onto an instantiation of the older version until you reboot. I have done a lot of rebooting.
I'd like a simpler way too. I'd also like this forum to respect my line breaks in comments, instead it just smushes all my paragraphs into one giant block.
I tried to send video from my app to the extension.
If I (try to) send a IOSurfaceRef, I get an exception encodeDataAt:ofObjCType: unencodable type (^{__IOSurface=}) in my app.
If I (try to) send an xpc_object_t derived from that IOSurfaceRef, using IOSurfaceCreateXPCObject, I get this error:
<NSXPCConnection: 0x6000031e43c0> connection to service with pid 17661 created from an endpoint: Exception caught during decoding of received selector sendIOSurfaceToExtension:, dropping incoming message. Exception: Exception while decoding argument 0 (#2 of invocation): Exception: Attempt to decode an xpc type but whitelist does not specify an XPC type '<no key>'.
Someone asked a similar question a year ago on Stack Overflow, the answer was "whitelist it", but whitelisting should only be necessary for objects in connection classes, no? I'm sending my frames one at a time, not in a collection. There's an API to set the XPC type on a parameter of an interface method - setXPCType:forSelector:argumentIndex:ofReply:, but I don't know what value to use. I thought it was supposed to Just Work™?
a year late, but you're trying to send an IOSurfaceRef, you need to send an IOSurface (see IOSurface/IOSurfaceObjC.h)
under the Info tab, you'll find "Custom macOS Application Properties" or "Custom iOS Application Properties". Hover over any one of the existing properties, and you'll see a little + or - in a circle appear. Click on the tiny + to add new properties.
I should add that I have no idea if the source code is the source code of the binary I am using. The binary displays version 666.4.0, while the source code has CFBundleVersion = 2.3d1 in its Info.plist
I did examine the header map files in the working and non-working case when the problematic header had Project target membership.
The only difference was in the dext's -all-non-framework-target-headers.hmap, which was empty in the non-working case (built as a consequence of building the enclosing app), and contained an entry leading to the problematic driver in the working case (building the dext target directly).
Again, I have no idea why there would be any differences.