I want to establish an XPC connection between a network extension and a launch agent. Right now that launch agent is a "sample" app as a stand-in for an existing non-app-store app that is going to be gaining some functionality.
My intend is that the NE starts a connection to the launch agent and exposes an interface so that the launch agent can invoke a method on an instance in the network extension. The launch agent is going to keep track of any connections established by the NE and invoke methods as needed on any live NE.
My symptom is that my sample launch agent app is not launched automatically like I expected. If I launch the sample app manually I can see my logging that is has created the NSXPCListener instance, but no logging in the [listener:shouldAcceptNewConnection:] method. On the network extension side, I see my invalidation handler called immediately after resume is invoked.
I figure I've done at least one of two things wrong:
I'm installing that with a command like:
In the network extension I make a connection with code like:
In the sample app that is intended to be the launch agent I have code like:
and then later on in the sample app I have the listener:
My intend is that the NE starts a connection to the launch agent and exposes an interface so that the launch agent can invoke a method on an instance in the network extension. The launch agent is going to keep track of any connections established by the NE and invoke methods as needed on any live NE.
My symptom is that my sample launch agent app is not launched automatically like I expected. If I launch the sample app manually I can see my logging that is has created the NSXPCListener instance, but no logging in the [listener:shouldAcceptNewConnection:] method. On the network extension side, I see my invalidation handler called immediately after resume is invoked.
I figure I've done at least one of two things wrong:
set up the launch agent wrong, so that the OS doesn't know how to launch it
set up the connection in the NE wrong so that it is being rejected without even trying to connect
Code Block <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>TEAMID.group.my.stuff</string> <key>Program</key> <string>/Users/me/.../build/Debug/Sample.app/Contents/MacOS/Sample</string> <key>MachServices</key> <dict> <key>TEAMID.group.my.stuff</key> <true/> </dict> </dict> </plist>
I'm installing that with a command like:
Code Block launchctl load path/to/com.me.Sample.plist
In the network extension I make a connection with code like:
Code Block NSXPCConnection* xpcConnection = [[NSXPCConnection alloc] initWithMachServiceName:@"TEAMID.group.my.stuff" options:0]; xpcConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCIPC)]; xpcConnection.exportedObject = self; xpcConnection.invalidationHandler = ^() { ... some logging }]; xpcConnection.interruptionHandler = ^() { ... some logging }]; [xpcConnection resume];
In the sample app that is intended to be the launch agent I have code like:
Code Block xpcListener = [[NSXPCListener alloc] initWithMachServiceName:@"TEAMID.group.my.stuff"]; xpcListener.delegate = self; [xpcListener resume];
and then later on in the sample app I have the listener:
Code Block - (BOOL)listener:(NSXPCListener*)listener shouldAcceptNewConnection:(NSXPCConnection*)connection { connection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol:@protocol(XPCIPC)]; connection.invalidationHandler = ^() { ... some logging }; connection.interruptionHandler = ^() { ... some logging }; [connection resume]; [connection remoteObjectProxyWithErrorHandler:^(NSError* error) { ... some logging }]; return YES; }