在10.9上以编程方式启用辅助设备的访问

Vin*_*pai 38 macos cocoa accessibility objective-c accessibility-api

我想在10.9上以编程方式启用对辅助设备的访问.在10.8及更低版本中,我使用以下Applescript来启用辅助设备的访问:

tell application "System Events"
if UI elements enabled is false then
    set UI elements enabled to true
end if
end tell
Run Code Online (Sandbox Code Playgroud)

凭借10.9,Apple已将可访问性选项移至系统偏好设置➞安全和隐私➞隐私➞辅助功能.与以前版本的OS X(对所有应用程序使用通用复选框)不同,10.9中的新功能允许用户单独选择哪些应用程序可以控制系统以执行其各种脚本功能.

关于可访问性的新系统首选项

Apple尚未向开发人员提供任何API,以便以编程方式为应用程序启用辅助功能.因此,当应用程序使用辅助功能API时,Mac OS 10.9将提示最终用户权限的对话框以启用辅助功能.此外,用户必须在启用辅助功能后重新启动应用程序.

Xcode为10.9 OS提供的默认提示对话框

我们可以使用Applescript或任何其他API以编程方式在10.9上启用对辅助设备的访问吗?任何帮助解决这个问题将不胜感激.

zou*_*oul 42

这不能解答您的问题,但了解10.9中出现的新API调用并让您显示授权屏幕或绕过它是很好的:

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
Run Code Online (Sandbox Code Playgroud)

传递YES将强制显示授权屏幕,传递NO将默默跳过它.返回值与返回的值相同AXAPIEnabled(),在10.9中已弃用.要确保该功能在您的系统上可用,只需将其与NULL以下内容进行比较:

if (AXIsProcessTrustedWithOptions != NULL) {
    // 10.9 and later
} else {
    // 10.8 and older
}
Run Code Online (Sandbox Code Playgroud)

您需要添加ApplicationServices.framework到项目中,然后导入.m或.h文件:

#import <ApplicationServices/ApplicationServices.h>
Run Code Online (Sandbox Code Playgroud)

很遗憾,授权屏幕不允许用户直接授权应用程序,它只是打开系统偏好设置的右侧部分.顺便说一下,你可以直接做,而无需通过无用的系统对话:

tell application "System Preferences"
    set securityPane to pane id "com.apple.preference.security"
    tell securityPane to reveal anchor "Privacy_Accessibility"
    activate
end tell
Run Code Online (Sandbox Code Playgroud)

或使用目标C:

NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];
Run Code Online (Sandbox Code Playgroud)

这可以与第一个代码段配对,以测试是否accessibilityEnabled通过传递@NOkAXTrustedCheckOptionPrompt阻止系统弹出窗口出现,而是直接打开"辅助功能"首选项窗格:

NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @NO};
BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options);
if (!accessibilityEnabled) {
    NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]];
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*iVR 11

我建议不要使用所有的 sqlite3 和 AppleScript hack,因为它们将来可能会停止工作,而且还有一个合适的 api。

除此之外,您实际上可以监控用户是否点击了您的应用程序的辅助功能设置,以便在用户授予权限时您可以执行一些操作。

(Swift 5,在 Mojave、Catalina、Big Sur 上测试)

阅读特权

private func readPrivileges(prompt: Bool) -> Bool {
    let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: prompt]
    let status = AXIsProcessTrustedWithOptions(options)
    return status
}
Run Code Online (Sandbox Code Playgroud)

监控可访问性的变化

DistributedNotificationCenter.default().addObserver(forName: NSNotification.Name("com.apple.accessibility.api"), object: nil, queue: nil) { _ in
  DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    self.updatePrivileges()
  }
}
Run Code Online (Sandbox Code Playgroud)

最好在收到通知后再次阅读权限,因为根据我的经验,通知本身并没有真正起作用。因此,在updatePrivileges(), 运行readPrivileges()以获取新状态。

您需要延迟,因为更改需要一些时间才能反映。

在监控时您需要记住的另一件事是,对于获得不同权限的任何应用程序都会触发通知,因此如果用户授予或撤销不同的应用程序,您仍然会收到通知。

另外,当您不再需要观察者时,不要忘记移除观察者。

编辑:

资料来源:Piddlesoft 的可访问性测试平台


Max*_*akh 10

虽然@ user2865860的答案效果很好,但我发布的整个代码示例在10.9上完美地运行以节省其他时间.您需要获得root权限,因此它会提示用户输入密码.

char *command= "/usr/bin/sqlite3";
char *args[] = {"/Library/Application Support/com.apple.TCC/TCC.db", "INSERT or REPLACE INTO access  VALUES('kTCCServiceAccessibility','com.yourapp',0,1,0,NULL);", nil};
AuthorizationRef authRef;
OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authRef);
if (status == errAuthorizationSuccess) {
    status = AuthorizationExecuteWithPrivileges(authRef, command, kAuthorizationFlagDefaults, args, NULL);
    AuthorizationFree(authRef, kAuthorizationFlagDestroyRights);
    if(status != 0){
        //handle errors...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 从Sierra开始,这已不再适用.现在,即使是root用户,数据库文件也是只读的.您可以关闭操作系统的"系统完整性保护"(https://support.apple.com/en-us/HT204899),然后您可以再次使该文件可写,但这不是完全建议的,并且永远不会如果您试图让用户在Mac App中执行此操作,它会通过App Review. (4认同)
  • 为了帮助澄清一些,_CREATE TABLE访问(服务TEXT NOT NULL,客户端TEXT NOT NULL,client_type INTEGER NOT NULL,允许INTEGER NOT NULL,prompt_count INTEGER NOT NULL,csreq BLOB,CONSTRAINT键PRIMARY KEY(service,client,client_type)) ; _第一个0代表"client_type",如果你引用二进制文件,它似乎是1,如果你引用了软件包名称则为0.启用了下一个,对我们来说应该是1.最后是prompt_count,不知道:) (2认同)

小智 9

您可以直接编辑TCC.db文件.为了在没有用户交互的情况下安装Divvy,我必须这样做.只需将com.mizage.divvy替换为您的程序即可.

sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT INTO access VALUES('kTCCServiceAccessibility','com.mizage.divvy',0,1,1,NULL);" 
Run Code Online (Sandbox Code Playgroud)

要删除条目:

sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "delete from access where client='com.mizage.divvy';"
Run Code Online (Sandbox Code Playgroud)

  • 自从塞拉利昂再也没有可能了 (2认同)

Ser*_* L. 9

我找到了以下代码片段,它在OS X 10.9中正确地请求了辅助功能权限:

if (AXIsProcessTrustedWithOptions != NULL) {
    // 10.9 and later
    const void * keys[] = { kAXTrustedCheckOptionPrompt };
    const void * values[] = { kCFBooleanTrue };

    CFDictionaryRef options = CFDictionaryCreate(
            kCFAllocatorDefault,
            keys,
            values,
            sizeof(keys) / sizeof(*keys),
            &kCFCopyStringDictionaryKeyCallBacks,
            &kCFTypeDictionaryValueCallBacks);

    return AXIsProcessTrustedWithOptions(options);
}

// OS X 10.8 and older
Run Code Online (Sandbox Code Playgroud)