macos - How can an application check if it has permission to control another application through AppleScript without blocking? -

I'm writing an AppKit macOS application that will use AppleScriptApple events to automate anoth

I'm writing an AppKit macOS application that will use AppleScript / Apple events to automate another application. I need to know ahead of time whether or not my app has permission to do this for the specific other application it wants to automate. I also need to trigger the "Foo.app wants access to control Bar.app" permission dialog if it hasn't already been shown.

The one way I can think of to do this is to just run an AppleScript that attempts to automate the other app in some rudimentary way and see what happens. However, if the permission dialog appears, that script will block until the dialog has been dismissed.

Is there a way to check this without blocking?

I'm writing an AppKit macOS application that will use AppleScript / Apple events to automate another application. I need to know ahead of time whether or not my app has permission to do this for the specific other application it wants to automate. I also need to trigger the "Foo.app wants access to control Bar.app" permission dialog if it hasn't already been shown.

The one way I can think of to do this is to just run an AppleScript that attempts to automate the other app in some rudimentary way and see what happens. However, if the permission dialog appears, that script will block until the dialog has been dismissed.

Is there a way to check this without blocking?

Share Improve this question asked Nov 19, 2024 at 23:59 Bri BriBri Bri 2,2623 gold badges24 silver badges65 bronze badges 2
  • 1 Does stackoverflow/a/52520694/10853463 help? – red_menace Commented Nov 20, 2024 at 0:31
  • @red_menace Yes, I think that'll do what I need. It's not perfect, in that AEDeterminePermissionToAutomateTarget also will block if you pass true to askUserIfNeeded, but it can be checked to see if permission is required without blocking. And I think I could call it in another thread in its blocking form to trigger the permission dialog. – Bri Bri Commented Nov 20, 2024 at 1:08
Add a comment  | 

1 Answer 1

Reset to default 0

I was able to adapt the answer in this thread to something that works for my purposes. The key issue is that AEDeterminePermissionToAutomateTarget can block under two circumstances:

  • Its askUserIfNeeded parameter is true, and it prompts the user for permission
  • There is already an active prompt for the specified application

Given that, the following will check if the current application has permission to send Apple events to the application with the given bundle ID, and do so in a non-blocking manner, prompting the user as necessary:

static _Atomic bool promptingUser = false;

static void promptUserForAppleEventPermissions(NSString *appId)
{
    if (promptingUser) {
        return;
    }
    
    promptingUser = true;
    
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        @autoreleasepool {
            NSAppleEventDescriptor *targetAppEventDescriptor;
            targetAppEventDescriptor = [NSAppleEventDescriptor descriptorWithBundleIdentifier:appId];
            AEDeterminePermissionToAutomateTarget(targetAppEventDescriptor.aeDesc, typeWildCard, typeWildCard, true);    
            promptingUser = false;
        }
    });
}

bool checkAppleEventPermissionsForApplicationId(NSString *appId)
{
    if (promptingUser) {
        NSLog(@"Still waiting for user prompt");
        return false;
    }
    
    OSStatus status;
    NSAppleEventDescriptor *targetAppEventDescriptor;
    targetAppEventDescriptor = [NSAppleEventDescriptor descriptorWithBundleIdentifier:appId];

    status = AEDeterminePermissionToAutomateTarget(targetAppEventDescriptor.aeDesc, typeWildCard, typeWildCard, false);
    
    switch (status) {
        case 0: // noErr
            return true;
            
        case -600: //procNotFound
            NSLog(@"App not running: %@", appId);
            return false;

        case -1744: // errAEEventWouldRequireUserConsent
            NSLog(@"App requires user consent: %@", appId);
            promptUserForAppleEventPermissions(appId);
            return false;

        case -1743: //errAEEventNotPermitted
            NSLog(@"User denied permission to control app: %@", appId);
            // Prompt user to manually grant permission in System Settings here
            return false;

        default:
            NSLog(@"Received unexpected error code %d:", status, appId);
            return false;
    }
}

Note that checkAppleEventPermissionsForApplicationId is not thread-safe, since I don't need a thread-safe version for my purposes.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1742389906a4434804.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信