苹果仍然需要在这方面努力,它并不完美,对用户不友好,也没有很好的文档记录。但这是一个可行的解决方案。
从 OSX 10.14 (Mojave) 开始,如果用户允许您的应用程序与其他应用程序通信,您必须询问 OSX 的系统完整性保护 (SIP)。
为了使其正常工作,您需要向应用程序的 .plist 文件添加一个条目:
key: NSAppleEventsUsageDescription
value: [Some description why you need to use AppleEvents]
Note:您不能为更多应用程序使用更多条目。它的一个条目。因此,请明智地选择您的描述。此描述将显示在 Apple 的对话框中,要求用户接受。
如果您像我一样有 XPC 服务,请将其放在您的主应用程序中,而不是服务中。
现在在您的应用程序中 - 在使用 Apple 事件之前 - 检查当前状态(如果 AppleEvents 允许或不允许)。我写了这个方法:
- (BOOL)checkSIPforAppIdentifier:(NSString*)identifier {
// First available from 10.14 Mojave
if (@available(macOS 10.14, *)) {
OSStatus status;
NSAppleEventDescriptor *targetAppEventDescriptor;
targetAppEventDescriptor = [NSAppleEventDescriptor descriptorWithBundleIdentifier:identifier];
status = AEDeterminePermissionToAutomateTarget(targetAppEventDescriptor.aeDesc, typeWildCard, typeWildCard, true);
switch (status) {
case -600: //procNotFound
NSLog(@"Not running app with id '%@'",identifier);
break;
case 0: // noErr
NSLog(@"SIP check successfull for app with id '%@'",identifier);
break;
case -1744: // errAEEventWouldRequireUserConsent
// This only appears if you send false for askUserIfNeeded
NSLog(@"User consent required for app with id '%@'",identifier);
break;
case -1743: //errAEEventNotPermitted
NSLog(@"User didn't allow usage for app with id '%@'",identifier);
// Here you should present a dialog with a tutorial on how to activate it manually
// This can be something like
// Go to system preferences > security > privacy
// Choose automation and active [APPNAME] for [APPNAME]
return NO;
default:
break;
}
}
return YES;
}
像这样称呼它:
[self checkSIPforAppIdentifier:@"com.apple.mail"];
您可以在 AppleEvents.h 中找到详细信息 - 这是所使用方法的副本:
AEDeterminePermissionToAutomateTarget()
讨论:确定当前应用程序是否能够发送
具有给应用程序的给定 eventClass 和 eventID 的 AppleEvent
描述为目标地址描述。
Mac OS 10.14 及更高版本对应用程序提出了额外要求
当他们将 AppleEvents 发送到其他应用程序以确保
用户知道并同意允许此类控制或
信息交换。通常这涉及提示用户
应用程序第一次尝试以安全的方式发送
AppleEvent 到另一个应用程序。
如果用户同意,那么该应用程序可以将事件发送到
目标。如果用户不同意,则任何未来的发送尝试
AppleEvents 将导致失败,并出现 errAEEventNotPermissioned
回。允许在没有提示的情况下发送某些 AppleEvents
用户。将 eventClass 和 eventID 的 typeWildCard 传递给
确定是否允许从此应用程序发送每个事件
到目标。
应用程序无需向目标发送 AppleEvent 即可确定
应用程序,是否允许将 AppleEvents 发送到
具有此功能的目标。如果askUserIfNeeded为真,并且这
应用程序还没有权限将 AppleEvents 发送到
target,然后会询问用户是否可以授予权限;如果
AskUserIfNeeded 为 false 并且未授予权限,则
将返回 errAEEventWouldRequireUserConsent。
目标 AEAddressDesc 必须引用已在运行的应用程序。
Results
如果当前应用程序被允许发送给定的 AppleEvent
到目标,则将返回 noErr。如果当前
不允许应用程序发送事件,errAEEventNotPermission
将被退回。如果目标应用程序没有运行,那么
将返回 procNotFound。如果askUserIfNeeded为假,并且这
尚不允许应用程序向目标发送 AppleEvents,
然后将返回 errAEEventWouldRequireUserConsent。
Mac OS X 线程:
从 10.14 版本开始线程安全。不要在您的设备上调用此函数
主线程,因为如果用户
需要提示同意。
参数:
target:
指向地址描述符的指针。致电之前
AEDeterminePermissionToAutomateTarget,您将描述符设置为
确定 Apple 事件的目标应用程序。目标
地址描述符必须引用正在运行的应用程序。如果目标
应用程序位于另一台计算机上,则远程 AppleEvents 必须是
在该计算机上为用户启用。
theAEEventClass:要确定的Apple事件的事件类
的许可。
theAEEventID:苹果事件的事件ID,判断权限
为了。
AskUserIfNeeded:布尔值;如果为真,并且该应用程序不
但有权将事件发送到目标应用程序,然后
提示用户获取权限。如果为 false,则不提示
用户。
结论:
正如前面提到的,它并不完美。
- 目标应用程序必须运行 - 否则它将返回 -600
- 一旦被拒绝,用户只能手动激活它——这感觉不太好和流畅。
- 它是线程安全的,所以你不应该在主线程中调用它(手动激活的对话框除外)