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 Answer
Reset to default 0I 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
true
toaskUserIfNeeded
, 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