Décollage d'une fusée spaciale : Avec fastlane, notre processus de build part dans l'espace.
Image https://quentin.klein.onl/2020/10/24/builder-et-signer-son-application-android-en-release/
Décollage d'une fusée spaciale : Avec fastlane, notre processus de build part dans l'espace. Image https://quentin.klein.onl/2020/10/24/builder-et-signer-son-application-android-en-release/

Cet article fait partie d’une série de 4.
L’objectif est de décrire comment faire pour optimiser un maximum le déploiement d’une application Android en automatisant les étapes 🤖.

1 – 📦 Builder et signer son application Android
2 – 🚀 Automatiser les builds avec Fastlane
3 (1) – 🔥 Déployer son application sur Firebase
3 (2) – 🛳 Déployer son application sur le Play Store
4 – 🤖 Utiliser Gitlab pour déployer son application lors d’un tag de release sur git.

Dans la seconde partie de cette série, nous allons voir comment utiliser fastlane pour générer notre application Android (app bundle ou apk).


🕰 On en était où déjà ?

Dans le dernier article, on a vu comment faire pour automatiser le build de son application en mode release.

Grâce à cela, on peut désormais créer une application dans le but de la déployer, en prod ou en test, sans devoir y passer 4 heures. 👍

Malgré tout, il est possible de faire encore mieux. 😮

Aujourd’hui, on utilise gradle directement pour lancer nos builds.
Ce n’est pas mal. C’est même plutôt bien.

Mais demain, que se passe-t-il si Android change de build system ? 🙀
Et une fois que notre build est fait, il faut quand même se faire le changelog à la main. 😩
Et les screenshots pareils (s’il y en a besoin).
Pareil pour l’upload du build…

Bref, tout un tas de petites actions encore manuelles qui peuvent être automatisées pour ne pas avoir à le faire à chaque fois.


🍔 Fastlane, arrête de builder toi même

Fastlane, c’est un super outil pour arrêter de faire un taf de grille pain
(si le collègue qui m’a sorti cette punchline un jour me lis, AJ, sache que c’était la meilleure punchline du monde et que je l’utilise quasiment tous les jours).

un grille pain
Un beau grille pain. Qui fait un travaille de grille pain.
Il grille du pain. Rien de plus rien de moins.
Source : pexels

Je ne vais pas pouvoir être totalement exhaustif sur ce que fait Fastlane.

  1. Premièrement, parce qu’il fait vraiment beaucoup de choses.
  2. Ensuite, parce qu’un système de plugin communautaire rajoute encore par-dessus ! 🌈

Cependant, en résumé, ce qu’on peut retenir, c’est qu’on va pouvoir faire ça:

  • modification du numéro de version
  • changelog
  • screenshots pour les stores
  • génération du build
  • déploiement
  • message slack (ou autres)
  • git (commit / tag / push)

Tout ce qu’on veut pour nous permettre d’automatiser encore plus nos déploiements. 🤖

✈️ Installation de Fastlane

Pour commencer, on va faire simple, on va installer fastlane.

Commencez par vous rendre à la racine de votre projet. C’est là qu’on va travailler.

On va répéter un peu le tuto officiel, mais si je vous envoie vous balader sur le site de chaque outil que j’utilise en mode vas-y installe ça on risque de ne pas aller bien loin.

💎 Ruby

Pour commencer, fastlane est fait en ruby, donc il vous faudra installer ruby si ce n’est pas déjà fait.

Pour faire cela, lancez un

ruby -v

Soit ça fonctionne, soit ça ne fonctionne pas et vous pouvez faire

brew install ruby

Je suis un fervent défenseur de Homebrew 🍺, et fastlane est disponible dessus…. Pour autant, je vous conseille de ne pas passer par là pour fastlane (ce n’est d’ailleurs pas la méthode recommandée sur le site officiel).

📦 Bundler

De ce fait, on va passer par un Gemfile (une sorte de build.gradle pour fastlane on dira).

Créez un fichier Gemfile à la racine de votre projet et mettez-y le contenu suivant

source "https://rubygems.org"

gem "fastlane"

EN GROS, ça dit d’aller chercher fastlane 🙂 là où il faut. Mais surtout, on fait ça parce qu’on va utiliser bundler.

Je n’ai pas forcément tout compris à l’histoire, mais en gros ça gère les imports/dépendances/require (utile pour les plugins)…

Et en vrai, tant que ça marche… (d’ailleurs je devrais peut-être écrire un truc là-dessus un jour)

🚀 Fastlane

Du coup, une fois notre Gemfile créé on va lancer un

bundle update

Cette commande va nous créé un Gemfile.lock (même principe que les npm lock etc, ça permet de reproduire les builds en ayant toujours les mêmes versions de lib).

On ajoute les 2 fichiers au dépôt git et on a fini, Fastlane est installé 🎉

Maintenant, quand on voudra lancer fastlane on pourra faire

bundle exec fastlane

Mais ne le faites pas tout de suite, sinon ça ne va pas très bien fonctionner… On va commencer par initialiser tout ça !

Ho, une dernière chose…

Je n’ai pas forcément bien compris pourquoi, mais fastlane a besoin de 2 variables d’environnement pour fonctionner correctement.

LC_ALL: "en_US.UTF-8"
LANG: "en_US.UTF-8"

Je vous invite donc à les rajouter à la fin de votre .zshrc, .bashrc, bash profile ou autre !!

📁 Le dossier fastlane

La première chose que l’on va faire dans notre projet, c’est d’initialiser fastlane.

Bah oui, parce que là, tout ce qu’on a fait c’est l’installer…

Donc allons-y. Toujours dans notre répertoire projet

bundle exec fastlane init

De là fastlane va vous demander tout un tas d’information dont

  • Le nom de package (ou plutôt l’applicationId)
  • Le json secret file (passez cette étape, on y reviendra quand on fera un déploiement avec fastlane)
  • Et une question pour l’upload Google Play. Même combat, on passe et on y reviendra.

Et là bingo ! Tout est installé et vous avec un nouveau dossier fastlane créé à la racine de votre projet. 👏

Le contenu de ce dossier est un peu sommaire pour le moment.

  • l’Appfile, qui contient un peu la conf de ce qu’on veut
  • le Fastfile qui contient nos lanes, une lane étant une sorte de target, d’étape ou autres. Bref une fonction qui va faire quelque chose.

Tout ça pour dire que maintenant, on est prêts 💪


🚀 Optimiser son build

Maintenant qu’on dispose de fastlane, on va essayer de mettre un maximum de choses dedans et un minimum de choses dans notre build.gradle.

La première étape, ça reste quelque chose de simple, on va builder notre application en utilisant fastlane.

Allez, on va pimper notre Fastfile et notre build.gradle pour transformer tout ça !
Image pexles

🔀 A la découverte des lanes

Pour faire notre première lane, on va commencer simple.

Que diriez-vous de… faire un build de notre application ?

Pour cela, ouvrez le fichier fastlane/Fastfile.

default_platform(:android)

platform :android do

  desc "Runs all the tests"
  lane :test do
    gradle(task: "test")
  end

end

J’ai un peu simplifié ce qu’il s’y trouve, mais en gros, une lane, c’est cette partie-là:

desc "Runs all the tests"
lane :test do
    gradle(task: "test")
end

Une lane est composée de

  • Une description desc
  • Un titre/nom :test
  • Une liste de commandes (soit internes, soit externes)

Ce que fait cette lane c’est Run all the tests, elle s’appelle test, et pour faire cela, elle lance la tâche gradle test.

Simple pour l’instant non ? 🙃

En avant donc pour notre lane de build, si on va regarder la doc de l’action (oui cela s’appelle une action) gradle sur fastlane, on voit qu’il peut prendre un paquet de paramètres.

Reteons les plus utiles à première vue

  • task (ou tasks)
  • flavor
  • build_type

Je ne dis pas que les autres ne sont pas utiles, mais à première vue, on n’en aura pas besoin de suite.

Une fois armé de cette documentation, faire notre première lane de build semble être un jeu d’enfant ! 🎮

🧙‍♂️ Fastlane, build mon app !

Sans plus attendre, on va écrire notre lane de build.

Pas de trailer, pas de suspens:

desc "Build our Android App"
lane :build do
    gradle(task: 'bundle', build_type: 'Release')
end

Donc, sans vouloir abuser, on va regarder 10 secondes ce qu’on a fait.

Notre lane s’appelle build, pour l’appeler on devra donc utiliser ce nom.
Ce qu’elle fait c’est Build our Android App. Difficile de faire plus parlant.
Et enfin, pour faire cela, elle exécute une tâche gradle qui est bundle en mode release.

NDLR: Si vous voulez faire un bon gros APK des familles, utilisez assemble au lieu de bundle

Et voilà. 🚀 On teste ça ? Ouvrez votre terminal et essayez

bundle exec fastlane android build

On va s’arrêter 2 secondes sur cette commande. bundle exec fastlane, on connaît.

Mais android build ?

Bon, pas besoin d’être un génie, android, c’est la platform (regardez en haut du Fastfile), on pouvait se passer de le préciser grâce au

default_platform(:android)

Mais ça ne mange pas de pain de le préciser.

Et build, c’est tout simplement le nom de notre lane, comme je vous disais plus haut !

Une fois exécuté, notre app bundle se situe dans le dossier de build classique (généralement app/build/outputs/).

🤮 C’est tout ? C’est naze.

Arrivez là, c’est clair que c’est comme ça que je réagirais…

En gros on a fait quoi ?

  • Installé ruby (si pas déjà installé)
  • Installé fastlane (via bundler)
  • Créé une lane

Tout ça pour faire ce qu’on savait faire en une tâche gradle lors de l’article sur la génération d’une app de release ?

Sacré investissement pour pas grand-chose….

Mais, il faut voir plus loin ! Fastlane s’avère vraiment sympa dans de nombreuses situations.

Voici quelques exemples:

🤯 Un projet multi flavor

Imaginez, un projet avec 2 ou 3 (ou plus flavors) à builder. Relou les commandes gradle à retenir…

desc "Build the flavor Free of our app"
lane :build_free do
    gradle(task: 'bundle', flavor: 'Free', build_type: 'Release')
end

desc "Build the flavor Paid of our app"
lane :build_paid do
    gradle(task: 'bundle', flavor: 'Paid', build_type: 'Release')
end

desc "Build all the flavors of our app"
lane :build do
    build_free
    build_paid
end

En quelques lanes, très simples à retenir, on peut builder l’une de nos flavors ou toutes !

./gradlew :app:bundleFreeRelease :app:bundlePaidRelease

vs

bundle exec fastlane android build

🧹 Un peu de ménage ?

Et d’ailleurs, cela serait plus propre de nettoyer un peu notre dossier avant tout ça non ? 🧼

Avec gradlew, ça ressemble à ça

./gradlew :app:clean :app:bundleFreeRelease :app:bundlePaidRelease

Et bien, modifions notre lane.

desc "Build all the flavors of our app"
lane :build do
    gradle(task: clean)
    build_free
    build_paid
end

et c’est toujours

bundle exec fastlane android build

🔝 Améliorer ses lanes

On voit que nos lanes fonctionnent plutôt bien, mais dans un effort de les rendre plus lisibles et plus réutilisables comment pouvons-nous faire ?

🧠 Utiliser les options

On remarque dans nos exemples qu’on a un cas simple où on pourrait passer une option et factoriser un peu notre code

NDLR: Rien n’est moins utilisable ou compréhensible qu’un code trop factorisé, donc à utiliser avec parcimonie !

desc "Build the flavor Free of our app"
lane :build_free do
    gradle(task: 'bundle', flavor: 'Free', build_type: 'Release')
end

desc "Build the flavor Paid of our app"
lane :build_paid do
    gradle(task: 'bundle', flavor: 'Paid', build_type: 'Release')
end

desc "Build all the flavors of our app"
lane :build do
    build_free
    build_paid
end

On voit que nos 2 flavors peuvent être simplifiées si on passait le nom de la flavor en paramètre.

Pour cela, on va utiliser la syntaxe suivante

desc "Build a given flavor of our app"
lane :build_flavor do |options|
    flavor = options[:flavor]
end

Avec cette syntaxe, nous disons à fastlane que nous passons un paramètre flavor à notre lane et qu’il peut utiliser ce paramètre.

On remarque qu’options est un dictionnaire (liste de clés-valeurs) et que c’est pour cela qu’on peut accéder à notre paramètre en faisant options[:flavor]

desc "Build a given flavor of our app"
lane :build_flavor do |options|
    flavor = options[:flavor]
    gradle(task: 'bundle', flavor: flavor, build_type: 'Release')
end

desc "Build all the flavors of our app"
lane :build do
    gradle(task: clean)
    build_flavor(flavor: 'Free')
    build_flavor(flavor: 'Paid')
end

Voilà pour l’exemple des options.

Quand je vous disais qu’il faut faire attention à ne pas trop factoriser, c’est aussi pour vos sensibiliser à garder un code qui fait des choses compréhensibles en le lisant, mais surtout à ne pas réécrire la roue.

Par exemple

desc "Build a given flavor of our app in a specific type"
lane :build_flavor do |options|
    flavor = options[:flavor]
    build_type = options[:build_type]
    gradle(task: 'bundle', flavor: flavor, build_type: build_type)
end

Pour faire ça, autant utiliser directement l’action gradle et ne pas faire une lane…

📨 Renvoyer nos résultats

Parfois, on va avoir envie que nos lanes renvoient des choses, par exemple un était ou même un résultat.

Par exemple, on pourrait renvoyer un emoji à la fin de notre build ! Pour cela, en ruby, il suffit de mettre la dernière action lancée ou variable utilisée en fin de lane, elle sera renvoyée automatiquement.

desc "Build a given flavor of our app"
lane :build_flavor do |options|
    flavor = options[:flavor]
    gradle(task: 'bundle', flavor: flavor, build_type: 'Release')
    "📦"
end

desc "Build all the flavors of our app"
lane :build do
    gradle(task: clean)
    result = build_flavor(flavor: 'Free')
    # result = "📦"
end

Bon, ok, on ne voit pas forcément l’intérêt tout de suite.

Mais, croyez-moi, ça viendra

🖨 Afficher des informations

Une dernière chose importante pour tout bon dev qui se respecte, ce sont les messages de retour dans la console.

Les vrais, ils débuguent au PRINT bordel (j’vais m’faire des potes ici).

Avouons-le, avoir des retours d’affichage, ça ne mange pas de pain et c’est toujours sympa de voir l’avancée au fur et à mesure.

Dans fastlane, une action existe déjà pour interagir avec l’utilisateur, c’est UI.

Avec UI, on va pouvoir afficher des messages, mais aussi prompter des choses à l’utilisateur si besoin.

J’ai tiré quelques exemples de la documentation officielle:

UI.message "Neutral message (usually white)"
UI.success "Successfully finished processing (usually green)"
UI.error "Wahaha, what's going on here! (usually red)"
UI.important "Make sure to use Windows (usually yellow)"

UI.header "Inputs" # a big box

name = UI.input("What's your name? ")
if UI.confirm("Are you '#{name}'?")
  UI.success "Oh yeah"
else
  UI.error "Wups, invalid"
end

UI.password("Your password please: ")

Pas mal et plutôt complet on est d’accord ?!

Dans notre situation, on peut par exemple informer qu’on va lancer un build sur une certaine flavor, donc notre Fastfile pourrait ressembler à

desc "Build a given flavor of our app"
lane :build_flavor do |options|
    UI.message "Building Android App with Flavor #{options[:flavor]}"
    flavor = options[:flavor]
    gradle(task: 'bundle', flavor: flavor, build_type: 'Release')
    UI.success "Application bundled"   
end

On pourrait même imaginer un cas où on aurait oublié de passer la flavor en paramètres et la demander à l’utilisateur

desc "Build a given flavor of our app"
lane :build_flavor do |options|
    flavor = ""
    if options[:flavor] && options[:flavor].to_s.length > 0
        flavor = options[:flavor]
    else
        UI.important "Oops, looks like the flavor is missing !"
        flavor = UI.input("What is the flavor you want to build ?")
    end 
    UI.message "Building Android App with Flavor #{flavor}"
    gradle(task: 'bundle', flavor: flavor, build_type: 'Release')
    UI.success "Application bundled"   
end

Ca en jette !


🥳 Pour résumer

On en est à la 2ème partie de notre tutos complet sur l’optimisation (mais surtout l’automatisation) de ses build Android.

Dans la première partie, nous avons vu comment faire en sorte de stocker nos clés de manière propre et sécurisée (hors git) et faire des releases en CLI.

Ici, nous venons de voir comment installer fastlane et l’utiliser pour builder notre application. 🚀

Comme nous avons pu le constater, grâce à fastlane, nous allons pouvoir, builder, afficher, lier et communiquer en retour pour nos applications.

De là, vous devez vous dire que vous pouviez vous passer par gradle pour faire tout ça… et c’est vrai ! 😤

La suite, maintenant que les bases sont posées, cela va être de déployer notre application !
Parce que c’est bien beau de faire un bundle de manière automatisée, mais si on doit l’envoyer à la main à nos testeurs, sur le store ou firebase, cela perd tout son intérêt. 🤫

Rendez-vous donc dans la 3ème partie de cette série pour voir ensemble: Comment déployer son application Android sur Firebase avec Fastlane. 🔥

1 – 📦 Builder et signer son application Android
2 – 🚀 Automatiser les builds avec Fastlane
3 (1) – 🔥 Déployer son application sur Firebase
3 (2) – 🛳 Déployer son application sur le Play Store
4 – 🤖 Utiliser Gitlab pour déployer son application lors d’un tag de release sur git.

Dernière modification: 9 novembre 2020