web-dev-qa-db-fra.com

Activer l'accès par programmation pour les appareils d'assistance sur 10.9

Je souhaite activer l'accès par programmation aux dispositifs d'assistance sur 10.9. À partir de 10.8, j’utilisais Applescript pour permettre l’accès des appareils fonctionnels:

tell application "System Events"
if UI elements enabled is false then
    set UI elements enabled to true
end if
end tell

Avec la version 10.9, Apple a déplacé les options d'accessibilité dans les préférences système ➞ Sécurité et confidentialité ➞ Confidentialité ➞ Accessibilité. Contrairement aux versions précédentes d'OS X, qui utilisaient une case à cocher universelle pour toutes les applications, la nouvelle fonctionnalité de 10.9 permet aux utilisateurs de choisir individuellement les applications pouvant prendre le contrôle du système pour exécuter leurs différentes fonctions de script.

The new system preferences regarding accessibility

Apple n'a fourni aucune API aux développeurs pour activer par programmation l'accès à une application. Donc, Mac OS 10.9 invitera une boîte de dialogue à demander à l'utilisateur final l'autorisation d'activer l'accessibilité lorsque l'application utilise des API d'accessibilité. De plus, l'utilisateur doit relancer l'application après avoir activé l'accessibilité.

Default Prompt dialog put up by 10.9 OS for Xcode

Pouvons-nous autoriser l'accès par programmation aux dispositifs d'assistance sur 10.9 à l'aide d'Applescript ou de tout autre API? Toute aide pour résoudre ce problème serait grandement appréciée.

35
Vinpai

Cela ne répond pas à votre question, mais il est bon de connaître un nouvel appel d'API apparu dans 10.9 qui vous permet d'afficher l'écran d'autorisation ou de le contourner:

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

Si vous passez YES, l'écran d'autorisation sera forcé à apparaître. Si vous passez NO, il l'ignorera silencieusement. La valeur de retour est identique à celle renvoyée par AXAPIEnabled(), qui devient obsolète dans 10.9. Pour vous assurer que la fonction est disponible sur votre système, comparez-la simplement à NULL:

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

Vous devrez ajouter ApplicationServices.framework à votre projet et importer dans votre fichier .m ou .h:

#import <ApplicationServices/ApplicationServices.h>

C’est dommage que l’écran d’autorisation ne permette pas à l’utilisateur d’autoriser directement l’application, il ouvre simplement la partie droite des Préférences Système. Ce que vous pouvez faire directement, en passant, sans passer par le dialogue système inutile:

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

ou en utilisant Objective C:

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

Cela peut être associé au premier extrait de code pour vérifier si accessibilityEnabled en passant de @NO à kAXTrustedCheckOptionPrompt tout en empêchant la fenêtre contextuelle du système d'apparaître et en ouvrant directement le volet des préférences d'accessibilité:

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

Bien que la réponse de @ user2865860 fonctionne bien, je pensais que je posterais l'intégralité de l'exemple de code qui fonctionne parfaitement sous 10.9 pour gagner du temps. Vous devez obtenir les privilèges root pour pouvoir inviter un utilisateur à entrer le mot de passe.

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...
    }
}
9
Max Al Farakh

Vous pouvez modifier le fichier TCC.db directement. Je devais le faire afin de faire installer Divvy sans interaction de l'utilisateur. Il suffit de remplacer com.mizage.divvy par votre programme.

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

Pour supprimer l'entrée:

Sudo sqlite3 /Library/Application\ Support/com.Apple.TCC/TCC.db "delete from access where client='com.mizage.divvy';"
8
user2865860

J'ai trouvé l'extrait de code suivant qui demande correctement les autorisations d'accessibilité sous 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
7
Sergey L.

J'étais moi-même aux prises avec ce problème et, après quelques recherches, j'ai trouvé ce qui suit:

  1. Le piratage de la base de données sqlite présente l'inconvénient majeur d'utiliser des services d'autorisation. Tout d'abord, une boîte de dialogue apparaît pour indiquer à l'utilisateur qu'une application souhaite installer un utilitaire utilitaire (même s'il ne s'agit que d'une soumission de lancement utilisant SMJobSubmit). Deuxièmement, cela ne fonctionne pas pour les applications en bac à sable et donc pas de magasin d'applications.

  2. @ Max Al Faeakh utilise AuthorizationExecuteWithPrivileges qui est obsolète. Vous devez utiliser launchd avec la variable SMJobSubmit ci-dessus. Quoi qu'il en soit, cela nécessite toujours une autorisation. Cela nécessite également une application auxiliaire comme celle-ci one .

Je suppose que le mieux est d’utiliser soit:

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

ou

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

et ouvrez le volet de préférences manuellement à l'aide, par exemple, d'une structure de pont de script:

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

La classe SBSystemPreferencesPane vient sous la forme d'un fichier SBSystemPreferences.h qui peut être généré: 

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

Merci pour ces exemples de script Shell de @NightFlight, qui sont vraiment utiles. J'ai utilisé cela avec AppleScript dans une application Python, comme suit:

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

Cela a bien fonctionné pour moi en code Python en tant que chaîne.

Edit (7 novembre 2014):

Si vous voulez essayer cela dans l'éditeur AppleScript, utilisez un échappement de caractère légèrement différent, comme ci-dessous:

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

Pour Mac OS X avant 10.9, c'est encore plus simple:

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

Juste besoin de toucher un fichier. Le code AppleScript mentionné dans le code Python ci-dessus peut également être utilisé dans d'autres langages.

1
Jake W

Le sqlite3 "bidouille" est génial. 

J'ai dû utiliser les autorisations "1,1,1" (peu importe ce que cela signifie) pour que cela fonctionne. 

Notez que la combinaison d'autorisations, et non le client (nom du programme), est la clé unique de la base de données. 

0
a.out

Merci tout le monde.

J'émets les éléments suivants déclenchés à partir de la fenêtre de connexion pour m'assurer que seuls les éléments souhaités sont contrôlés à chaque session:

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