How to use Photos.app scripting targets from sandboxed apps

I'm writing an app for the macOS App Store in C++/QT with now some mixed in Objective C, and I'm currently trying to add the following functionality :

Create an album in the Apple Photos app, then add some videos to it given their id (videos that are already in the library, not importing videos).

For this, I've written the hybrid C++/Objective C function:

char *Obj_C::obj_C_addMediaToAlbum(char *albumName, char *mediaId)
{
    NSString *objAlbumName = [NSString stringWithUTF8String: albumName];
    NSString *mediaIdS = [NSString stringWithUTF8String: mediaId];

    NSString *source = [NSString stringWithFormat:@"tell application \"Photos\"\n"
                                                  @"    set selMedia to (get media items whose id contains \"%@\")\n"
                                                  @"    if not (album \"Trash from %@\" exists) then\n"
                                                  @"        make new album named \"Trash from %@\"\n"
                                                  @"    end if\n"
                                                  @"    add selMedia to album \"Trash from %@\"\n"
                                                  @"end tell", mediaIdS, objAlbumName, objAlbumName, objAlbumName];

    NSDictionary *errorDictionary;
    NSAppleScript *script = [[NSAppleScript alloc] initWithSource:source];

    NSAppleEventDescriptor *resultDesc = [script executeAndReturnError:&errorDictionary];

    NSString *returnString = @OBJ_C_SUCCESS_STRING;
    if ( resultDesc ) { // was successful
        return (char *)[returnString UTF8String];
    }
    else{
        returnString = [NSString stringWithFormat:@"%@", errorDictionary];
        return (char *)[returnString UTF8String];
    }
}

I've added the following elements to my entitlements file, after looking at the Photos.sdef file which describes the scripting targets available for the Photos app:

<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
      <true/>
    <key>com.apple.security.automation.apple-events</key>
      <true/>
    <key>com.apple.security.scripting-targets</key>
      <dict>
        <key>com.apple.Photos</key>
          <array>
            <string>com.apple.Photos.library.read-write</string>
            <string>com.apple.Photos.spotlight</string>
          </array>
      </dict>
  </dict>
</plist>

And the following to my .plist file as I read somewhere it's necessary:

	<key>NSAppleEventsUsageDescription</key>
	<string>The app uses events to control Apple Photos, to help you identify duplicates within you library.</string>

When I run this outside the sandbox, it runs fine. However, if I attempt inside the sandbox, I get the error AppleEvents/sandbox: Returning errAEPrivilegeError/-10004 and denying dispatch of event core/getd from process '<private>'/0x0-0x130f30e, pid=63826, because it is not entitled to send an AppleEvent to this process. when looking in the console and the output from my function is :

{
    NSAppleScriptErrorAppName = Photos;
    NSAppleScriptErrorBriefMessage = "A privilege violation occurred.";
    NSAppleScriptErrorMessage = "Photos got an error: A privilege violation occurred.";
    NSAppleScriptErrorNumber = "-10004";
    NSAppleScriptErrorRange = "NSRange: {51, 68}";
}

I also get the same error if instead of the whole complex AppScript command, I only give the command : "tell application \"Photos\" to make new album named \"Test album\", so it doesn't seem to come from one element of the script itself.

**I don't understand: what am I missing to make it work correctly ? **

NB:

If instead I use com.apple.security.temporary-exception.apple-events with my entitlements file being :

<plist version="1.0">
  <dict>
    <key>com.apple.security.app-sandbox</key>
      <true/>
    <key>com.apple.security.automation.apple-events</key>
      <true/>
    <key>com.apple.security.temporary-exception.apple-events</key>
      <array>
         <string>com.apple.Photos</string>
      </array>
  </dict>
</plist>

It then works, but it doesn't seem the safe way to do it nor the approved way to do it from my understanding of the temporary exception being intended to be replaced by the scripting targets when available, and they are available for the Photos app...

Once you're in the Sandbox, you're in the sandbox. You might have better luck just coding against the actual PhotoKit frameworks - https://developer.apple.com/documentation/photokit

I'm currently trying to add the following functionality

Have you tried doing this using the Photos framework? My experience is that using a dedicated API is a lot easier than monkeying around with Apple events.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hey, thanks for the answer.

No I didn't try the Photos framework. At the beginning, I wanted something quick and easy, calling osascript but that didn't work, so I implemented it in objective c using NSAppleScript. I've spent so much time trying to understand what's not working for the sandbox, it's really annoying. In the end you're right, it might've been easier to use another approach 🤷‍♂️

I mean, it works now, using the temporary exception entitlement. But I'm still wondering what is wrong with the indicated, "Apple Approved" entitlements of scripting targets ...

I mean, it works now, using the temporary exception entitlement.

I don’t work for App Review, and thus can’t give you definitive answers on their behalf, but my experience is that they are very reluctant to accept apps that use temporary exception entitlements.

I'm still wondering what is wrong with the indicated, "Apple Approved" entitlements of scripting targets

Likewise. I’m usually able to debug such problems but it’s not easy and so not something that I have time for here on DevForums. If you want to go down that path, open a DTS tech support incident and we can pick things up in that context.

However, and this is why I asked about Photos framework, I generally think that Photos framework is a better option than Apple events. So, if you can achieve your goals using Photos framework, that will avoid any App Review entanglements and yield code that’s more sustainable in the long term.

Oh, and if Photos framework doesn’t do what you need then you can file an enhancement request about that and use that ER as justification for why you’ve gone down the Apple events path (-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks again !

In fact App Review approved my app with the temporary entitlements, yesterday ! I guess they know that the target groups are a mess ? 😅

In any case, thanks and if in the future I find the time to debug and perfect, I’ll try your suggestions ! 😊

How to use Photos.app scripting targets from sandboxed apps
 
 
Q