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

我想在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 

随着10.9,苹果已将可访问性选项移到系统偏好设置➞安全和隐私➞隐私➞可访问性。 与以前版本的OS X(对所有应用程序使用通用checkbox)不同,10.9中的新function允许用户单独select哪些应用程序可以控制系统执行各种脚本function。

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

苹果没有提供任何API给开发人员以编程方式启用应用程序的可访问性。 因此,当应用程序使用可访问性API时,Mac OS 10.9将提示最终用户权限对话框以启用辅助function。 此外,用户必须在启用辅助function后重新启动应用程序。

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

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

这并不能回答你的问题,但是知道10.9中出现的一个新的API调用是很好的,可以让你显示授权屏幕或绕过它:

 NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES}; BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options); 

通过YES将强制授权屏幕出现,通过NO将默默地跳过它。 返回值与AXAPIEnabled()返回的值相同,在10.9中不再使用。 要确保该函数在系统上可用,只需将它与NULL进行比较:

 if (AXIsProcessTrustedWithOptions != NULL) { // 10.9 and later } else { // 10.8 and older } 

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

 #import <ApplicationServices/ApplicationServices.h> 

很遗憾,授权屏幕不允许用户直接授权应用程序,只是打开系统偏好设置的正确部分。 顺便说一句,你可以直接做,而不需要经过无用的系统对话:

 tell application "System Preferences" set securityPane to pane id "com.apple.preference.security" tell securityPane to reveal anchor "Privacy_Accessibility" activate end tell 

或者使用Objective C:

 NSString *urlString = @"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"; [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:urlString]]; 

这可以与第一个代码片段配对,以通过将@NO传递给kAXTrustedCheckOptionPrompt同时防止出现系统popup窗口,直接打开辅助function选项面板来testingaccessibilityEnabled

 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]]; } 

虽然@ user2865860的答案效果很好,但是我会发布完整的代码示例,在10.9上完美工作以节省一些时间。 您需要获得root权限,因此会提示用户input密码。

 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... } } 

您可以直接编辑TCC.db文件。 我必须这样做才能使Divvy无需用户交互安装。 只需将com.mizage.divvyreplace为您的程序。

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

要删除条目:

 sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "delete from access where client='com.mizage.divvy';" 

我发现下面的代码片断正确地请求OS X 10.9中的辅助function权限:

 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 

我自己正在努力,经过一些研究,我发现了以下几点:

  1. 黑客的SQLite数据库有使用授权服务的主要缺点。 首先,这将popup一个对话框,告诉用户应用程序想要安装一个实用程序帮助程序(即使它只是一个使用SMJobSubmit启动提交)。 其次,它不适用于沙盒应用程序,因此没有应用程序商店。

  2. @Max Al Faeakh使用已弃用的AuthorizationExecuteWithPrivileges 。 您需要使用上面的SMJobSubmit launchd。 无论如何,这仍然需要授权。 它也需要像这样的辅助应用程序。

我想最好的是使用:

 NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @YES}; BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options); 

要么

 NSDictionary *options = @{(id)kAXTrustedCheckOptionPrompt: @NO}; BOOL accessibilityEnabled = AXIsProcessTrustedWithOptions((CFDictionaryRef)options); 

并使用脚本桥架构手动打开首选项窗格:

 SBSystemPreferencesApplication *prefs = [SBApplication applicationWithBundleIdentifier:@"com.apple.systempreferences"]; [prefs activate]; SBSystemPreferencesPane *pane = [[prefs panes] find:^BOOL(SBSystemPreferencesPane *elem) { return [[elem id] isEqualToString:@"com.apple.preference.security"]; }]; SBSystemPreferencesAnchor *anchor = [[pane anchors] find:^BOOL(SBSystemPreferencesAnchor *elem) { return [[elem name] isEqualToString:@"Privacy_Accessibility"]; }]; [anchor reveal]; 

SBSystemPreferencesPane类形成一个SBSystemPreferences.h文件,可以生成:

 sdef "/Applications/System Preferences.app" | sdp -fh --basename SBSystemPreferences -o SBSystemPreferences.h 

感谢@NightFlight这个shell脚本样例,这真的很有帮助。 我在Python应用程序中使用了AppleScript,如下所示:

 set sh to "touch /private/var/db/.AccessibilityAPIEnabled && sqlite3 \\"/Library/Application Support/com.apple.TCC/TCC.db\\" \\"INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.godevnode',0,1,0,NULL);\\"" do shell script sh with administrator privileges 

它在Python代码中作为一个string很好。

编辑(2014年11月7日):

如果你想在AppleScript Editor中尝试这个,请使用稍微不同的字符转义符,如下所示:

 set sh to "touch /private/var/db/.AccessibilityAPIEnabled && sqlite3 \"/Library/Application Support/com.apple.TCC/TCC.db\" \"INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.godevnode',0,1,0,NULL);\"" do shell script sh with administrator privileges 

对于10.9之前的Mac OS X,更简单:

 accessibility_api_file = "/private/var/db/.AccessibilityAPIEnabled" def __enable_accessibility_api(): try: script = 'do shell script "touch %s" with administrator ' \ 'privileges' % accessibility_api_file result = applescript.AppleScript(script).run() log.debug("Tried to enable accessibility api, result=" + result) return True except applescript.ScriptError as err: log.error(str(err)) return False 

只需要触摸一个文件。 上面Python代码中提到的AppleScript也可以用在其他语言中。

感谢大家。

我从login窗口触发以下内容,以确保只对每个会话所需的项目进行控制:

 # Enable Service Accessibility for Textpander and others # Clear the acess table. sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "DELETE FROM access" # Enter the access we wish to have. sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT INTO access VALUES ('kTCCServiceAccessibility','com.apple.systempreferences',0,1,1,NULL)" sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT INTO access VALUES ('kTCCServiceAccessibility','de.petermaurer.textpanderdaemon',0,1,1,NULL)" 

sqlite3“黑客”是伟大的。

我必须使用权限“1,1,1”(无论这意味着什么)来完成这项工作。

请注意,权限组合,而不是客户端(即程序名称)是唯一的数据库密钥。