objective-cmacoscocoasandboxscripting-bridge

AppleScripting sandboxed app from another sandboxed app using ScriptingBridge


I'm trying to script a sandboxed app (which I wrote) from another sandboxed app using ScriptingBridge. I have access groups set up in the target app's sdef, and entitlements configured in the scripting app's sandbox entitlements. However, when I try to send Apple Events to the target (using ScriptingBridge), I see warning: failed to get scripting definition from ~/<snip>/MyApp.app; it may not be scriptable. logged in the console (the path to the target app is correct).

I've been able to reproduce the problem with a lightly modified version of the Sketch sample code app and a very simple test app that uses scripting bridge. I added <access-group identifier="com.apple.CocoaExamples.Sketch.Draw" access="rw"/> to many elements in Sketch.sdef, as well as turned on sandboxing for Sketch.

Then, in my test app, I turned on sandboxing with the following entitlements:

<?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>com.apple.security.app-sandbox</key>  
    <true/>  
    <key>com.apple.security.scripting-targets</key>  
    <dict>  
        <key>com.apple.CocoaExamples.Sketch</key>  
        <array>  
            <string>com.apple.CocoaExamples.Sketch.Draw</string>  
        </array>  
    </dict>  
</dict>  
</plist>  

The app does the following:

#import "ViewController.h"  
#import "Sketch.h"  

@implementation ViewController  
- (IBAction)draw:(id)sender {  
    SketchApplication *sketch = [SBApplication applicationWithBundleIdentifier:@"com.apple.CocoaExamples.Sketch"];  
    if (![sketch isKindOfClass:[NSClassFromString(@"SketchApplication") class]]) {  
        NSLog(@"Unable to get SketchApplication for Sketch");  
    }  
}  
@end

Upon the call to -applicationWithBundleIdentifier:, the "warning: failed to get scripting definition" message is logged, and the object returned is an instance of SBApplication rather than a SketchApplication.

If I turn off sandboxing in the test app, the error is not logged, and -applicationWithBundleIdentifier: returns a SketchApplication as expected. The same is true if I add the com.apple.security.temporary-exception.apple-events entitlement, though I believe this is unlikely to pass app store review.

Am I missing something beyond defining access groups in the target's sdef and adding the com.apple.security.scripting-targets entitlement? Does this work for anyone?

I've uploaded the test app and my modified Sketch projects here: https://www.dropbox.com/s/cdml9n5npu8o2m3/SandboxScriptTest.zip?dl=0


Solution

  • I filed a tech support incident with Apple about this, and they confirmed that it is a bug. The only workaround they suggested is to hold onto the (valid) instance of SketchApplication returned by the first call to -applicationWithBundleIdentifier: when Sketch is running for later use. This is not really a viable workaround at all in my particular case since the target app is very likely to already be running before the scripting app is launched.

    I've filed a radar for this: rdar://27625862.

    The other option is to use the com.apple.security.temporary-exception.apple-events sandbox entitlement. I'll do that for now, and hope that I can justify its use for app store review.