31 votes

Permissions personnalisées Android - Marshmallow

Contexte

Historiquement, les autorisations personnalisées d'Android ont été un désordre y dépendent de l'ordre d'installation qui était connu pour exposer les vulnérabilités .

Avant l'API 21, il existait une solution de contournement troublante selon laquelle le fait de déclarer la permission personnalisée d'une autre application dans votre manifeste permettait d'obtenir cette permission... Cependant, depuis l'API 21, une seule application peut déclarer une permission personnalisée et l'installation d'une autre application déclarant cette même permission sera empêchée.

Les alternatives sont de réinstaller l'application nécessitant la permission, afin qu'elles soient détectées par le système, mais cela n'est pas une bonne expérience pour l'utilisateur . Ou vérifier au moment de l'exécution les autorisations de l'application appelante, mais qui n'est pas sans présenter des défauts théoriques .

Problème

Depuis Android Marshmallow (6.0 - API 23), une application doit demander la permission à l'utilisateur, d'utiliser sa propre permission personnalisée . Une autorisation personnalisée déclarée n'est pas automatiquement accordée.

Cela semble curieux, étant donné qu'une seule application peut désormais le déclarer.

Pour répliquer

Déclarez la permission personnalisée et un BroadcastReceiver dans le manifeste.

<permission
    android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
    android:description="@string/control_description"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/control_label"
    android:protectionLevel="normal or dangerous"/>

<uses-permission
    android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>

// etc

<receiver
    android:name="com.example.app.MyBroadcastReceiver"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
    <intent-filter android:priority="999">
        <action android:name="com.example.app.REQUEST_RECEIVER"/>
    </intent-filter>
</receiver>

Depuis une application tierce, déclarez qu'elle utilise la permission personnalisée dans le manifeste (et acceptez-la via une boîte de dialogue ou les paramètres) et appelez :

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");

    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {

        // getResultCode();

        }
    }, null, Activity.RESULT_CANCELED, null, null);

Le résultat sera CANCELED et le journal indiquera :

system_process W/BroadcastQueue : Déni de permission : réception de l'intention { act=com.example.app.REQUEST_RECEIVER flg=0x10 (has extras) } to com.example.app/.MyBroadcastReceiver nécessite com.example.app.permission.CONTROL_EXAMPLE_APP en raison de l'expéditeur com.example.thirdparty

Si j'utilise la norme ActivityCompat.requestPermissions() pour permettre à l'utilisateur d'accepter la permission, le récepteur, comme on peut s'y attendre, fonctionne correctement.

Pregunta

Est-ce un comportement attendu ? Ou ai-je négligé quelque chose ?

Il semblerait ridicule d'élever un dialogue disant

L'application Example App veut la permission d'utiliser Example App

Et cela peut effectivement concerner l'utilisateur, en lui fournissant une demande aussi absurde.

Je peux bien sûr changer la description et le nom de l'autorisation en quelque chose qu'ils accepteraient, par exemple communiquer avec d'autres applications installées Mais avant de soupirer et d'adopter cette approche, j'ai pensé que je devais poser cette question.

Nota

L'exemple de la diffusion ordonnée consiste à reproduire le problème. Mon application utilise d'autres implémentations de fournisseurs de contenu et un service lié. Ce n'est pas une implémentation alternative que j'exige, c'est une confirmation du problème.

Merci d'avoir lu jusqu'ici.

Edit : Pour clarifier, pour d'autres implémentations, comme la déclaration d'une permission sur un service (ce qui serait très simple à reproduire), la permission personnalisée déclarée est automatiquement accordée.

3voto

Igor Tyulkanov Points 1781

Si j'ai bien compris, vous avez essayé de faire la chose suivante (du moins, c'est ainsi que j'ai pu reproduire votre problème) :

  1. Vous déclarez votre nouvelle permission personnalisée dans la première application (appelons-la F).

    <permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"
        android:description="@string/control_description"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/control_label"
        android:protectionLevel="normal or dangerous"/>
  2. Vous définissez que votre application F utilise com.example.app.permission.CONTROL_EXAMPLE_APP permission. C'est ce que dit la directive.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
  3. Vous déclarez votre récepteur de diffusion personnalisé dans votre application F. Pour communiquer avec cette diffusion, votre application (peu importe laquelle, F ou une autre application) doit obtenir votre autorisation personnalisée.

    <receiver
        android:name="com.example.app.MyBroadcastReceiver"
        android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">
        <intent-filter android:priority="999">
            <action android:name="com.example.app.REQUEST_RECEIVER"/>
        </intent-filter>
    </receiver>
  4. Vous définissez que votre deuxième application (appelons-la S) utilise com.example.app.permission.CONTROL_EXAMPLE_APP permission. Parce que vous voulez autoriser l'application S à envoyer des messages de diffusion au récepteur de l'application F.

    <uses-permission
        android:name="com.example.app.permission.CONTROL_EXAMPLE_APP"/>
  5. Enfin, vous essayez d'envoyer un message de diffusion depuis votre application S en utilisant ce code.

    final Intent intent = new Intent("com.example.app.REQUEST_RECEIVER");
    context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", new BroadcastReceiver() {
            @Override
            public void onReceive(final Context context, final Intent intent) {
                // getResultCode();
            }
        }, null, Activity.RESULT_CANCELED, null, null);

    Et, c'est important vous avez accordé la permission à votre application S, mais pas à votre application F.

    En conséquence, votre récepteur de diffusion déclaré dans l'application F n'a rien reçu.

  6. Après avoir accordé la permission à votre application F (Notez que maintenant S et F ont accordé votre permission personnalisée) tout fonctionne bien. Le récepteur de diffusion déclaré dans l'application F a reçu un message de l'application S.

Je suppose que c'est un comportement correct, car cette doc nous dit :

Notez que, dans cet exemple, la permission DEBIT_ACCT n'est pas seulement déclarée avec l'élément, son utilisation est également demandée avec l'élément. Vous devez demander son utilisation pour que d'autres composants de l'application puissent lancer l'activité protégée, même si la protection est imposée par l'application elle-même.

Et l'application qui déclare une permission doit également demander la même permission pour communiquer avec elle-même.

Par conséquent, l'API Android 23 doit obtenir l'accès à l'utilisation de votre formulaire d'autorisation de l'utilisateur en premier. Et nous devons obtenir 2 permissions accordées, d'abord de l'application F (parce que la ligne directrice le dit) et ensuite de l'application S (parce que nous avons juste besoin d'obtenir l'accès).

Mais je n'ai pas compris votre prochain point :

Il semblerait ridicule d'élever un dialogue en disant

L'application Example App veut la permission d'utiliser Example App

Mon API native Android 23 m'affiche quelque chose comme ça :

L'application Exemple App veut

0voto

Michal Dvorak Points 46

Je pense que le problème dans votre exemple est que vous exigez explicitement que les deux vos applications bénéficient de l'autorisation personnalisée.

Cette partie exige, que le com.example.thirdparty L'application a la permission :

<receiver
    android:name="com.example.app.MyBroadcastReceiver"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">

Et cette partie exige, que le com.example.app L'application a également l'autorisation :

context.sendOrderedBroadcast(intent, "com.example.app.permission.CONTROL_EXAMPLE_APP", ...

Vous mentionnez que vous n'avez pas ce problème lorsque vous utilisez un service. Je ne sais pas comment vous utilisez exactement le service, mais si vous le déclarez simplement comme ceci :

<service
    android:name="com.example.app.MyService"
    android:permission="com.example.app.permission.CONTROL_EXAMPLE_APP">

et ensuite le lier comme ceci :

context.bindService(serviceIntent, mServiceConnection, ...

alors il suffit que com.example.thirdparty a l'autorisation accordée, tandis que com.example.app n'a pas besoin de l'avoir.

En d'autres termes, je pense que ce comportement a été conçu à dessein, et la différence que vous voyez entre le comportement de diffusion et de service est que, dans le cas de la diffusion, vous demandez spécifiquement que l'élément com.example.app a l'autorisation personnalisée, alors que dans le cas du service, vous ne l'avez pas.

J'espère que je n'ai pas mal compris votre problème. Si c'est le cas, faites-le moi savoir et je supprimerai cette réponse.

0voto

Je ne pense pas qu'il soit complètement vrai qu'une permission personnalisée déclarée ne sera pas automatiquement accordée à l'application. Si la permission personnalisée a le niveau de protection "normal" ou "signature", alors la permission est accordée au moment de l'installation. Dans le cas contraire, si le niveau de protection est "dangereux", il s'agit d'une permission d'exécution et elle fonctionne comme les autres permissions dangereuses : vous devrez demander à l'utilisateur d'accorder la permission à l'application.

-1voto

Vijai Points 484

Bien que cela puisse être ambigu pour l'utilisateur de voir une demande de permission pour l'application qui est déclarée dans la même application, c'est ainsi qu'Android est conçu pour fonctionner depuis marshmallow. Je pense que, du point de vue d'Android, le comportement est comme prévu et correct.

-2voto

Venkatesh Points 704

Ajoutez d'abord les permissions dans le fichier manifeste après

 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X