Maintenant que la théorie a été vue, place à la pratique ! Je vous propose de voir, pas à pas, comment, depuis Android 6.0, il convient de demander une permission. Pour nous aider, nous allons nous baser sur un fil rouge : demander l’autorisation de passer un coup de téléphone après appuie sur un bouton.
L’intégralité de ce cours est disponible dans le CourseLab OpenClassrooms !
Plan
- Les permissions sous Android (1/6) : Android et les permissions
- Les permissions sous Android (2/6) : Les différentes permissions
- Les permissions sous Android (3/6) : Demander une permission (½)
- Les permissions sous Android (4/6) : Demander une permission (2/2)
- Les permissions sous Android (5/6) : Demander plusieurs permissions
- Les permissions sous Android (6/6) : Prendre en compte une politique de sécurité particulière
Le fichier build.gradle
Avant d’aller plus loin, il convient de vérifier une toute petite chose au niveau du fichier build.gradle du module qui sera votre application. Pour profiter pleinement de ce tutoriel, il convient que les champs compileSdkVersion
et targetSdkVersion
soient, à minima, à 23
.
Par exemple, voici ce à quoi ressemble le fichier de mon côté :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
Le manifest
La première étape, quand on nécessite une permission au sein d’une application Android, est de la déclarer dans le fichier AndroidManifest.xml.
Lorsque vous créez un nouveau projet Android contenant au moins une activité via Android Studio, votre fichier AndroidManifest.xml doit sensiblement ressembler à ça :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Comme vous pouvez le constater, plusieurs éléments, représentés par des balises XML, composent ce fichier. Revenons rapidement dessus :
- La balise
<manifest />
encapsule tout le contenu du fichier. C’est ce qu’on appelle une balise root en XML. C’est au sein de cette balise qui encapsule tout le contenu du fichier. - La balise
<application />
permet de décrire l’application comme par exemple l’icône de votre application, s’il s’agit d’un jeu ou non, le thème de celle-ci, une classeApplication
spécifique si celle-ci est personnalisée, si l’application supporte le notamment de personnaliser la classeApplication
de votre application si celle-ci supporte le RTL (right-to-left) ou non, etc. C’est au sein de cette balise que l’on va notamment déclarer les activités, les services, les receivers et les providers. - La balise
<activity />
permet de déclarer une activité, c’est-à-dire un écran qui compose l’application.
C’est dans ce fichier que nous allons déclarer les permissions et plus particulièrement entre les balises <manifest />
.
Une permission se déclare à l’aide de la balise <uses-permission />
et de l’attribut android:name
. C’est au niveau de cet attribut que nous allons spécifier le nom de la permission requise par notre application.
Dans le cadre de notre fil rouge, à savoir passer un coup de fil, nous pouvons demander la permission CALL_PHONE
.
Il convient donc d’ajouter la ligne suivante à notre fichier AndroidManifest.xml :
1
|
|
Le fichier complet doit donc maintenant ressembler à ça :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
Il est important de noter qu’il est possible d’avoir une gestion un peu plus fine des permissions à travers l’attribut android:maxSdkVersion
ou encore la balise <uses-permission-sdk-23 />
. Nous n’allons pas les aborder dans ce cours, mais vous pouvez toujours jeter un petit coup d’œil à la documentation ici et ici.
Un peu de Java
Le code de base
Puisque les bonnes pratiques nous recommandent de travailler dans des fragments plutôt que dans des activités, nous allons travailler dans un… fragment ! ;)
Voici le code de base sur lequel nous allons nous appuyer dans le reste de ce tutoriel :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
|
Et le layout associé :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Comme vous pouvez le constater, notre application est extrêmement simple puisqu’elle se compose d’un simple bouton, qui lorsqu’on clique dessus, permet de lancer un appel.
Une fois exécutée, voici ce à quoi ressemble l’application :
Dans les prochaines lignes de code, je vous propose que l’on mette en place le (très) petit morceau de code permettant de lancer un appel au clic sur l’unique bouton composant notre interface graphique, tout en ignorant les contraintes liées à Android 6.0.
Passer un appel est très simple puisqu’il nous faut uniquement :
- une
Intent
avec l’actionACTION_CALL
; - une
Uri
avec le numéro avec le numéro de téléphone.
Puisque le code est relativement simple, je vous propose de vous livrer le contenu de la méthode onClick
sans plus de détails que ça :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
Je vous propose que l’on exécute notre application sur deux terminaux tournant sur deux versions d’Android différentes :
- un LG Nexus 4 sous Android 4.4.1 ;
- un LG Nexus 5 sous Android 6.0.1.
Sur le LG Nexus 4 qui tourne sous Android 4.4.1, il n’y a aucun problème, l’appel se fait bien comme en témoigne la capture d’écran ci-dessous :
Si nous exécutons maintenant la même application sur le LG Nexus 5 sous Android 6.0.1, nous constatons, au moment du clic sur le bouton, un crash. Voici ce que nous dit la stacktrace :
FATAL EXCEPTION: main
Process: com.domain.packagename, PID: 25374
java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.CALL dat=tel:xxxxxxxxxx cmp=com.android.server.telecom/.components.UserCallActivity } from ProcessRecord{bccd16c 25374:com.domain.packagename/u0a27} (pid=25374, uid=10027) with revoked permission android.permission.CALL_PHONE
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2658)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1507)
at android.app.Activity.startActivityForResult(Activity.java:3930)
at android.app.Activity.startActivityForResult(Activity.java:3890)
at android.support.v4.app.FragmentActivity.startActivityFromFragment(FragmentActivity.java:849)
at android.support.v4.app.FragmentActivity$HostCallbacks.onStartActivityFromFragment(FragmentActivity.java:907)
at android.support.v4.app.Fragment.startActivity(Fragment.java:916)
at com.domain.packagename.MainActivityFragment.onClick(MainActivityFragment.java:32)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Ce qu’il faut retenir de cette stacktrace, c’est la première ligne et plus particulièrement les mots clefs suivants :
- SecurityException
- Permission Denial
- revoked permission
- android.permission.CALL_PHONE
Qu’est-ce que ces mots clefs signifient ?
Ce qu’il faut comprendre de ces mots clefs, c’est que du fait que l’on soit sous Android 6.0 et que la permission CALL_PHONE
soit considérée comme une permissions dangereuse, nous devons explicitement demander l’autorisation à l’utilisateur. Cette permission n’est plus automatiquement acceptée à l’installation de l’application.
Nous allons voir comment gérer Android 6.0 dans le chapitre suivant !
En résumé
Demander une permission dans les anciennes versions d’Android se faisait simplement à l’aide de l’ajout d’une ligne dans le fichier AndroidManifest.xml.
La gestion fine des permissions sous Android 6.0 rend les choses un peu plus compliqués.
A lire aussi…