Retour au blog
    23 août 2026Tutorial

    Accepter les dialogues d'autorisation au démarrage — puis désactiver en cours de test

    Toutes les suites mobiles rencontrent ce problème dès le premier jour. L'application démarre, iOS demande les notifications, puis la localisation, puis le suivi publicitaire, et chaque test qui ne porte pas sur les autorisations meurt sur un dialogue qu'il n'a jamais demandé.

    Vous positionnez donc appium:autoAcceptAlerts et la suite passe au vert.

    Puis quelqu'un écrit le seul test qui porte justement sur les autorisations — celui qui vérifie que la demande de localisation apparaît, appuie sur Refuser et contrôle l'état vide — et découvre que la capacité qui avait sauvé la suite est désormais ce qui le bloque. L'alerte a disparu avant que le test ait pu la voir.

    Voici le tableau exact de ce qui relève de la session, de ce qui se modifie à l'exécution, et de ce qu'il faut employer sur chaque plateforme.

    Niveau 1 : les capacités de session

    Elles se définissent à la création de la session. Ce sont celles vers lesquelles tout le monde se tourne en premier — et, comme le montre la section suivante, ce n'est pas le niveau que vous voulez réellement piloter.

    iOS (XCUITest). appium:autoAcceptAlerts — « Accepter automatiquement toutes les alertes iOS si elles apparaissent. Cela inclut les alertes d'autorisation d'accès à la vie privée (localisation, contacts, photos). false par défaut. » appium:autoDismissAlerts en est l'image inversée. Notez ce que recouvre la formulation : les alertes système, y compris les demandes d'autorisation, et pas seulement les UIAlertController de votre propre application.

    Android (UiAutomator2). Il n'existe pas d'équivalent d'autoAcceptAlerts, parce que les autorisations d'exécution Android ne sont pas vraiment des alertes que l'on accepte — ce sont des droits que l'on peut accorder avant même que le dialogue n'apparaisse. C'est appium:autoGrantPermissions : « Accorder ou non automatiquement toutes les autorisations demandées par l'application au démarrage d'un test. »

    Trois contraintes qui mordent en pratique :

    • Le targetSdkVersion du manifeste doit être ≥ 23 et l'appareil doit être sous Android 6 ou plus.
    • Les applications dont le targetSdkVersion est ≤ 22 « doivent être réinstallées pour que les autorisations soient accordées » — par exemple avec appium:fullReset.
    • Les droits sont accordés au moment de l'installation. Si votre session réutilise une application déjà installée, la capacité n'a rien sur quoi agir. C'est de loin la raison la plus fréquente pour laquelle on rapporte qu'« autoGrantPermissions ne fonctionne pas ».

    Et pour les autorisations spéciales — accès aux notifications, capture audio ou vidéo — le mécanisme d'octroi ordinaire ne suffit pas ; la documentation renvoie vers mobile: changePermissions avec la cible appops. Nous y venons plus bas.

    Une réserve iOS à intégrer une bonne fois : la capacité appium:permissions, celle qui permet de prérégler l'état des autorisations par service, « permet de définir les autorisations pour le bundle applicatif indiqué sur Simulateur uniquement ». Sur un iPhone réel, elle n'est pas disponible. L'état des autorisations sur appareil iOS réel se gère par les dialogues, ou par l'état dans lequel l'appareil a été laissé.

    Les deux réglages qui pilotent réellement le comportement

    Les capacités ne sont pas le mécanisme. Elles sont une commodité qui en initialise un, et le mécanisme sous-jacent est modifiable à l'exécution — ce qui veut dire que la bascule en cours de session que tout le monde croit impossible tient en deux lignes.

    Quand le pilote construit sa session d'automatisation iOS sous-jacente, il fait exactement ceci :

    js
    if (driver.opts.autoAcceptAlerts) {
      wdaCaps.defaultAlertAction = 'accept';
    } else if (driver.opts.autoDismissAlerts) {
      wdaCaps.defaultAlertAction = 'dismiss';
    }

    appium:autoAcceptAlerts est donc une façade pour un réglage nommé defaultAlertAction. Et defaultAlertAction est enregistré dans la table des réglages, ce qui permet de l'écrire à tout moment pendant la session. Le pilote transmet toute clé de réglage qu'il ne traite pas spécialement directement au point d'entrée « settings » de l'agent : un simple appel à setSettings l'atteint donc.

    java
    // Turn auto-accept off, mid-session
    getAppiumDriver().setSettings(ImmutableMap.of("defaultAlertAction", ""));
    
    // ... assert on the dialog, tap what you want ...
    
    // Turn it back on
    getAppiumDriver().setSettings(ImmutableMap.of("defaultAlertAction", "accept"));

    Vous verrez "off" employé comme valeur de désactivation, et cela fonctionne — mais par accident plutôt que par conception. Le traitement est une simple comparaison à accept et dismiss ; toute autre valeur retombe dans une branche qui journalise 'off' default alert action is unsupported et ne fait rien. Le comportement voulu, avec une ligne d'avertissement par alerte. La chaîne vide est la valeur explicitement testée, qui sort immédiatement sans bruit dans les journaux. (null fonctionne aussi, mais ImmutableMap refuse les valeurs nulles, ce qui explique précisément pourquoi "off" est ce vers quoi on se tourne en Java.)

    Cela mérite d'être su justement parce que rien de tout cela ne figure dans la documentation des réglages du pilote : defaultAlertAction n'y est pas listé, et la réponse du forum Appium sur cette question est « retirez autoAccept et gérez tout vous-même ». Cette réponse n'est plus à jour. Le réglage existe, il se relit, et c'est la forme correcte de la chose.

    autoClickAlertSelector, et pourquoi il est consulté en premier

    Le second réglage est autoClickAlertSelector :

    Sélecteur personnalisé pour un bouton d'alerte. Permet de localiser automatiquement un élément dans la hiérarchie d'une alerte et d'appuyer dessus dès qu'une nouvelle alerte est détectée.

    Ce réglage est prioritaire sur les capacités appium:autoAcceptAlerts et appium:autoDismissAlerts.

    « Prioritaire » est à prendre au pied de la lettre : quand une alerte apparaît, le sélecteur est consulté en premier, et s'il est défini le gestionnaire appuie puis sort sans jamais consulter defaultAlertAction — y compris lorsque l'appui échoue. Il est strictement plus expressif que le booléen, puisqu'il désigne quel bouton recevra l'appui, au lieu d'accepter ce que l'OS considère comme le choix par défaut :

    js
    await driver.updateSettings({
      autoClickAlertSelector: "**/XCUIElementTypeButton[`label CONTAINS[c] 'allow'`]",
    });

    Pour le désactiver, affectez-lui une chaîne vide. Ce n'est pas une astuce : une valeur vide fait l'objet d'un traitement particulier en amont de toute analyse, et elle démonte en outre le moniteur d'alertes au lieu de simplement ne rien apparier :

    java
    getAppiumDriver().setSettings(ImmutableMap.of("autoClickAlertSelector", ""));

    Ne le désactivez pas en fournissant un sélecteur valide qui n'apparie rien. Cela laisse le moniteur en fonctionnement et fait payer une requête de chaîne de classes sur chaque alerte, sans bénéfice. Notez aussi que le « une erreur est levée si le sélecteur fourni est invalide » de la documentation ne concerne que les valeurs non vides — l'étape d'analyse n'est jamais atteinte pour une chaîne vide.

    Les deux ensemble

    Parce que le sélecteur court-circuite l'action d'alerte, désactiver complètement le traitement automatique suppose d'effacer les deux, dans cet ordre :

    java
    private void pauseAlertHandling() {
      getAppiumDriver().setSettings(ImmutableMap.of("autoClickAlertSelector", ""));
      getAppiumDriver().setSettings(ImmutableMap.of("defaultAlertAction", ""));
    }
    
    private void resumeAlertHandling() {
      getAppiumDriver().setSettings(ImmutableMap.of("defaultAlertAction", "accept"));
    }

    Effacer uniquement defaultAlertAction alors qu'un sélecteur est encore défini ne change strictement rien, puisque c'est le sélecteur qui traite vos alertes. C'est le mode de défaillance à surveiller si vous avez configuré les deux : la désactivation semble sans effet, et on croit que le réglage a été ignoré.

    Branchez cette paire sur @BeforeEach / @AfterEach et les tests dédiés aux autorisations vivent dans la même session et la même suite que tout le reste, sans second jeu de capacités.

    Vous pouvez aussi démarrer la session avec le réglage plutôt qu'avec la capacité booléenne, grâce au préfixe appium:settings[...] d'Appium :

    json
    {
      "platformName": "iOS",
      "appium:automationName": "XCUITest",
      "appium:settings[autoClickAlertSelector]": "**/XCUIElementTypeButton[`label CONTAINS[c] 'allow'`]"
    }

    Même effet qu'autoAcceptAlerts, mais le comportement réside désormais quelque part que vous pouvez modifier sans démonter la session.

    Niveau 2, Android : révoquer et réaccorder à l'exécution

    Le levier d'exécution d'Android ne concerne pas du tout les alertes — il porte sur l'octroi lui-même. Le mobile: changePermissions du pilote UiAutomator2 « modifie les autorisations d'un paquet à l'exécution » :

    ArgumentValeursRemarques
    permissionsnom d'autorisation, tableau, ou allall ne fonctionne qu'avec target: pm
    appPackagenom de paquetpar défaut, l'application testée
    actiongrant (défaut) / revoke pour pm ; allow / deny / ignore / default pour appops
    targetpm (défaut) ou appopsappops exige l'option de sécurité serveur adb_shell du pilote

    Toute la suite démarre donc avec les autorisations accordées, et le seul test qui a besoin du dialogue commence par les révoquer et laisse l'application demander :

    java
    // Start clean: revoke, so the next launch actually prompts
    driver.executeScript("mobile: changePermissions", Map.of(
        "permissions", "android.permission.ACCESS_FINE_LOCATION",
        "action", "revoke"));
    
    driver.executeScript("mobile: activateApp", Map.of("appId", "com.mycompany.myapp"));
    // ... assert the system dialog, tap Deny, assert your empty state ...
    
    // Hand it back for the rest of the suite
    driver.executeScript("mobile: changePermissions", Map.of(
        "permissions", "all", "action", "grant"));

    Et pour vérifier l'état plutôt que de le supposer, mobile: getPermissions accepte un type valant denied, granted ou requested (la valeur par défaut) et renvoie une liste de noms d'autorisations. « Est-ce que l'octroi a bien été appliqué ? » cesse d'être une séance de débogage pour devenir une assertion.

    Notez le motif « révoquer puis relancer ». Révoquer une autorisation qu'un processus en cours détient déjà n'est pas quelque chose que l'application encaisse élégamment — Android peut tuer le processus. Faites-le avant d'activer l'application, pas au milieu d'un parcours, sauf si tuer l'application est précisément ce que vous testez.

    Niveau 3 : traiter une alerte à la main

    Quand vous devez simplement gérer le dialogue qui est devant vous :

    iOSmobile: alert prend une action valant accept, dismiss ou getButtons, plus un buttonLabel facultatif. getButtons est sous-employé et vraiment pratique : vérifiez le jeu exact de boutons proposé par l'OS avant de vous engager à appuyer sur l'un d'eux, ce qui permet d'attraper les différences de formulation entre versions d'iOS au lieu d'échouer sur un libellé codé en dur.

    js
    const buttons = await driver.execute("mobile: alert", { action: "getButtons" });
    // e.g. ["Don't Allow", "Allow Once", "Allow While Using App"]
    await driver.execute("mobile: alert", { action: "accept", buttonLabel: "Allow Once" });

    Androidmobile: acceptAlert et mobile: dismissAlert, tous deux avec un buttonLabel facultatif. La documentation est d'une honnêteté rafraîchissante sur leur fiabilité : « Cette méthode peut ne pas toujours être fiable, car il n'existe pas de standard unique décrivant à quoi ressemblent les alertes Android dans la représentation d'accessibilité. » Passez un buttonLabel explicite quand vous le connaissez, et préférez changePermissions à l'appui sur un dialogue pour tout ce qui touche aux autorisations.

    Deux autres réglages iOS bons à connaître pendant que vous y êtes :

    • acceptAlertButtonSelector / dismissAlertButtonSelector — des chaînes de classes qui changent le bouton sur lequel appuient les commandes W3C standard Accept Alert / Dismiss Alert. Pour « gérer des boutons d'acceptation au texte arbitraire », c'est-à-dire les dialogues internes à l'application dont les boutons disent J'ai compris et Plus tard.
    • respectSystemAlerts — « Basculer ou non automatiquement l'application active vers le springboard système si un élément d'alerte native est détecté. » false par défaut. Si votre traitement d'alertes fonctionne partout sauf quand une demande système se superpose à votre application, activez-le avant de commencer à soupçonner le pilote.

    Une politique qui tient dans le temps

    SituationÀ employer
    Les demandes d'autorisation sont du bruit dans 95 % des testsiOS : appium:settings[autoClickAlertSelector]. Android : appium:autoGrantPermissions
    Un test doit vérifier la demande elle-mêmeiOS : mettre autoClickAlertSelector et defaultAlertAction à "", puis restaurer. Android : mobile: changePermissionsrevoke, puis relancer
    Autorisations spéciales (notifications, capture)Android : mobile: changePermissions avec target: appops
    La formulation varie selon la version d'OSmobile: alertgetButtons, vérifier, puis agir
    Dialogue interne, boutons non standardacceptAlertButtonSelector / dismissAlertButtonSelector
    Simulateur iOS, état préréglé avant lancementappium:permissions (Simulateur uniquement)

    Le fil conducteur : préférez le réglage à la capacité, même quand les deux conviendraient aujourd'hui. La capacité est une décision que l'on prend une fois par session et avec laquelle on vit ensuite ; le réglage est une décision que l'on peut reprendre test par test. Une suite mobile finit toujours par contenir le test qui a besoin de l'inverse du comportement par défaut, et découvrir cela après avoir construit 400 tests autour d'une capacité est un moment coûteux pour apprendre que la couche en dessous était modifiable depuis le début.

    Ce qui change sur un appareil réel

    Deux choses, et les deux jouent en votre faveur une fois que vous les connaissez.

    Le fait qu'appium:permissions soit réservé au Simulateur signifie que l'état des autorisations sur un iOS réel vient de l'appareil lui-même — de ce que la session précédente y a laissé. Sur un parc partagé, c'est une source d'échecs mystérieux : vous ne savez pas de quel état vous avez hérité. Sur un appareil dédié, cet état est le vôtre et il est stable d'une exécution à l'autre : « accordées au début de la suite » devient donc quelque chose que vous établissez une fois et sur quoi vous pouvez compter, au lieu de le reconstruire à chaque session.

    Le revers, c'est qu'un état stable reste un état. Rendez la condition initiale explicite à la préparation de la suite — en accordant ou en révoquant délibérément — plutôt que de laisser l'exécution N hériter par accident de l'exécution N−1.

    Et quand une demande passe malgré tout entre les mailles en CI, ce qui met fin au débat le plus vite, c'est de la voir : une vidéo de l'exécution et l'arbre des éléments au moment de l'échec vous disent en quelques secondes si le dialogue est apparu sans être traité, ou s'il n'est jamais apparu. Ces deux échecs produisent des traces d'exécution identiques et appellent des correctifs totalement différents.

    Exécutez votre suite Appium sur un appareil réel dédié →

    Prêt à tester sur de vrais appareils ?

    Connectez-vous avec Google ou GitHub et accédez à de vrais appareils iOS et Android depuis votre navigateur — gratuit à l'essai.

    👋 Bonjour! Besoin d'aide? Discutez avec nous!

    Discutez avec nous

    En ligne

    Avant de commencer

    Partagez vos coordonnées pour que nous puissions vous recontacter.