3

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

Andrew Madsen
  • 21,309
  • 5
  • 56
  • 97
  • It seems this happens only if the target application is *already* running; it works otherwise. – l'L'l Jul 24 '16 at 19:58
  • That's interesting. In my test app, if Sketch is not running, clicking the Draw button opens Sketch and the call to `-applicationWithBundleIdentifier:` succeeds. However, on the next click, with Sketch now running, it fails. – Andrew Madsen Jul 24 '16 at 23:07
  • Yes, it's strange that it works the first time actually without needing the temporary-exception entitlement. – l'L'l Jul 25 '16 at 04:22

1 Answers1

1

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.

Andrew Madsen
  • 21,309
  • 5
  • 56
  • 97
  • On working on this further, it seems that `com.apple.security.temporary-exception.apple-events` actually doesn't work. Not sure why I thought it did when I wrote the original question. – Andrew Madsen Jul 30 '16 at 21:06
  • Does it work okay in AppleScript? SB is buggy and crippled by design, so it's not unusual for stuff to break in SB despite working fine in AS. If so, the answer is to chuck SB and use AS via the AppleScript-ObjC bridge, which allows you to interact with AS script objects and handlers much like native Cocoa classes and methods. [Quick HowTo here](http://appscript.sourceforge.net/asoc.html). OTOH, if the bug's in the sandbox system then you're probably stuffed till Apple fix it at source. (p.s. Consider posting your ticket on [OpenRadar](http://openradar.appspot.com) for reference too.) – foo Jul 31 '16 at 13:35
  • Sure enough, using `NSAppleScript` to run a regular script works fine. Using ASOC is probably overkill for me. It's too bad SB doesn't work well here. It's a really nice idea in theory. Thank you! – Andrew Madsen Jul 31 '16 at 21:01
  • Use ASOC if you need to pass values between AS and ObjC as it bridges all the common data types (NSInteger, NSString, NSArray, etc) for you. As for SB—tell me about it. This was a [solved problem](http://appscript.sourceforge.net) till the AppleScript team screwed it up again. I still use appscript in my own work because it's the only AS alternative that works right, but I'm no longer interested in providing public support when Apple are clearly determined to run the whole stack into the ground. Sooner Apple dumps that deadweight and hands over to the JSCore and XPC Services folks, the better. – foo Aug 01 '16 at 16:43