Подтвердить что ты не робот

Включить доступ для вспомогательных устройств программным способом на 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 Apple переместила параметры доступности в Системные настройки ➞ Безопасность и конфиденциальность ➞ Конфиденциальность ➞ Доступность. В отличие от предыдущих версий OS X, которые использовали универсальный флажок для всех приложений, новая функциональность в 10.9 позволяет пользователям индивидуально выбирать, какие приложения могут получить контроль над системой, чтобы выполнять свои различные скриптовые функции.

The new system preferences regarding accessibility

Apple не предоставила разработчикам API для программного обеспечения доступности для приложения. Таким образом, Mac OS 10.9 предложит диалоговое окно для разрешения конечного пользователя для обеспечения доступности, когда приложение использует API-интерфейсы доступности. Кроме того, пользователю необходимо перезапустить приложение после включения доступности.

Default prompt dialog put up by 10.9 OS for Xcode

Можем ли мы разрешить доступ для вспомогательных устройств программным путем на 10.9 с использованием Applescript или любых других API? Любая помощь в решении этой проблемы будет с благодарностью.

4b9b3361

Ответ 1

Это не отвечает на ваш вопрос, но хорошо знать о новом вызове API, который появился в 10.9, и позволяет отображать экран авторизации или обходить его:

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

Это может быть сопряжено с первым фрагментом кода, чтобы проверить, будет ли accessibilityEnabled передаваться @NO в kAXTrustedCheckOptionPrompt, пока не появляется всплывающее окно системы, и вместо этого открывать панель настроек специальных возможностей напрямую:

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

Ответ 2

В то время как ответ @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...
    }
}

Ответ 3

Вы можете напрямую отредактировать файл 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);" 

Чтобы удалить запись:

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

Ответ 4

Я нашел следующий фрагмент кода, который правильно запрашивает разрешения на доступность в 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

Ответ 5

Я боролся с этим сам, и после небольшого исследования я обнаружил следующее:

  • Взлом базы данных sqlite имеет существенный недостаток в использовании служб авторизации. Сначала появится диалоговое окно с сообщением пользователю о том, что приложение хочет установить помощник утилиты (хотя это только один запуск с помощью SMJobSubmit). Во-вторых, он не работает для изолированных приложений и, следовательно, не имеет хранилища приложений.

  • @Max Al Faeakh использует AuthorizationExecuteWithPrivileges, который устарел. Вам нужно использовать launchd с указанным выше SMJobSubmit. Во всяком случае, это все еще требует авторизации. Для этого также требуется дополнительное приложение one.

Я думаю, лучше всего использовать либо:

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

Ответ 6

Спасибо за эту оболочку script образцов от @NightFlight, которые действительно полезны. Я использовал это с AppleScript в приложении Python, например:

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 как строка.

Изменить (7 ноября 2014 года):

Если вы хотите попробовать это в редакторе AppleScript, используйте несколько другой escape-код, как показано ниже:

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

Для Mac OS X до 10.9 это еще проще:

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

Просто нужно коснуться одного файла. AppleScript, упомянутый выше в коде Python, также может использоваться на других языках.

Ответ 7

Чтобы добавить к этому, вы можете фактически отслеживать, нажимает ли пользователь настройку доступности для вашего приложения, чтобы вы могли выполнять некоторые действия, когда пользователь предоставляет разрешение.

(Swift 5, работает на Мохаве)

чтение значений (правильный путь для Мохаве):

private func readPrivileges(prompt: Bool) -> Bool {
    let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as NSString: prompt]
    let status = AXIsProcessTrustedWithOptions(options)
    os_log("Reading Accessibility privileges - Current access status %{public}@", type: .info, String(status))
    return status
}

Мониторинг изменений доступности:

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

Лучше всего прочитать привилегии снова после получения уведомления, так как само уведомление на самом деле не работает в моем опыте. Поэтому внутри updatePrivileges() запустите readPrivileges() чтобы получить новый статус.

Вам нужна задержка, потому что для отражения изменений требуется некоторое время.

Еще одна вещь, которую вы должны иметь в виду при мониторинге, это то, что уведомление будет запущено для любого приложения, которое получает другие разрешения, поэтому, если пользователь предоставит или отменит другое приложение, вы все равно получите уведомление.

Кроме того, не забудьте удалить наблюдателя, когда он вам больше не нужен.

редактировать:

Источник: Accessibility Testbench от Piddlesoft

Ответ 8

sqlite3 "взломать" отлично.

Мне пришлось использовать разрешения "1,1,1" (что бы это ни значило), чтобы сделать эту работу.

Обратите внимание, что комбинация разрешений, а не клиент (то есть имя программы) - это уникальный ключ базы данных.

Ответ 9

Спасибо всем.

Я выхожу из окна входа в систему, чтобы обеспечить контроль только тем элементам, которые мы хотим получить в каждом сеансе:

# 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)"