Launch helper from sandboxed application

2020-07-17 04:40发布

问题:

I have a sandboxed application. I need it to launch a helper application (from within the main application's bundle) every time it starts up. However, this fails:

NSError *error;
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:helperURL
                               options:NSWorkspaceLaunchDefault
                               configuration:nil
                               error:&error];

The error is:

The application “Helper” could not be launched because it is corrupt., NSUnderlyingError=0x10214c700 "The operation couldn’t be completed. (OSStatus error -10827.)"}

Now, the error is misleading, because the app launches fine if I disable the sandbox entitlement. Apparently this is a bug, as reported here.

My question is: Is there a workaround?

I could use SMLoginItemSetEnabled, as described here:

Pass true to start the helper application immediately and indicate that it should be started every time the user logs in. Pass false to terminate the helper application and indicate that it should no longer be launched when the user logs in.

But, I can't use this API without asking the user first, because of App Store Review Guideline 2.26:

Apps that are set to auto-launch or to have other code automatically run at startup or login without user consent will be rejected

So, using this workaround would mean asking the user "Is it OK to launch a helper every time you log in? If not, you can't use this app!" Clearly, that's not ideal...

回答1:

A viable workaround is to use NSTask to spawn /usr/bin/open and give it the helper app's path:

NSTask *task = [NSTask new];
[task setLaunchPath: @"/usr/bin/open"];
[task setArguments: [NSArray arrayWithObjects: helperPath, nil]];
[task launch];

This runs fine from the sandbox, and appears to be compatible with the Mac App Store Review Guidelines.

Update: On further examination, this technique frequently fails with the error

The application cannot be opened because its executable is missing.

This error does not occur when I've turned off sandboxing. So there must be a better solution...



回答2:

You can use SMLoginItemSetEnabled. You have to ask user consent once. After all, a helper application launched for the first time with SMLoginItemSetEnabled is automatically launched every time the user logs in.