Créer une application Android avec Visual studio cours
Créer une application Android avec Visual studio cours PDF
...
1.2 Exemple-01 : importation d'un exemple Android
1.2.1 Création du projet
Créons avec Android Studio un premier projet Android. Tout d'abord créons un dossier [exemples] vide o๠seront placés tous nos projets :
puis créons un projet avec Android Studio. Nous allons tout d'abord importer un des exemples livrés avec l'IDE [1-5] :
L'import du projet peut aboutir à des erreurs dès à l’inadéquation entre l'environnement utilisé lors de la création du projet et celui utilisé ici pour son exécution. C'est une occasion pour voir comment résoudre ce type d'erreurs. Ici, nous avons l'erreur suivante :
Le projet importé est configuré par le fichier [build.gradle] [2] suivant :
1. buildscript {
2. repositories { jcenter()
3. 4. }
5. dependencies {
6. classpath 'com.android.tools.build:gradle:2.1.0'
7. }
8. }
9.
10.
11. apply plugin: 'com.android.application'
12. repositories {
13. jcenter()
14. }
15. 16. dependencies {
17. compile "com.android.support:support-v4:23.3.0"
18. compile "com.android.support:support-v13:23.3.0"
19. compile "com.android.support:cardview-v7:23.3.0"
20. 21. }
22. // The sample build uses multiple directories to
23. // keep boilerplate and common code separate from
24. // the main sample code.
25. List dirs = [
26. 'main', // main sample code; look here for the interesting stuff.
27. 'common', // components that are reused by multiple samples
28. 'template'] // boilerplate code that is generated by the sample template process
29. 30. android { compileSdkVersion 21
31. 32. buildToolsVersion "23.0.3"
33. defaultConfig {
34. minSdkVersion 21
35. targetSdkVersion 21
36. }
37. compileOptions {
38. sourceCompatibility JavaVersion.VERSION_1_7
39. targetCompatibility JavaVersion.VERSION_1_7
40. }
41. sourceSets {
42. main {
43. dirs.each { dir ->
44. java.srcDirs "src/${dir}/java"
45. res.srcDirs "src/${dir}/res"
46. }
47. }
48. androidTest.setRoot('tests')
49. androidTest.java.srcDirs = ['tests/src']
50. }
51. 52. aaptOptions {
53. noCompress "pdf"
54. }
55. }
- l'erreur signalée est dè aux lignes 31, 34-35 : nous n'avons pas de SDK 21. Nous remplaà§ons cette version par la version 23 dont nous disposons.
Dans le fichier [build.gradle], Android Studio fait des suggestions comme ci-dessous :
Pour accepter les suggestions, on fait [alt-entrée] sur la suggestion :
On peut avoir également une erreur sur la version de Gradle :
Cette erreur vient d'une inadéquation entre la version de Gradle demandée par le fichier [build.gradle] du projet (la 2.10 ligne 6 cidessous) :
1. buildscript {
2. repositories {
3. jcenter()
4. }
5. dependencies {
6. classpath 'com.android.tools.build:gradle:2.1.0'
7. }
8. }
et celle inscrite dans le fichier [/gradle/wrapper/gradle-wrapper.properties] :
1. #Wed Apr 10 15:27:10 PDT 2013
2. distributionBase=GRADLE_USER_HOME
3. distributionPath=wrapper/dists
4. zipStoreBase=GRADLE_USER_HOME
5. zipStorePath=wrapper/dists
6. distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
Ligne 6, ci-dessus, il faut remplacer 2.8 par 2.10.
Pour avoir accès au fichier [/gradle/wrapper/gradle-wrapper.properties], il faut utiliser la perspective projet du projet :
Ceci corrigé, on peut alors compiler l'application [1], lancer l'émulateur Genymotion [2] puis exécuter le projet [3] :
Arrêtons l'application :
On peut maintenant fermer le projet. Nous allons en créer un nouveau.
1.2.2 Quelques points sur l'IDE
1.2.2.1 Les perspectives
L'IDE Android Studio (AS) offre différentes perspectives pour travailler avec un projet. Nous en utiliserons principalement deux :
- la perspective [Android] [1] :
- la perspective [Project] [4] ;
La plupart du temps nous travaillerons avec la perspective [Android]. Lorsque nous dupliquerons un projet dans un autre, nous aurons besoin de la perspective [Project]. 1.2.2.2 Gestion de l'exécution
Il y a plusieurs faà§ons d'exécuter / arrêter / réexécuter un projet AS. Il y a tout d'bord les boutons de la barre d'outils :
Le bouton [Rerun] [3], arrête l'exécution du projet [2] puis le relance [1].
1.2.2.3 Gestion du cache
Android Studio entretient un cache des projets qu'il gère dans le but de rendre l'IDE la plus réactive possible. Avec la version Android 2.1 (mai 2016), souvent ce cache ne prenait pas en compte les modifications de code que l'on venait de faire. Dans ce cas, il faut invalider ce cache :
Avec Android 2.1 (mai 2016), l'opération précédente devait être faite de nombreuses fois et parfois cela n'était pas suffisant à résoudre l'anomalie détectée. La solution a été d'inhiber la technologie [Instant Run] :
- en [3-4], tout a été désactivé ;
Dans tout ce qui suit, on a travaillé avec cette configuration du cache et on n'a pas rencontré de problèmes.
1.2.2.4 Gestion des logs
Lors de l'exécution d'un projet, des logs s'affichent dans le moniteur Android :
Dans l'onglet [Android Monitor] [1], les logs s'affichent dans l'onglet [logcat] [2]. Le bouton [3] permet d'effacer les logs. Ce bouton est utile lorsqu'on veut voir les logs d'une action particulière :
- on efface les logs ;
- sur le périphérique Android, on fait l'action dont on veut les logs ;
- les logs qui apparaissent alors sont ceux liés à l'action faite ;
Il existe plusieurs niveux de logs [4]. Par défaut, c'est le mode [Verbose] qui est sélectionné. Il signifie que les logs de tous les niveaux sont affichés. On peut avec [4], sélectionner un niveau particulier.
Les logs sont très utiles pour savoir à quels moments de l'exécution d'un projet certaines méthodes sont affichées. Nous y aurons souvent recours. Prenons le code de la classe [MainActivity] du projet [Exemple-01] :
1. package com.example.android.pdfrendererbasic;
2. 3. import android.app.Activity;
4. import android.app.AlertDialog;
5. import android.os.Bundle;
6. import android.view.Menu;
7. import android.view.MenuItem;
8. 9. public class MainActivity extends Activity {
10. 11. public static final String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic";
12. 13. @Override
14. protected void onCreate(Bundle savedInstanceState) {
15. super.onCreate(savedInstanceState);
16. setContentView(R.layout.activity_main_real);
17. if (savedInstanceState == null) {
18. getFragmentManager().beginTransaction()
19. .add(R.id.container, new PdfRendererBasicFragment(),
20. FRAGMENT_PDF_RENDERER_BASIC)
21. .commit();
22. }
23. }
24. 25. @Override
26. public boolean onCreateOptionsMenu(Menu menu) {
27. getMenuInflater().inflate(R.menu.main, menu);
28. return true;
29. }
30. 31. @Override
32. public boolean onOptionsItemSelected(MenuItem item) {
33. switch (item.getItemId()) {
34. case R.id.action_info:
35. new AlertDialog.Builder(this)
36. .setMessage(R.string.intro_message)
37. .setPositiveButton(android.R.string.ok, null)
38. .show();
39. return true;
40. }
41. return super.onOptionsItemSelected(item);
42. }
43. }
Ci-dessus, les méthodes [onCreate, ligne 14], [onCreateOptionsMenu, ligne 26] sont des méthodes de la classe parent [Activity] (ligne 9). Elles sont appelées à différents moments du cycle de vie de l'application. Parfois elles sont exécutées plusieurs fois. Même lorsqu'on lit les docs, il est parfois difficile de dire si une telle méthode du cycle de vie va s'exécuter avant ou après une méthode qu'on aurait écrite nous-mêmes. Or cette information est souvent importante à connaître. On peut alors mettre des logs comme ci-dessous :
1. public class MainActivity extends Activity { 2.
3. public static final String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic"; 4.
5. @Override
6. protected void onCreate(Bundle savedInstanceState) {
7. Log.d("MainActivity","onCreate");
8. super.onCreate(savedInstanceState);
9. ...
10. }
11.
12. @Override
13. public boolean onCreateOptionsMenu(Menu menu) {
14. Log.d("MainActivity","onCreateOptionsMenu");
15. getMenuInflater().inflate(R.menu.main, menu); 16. ...
17. }
18.
19. @Override
20. public boolean onOptionsItemSelected(MenuItem item) {
21. Log.d("MainActivity","onOptionsItemSelected");
22. switch (item.getItemId()) {
23. ...
24. }
25. }
- lignes 7, 14 et 21 on utilise la classe [Log]. Cette classe permet d'écrire des logs sur la console Android [logcat]. Les logs sont classés en divers niveaux (info, warning, debug, verbose, error). [Log.d] affiche des logs de niveau [debug]. Son premier argument est la source du message de log. En effet, diverses sources peuvent émettre des messages sur la console de logs. Afin de pouvoir les différencier, on utilise ce premier argument. Le second argument est le message à écrire sur la console de logs ;
Si nous exécutons de nouveau le projet [Exemple-01], nous obtenons les logs suivants :
1. 05-28 08:37:12.709 23881-23881/com.example.android.pdfrendererbasic D/MainActivity: onCreate
2. 05-28 08:37:12.778 23881-23923/com.example.android.pdfrendererbasic D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
3. 4. [ 05-28 08:37:12.781 23881:23881 D/ ]
5. HostConnection::get() New Host ...
6. 05-28 08:37:12.967 23881-23881/com.example.android.pdfrendererbasic D/MainActivity: onCreateOptionsMenu
On découvre ainsi que la méthode [onCreate] qui crée l'activité Android est exécutée avant la méthode [onCreateOptionsMenu] qui crée le menu de l'application.
Maintenant si on clique sur l'option de menu dans l'émulateur Android [1] :
le log suivant est ajouté dans la console de logs :
05-28 08:41:22.881 23881-23881/com.example.android.pdfrendererbasic D/MainActivity: onOptionsItemSelected
Dans la suite, nous ajouterons souvent dans le code Android des instructions de logs. La plupart du temps, nous ne les commenterons pas. Elles sont là juste pour inviter le lecteur à regarder la console de logs afin de comprendre progressivement le cycle de vie d'une application Android.
1.2.2.5 Gestion de l'émulateur [Genymotion]
Parfois, l'émulateur Genymotion plante et on ne peut plus le relancer. Cela vient du fait que des processus Virtualbox sont restés vivants dans le gestionnaire des tà¢ches. Ouvez celui-ci [Ctrl-Alt-Supp] et supprimez toutes les tà¢ches Virtualbox présentes :
Ceci fait, relancez l'émulateur Genymotion à partir d'Android Studio.
1.2.2.6 Gestion du binaire APK créé
Il y a deux versions : celle dite [debug] et l'autre dite [debug-unaligned]. C'est la première qu'il faut utiliser, l'autre étant une version intermédiaire. Le binaire .pak produit en [4] peut être transféré directement sur un émulateur ou un périphérique Android. Pour le transférer sur un émulateur, il suffit de le tirer / déposer sur l'émulateur avec la souris.
…
1.3 Exemple-02 : un projet Android basique
Créons avec Android Studio un nouveau projet Android [1-12] :
En [13], on exécute l'application. On obtient alors l'affichage [14] sur l'émulateur Genymotion.
1.3.1 Configuration Gradle
Le projet créé est configuré par le fichier [build.gradle] suivant :
1. apply plugin: 'com.android.application'
2. 3. android { compileSdkVersion 23
4. 5. buildToolsVersion "23.0.3"
6. defaultConfig {
7. applicationId "exemples.android"
8. minSdkVersion 15 targetSdkVersion 23
9.
10. versionCode 1
11. versionName "1.0"
12. }
13. 14. buildTypes {
15. release {
16. minifyEnabled false
17. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18. }
19. }
20. }
21. 22. dependencies { compile fileTree(dir: 'libs', include: ['*.jar'])
23. 24. testCompile 'junit:junit:4.12'
25. compile 'com.android.support:appcompat-v7:23.4.0'
26. }
Ce fichier a été généré par l'IDE avec les éléments de sa configuration. C'est un fichier minimal que nous allons progressivement enrichir.
- lignes 3-12 : les caractéristiques de l'application Android ;
- lignes 22-25 : ses dépendances. C'est surtout là que nous amènerons des modifications selon les exemples étudiés ;
1.3.2 Le manifeste de l'application
Le fichier [AndroidManifest.xml] [1] fixe les caractéristiques du binaire de l'application Android. Son contenu est ici le suivant :
1.
2.
3. package="exemples.android">
4. <application
5. android:allowBackup="true"
6. android:icon="@mipmap/ic_launcher"
7. android:label="@string/app_name"
8. android:supportsRtl="true"
9. android:theme="@style/AppTheme">
10.
11. 12.
13.
14.
15.
16.
17.
- ligne 3 : le paquetage du projet Android ;
- ligne 10 : le nom de l'activité ;
Ces deux renseignements viennent des saisies faites lors de la création du projet :
- la ligne 3 du manifeste (package) vient de la saisie [4] ci-dessus. Un certain nombre de classes sont automatiquement générées dans ce package ;
- la ligne 10 du manifeste (nom de l'activité) vient de la saisie [1] ci-dessus ; Revenons au manifeste :
1.
2.
3. package="exemples.android">
4. <application
5. android:allowBackup="true"
6. android:icon="@mipmap/ic_launcher"
7. android:label="@string/app_name"
8. android:supportsRtl="true"
9. android:theme="@style/AppTheme">
10.
11.
12.
13.
14.
15. 16.
17.
- ligne 10 : l'activité principale de l'application. Elle référence la classe [1] ci-dessus ;
- ligne 6 : l'icà´ne [2] de l'application. Elle peut être changée ;
- ligne 7 : le libellé de l'aplication. Il se trouve dans le fichier [strings.xml] [3] :
1.
2. Exemple-02
3.
Le fichier [strings.xml] contient les chaînes de caractères utilisées par l'application. Ligne 2, le nom de l'application provient de la saisie faite lors de la construction du projet [4] :
- ligne 10 : une balise d'activité. Une application Android peut avoir plusieurs activités ;
- ligne 12 : l'activité est désignée comme étant l'activité principale ;
- ligne 13 : et elle doit apparaître dans la liste des applications qu'il est possible de lancer sur l'appareil Android.
1.3.3 L'activité principale
Une application Android repose sur une ou plusieurs activités. Ici une activité [1] a été générée : [MainActivity]. Une activité peut afficher une ou plusieurs vues selon son type. La classe [MainActivity] générée est la suivante :
1. 2. package exemples.android;
3. import android.support.v7.app.AppCompatActivity;
4. import android.os.Bundle;
5. 6. public class MainActivity extends AppCompatActivity {
7. 8. @Override
9. protected void onCreate(Bundle savedInstanceState) {
10. super.onCreate(savedInstanceState);
11. setContentView(R.layout.activity_main);
12. }
13. }
- ligne 6 : la classe [MyActivity] étend la classe Android [AppCompatActivity]. Ce sera le cas de toutes les activités futures ;
- ligne 9 : la méthode [onCreate] est exécutée lorsque l'activité est créée. C'est avant l'affichage de la vue associée à l'activité ;
- ligne 10 : la méthode [onCreate] de la classe parente est appelée. Il faut toujours le faire ;
- ligne 11 : le fichier [activity_main.xml] [2] est la vue associée à l'activité. La définition XML de cette vue est la suivante : a)
b) <RelativeLayout
c) xmlns:android="http://schemas.android.com/apk/res/android"
d) xmlns:tools="http://schemas.android.com/tools"
e) android:layout_width="match_parent"
f) android:layout_height="match_parent"
g) android:paddingLeft="@dimen/activity_horizontal_margin"
h) android:paddingRight="@dimen/activity_horizontal_margin"
i) android:paddingTop="@dimen/activity_vertical_margin"
j) android:paddingBottom="@dimen/activity_vertical_margin"
k) tools:context="exemples.android.MainActivity">
l)
m) <TextView
n) android:text="Hello World!"
o) android:layout_width="wrap_content"
p) android:layout_height="wrap_content"/>
q)
- lignes b-k : le gestionnaire de mise en forme. Celui qui a été choisi par défaut est le type [RelativeLayout]. Dans ce type de conteneur, les composants sont placés les uns par rapport aux autres (à droite de, à gauche de, dessous, au-dessus) ;
- lignes m-p : un composant de type [TextView] qui sert à afficher du texte ;
- ligne n : le texte affiché. Il est déconseillé de mettre du texte en dur dans les vues. Il est préférable de déplacer ces textes dans le fichier [res/values/strings.xml] [3] :
Le texte affiché sera donc [Hello World!]. O๠sera-t-il affiché ? Le conteneur [RelativeLayout] va remplir l'écran. Le [TextView] qui est son seul et unique élément sera affiché en haut et à gauche de ce conteneur, donc en haut et à gauche de l'écran ;
Que signifie [R.layout.activity_main] ligne 11 ? Chaque ressource Android (vues, fragments, composants, ...) se voit attribuer un identifiant. Ainsi une vue [V.xml] se trouvant dans le dossier [res / layout] sera identifiée par [R.layout.V]. R est une classe générée dans le dossier [app / build / generated] [1-3] :
La classe [R] est la suivante :
1. ...............
2. public static final class string {
3. public static final int abc_action_bar_home_description=0x7f060000;
4. public static final int abc_action_bar_home_description_format=0x7f060001;
5. public static final int abc_action_bar_home_subtitle_description_format=0x7f060002;
6. ...
7. public static final int app_name=0x7f060014;
8. 9. }
10. public static final class layout {
11. public static final int abc_action_bar_title_item=0x7f040000;
12. public static final int abc_action_bar_up_container=0x7f040001;
13. ...
14. public static final int activity_main=0x7f040019;
15. ...
16. 17. }
18. public static final class mipmap {
19. public static final int ic_launcher=0x7f030000;
20. }
- ligne 14 : l'attribut [R.layout.activity_main] est l'identifiant de la vue [res / layout / activity_main.xml] ;
- ligne 7 : l'attribut [R.string.app_name] est l'identifiant de la chaîne [app_name] dans le fichier [res / values / string.xml] :
- ligne 19 : l'attribut [R.mipmap.ic_launcher] est l'identifiant de l'image [res / mipmap / ic_launcher] ;
On se souviendra donc que lorsqu'on référence [R.layout.activity_main] dans le code, on référence un attribut de la classe [R]. L'IDE nous aide à connaître les différents éléments de cette classe :
1.3.4 Exécution de l'application
Pour exécuter une application Android, il nous faut créer une configuration d'exécution :
- en [1], choisir [Edit Configurations] ;
- le projet a été créé avec une configuration [app] que nous allons supprimer [2] pour la recréer ; - en [3], créer une nouvelle configuration d'exécution ;
- en [4], choisir [Android Application] ;
- en [5], dans la liste déroulante choisir le module [app] ;
- en [6-8], garder les valeurs proposées par défaut ;
- en [7], l'activité par défaut est celle définie dans le fichier [AndroidManifest.xml] (ligne 1 ci-dessous) :
1.
2.
3.
4. 5.
6.
7.
- en [8], sélectionner [Show Chooser Dialog] qui permet de choisir le périphérique d'exécution de l'application (émulateur,
tablette) ;
- en [9], on indique que ce choix doit être mémorisé ;
- en [11], lancer le gestionnaire des émulateurs [Genymotion] (cf paragraphe 9.9, page 638) ;
- en [12], sélectionner un émulateur de tablette et lancez le [13] ;
- en [14], exécutez la configuration d'exécution [app] ;
- en [15] est présenté le formulaire de choix du périphérique d'exécution. Un seul est ici disponible : l'émulateur [Genymotion] lancé précédemment ;
L'émulateur logiciel affiche au bout d'un moment la vue suivante :
1.3.5 Le cycle de vie d'une activité
Rvenons sur le code de l'activité [MainActivity] :
1. 2. package exemples.android;
3. import android.support.v7.app.AppCompatActivity;
4. import android.os.Bundle;
5. 6. public class MainActivity extends AppCompatActivity {
7. 8. @Override
9. protected void onCreate(Bundle savedInstanceState) {
10. super.onCreate(savedInstanceState);
11. setContentView(R.layout.activity_main);
12. }
13. }
La méthode [onCreate] des lignes 8-12 fait partie des méthodes qui peuvent être appelées au cours du cycle de vie d'une activité. La documentation Android donne la liste de celles-ci :
- [1] : la méthode [onCreate] est appelée au démarrage de l'activité. C'est dans cette méthode qu'on associe l'activité à une vue et qu'on récupère les références des composants de celle-ci ;
- [2-3] : les méthodes [onStart, onResume] sont ensuite appelées. On voit que la méthode [onResume] est la dernière méthode à être exécutée avant d'arriver à l'état [4] de l'activité en cours d'exécution ;
1.4 Exemple-03 : réécriture du projet [Exemple-02] avec la bibliothèque [Android Annotations]
Nous allons maintenant introduire la bibliothèque [] qui facilite l'écriture des applications Android. Pour cela on duplique l'exemple [Exemple-02] dans [Exemple-03] en suivant la procédure [1-16].
- en [1], prenez la perspective [Project] pour voir la totalité du projet Android ;
Note : entre [14] et [15], on est passé d'une perspective [Android] à une perspective [Project] (cf paragraphe 1.2.2.1, page 18).
Nous modifions ensuite le fichier [res / values / strings.xml] [17] :
Le fichier [strings.xml] est modifié de la faà§on suivante :
1.
2. Exemple-03
3.
Maintenant, nous exécutons la nouvelle application qui a repris toute la configuration de [Exemple-02] :
En [19], nous obtenons le même résultat qu'avec [Exemple-02] mais avec un nouveau nom.
Nous allons maintenant introduire la bibliothèque [Android Annotations] que nous appellerons par facilité AA. Cette bibliothèque introduit de nouvelles classes pour annoter les sources Android. Ces annotations vont être utilisées par un processeur qui va créer de nouvelles classes Java dans le module, classes qui participeront à la compilation de celui-ci au même titre que les classes écrites par le développeur. On a ainsi la chaîne de compilation suivante :
Nous allons tout d'abord mettre dans le fichier [build.gradle] les dépendances sur le compilateur d'annotations AA (processeur cidessus) :
1. def AAVersion = '4.0.0'
2. 3. dependencies {
4. apt "org.androidannotations:androidannotations:$AAVersion"
5. compile "org.androidannotations:androidannotations-api:$AAVersion"
6. compile 'com.android.support:appcompat-v7:23.4.0'
7. compile fileTree(dir: 'libs', include: ['*.jar'])
8. }
- les lignes 4-5 ajoutent les deux dépendances qui forment la bibliothèque AA ;
Le fichier [build.gradle] est modifié de nouveau pour utiliser un plugin appelé [android-apt] qui modifie le processus de compilation en deux étapes :
- traitement des annotations Android, ce qui donne naissance à de nouvelles classes ; - compilation de l'ensemble des classes du projet ;
1. buildscript {
2. repositories {
3. mavenCentral()
4. 5. }
6. dependencies {
7. // Since Android's Gradle plugin 0.11, you have to use android-apt >= 1.3
8. classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
9. }
10. }
11. 12. apply plugin: 'com.android.application'
13. apply plugin: 'android-apt'
- ligne 8 : version du plugin [android-apt] qui sera cherchée dans le dépà´t Maven central (ligne 3) ;
1.2 |
Exemple-01 : importation d'un exemple Android |
1.2.1 Création du projet
Créons avec Android Studio un premier projet Android. Tout d'abord créons un dossier [exemples] vide o๠seront placés tous nos projets :
puis créons un projet avec Android Studio. Nous allons tout d'abord importer un des exemples livrés avec l'IDE [1-5] :
L'import du projet peut aboutir à des erreurs dès à l’inadéquation entre l'environnement utilisé lors de la création du projet et celui utilisé ici pour son exécution. C'est une occasion pour voir comment résoudre ce type d'erreurs. Ici, nous avons l'erreur suivante :
Le projet importé est configuré par le fichier [build.gradle] [2] suivant :
1. |
buildscript { |
2. |
repositories { jcenter() |
3. 4. |
} |
5. |
dependencies { |
6. |
classpath 'com.android.tools.build:gradle:2.1.0' |
7. |
} |
8. |
} |
9. 10. 11. |
apply plugin: 'com.android.application' |
12. |
repositories { |
13. |
jcenter() |
14. |
} |
15. 16. |
dependencies { |
17. |
compile "com.android.support:support-v4:23.3.0" |
18. |
compile "com.android.support:support-v13:23.3.0" |
19. |
compile "com.android.support:cardview-v7:23.3.0" |
20. 21. |
} |
22. |
// The sample build uses multiple directories to |
23. |
// keep boilerplate and common code separate from |
24. |
// the main sample code. |
25. |
List dirs = [ |
26. |
'main', // main sample code; look here for the interesting stuff. |
27. |
'common', // components that are reused by multiple samples |
28. |
'template'] // boilerplate code that is generated by the sample template process |
29. 30. |
android { compileSdkVersion 21 |
31. 32. |
buildToolsVersion "23.0.3" |
33. |
defaultConfig { |
34. |
minSdkVersion 21 |
35. |
targetSdkVersion 21 |
36. |
} |
37. |
compileOptions { |
38. |
sourceCompatibility JavaVersion.VERSION_1_7 |
39. |
targetCompatibility JavaVersion.VERSION_1_7 |
40. |
} |
41. |
sourceSets { |
42. |
main { |
43. |
dirs.each { dir -> |
44. |
java.srcDirs "src/${dir}/java" |
45. |
res.srcDirs "src/${dir}/res" |
46. |
} |
47. |
} |
48. |
androidTest.setRoot('tests') |
49. |
androidTest.java.srcDirs = ['tests/src'] |
50. |
} |
51. 52. |
aaptOptions { |
53. |
noCompress "pdf" |
54. |
} |
55. |
} |
- l'erreur signalée est dè aux lignes 31, 34-35 : nous n'avons pas de SDK 21. Nous remplaà§ons cette version par la version 23 dont nous disposons.
Dans le fichier [build.gradle], Android Studio fait des suggestions comme ci-dessous :
Pour accepter les suggestions, on fait [alt-entrée] sur la suggestion :
On peut avoir également une erreur sur la version de Gradle :
Cette erreur vient d'une inadéquation entre la version de Gradle demandée par le fichier [build.gradle] du projet (la 2.10 ligne 6 cidessous) :
1. |
buildscript { |
2. |
repositories { |
3. |
jcenter() |
4. |
} |
5. |
dependencies { |
6. |
classpath 'com.android.tools.build:gradle:2.1.0' |
7. |
} |
8. |
} |
et celle inscrite dans le fichier [/gradle/wrapper/gradle-wrapper.properties] :
1. #Wed Apr 10 15:27:10 PDT 2013
2. |
distributionBase=GRADLE_USER_HOME |
3. |
distributionPath=wrapper/dists |
4. |
zipStoreBase=GRADLE_USER_HOME |
5. |
zipStorePath=wrapper/dists |
6. |
distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip |
Ligne 6, ci-dessus, il faut remplacer 2.8 par 2.10.
Pour avoir accès au fichier [/gradle/wrapper/gradle-wrapper.properties], il faut utiliser la perspective projet du projet :
Ceci corrigé, on peut alors compiler l'application [1], lancer l'émulateur Genymotion [2] puis exécuter le projet [3] :
Arrêtons l'application :
On peut maintenant fermer le projet. Nous allons en créer un nouveau.
1.2.2 Quelques points sur l'IDE
1.2.2.1 Les perspectives
L'IDE Android Studio (AS) offre différentes perspectives pour travailler avec un projet. Nous en utiliserons principalement deux :
- la perspective [Android] [1] :
- la perspective [Project] [4] ;
La plupart du temps nous travaillerons avec la perspective [Android]. Lorsque nous dupliquerons un projet dans un autre, nous aurons besoin de la perspective [Project]. 1.2.2.2 Gestion de l'exécution
Il y a plusieurs faà§ons d'exécuter / arrêter / réexécuter un projet AS. Il y a tout d'bord les boutons de la barre d'outils :
Le bouton [Rerun] [3], arrête l'exécution du projet [2] puis le relance [1].
1.2.2.3 Gestion du cache
Android Studio entretient un cache des projets qu'il gère dans le but de rendre l'IDE la plus réactive possible. Avec la version Android 2.1 (mai 2016), souvent ce cache ne prenait pas en compte les modifications de code que l'on venait de faire. Dans ce cas, il faut invalider ce cache :
Avec Android 2.1 (mai 2016), l'opération précédente devait être faite de nombreuses fois et parfois cela n'était pas suffisant à résoudre l'anomalie détectée. La solution a été d'inhiber la technologie [Instant Run] :
- en [3-4], tout a été désactivé ;
Dans tout ce qui suit, on a travaillé avec cette configuration du cache et on n'a pas rencontré de problèmes.
1.2.2.4 Gestion des logs
Lors de l'exécution d'un projet, des logs s'affichent dans le moniteur Android :
Dans l'onglet [Android Monitor] [1], les logs s'affichent dans l'onglet [logcat] [2]. Le bouton [3] permet d'effacer les logs. Ce bouton est utile lorsqu'on veut voir les logs d'une action particulière :
- on efface les logs ;
- sur le périphérique Android, on fait l'action dont on veut les logs ;
- les logs qui apparaissent alors sont ceux liés à l'action faite ;
Il existe plusieurs niveux de logs [4]. Par défaut, c'est le mode [Verbose] qui est sélectionné. Il signifie que les logs de tous les niveaux sont affichés. On peut avec [4], sélectionner un niveau particulier.
Les logs sont très utiles pour savoir à quels moments de l'exécution d'un projet certaines méthodes sont affichées. Nous y aurons souvent recours. Prenons le code de la classe [MainActivity] du projet [Exemple-01] :
1. |
package com.example.android.pdfrendererbasic; |
2. 3. |
import android.app.Activity; |
4. |
import android.app.AlertDialog; |
5. |
import android.os.Bundle; |
6. |
import android.view.Menu; |
7. |
import android.view.MenuItem; |
8. 9. |
publicclass MainActivity extends Activity { |
10. 11. |
publicstaticfinal String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic"; |
12. 13. |
@Override |
14. |
protectedvoid onCreate(Bundle savedInstanceState) { |
15. |
super.onCreate(savedInstanceState); |
16. |
setContentView(R.layout.activity_main_real); |
17. |
if (savedInstanceState == null) { |
18. |
getFragmentManager().beginTransaction() |
19. |
.add(R.id.container, new PdfRendererBasicFragment(), |
20. |
FRAGMENT_PDF_RENDERER_BASIC) |
21. |
.commit(); |
22. |
} |
23. |
} |
24. 25. |
@Override |
26. |
publicboolean onCreateOptionsMenu(Menu menu) { |
27. |
getMenuInflater().inflate(R.menu.main, menu); |
28. |
returntrue; |
29. |
} |
30. 31. |
@Override |
32. |
publicboolean onOptionsItemSelected(MenuItem item) { |
33. |
switch (item.getItemId()) { |
34. |
case R.id.action_info: |
35. |
new AlertDialog.Builder(this) |
36. |
.setMessage(R.string.intro_message) |
37. |
.setPositiveButton(android.R.string.ok, null) |
38. |
.show(); |
39. |
returntrue; |
40. |
} |
41. |
returnsuper.onOptionsItemSelected(item); |
42. |
} |
43. |
} |
Ci-dessus, les méthodes [onCreate, ligne 14], [onCreateOptionsMenu, ligne 26] sont des méthodes de la classe parent [Activity] (ligne 9). Elles sont appelées à différents moments du cycle de vie de l'application. Parfois elles sont exécutées plusieurs fois. Même lorsqu'on lit les docs, il est parfois difficile de dire si une telle méthode du cycle de vie va s'exécuter avant ou après une méthode qu'on aurait écrite nous-mêmes. Or cette information est souvent importante à connaître. On peut alors mettre des logs comme ci-dessous :
1. publicclass MainActivity extends Activity { 2. 3. publicstaticfinal String FRAGMENT_PDF_RENDERER_BASIC = "pdf_renderer_basic"; 4. |
5. @Override 6. protectedvoid onCreate(Bundle savedInstanceState) { 7. Log.d("MainActivity","onCreate"); 8. super.onCreate(savedInstanceState); |
9. ... 10. } 11. 12. @Override 13. publicboolean onCreateOptionsMenu(Menu menu) { 14. Log.d("MainActivity","onCreateOptionsMenu"); |
15. getMenuInflater().inflate(R.menu.main, menu); 16. ... 17. } 18. |
19. @Override 20. publicboolean onOptionsItemSelected(MenuItem item) { |
21. Log.d("MainActivity","onOptionsItemSelected"); 22. switch (item.getItemId()) { |
23. ... 24. } |
25. } |
- lignes 7, 14 et 21 on utilise la classe [Log]. Cette classe permet d'écrire des logs sur la console Android [logcat]. Les logs sont classés en divers niveaux (info, warning, debug, verbose, error). [Log.d] affiche des logs de niveau [debug]. Son premier argument est la source du message de log. En effet, diverses sources peuvent émettre des messages sur la console de logs. Afin de pouvoir les différencier, on utilise ce premier argument. Le second argument est le message à écrire sur la console de logs ;
Si nous exécutons de nouveau le projet [Exemple-01], nous obtenons les logs suivants :
1. |
05-28 08:37:12.709 23881-23881/com.example.android.pdfrendererbasic D/MainActivity: onCreate |
2. |
05-28 08:37:12.778 23881-23923/com.example.android.pdfrendererbasic D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true |
3. 4. |
[ 05-28 08:37:12.781 23881:23881 D/ ] |
5. |
HostConnection::get() New Host ... |
6. 05-28 08:37:12.967 23881-23881/com.example.android.pdfrendererbasic D/MainActivity: onCreateOptionsMenu
On découvre ainsi que la méthode [onCreate] qui crée l'activité Android est exécutée avant la méthode [onCreateOptionsMenu] qui crée le menu de l'application.
Maintenant si on clique sur l'option de menu dans l'émulateur Android [1] :
le log suivant est ajouté dans la console de logs :
05-28 08:41:22.881 23881-23881/com.example.android.pdfrendererbasic D/MainActivity: onOptionsItemSelected
Dans la suite, nous ajouterons souvent dans le code Android des instructions de logs. La plupart du temps, nous ne les commenterons pas. Elles sont là juste pour inviter le lecteur à regarder la console de logs afin de comprendre progressivement le cycle de vie d'une application Android.
1.2.2.5 Gestion de l'émulateur [Genymotion]
Parfois, l'émulateur Genymotion plante et on ne peut plus le relancer. Cela vient du fait que des processus Virtualbox sont restés vivants dans le gestionnaire des tà¢ches. Ouvez celui-ci [Ctrl-Alt-Supp] et supprimez toutes les tà¢ches Virtualbox présentes :
Ceci fait, relancez l'émulateur Genymotion à partir d'Android Studio.
1.2.2.6 Gestion du binaire APK créé
Il y a deux versions : celle dite [debug] et l'autre dite [debug-unaligned]. C'est la première qu'il faut utiliser, l'autre étant une version intermédiaire. Le binaire .pak produit en [4] peut être transféré directement sur un émulateur ou un périphérique Android. Pour le transférer sur un émulateur, il suffit de le tirer / déposer sur l'émulateur avec la souris.
…
1.3 |
Exemple-02 : un projet Android basique |
Créons avec Android Studio un nouveau projet Android [1-12] :
En [13], on exécute l'application. On obtient alors l'affichage [14] sur l'émulateur Genymotion.
1.3.1 Configuration Gradle
Le projet créé est configuré par le fichier [build.gradle] suivant :
1. |
apply plugin: 'com.android.application' |
||
2. 3. |
android { compileSdkVersion 23 |
||
4. 5. |
buildToolsVersion "23.0.3" |
||
6. |
defaultConfig { |
||
7. |
applicationId "exemples.android" |
||
8. |
minSdkVersion 15 targetSdkVersion 23 |
||
9. 10. |
versionCode 1 |
||
11. |
versionName "1.0" |
||
12. |
} |
||
13. 14. |
buildTypes { |
||
15. |
release { |
||
16. |
minifyEnabled false |
||
17. |
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' |
||
18. |
} |
||
19. |
} |
||
20. |
} |
||
21. 22. |
dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) |
||
23. 24. |
testCompile 'junit:junit:4.12' |
||
25. |
compile 'com.android.support:appcompat-v7:23.4.0' |
26. }
Ce fichier a été généré par l'IDE avec les éléments de sa configuration. C'est un fichier minimal que nous allons progressivement enrichir.
- lignes 3-12 : les caractéristiques de l'application Android ;
- lignes 22-25 : ses dépendances. C'est surtout là que nous amènerons des modifications selon les exemples étudiés ;
1.3.2 Le manifeste de l'application
Le fichier [AndroidManifest.xml] [1] fixe les caractéristiques du binaire de l'application Android. Son contenu est ici le suivant :
1. |
|
2. |
|
3. |
package="exemples.android"> |
4. |
<application |
5. |
android:allowBackup="true" |
6. |
android:icon="@mipmap/ic_launcher" |
7. |
android:label="@string/app_name" |
8. |
android:supportsRtl="true" |
9. |
android:theme="@style/AppTheme"> |
10. |
|
11. 12. |
|
13. |
|
14. |
|
15. |
|
16. |
17.
- ligne 3 : le paquetage du projet Android ;
- ligne 10 : le nom de l'activité ;
Ces deux renseignements viennent des saisies faites lors de la création du projet :
- la ligne 3 du manifeste (package) vient de la saisie [4] ci-dessus. Un certain nombre de classes sont automatiquement générées dans ce package ;
- la ligne 10 du manifeste (nom de l'activité) vient de la saisie [1] ci-dessus ; Revenons au manifeste :
1. |
|
2. |
|
3. |
package="exemples.android"> |
4. |
<application |
5. |
android:allowBackup="true" |
6. |
android:icon="@mipmap/ic_launcher" |
7. |
android:label="@string/app_name" |
8. |
android:supportsRtl="true" |
9. |
android:theme="@style/AppTheme"> |
10. |
|
11. |
|
12. |
|
13. |
|
14. |
|
15. 16. |
|
17. |
- ligne 10 : l'activité principale de l'application. Elle référence la classe [1] ci-dessus ;
- ligne 6 : l'icà´ne [2] de l'application. Elle peut être changée ;
- ligne 7 : le libellé de l'aplication. Il se trouve dans le fichier [strings.xml] [3] :
1.
2. |
"app_name">Exemple-02 |
3. |
Le fichier [strings.xml] contient les chaînes de caractères utilisées par l'application. Ligne 2, le nom de l'application provient de la saisie faite lors de la construction du projet [4] :
- ligne 10 : une balise d'activité. Une application Android peut avoir plusieurs activités ;
- ligne 12 : l'activité est désignée comme étant l'activité principale ;
- ligne 13 : et elle doit apparaître dans la liste des applications qu'il est possible de lancer sur l'appareil Android.
1.3.3 L'activité principale
Une application Android repose sur une ou plusieurs activités. Ici une activité [1] a été générée : [MainActivity]. Une activité peut afficher une ou plusieurs vues selon son type. La classe [MainActivity] générée est la suivante :
1. 2. |
package exemples.android; |
3. |
import android.support.v7.app.AppCompatActivity; |
4. |
import android.os.Bundle; |
5. 6. |
publicclass MainActivity extends AppCompatActivity { |
7. 8. |
@Override |
9. |
protectedvoid onCreate(Bundle savedInstanceState) { |
10. |
super.onCreate(savedInstanceState); |
11. |
setContentView(R.layout.activity_main); |
12. |
} |
13. }
- ligne 6 : la classe [MyActivity] étend la classe Android [AppCompatActivity]. Ce sera le cas de toutes les activités futures ;
- ligne 9 : la méthode [onCreate] est exécutée lorsque l'activité est créée. C'est avant l'affichage de la vue associée à l'activité ;
- ligne 10 : la méthode [onCreate] de la classe parente est appelée. Il faut toujours le faire ;
- ligne 11 : le fichier [activity_main.xml] [2] est la vue associée à l'activité. La définition XML de cette vue est la suivante : a)
b) |
<RelativeLayout |
c) |
xmlns:android="http://schemas.android.com/apk/res/android" |
d) |
xmlns:tools="http://schemas.android.com/tools" |
e) |
android:layout_width="match_parent" |
f) |
android:layout_height="match_parent" |
g) |
android:paddingLeft="@dimen/activity_horizontal_margin" |
h) |
android:paddingRight="@dimen/activity_horizontal_margin" |
i) |
android:paddingTop="@dimen/activity_vertical_margin" |
j) |
android:paddingBottom="@dimen/activity_vertical_margin" |
k) |
tools:context="exemples.android.MainActivity"> |
l) m) |
<TextView |
n) |
android:text="Hello World!" |
o) |
android:layout_width="wrap_content" |
p) |
android:layout_height="wrap_content"/> |
q) |
- lignes b-k : le gestionnaire de mise en forme. Celui qui a été choisi par défaut est le type [RelativeLayout]. Dans ce type de conteneur, les composants sont placés les uns par rapport aux autres (à droite de, à gauche de, dessous, au-dessus) ;
- lignes m-p : un composant de type [TextView] qui sert à afficher du texte ;
- ligne n : le texte affiché. Il est déconseillé de mettre du texte en dur dans les vues. Il est préférable de déplacer ces textes dans le fichier [res/values/strings.xml] [3] :
Le texte affiché sera donc [Hello World!]. O๠sera-t-il affiché ? Le conteneur [RelativeLayout] va remplir l'écran. Le [TextView] qui est son seul et unique élément sera affiché en haut et à gauche de ce conteneur, donc en haut et à gauche de l'écran ;
Que signifie [R.layout.activity_main] ligne 11 ? Chaque ressource Android (vues, fragments, composants, ...) se voit attribuer un identifiant. Ainsi une vue [V.xml] se trouvant dans le dossier [res / layout] sera identifiée par [R.layout.V]. R est une classe générée dans le dossier [app / build / generated] [1-3] :
La classe [R] est la suivante :
1. |
............... |
2. |
publicstaticfinalclass string { |
3. |
publicstaticfinalint abc_action_bar_home_description=0x7f060000; |
4. |
publicstaticfinalint abc_action_bar_home_description_format=0x7f060001; |
5. |
publicstaticfinalint abc_action_bar_home_subtitle_description_format=0x7f060002; |
6. |
... |
7. |
publicstaticfinalint app_name=0x7f060014; |
8. 9. |
} |
10. |
publicstaticfinalclass layout { |
11. |
publicstaticfinalint abc_action_bar_title_item=0x7f040000; |
12. |
publicstaticfinalint abc_action_bar_up_container=0x7f040001; |
13. |
... |
14. |
publicstaticfinalint activity_main=0x7f040019; |
15. |
... |
16. 17. |
} |
18. |
publicstaticfinalclass mipmap { |
19. |
publicstaticfinalint ic_launcher=0x7f030000; |
20. }
- ligne 14 : l'attribut [R.layout.activity_main] est l'identifiant de la vue [res / layout / activity_main.xml] ;
- ligne 7 : l'attribut [R.string.app_name] est l'identifiant de la chaîne [app_name] dans le fichier [res / values / string.xml] :
- ligne 19 : l'attribut [R.mipmap.ic_launcher] est l'identifiant de l'image [res / mipmap / ic_launcher] ;
On se souviendra donc que lorsqu'on référence [R.layout.activity_main] dans le code, on référence un attribut de la classe [R]. L'IDE nous aide à connaître les différents éléments de cette classe :
1.3.4 Exécution de l'application
Pour exécuter une application Android, il nous faut créer une configuration d'exécution :
- en [1], choisir [Edit Configurations] ;
- le projet a été créé avec une configuration [app] que nous allons supprimer [2] pour la recréer ; - en [3], créer une nouvelle configuration d'exécution ;
- en [4], choisir [Android Application] ;
- en [5], dans la liste déroulante choisir le module [app] ;
- en [6-8], garder les valeurs proposées par défaut ;
- en [7], l'activité par défaut est celle définie dans le fichier [AndroidManifest.xml] (ligne 1 ci-dessous) :
1. |
".MainActivity"> |
2. |
|
3. |
"android.intent.action.MAIN"/> |
4. 5. |
"android.intent.category.LAUNCHER"/> |
6. |
|
7.
- en [8], sélectionner [Show Chooser Dialog] qui permet de choisir le périphérique d'exécution de l'application (émulateur,
tablette) ;
- en [9], on indique que ce choix doit être mémorisé ;
- en [11], lancer le gestionnaire des émulateurs [Genymotion] (cf paragraphe 9.9, page 638) ;
- en [12], sélectionner un émulateur de tablette et lancez le [13] ;
- en [14], exécutez la configuration d'exécution [app] ;
- en [15] est présenté le formulaire de choix du périphérique d'exécution. Un seul est ici disponible : l'émulateur [Genymotion] lancé précédemment ;
L'émulateur logiciel affiche au bout d'un moment la vue suivante :
1.3.5 Le cycle de vie d'une activité
Rvenons sur le code de l'activité [MainActivity] :
1. 2. |
package exemples.android; |
3. |
import android.support.v7.app.AppCompatActivity; |
4. |
import android.os.Bundle; |
5. 6. |
publicclass MainActivity extends AppCompatActivity { |
7. 8. |
@Override |
9. |
protectedvoid onCreate(Bundle savedInstanceState) { |
10. |
super.onCreate(savedInstanceState); |
11. |
setContentView(R.layout.activity_main); |
12. |
} |
13. |
} |
La méthode [onCreate] des lignes 8-12 fait partie des méthodes qui peuvent être appelées au cours du cycle de vie d'une activité. La documentation Android donne la liste de celles-ci :
- [1] : la méthode [onCreate] est appelée au démarrage de l'activité. C'est dans cette méthode qu'on associe l'activité à une vue et qu'on récupère les références des composants de celle-ci ;
- [2-3] : les méthodes [onStart, onResume] sont ensuite appelées. On voit que la méthode [onResume] est la dernière méthode à être exécutée avant d'arriver à l'état [4] de l'activité en cours d'exécution ;
1.4 Exemple-03 : réécriture du projet [Exemple-02] avec la bibliothèque [Android Annotations]
Nous allons maintenant introduire la bibliothèque qui facilite l'écriture des applications Android. Pour cela on duplique l'exemple [Exemple-02] dans [Exemple-03] en suivant la procédure [1-16].
- en [1], prenez la perspective [Project] pour voir la totalité du projet Android ;
Note : entre [14] et [15], on est passé d'une perspective [Android] à une perspective [Project] (cf paragraphe 1.2.2.1, page 18).
Nous modifions ensuite le fichier [res / values / strings.xml] [17] :
Le fichier [strings.xml] est modifié de la faà§on suivante :
1. |
|
2. |
"app_name">Exemple-03 |
3. |
Maintenant, nous exécutons la nouvelle application qui a repris toute la configuration de [Exemple-02] :
En [19], nous obtenons le même résultat qu'avec [Exemple-02] mais avec un nouveau nom.
Nous allons maintenant introduire la bibliothèque [Android Annotations] que nous appellerons par facilité AA. Cette bibliothèque introduit de nouvelles classes pour annoter les sources Android. Ces annotations vont être utilisées par un processeur qui va créer de nouvelles classes Java dans le module, classes qui participeront à la compilation de celui-ci au même titre que les classes écrites par le développeur. On a ainsi la chaîne de compilation suivante :
Nous allons tout d'abord mettre dans le fichier [build.gradle] les dépendances sur le compilateur d'annotations AA (processeur cidessus) :
1. def AAVersion = '4.0.0'
2. 3. |
dependencies { |
4. |
apt "org.androidannotations:androidannotations:$AAVersion" |
5. |
compile "org.androidannotations:androidannotations-api:$AAVersion" |
6. |
compile 'com.android.support:appcompat-v7:23.4.0' |
7. |
compile fileTree(dir: 'libs', include: ['*.jar']) |
8. }
- les lignes 4-5 ajoutent les deux dépendances qui forment la bibliothèque AA ;
Le fichier [build.gradle] est modifié de nouveau pour utiliser un plugin appelé [android-apt] qui modifie le processus de compilation en deux étapes :
- traitement des annotations Android, ce qui donne naissance à de nouvelles classes ; - compilation de l'ensemble des classes du projet ;
1. |
buildscript { |
2. |
repositories { |
3. |
mavenCentral() |
4. 5. |
} |
6. |
dependencies { |
7. |
// Since Android's Gradle plugin 0.11, you have to use android-apt >= 1.3 |
8. |
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' |
9. |
} |
10. |
} |
11. 12. |
apply plugin: 'com.android.application' |
13. |
apply plugin: 'android-apt' |
- ligne 8 : version du plugin [android-apt] qui sera cherchée dans le dépà´t Maven central (ligne 3) ;