###### tags: `common` `guides` `CICD`
# CICD mobile Fastlane / github Actions
[toc]
## Introduction
Le but est de deployer sur Apple Store (TestFlight) et Play Store (Test Internes) de manière automatisé, en local et dans une CICD sur Github Actions.
**Déploiement Android :**
Play store attend un build "android app bundle" (.aab) avec un identifant d'app valide, un numéro de code de version incrémenté et signé avec la bonne keystore.
**Déploiement Apple :**
Play store attend un build "iOS App Store Package" (.ipa) avec un identifant d'app valide, un numéro de code de version incrémenté et signé avec un couple de certificat de distribution et provisionning profile valide.
Le build sera configuré, créer et signé en local, ou sur un runner github action et envoyé au stores via les API de chaque store.
Une fois les build uploadé sur TestFlight et PlayStore Test Interne.
### Prérequis
- Il faut un mac si vous souhaitez configurer une app ios.
- Il va vous falloir obtenir ou créer un certain nombre d'identifiants et certificats pour attester que l'on possède bien des droits de gestion/mise à jour sur notre app.
- Avant de faire des déploiement automatisé, il est conseillé d'upload un premier build manuellement (via xcode et google play console) et de Finaliser le renseignement des infos nécessaire sur les store. Un upload peut etre refusé si le propriétaire du compte n'a pas renseigné les infos nécessaire ou s'il n'a pas accepté les dernières règles (confidentialité ou autres).
### Certificats et identifiants nécessaires
:::warning
:warning: Si vous n'avez pas accès aux interfaces des store ou que vous n'avez pas les droits suffisants, rapprochez vous du propriétaire du compte de chacun des stores.
Certains éléments comme les clée api ne sont gérable que par des compte de haut niveau d'autorisation, vous devrez accompagner le propriétaire du compte pour les configurer et les obtenir.
:::
**Voici la liste des certificats et identifiants nécessaires ainsi que la façon de les obtenir :**
----
#### Android :
- un **"identifiant d'app"** : une sorte de nom de domaine inversé : com.company.app.dev par exemple.
:::warning
:warning: Une fois le premier build uplaod, il n'est possible d'upload que des build avec cet identifiant. Il est absolument impossible de modifier cet identifiant par la suite, en générale on essaye d'avoir le même que celui définit pour ios.
nb: Si vous avez pas encore publié votre app, vous pouvez la supprimer puis la recréer, c'est la seul solution pour changer cet identifiant.
:::
**Obtention :**




- une **uplaod keystore** valide : clée de signature unique pour une app android (on en peut pas uplaod le build s'il n'est aps signé avec la bonne keystore) la même clée peut etre utilisé pour plusieurs app.
:::warning
:warning: Une fois le premier build upload tout les autres uplaod doivent utiliser la même keystore. C'est très compliqué de faire changer la keystore reconnu pas le store une fois celui ci définit.
:::
**Obtention :**
Sur mac pour trouver le dossier ou l'outil keytool se trouve tapez cette commande :
```cmd
/usr/libexec/java_home
```
Cela devrais vous retourner un path tel que celui ci :
```
/Library/Java/JavaVirtualMachines/jdkX.X.X_XXX.jdk/Contents/Home
```
Utilisez la commande "cd" pour atteindre ce dossier puis
voici la commande pour générer une keystore depuis ce dossier:
```cmd
sudo keytool -genkey -v -keystore my-upload-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
```
Remplacez "my-key-alias" par un alias de votre choix, ou laissez le tel quel ce n'est pas très grave, mais ce sera votre alias de key.
Quand vous lancez la commande il vous sera demandé tout un tas d'infos :
Deux mots de passe (en générale on met le même), Nom et prénom, Unité organisationnelle, Entreprise, Ville, État, Code pays
Le mieux est de remplir ces information en fonction de votre situation, mais les seuls élément a bien retenir et noter sont les deux mot de passe.
Une fois terminé vous devriez trouvé la key "my-upload-key.keystore" à la racine de votre Dossier Utilisateur.
Si ce n'est aps le cas c'est qu'il a été créer dans le dossier ou la commande à été executé. Pour l'atteindre ouvrez le finder puis allez dans la barre du haut dans "Aller" > "Aller au dossier ..." et rentrer le même path que vous avez utilisé avec la commande "cd".




- les **infos de la keystore : keyAlias, keyPassword et storePassword** ( ces éléments sont choisis à la création de la clée, souvent les deux mot de passe sont identiques)
**Obtention :**
Lors de la création de votre Keystore vous avez définit le keyAlias dans la commande, et les deux mots de passe sont ceux définit lors de la création de la clé.




- un **JSON de clée api google** : pour s'identifier lors de l'upload automatique sur play store, peut upload toutes les app qui lui sont authorisé.
**Obtention :**
Le but est de créer une Key Api et de l'enregistrer comme utilisateur capable de gérer une ou des apps.
--> Connectez vous à [play.google.com/console](https://play.google.com/console) ne rentrez pas dans une app, dans le menu de gauche allez dans "Configuration" > Accès à l'API.
--> Scrollez jusqu'a "Identifiants" au niveau de "Compte de service". Vous devriez voir sur la droite un Texte gris "Découvrez comment créer des comptes de service" cliquez dessus.
--> Cela vous présente une modal avec les étapes à suivre, cliquez sur le lien de l'étape 1 (il vous dirige au bon endroit dans le site Google Cloud).
--> Assurez vous d'etre connecté sur avec le même compte que pour [play.google.com/console](https://play.google.com/console).
--> Si vous avez du changer de compte ou vous connecter, réutilisez le lien de l'étape 1 pour etre sur la bonne page.
--> Si vous avez une page blanche ou en erreur, voici la procedure pour atteindre la bonne page : cliquez sur le menu burger en haut a gauche > API et services > identifiants.
--> Dans la page, cliquez sur " + créer des identifiants" > "compte de service".
--> Entrez un nom pour le compte de service, cela va remplir le champs suivant.
--> Appuyez sur "Créer et continuer".
--> Séléctionnez le role "Utilisateur du compte de service".
--> Appuyez sur "Continuer".
--> L'étape suivante n'est pas utile ici, Appuyez sur "Ok" sans remplir les champs.
--> Vous avez créer un compte de service API google.
--> Cliquez sur votre nouveau compte dans la liste.
--> Allez dans l'onglet "Clés" du compte.
--> Cliquez sur "Ajouter une clé" > "Créer une clé" > "JSON".
--> Cela déclenche le téléchargement d'un fichier json **C'est votre clée API google.** mais ce n'est aps finit. Il faut donner des droit a votre compte de service sur votre app (comme si cétait un nouvel utilisateur).
:::warning
:warning: Conservez bien cette clé car vous ne pourrez pas la retélécharger, il faudra en créer une nouvelle et mettre à jour votre configuration de déploiement automatisé.
:::
--> Revenez sur [play.google.com/console](https://play.google.com/console) sur la page des Accès Api ou nous étions.
--> Si vous ne voyez pas votre nouveau compte de service, cliquez sur actualiser.
--> Au niveau de votre compte de service, appuyez sur "Gérer les autorisations de la Play console" pour définir les droits de ce compte.
--> Il y a 3 onglets, nous allons utiliser que les deux premiers :
"Autorisations de l'application" pour renseigner les application auquel ce compte a acces.
"Autorisations du compte" pour gérer les actions autorisées, En générale je coche tout sauf Administrateur et les données financières.
--> Enregistrez les modifications.
--> Votre compte de service est opérationnel et vous avez la clée pour l'utiliser.
----
#### iOS :
:::warning
:warning: Certains certificats ont une durée de validitée, il sera donc nécessaire d'anticiper et de les recréer un peut avant. Assurez vous ensuite de bien fournir les nouveau a toutes les personnes qui en ont besoin et d'update vos "secret de github".
:::
:::warning
:warning: Si les certificats ont déjà été crée et sont toujours valide, éviter de les recréer car cela pourrait invalider les précendents certificats. Il est donc préférable de vérifier si quelqu'un peut vous les fournir.
Si vous avez invalidé les précédents certificats, assurez vous de bien fournir les nouveau a toutes les personnes qui en ont besoin et d'update vos "secret de github".
:::
- l'**"identifiant d'app"** : une sorte de nom de domaine inversé : com.company.app.dev par exemple.
**Obtention :** il est définit à la création de l'app sur le compte apple store. Vous pouvez le retrouver sur [appstoreconnect.apple.com](http://appstoreconnect.apple.com/) allez dans Apps, selectionnez votre app, dans le menu de gauche allez dans "Informations sur l'app" et dans la section "Informations générale" vous trouverez "Identifiant de lot" c'est votre identifiant d'app.




- un **certificat de distribution p12** (signe l'app pour authoriser son upload sur le compte apple store propriétaire de l'app, le même certificat peut etre utilisé pour différentes apps) le format .p12 permet de partager le fichier protégé par un mot de passe pour qu'une autre personne ou un runner puisse l'installer sur sa machine MacOS.
**Obtention :** [Voici un guide qui explique toutes les étapes dont vous avez besoin pour génerer ce fichier.](https://sarunw.com/posts/how-to-share-ios-distribution-certificate/)
En résumé : il faut un mac pour générer une demande de certificat puis créer un certificat de distribution (.cer) sur [developer.apple.com](https://developer.apple.com), l'installer sur votre mac puis l'exporter au format .p12 en définissant un mot de passe.




- le **mot de passe du certificat de distribution p12** ex : "distribution.p12"
**Obtention :** c'est le mot de passe que vous avez définit lors de l'export de votre **certificat de distribution p12**




- un **mobile provisionning profile de distribution** (spécifique à l'app, lié au certificat de distribution et permet signer l'app) ex: "distribution.mobileprovision"
**Obtention :** Pour le générer il faut que l'app soit déja crée l'app sur le store et que vous aillez déjà crée un certificat de distribution pour pouvoir lier le profile à ces deux éléments. La création se passe sur [developer.apple.com](https://developer.apple.com).
[Voici un guide pour générer un profile de distribution](https://support.staffbase.com/hc/en-us/articles/115003598691-Creating-the-iOS-Provisioning-Profiles)




- une **clée apple api et identifiants de clée** : key_id, issuer_id et la clée .P8 (permet de s'identifier pour upload sur app store) permet d'upload toutes les apps d'un même compte apple store.
**Obtention :** Il faut d'abord créer la clée sur [appstoreconnect.apple.com](http://appstoreconnect.apple.com/)
[Voici la doc apple pour créer cette clée](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api)
Une fois la clée crée et téléchargé au format .P8 vous pouvez la retrouver dans [appstoreconnect.apple.com](http://appstoreconnect.apple.com/) > "Utilisateurs et accès" > onglet "Clés". vous devriez voir la liste de vos clée. Au dessus de la liste vous trouverez la "Issuer ID", c'est votre "issuer_id" et au niveau de chaque clées dans la colonne "IDENTIFIANT DE LA CLÉ" vous trouverez le "key_id".
:::warning
:warning: Vous ne pouvez télécharger cette clée qu'une fois, donc il faut bien la conserver, sinon il faudra en crée une nouvelle et ajuster vos configurations de deploiement automatisé.
:::
## Configuration du Projet
**Il est fortement déconseillé de publier ses clée et identifiant sur son git. il est donc préférable de commencer par update son fichier .gitignore pour protéger les fichier que nous allons ajouter.**
Ajoutez ces ligne à votre fichier **.gitignore** :
```.gitignore
#fastlane
*/fastlane/.env
*/fastlane/.env.*
# fastlane android
**/android/fastlane/google-cloud-api-key.json
**/android/key.properties
*.jks
# fastlane ios
*.p8
*.p12
**/ios/fastlane/appleApiKey.json
**/Gemfile.lock
**/ios/tmp.xcconfig
*.dSYM.zip
```
Adaptez selon votre projet mais aucun des fichiers senssibles ne doivent etre commit.
Nous allons configurer le projet pour qu'il soit pret pour des déploiement manuels, automatisé en local et automatisé sur github actions.
### Android
#### 1 - Configuration de la signature des build.
Nous allons ajouter la clée de signature et les infos de la clé dans notre projet, puis les utiliser pour configurer la signature.
:::warning
:warning: Si vous avez plusieurs environement de configuré, vous pouvez procéder de la même façon pour chacun. Vous trouverez la section [Environnements multiples](#Environnements-multiples) dans ce document qui donne plus de détails sur la gestion de multiples environnements.
:::
- Placez votre fichier "my-upload-key.keystore" dans ./android/app et renommez le en "my-upload-key.jks"
- Créez un fichier "key.properties" dans ./android avec ce contenu adapté à votre keystore :
```
# upload keystore
storeFile=my-upload-key.jks
keyAlias=my-key-alias
keyPassword=*******
storePassword=*******
```
- Ajouter ces lignes dans ```./android/app/build.gradle``` juste avant ```android {```
```diff
//....
+/**
+ * Get upload key properties from key.properties.
+ */
+def keystoreProperties = new Properties()
+def keystorePropertiesFile = rootProject.file('key.properties')
+if (keystorePropertiesFile.exists()) {
+ keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+}
android {
//....
```
Nous avons désormais accès au variables de notre key.properties dans ./android/app/build.gradle nous allons nous en servir pour définir la config de signature.
- Éditez la partie ```signingConfigs``` dans ```./android/app/build.gradle```
Créer ou éditez la partie release comme suis :
```diff
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
+ release {
+ keyAlias keystoreProperties['keyAlias']
+ keyPassword keystoreProperties['keyPassword']
+ storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null
+ storePassword keystoreProperties['storePassword']
+ }
}
```
Éditez la partie ```buildTypes``` dans ```./android/app/build.gradle```
Créer ou éditez la partie release comme suis :
```diff
buildTypes {
...
release {
...
+ signingConfig signingConfigs.release
...
}
}
```
De cette façon les build release vont se signer selon les config de notre fichier ```key.properties```
Biensûr vous pouvez adapater cette méthode si vous avez crée d'autre build type que debug et release.
#### 2 - Définir ou vérifier les identifiant de l'app et sa version.
Si vous voulez gérer plusieurs environnements via des fichier .env vous pouvez passer directement à l'étape 4.
Éditez la partie ```defaultConfig``` dans ```./android/app/build.gradle```
Vérifier ou éditez les champs "applicationId", versionCode et versionName :
```diff
defaultConfig {
applicationId com.company.app
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0.0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
//...
```
**applicationId :** a remplacer par votre "identifiant d'app"
**versionCode :** playStore demande une incrémentation à chaque upload ou refurea votre build.
**versionName :** version actuelle de votre projet, tant que le versionCode est incrémenté, on peut soumettre autant de fois que l'on veux le même versionName
### iOS
#### 1 - Installer les certificats
Il faut installer le **"certificat de distribution p12"** dans votre "trouseau d'accès" mac.
Pour cela double cliquez dessus une fenetre va vous demander le mot de passe du certificat .p12. Entrez le mot de passe puis vérifiez que le certificat apparait bien dans la parti "certificat" de l'application mac "trouseau d'accès".
Ensuite il faut declarer à xcode le **"mobile provisionning profile de distribution"**. Pour cela double cliquez sur le fichier, cela devrait ouvrir xcode ou focus sur votre fenetre xcode.
#### 2 - Définir les identifiants et les certificats du projet
Ouvrez votre projet (dossier ./ios de votre projet react-native) dans xcode.
Dans la barre de gauche selectionnez votre project (premier dossier de la liste, avec un icone bleu).
Dans la partie centrale vous pouvez désromais voir une autre barre de gauche qui vous présente le projet et ces "targets".
Selectionnez votre "target".
:::warning
:warning: Si vous avez plusieurs targets de configuré, vous pouvez procéder de la même façon pour chacune. Vous trouverez la section [Environnements multiples](#Environnements-multiples) dans ce document qui donne plus de détails sur la gestion de multiples environnements.
:::
Vous avez mainteant les configuration de votre "target" dans la partie centrale avec plusieurs onglets.
- Dans l'onglet "Build Settings"
--- section "Packaging" définissez ou vérifiez les valeurs suivantes :
**Bundle identifier :** cela doit etre l'"identifiant d'app"
--- section "Signing" définissez ou vérifiez les valeurs suivantes :
**Code signing style :** la valeur doit etre "manual"
**Code signing identity :** la valeur doit etre celle de votre certificat de distribution
**Development Team :** la valeur doit correspondre à l'identifiant d'équipe de votre certificat de distribution. Vous pouvez le voir entre parenthèse sur le champ précédent (Code signing identity)
**Provisionning Profile:** sélectionnez votre provisionning profile. (il vous sera proposé que les provisionning profile correspondant a votre bundle identifier et à votre certificat de distribution)
Assurez vous que chacune de ses configurations soit à chaque fois identique pour debug et release
- Dans l'onglet "General" vérifiez qu'il n'y a pas de message d'alerte. s'il y en a une, vérifiez bien la correspondance bundle identifier/certificat de distribution/team/provisionning profile et que les certificats sont toujours valides.
Votre "target" est à présent configuré pour etre signé et envoyé sur l'appStore manuellement.
## Déploiement Manuel
### Android
#### 1 - Build
Depuis la racine de votre projet React-native executez la commande :
```cd ./android && ./gradlew bundleRelease```
si vous avez plusieurs environnement de configurez adaptez "bundleRelease" pour définir la bonne cible, ex: "bundleDevRelease".
(Vous pouvez vous créer un script dans votre fichier ```./package.json```)
Cette commande va produire un fichier android app bundle (.aab) à l'emplacement ```./android/app/build/outputs/bundle/release/app-release.aab```
#### 2 - Upload sur le store
:::danger
:warning: Attention si c'est votre premier déploiement de cette app, elle va définir l'**upload key de référence** et l'**identifiant de l'app**. Assurez vous donc que vous avez bien rangé et sécurisé un exemplaire de votre upload key et ses identifiants. Assurez vous aussi que l'identifiant d'app que vous avez renseigné pour ce build ( via ./android/app/build.gradle ou via votre .env) est bien celui que vous voulez donner à cette app.
:::
**Si vous avez bien lu le message d'alerte ci dessus**, connectez vous à [play.google.com/console](https://play.google.com/console), selectionnez votre app puis allez dans le menu de gauche Tests > "Tests internes" et créez une nouvelle release.
Dans la partie App bundles, cliquez sur Importer et choissisez votre .aab que vous venez de produire dans le folder ```./android/app/build/outputs/bundle/release/app-release.aab``` puis attendez que le fichier soit uploadé, et finalisez la soumission de la release.
### iOS
#### 1 - Build
Pour build l'app iOS il faut utiliser XCode. Lancez Xcode et ouvrez le dossier ios de votre project react-native.
Une fois le projet chargé dans Xcode, dans la partie centrale haute de la fenetre Xcode, choisissez comme device cible```Any iOS Device (arm64)```. Si vous avez plusieurs environnements de configuré, choisissez le "scheme" correspondant.
Dans le menu mac de l'app xcode (barre collé en haut de l'écran) aller dans "product" > "archive".
Cela va prendre un peut de temps et produire un fichier .ipa. Une fois l'opération terminé xcode ouvre automatiquement une fenêtre "Organizer" qui vous permet de voir toutes vos archives d'.ipa.
Si vous avez perdu/fermé la fenetre "organizer" vous pouvez l'ouvrir a tout moment dans le menu mac de l'app xcode (barre collé en haut de l'écran) en allant dans "window" > "organizer".
La suite consiste a envoyer l'app sur appstore (étape suivante).
#### 2 - Upload sur le store
Dans la fenetre "organizer" d'xcode selectionnez le build .ipa que vous voulez envoyer sur appStore.
Cliquez sur "distribute app" et suivez les étapes sans rien changer jusqu'a arriver a l'étape qui demande de choisir un "provisionning profile", choisissez votre provisionning profile. puis continuez simpelment de valider les étapes suivantes.
Si vos config de projet, d'app et vos version sont accceptable par appstore l'upload devrait etre accepté et vous retrouverez sur [appstoreconnect.apple.com](http://appstoreconnect.apple.com/) dans la partie Testflight de votre app un nouveau build.
## Fastlane
Fastlane permet de simplifier les comandes et configuration pour automatiser les déploiement. Il va nous aider pour nos déploiement locaux mais aussi pour les déploiement via github action.
[Voici le site de fastlane](https://fastlane.tools)
### Install fastlane
Fastlane doit tout d'abord etre installé sur votre machine, voici deux commande pour l'installer :
```
# Using RubyGems
sudo gem install fastlane -NV
# Alternatively using Homebrew
brew cask install fastlane
```
### Android
Nous n'allons pas configurer fastlane via leur commande car nous voulons gérer nous même les configuration.
Voici les étapes à suivre:
#### 1 - Ajouter la clée Api Google Cloud
Cet clée va nous permettre de nous identifier er de publier sur le store google play via l'api.
- créez un dossier "./android/fastlane"
- Ajouter votre fichier json de clée API Google Cloud dans ```./android/fastlane```et nommez la ```google-cloud-api-key.json```
#### 2 - Setup fastlane
- créez ou éditez un fichier "./android/Gemfile" avec ce contenu :
```ruby
source "https://rubygems.org"
gem "fastlane"
```
- créez un fichier "./android/fastlane/Appfile" avec ce contenu :
```ruby
require 'dotenv'
Dotenv.load
json_key_file("./fastlane/google-cloud-api-key.json")
package_name('votre.identifiant.app')
# to use env variables :
#json_key_file ENV["GOOGLE_API_KEY_PATH"]
#package_name ENV["REACT_APP_PACKAGE_IDENTIFIER"]
```
Explication:
```ruby
require('dotenv')
Dotenv.load
```
Permet de récupérer les varibales de votre fichier .env ou celui défini dans la commande de lancement de fastlane.
ex : ```fastlane internal --env production``` lancera fastlane "internal" avec les variables de ```.env.production```
:::warning
:warning: attention fastlane vachercher le .env dans le folder fastlane. Nous verrons plus tard que pour éviter de mutiplier les .env nous allons créer une commande pour cloner le .env à la racine de votre projet vers les folder fastlane.
De plus il faut noter que ces variable ne seront utilisé que pour fastlane, cela n'affecte pas votre build js ou votre build native
:::
```ruby
json_key_file ENV["GOOGLE_API_KEY_PATH"]
package_name ENV["REACT_APP_PACKAGE_IDENTIFIER"]
```
**json_key_file** doit etre nourrit avec le path ou vous avez rengé votre clée api google.
Ce path est relatif au folder 'android', pour notre cas nous pouvons le définir directement ou ajouter ce paramètre au fichier .env :
```env
GOOGLE_API_KEY_PATH="./fastlane/google-cloud-api-key.json"
```
**package_name** est l'identifiant de votre app, pour notre cas nous pouvons le définir directement ou ajouter a votre fichier .env :
```env
REACT_APP_PACKAGE_IDENTIFIER="votre.identifiant.app" # éditez avec votre identifiant
```
Si vous avez plusieurs environnement, adaptez ces valeurs selon vos besoin dans chacun de vos fichers env.




- créez un fichier "./android/fastlane/Fastfile" avec ce contenu :
```ruby
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
default_platform(:android)
platform :android do
desc "Submit a new production Build to internal tests"
lane :internal_production do
gradle(task: "clean bundleRelease")
upload_to_play_store(
skip_upload_metadata: true,
skip_upload_changelogs: true,
skip_upload_screenshots: true,
skip_upload_images: true,
skip_upload_apk: true,
track: 'internal'
)
end
end
```
Explications :
Voici la partie qui défini votre lane de deploiement
```ruby
desc "Submit a new production Build to internal tests"
lane :internal_production do
gradle(task: "clean bundleRelease")
upload_to_play_store(
skip_upload_metadata: true,
skip_upload_changelogs: true,
skip_upload_screenshots: true,
skip_upload_images: true,
skip_upload_apk: true,
track: 'internal'
)
end
```
**gradle(task: "clean bundleRelease")** crée le build que vous souhaitez uplaod, ici un cas simple : "bundleRelease". Vous pouvez multiplier les lanes ou définir dynamiquement votre type de build.
**upload_to_play_store()** permet de configurer l'uplaod, **"track"** permet de définir dans quel canal créer une nouvelle release sur le compte store. Vous pouvez définir d'autres canaux de déploiement, ex :
'internal' > test internes
'alpha' > test sur le canal alpha
'beta' > test beta
Vous pouvez multiplier les lanes ou définir dynamiquement votre canal.
- créer un script et ajouter une commande dans votre fichier "package.json"
créer un folder "./scripts" à la racine de votre projet.
créez un fichier "publish_android.sh" dan votre dossier "scripts" avec ce contenu.
:::warning
:warning: Remplacez "nomDeVotreLane" par le nom de votre lane.
:::
```bash
#!/bin/bash
echo "Copy .env files to ./android/fastlane/ folder"
# copy needed .env to android fastlane folder
[ -f .env ] && cp .env ./android/fastlane/.env
[ -f .env.default ] && cp .env.default ./android/fastlane/.env.default
echo "Start android Fastlane: nomDeVotreLane"
# start fastlane
cd ./android && fastlane nomDeVotreLane
```
si vous avez plusieurs environnement vous pouvez ajuster comme suis :
```bash
#!/bin/bash
# check
if [ -n "$1" ]; then
ENVIRONNEMENT=$1
else
echo "load default config"
ENVIRONNEMENT=""
fi
echo "SELECTED ENV: $ENVIRONNEMENT"
echo "SELECTED LANE: nomDeVotreLane$ENVIRONNEMENT"
# copy needed .env to android fastlane folder
[ -f .env ] && cp .env ./android/fastlane/.env
[ -f .env.default ] && cp .env.default ./android/fastlane/.env.default
[ -f .env.${ENVIRONNEMENT} ] && cp .env.${ENVIRONNEMENT} ./android/fastlane/.env.${ENVIRONNEMENT}
# start fastlane
cd ./android && fastlane nomDeVotreLane${ENVIRONNEMENT} --env ${ENVIRONNEMENT}
```
Ajustez et ajouter ces lignes dans la partie "scripts" de votre fichier "package.json"
```diff
"scripts": {
//...
+ "publish:android": "./scripts/publish_android.sh",
+ "publish:android:production": "./scripts/publish_android.sh production",
//...
},
```
Explications :
ces commandes vont déclencher votre script "publish_android.sh".
Si vous avez plusieurs environnements il accepte un seul paramètre pour gérer diférents environnements ici "production".
la première commande vous permet de définir librement votre environnement cible ex :
```yarn publish:android``` si vous n'avez qu'un environnement (cela utilisera le .env)
```yarn publish:android production```
```yarn publish:android development```
la seconde commande est plus strict et peut vous éviter de lancer la commande pour un environnement qui n'existe pas.
```yarn publish:android:production```
#### 3 - Créer la lane pour le déploiement local automatisé
### Ios
Nous n'allons pas configurer fastlane via leur commande car nous voulons gérer nous même les configuration.
Voici les étapes à suivre:
#### 1 - Ajouter la clée Api Apple
Cet clée va nous permettre de nous identifier er de publier sur le store apple via l'api.
Ajouter votre fichier json de clée API Apple dans ```./ios/fastlane```et nommez la ```appleApiKey.json```
#### 2 - Setup fastlane
- créez ou éditez un fichier "./android/Gemfile" avec ce contenu :
```ruby
source "https://rubygems.org"
gem "fastlane"
```
- créez un dossier "./ios/fastlane"
- créez un fichier "./ios/fastlane/Appfile" avec ce contenu :
```ruby
require('dotenv')
Dotenv.load
#Set here global fastlane values
# to get variables from .env files : ENV["MY_VAR_NAME"]
```
Explication:
```ruby
require('dotenv')
Dotenv.load
```
Permet de récupérer les varibales de votre fichier .env ou celui défini dans la commande de lancement de fastlane.
ex : ```fastlane nomDeVotreLane --env production``` lancera fastlane avec les variables de ```.env.production```
:::warning
:warning: attention fastlane va chercher le .env dans le folder fastlane. Nous verrons plus tard que pour éviter de mutiplier les .env nous allons créer une commande pour cloner le .env à la racine de votre projet vers les folder fastlane.
:::
- créez un fichier "./ios/fastlane/Fastfile" avec ce contenu :
:::warning
:warning: Remplacez "projectName.xcworkspace" par le nom de votre fichier .xcworkspace et "schemeName" par le nom du scheme que vous voulez utiliser.
:::
```ruby
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
#
# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane
require('dotenv')
Dotenv.load
# to get variables from .env files : ENV["MY_VAR_NAME"]
opt_out_usage # prevent metrics track from fastlane
default_platform(:ios)
platform :ios do
desc "Push a new beta build to TestFlight localy"
lane :testFlight_production do
build_app(workspace: "projectName.xcworkspace", scheme: "schemeName")
upload_to_testflight(
skip_waiting_for_build_processing: true
api_key_path: "fastlane/appleApiKey.json",
)
end
end
```
**Explications :**
```ruby
require('dotenv')
Dotenv.load
# to get variables from .env files : ENV["MY_VAR_NAME"]
```
Cette partie vous permet d'accéder aux variables d'environnement si vous voulez par exemple faire varier la valeur de`api_key_path`.
Voici la partie qui défini votre lane de deploiement
```ruby
desc "Push a new beta build to TestFlight localy"
lane :testFlight_production do
build_app(workspace: "projectName.xcworkspace", scheme: "schemeName")
upload_to_testflight(
skip_waiting_for_build_processing: true
api_key_path: "fastlane/appleApiKey.json",
)
end
```
**lane :testFlight_production** déclare le nom de votre lane, si vous devez gérer plusieurs environnement vous pouvez déclarer plusieurs lanes qui ciblent différents schemes.
**build_app()** prépare un build signé de votre projet avec les configuartion du scheme choisis. (script de prebuild, identifiants, certificats définits,...) Il est donc nécessaire d'avoir installé correctement les certificats sur son mac.
**upload_to_testflight()** comme son nom l'indique permet d'envoyer le build à testflight,
**skip_waiting_for_build_processing** permet d'éviter à notre lane d'attendre d'autre retour d'apple que la conformation de l'acceptation de l'upload. sans cela l'attente des vérifications et autre validation user, peuvent durer longtemps, voir être infini.
- **créer un script et ajouter une commande dans votre fichier "package.json"**
créer un folder "./scripts" à la racine de votre projet.
créez un fichier "publish_ios.sh" dan votre dossier "scripts" avec ce contenu.
:::warning
:warning: Remplacez "nomDeVotreLane" par le nom de votre lane.
:::
```bash
#!/bin/bash
echo "Copy .env files to ./ios/fastlane/ folder"
# copy needed .env to ios fastlane folder
[ -f .env ] && cp .env ./ios/fastlane/.env
[ -f .env.default ] && cp .env.default ./ios/fastlane/.env.default
echo "Start ios Fastlane: nomDeVotreLane"
# start fastlane
cd ./ios && fastlane nomDeVotreLane
```
si vous avez plusieurs environnement vous pouvez ajuster comme suis :
```bash
#!/bin/bash
# check
if [ -n "$1" ]; then
ENVIRONNEMENT=$1
else
echo "load default config"
ENVIRONNEMENT=""
fi
echo "SELECTED ENV: $ENVIRONNEMENT"
echo "SELECTED LANE: nomDeVotreLane$ENVIRONNEMENT"
# copy needed .env to ios fastlane folder
[ -f .env ] && cp .env ./ios/fastlane/.env
[ -f .env.default ] && cp .env.default ./ios/fastlane/.env.default
[ -f .env.${ENVIRONNEMENT} ] && cp .env.${ENVIRONNEMENT} ./ios/fastlane/.env.${ENVIRONNEMENT}
# start fastlane
cd ./ios && fastlane nomDeVotreLane${ENVIRONNEMENT} --env ${ENVIRONNEMENT}
```
Ajustez et ajouter ces lignes dans la partie "scripts" de votre fichier "package.json"
```diff
"scripts": {
//...
+ "publish:ios": "./scripts/publish_ios.sh",
+ "publish:ios:production": "./scripts/publish_ios.sh production",
//...
},
```
Explications :
ces commandes vont déclencher votre script "publish_ios.sh".
Si vous avez plusieurs environnements il accepte un seul paramètre pour gérer diférents environnements ici "production".
la première commande vous permet de définir librement votre environnement cible ex :
```yarn publish:ios``` si vous n'avez qu'un environnement (cela utilisera le .env)
```yarn publish:ios production```
```yarn publish:ios development```
la seconde commande est plus strict et peut vous éviter de lancer la commande pour un environnement qui n'existe pas.
```yarn publishios:production```
## github actions
### 1 - définir les lane fastlane pour les github action
#### ANDROID
La lane android local est valable pour les github actions.
#### iOS
Pour pouvoir signer le build le runner de github action va devoir installer les certificats.
Cela implique que nous allons devoir créer une lane qui gère cela.
Voici la lane:
:::warning
:warning: Remplacez "projectName.xcworkspace" par le nom de votre fichier .xcworkspace et "schemeName" par le nom du scheme que vous voulez utiliser.
:::
```ruby
desc "Push a new build to TestFlight via github actions"
lane :testFilghtGithub do |options|
if options[:certificate_password]
# extract options to a variable
certificate_password = options[:certificate_password]
end
create_keychain(
name: 'ios_app_keychain',
password: certificate_password,
timeout: 1800,
default_keychain: true,
unlock: true,
lock_when_sleeps: false
)
import_certificate(
certificate_path: 'distribution.p12',
certificate_password: certificate_password,
keychain_name: 'ios_app_keychain',
keychain_password: certificate_password
)
install_provisioning_profile(path: 'distribution.mobileprovision')
update_project_provisioning(
xcodeproj: 'projectName.xcodeproj',
target_filter: 'github',
profile: 'distribution.mobileprovision',
build_configuration: 'Release'
)
build_app(workspace: "projectName.xcworkspace", scheme: "schemeName")
upload_to_testflight(
api_key_path: "fastlane/appleApiKey.json",
skip_waiting_for_build_processing: true
)
end
```
**Explications:**
```ruby
if options[:certificate_password]
# extract options to a variable
certificate_password = options[:certificate_password]
end
```
Cette partie permet de récupérer la valeur `certificate_password` des options de la fastlane. (ce mot de passe est celui du certificat .p12 et sera stocké dans les secrets github)
Pour passer des options il suffi d'ajouter `nom_option:valeur` à une commande lancement fastlane, ex:
`fastlane nomDeLane nom_option:valeur nom_option_2:valeur`
Nous verrons juste après comment nous allons gérer cela avec le script déclaré dans le `package.json`.
```ruby
create_keychain(
name: 'ios_app_keychain',
password: certificate_password,
timeout: 1800,
default_keychain: true,
unlock: true,
lock_when_sleeps: false
)
```
Cette partie permet de créer une keychain sur le runner macOS et de définir son password avec notre variable de mot de passe. (on utilise le password du certificat .p12 pour éviter de multiplier les variables pour rien)
```ruby
import_certificate(
certificate_path: 'distribution.p12',
certificate_password: certificate_password,
keychain_name: 'ios_app_keychain',
keychain_password: certificate_password
)
```
Cette partie permet d'importer le certificat de distribution .p12 en utilisant notre variable de password pour le fichier .p12 et la keychain.
```ruby
install_provisioning_profile(path: 'distribution.mobileprovision')
```
Cette partie permet d'importer notre mobile provisionning profile dans xcode su runner.
```ruby
update_project_provisioning(
xcodeproj: 'projectName.xcodeproj',
target_filter: 'github',
profile: 'distribution.mobileprovision',
build_configuration: 'Release'
)
```
Cette partie permet de s'assurer que le mobile provisionning profile du projet xcode cible bien celui que nous avons importé.
```ruby
build_app(workspace: "projectName.xcworkspace", scheme: "schemeName")
upload_to_testflight(
api_key_path: "fastlane/appleApiKey.json",
skip_waiting_for_build_processing: true
)
```
Cette partie reste la même que la fastlane locale, on build puis upload l'app.
### 2 - créer un script pour copier les fichiers d'env et lancer la lane github
Ajustez et ajouter ces lignes dans la partie "scripts" de votre fichier "package.json"
```diff
"scripts": {
//...
+ "publish:ios:github": "./scripts/publish_ios_github.sh",
//...
},
```
créez un fichier "publish_ios_github.sh" dan votre dossier "scripts" avec ce contenu.
```bash
#!/bin/bash
# check
if [ -n "$1" ]; then
DISTRIBUTION_P12_PASSWORD=$1
else
echo "load default config"
DISTRIBUTION_P12_PASSWORD=""
fi
echo "Copy .env files to ./ios/fastlane/ folder"
# copy needed .env to ios fastlane folder
[ -f .env ] && cp .env ./ios/fastlane/.env
[ -f .env.default ] && cp .env.default ./ios/fastlane/.env.default
echo "Start ios Fastlane: testFlightGithub"
# start fastlane
cd ./ios && fastlane testFlightGithub certificate_password:${DISTRIBUTION_P12_PASSWORD}
```
Ce script sera utilisé dans le workflow github ios et nous lui passeront le DISTRIBUTION_P12_PASSWORD issue des secret en paramètre $1.
### 3 - créer les jobs github actions
Créez un dossier ".github" à la racine de votre repo puis créez un dossier "workflows" dans votre dossier ".github". (il est probable que ces dossiers existent déjà)
et enfin créez un fichier "release-android.yml" et un fichier "release-ios.yml" dans votre dossier "workflows"
Dans votre dossier ".github/workflows/release-android.yml" incérez ce contenu :
```yml
name: release-android
on:
workflow_dispatch:
concurrency:
cancel-in-progress: true
group: release-android
# Needed secrets :
# DOTENV
# GOOGLE_CLOUD_API_KEY_B64
# KEY_PROPERTIES
# KEYSTORE_B64
jobs:
release-android:
name: Build and release Android app
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: "16.x"
cache: 'yarn'
cache-dependency-path: "app/yarn.lock"
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: "zulu"
java-version: 11
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- uses: actions/setup-ruby@v1
with:
ruby-version: "2.x"
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Write .env
shell: bash
run: |
echo "${{ secrets.DOTENV}}" > app/.env
- name: Write Google Cloud API Key
shell: bash
run: |
echo "${{ secrets.GOOGLE_CLOUD_API_KEY_B64}}" | base64 --decode > app/android/fastlane/google-cloud-api-key.json
- name: Write key properties
shell: bash
run: |
echo "${{ secrets.KEY_PROPERTIES}}" > app/android/key.properties
- name: Write key store
shell: bash
run: |
echo "${{ secrets.KEYSTORE_B64}}" | base64 --decode > app/android/app/my-upload-key.jks
- name: Install Fastlane
run: cd app/android && bundle install
- name: Install packages
run: cd app && yarn install
- name: Execute Fastlane command
run: cd app && yarn publish:android
```
Dans votre dossier ".github/workflows/release-ios.yml" incérez ce contenu :
```yml
name: release-ios
on:
workflow_dispatch:
concurrency:
cancel-in-progress: true
group: release-ios
# Needed secrets :
# DOTENV
# APPLE_API_KEY_SETTINGS_B64
# DISTRIBUTION_P12_B64
# DISTRIBUTION_P12_PASSWORD
# DISTRIBUTION_MOBILE_PROVISION_B64
jobs:
release-ios:
name: Build and release Ios app
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: "16.x"
cache: 'yarn'
cache-dependency-path: "app/yarn.lock"
- uses: actions/setup-ruby@v1
with:
ruby-version: "2.x"
- name: Cache CocoaPods packages
uses: actions/cache@v3
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
- name: Write .env
shell: bash
run: |
echo "${{ secrets.DOTENV}}" > app/.env
- name: Write Apple API Key config
shell: bash
run: |
echo "${{ secrets.APPLE_API_KEY_SETTINGS_B64}}" | base64 --decode > app/ios/fastlane/appleApiKey.json
- name: Write distribution.p12 file
shell: bash
run: |
echo "${{ secrets.DISTRIBUTION_P12_B64}}" | base64 --decode > app/ios/distribution.p12
- name: Write distribution.mobileprovision file
shell: bash
run: |
echo "${{ secrets.DISTRIBUTION_MOBILE_PROVISION_B64}}" | base64 --decode > app/ios/distribution.mobileprovision
- name: Install Fastlane
run: cd app/ios && bundle install
- name: Install packages
run: cd app && yarn install
- name: Install pods
run: cd app/ios && pod install
- name: Execute Fastlane command
run: cd app && yarn publish:ios:github ${{ secrets.DISTRIBUTION_P12_PASSWORD}}
```
**Explications :**
:::warning
:warning: Dans l'exemple nous travaillons dans un monorepo partagé entre l'app et son api. Si votre repo contient directement votre projet react-native ou que le path de votre projet est différent, vous devez adapter les path d'écriture de fichiers et les path des commandes selon votre structure de repo.
:::
- **Parties communes au deux fichiers .yml de workflows github :**
```yml
name: release-ios # release-android pour la version android
```
Cette partie déclare le nom du workflow.
```yml
on:
workflow_dispatch:
```
Cette partie déclare les cas déclenchement du workflow. Dans notre cas nous permettons de lancer manuellement votre workflows une fois qu'il est présent sur la branch master.
```yml
concurrency:
cancel-in-progress: true
group: release-ios # release-android pour la version android
```
Cette partie permet de cancel un workflow en cours si notre workflow est lancé. Dans notre cas le workflow `release-ios` annule les workflow
```yml
# Needed secrets :
# DOTENV
# APPLE_API_KEY_SETTINGS_B64
# DISTRIBUTION_P12_B64
# DISTRIBUTION_P12_PASSWORD
# DISTRIBUTION_MOBILE_PROVISION_B64
```
Ce commentaire liste simplement les secrets nécessaire au workflow. (ici ceux d'ios)
```yml
jobs:
release-ios:
name: Build and release Ios app
runs-on: macos-latest
steps:
```
Dans cette partie nous déclarons les jobs, dans notre cas 1 seul sera déclar: `release-ios`
`name`indique le nom d'affichage du job
`runs-on` définit le runner **macos-lastest** pour ios et **ubuntu-latest** pour android( type de machine qui doit faire tourner notre job)
`steps:` ouvre la liste des étapes que l'on veux suivre
```yml
- uses: actions/checkout@v2
- uses: actions/setup-node@v3
with:
node-version: "16.x"
cache: 'yarn'
cache-dependency-path: "app/yarn.lock"
```
`- uses:` Déclare l'utilisation d'actions gitflow de la communauté
`actions/checkout@v2` permet de checkout notre repo sur la machine (il peut etre configuré pour récupérer les sous repo ou autres)
`actions/setup-node@v3` permet d'installer/utiliser une version précise de node, ici on configure aussi le cache des modules yarn
- **Parties Ios :**
```yml
- uses: actions/setup-ruby@v1
with:
ruby-version: "2.x"
- name: Cache CocoaPods packages
uses: actions/cache@v3
with:
path: Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
```
**actions/setup-ruby@v1** permet de définir la version de ruby à utiliser
**actions/cache@v3** permet de mettre en place du cache sur les modules pods.
```yml
- name: Write .env
shell: bash
run: |
echo "${{ secrets.DOTENV}}" > app/.env
- name: Write Apple API Key config
shell: bash
run: |
echo "${{ secrets.APPLE_API_KEY_SETTINGS_B64}}" | base64 --decode > app/ios/fastlane/appleApiKey.json
- name: Write distribution.p12 file
shell: bash
run: |
echo "${{ secrets.DISTRIBUTION_P12_B64}}" | base64 --decode > app/ios/distribution.p12
- name: Write distribution.mobileprovision file
shell: bash
run: |
echo "${{ secrets.DISTRIBUTION_MOBILE_PROVISION_B64}}" | base64 --decode > app/ios/distribution.mobileprovision
- name: Install Fastlane
run: cd app/ios && bundle install
- name: Install packages
run: cd app && yarn install
- name: Install pods
run: cd app/ios && pod install
- name: Execute Fastlane command
run: cd app && yarn publish:ios:github ${{ secrets.DISTRIBUTION_P12_PASSWORD}}
```
La suite des étapes sont de simple run de commandes d'install de fastlane, d'install de modules node et pod et des création de fichiers en utilisant des secrets.
- **Parties Android :**
```yml
- name: Setup JDK 11
uses: actions/setup-java@v2
with:
distribution: "zulu"
java-version: 11
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- uses: actions/setup-ruby@v1
with:
ruby-version: "2.x"
- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
```
**actions/setup-java@v2** permet de définir le JDK Java à installer
**android-actions/setup-android@v2** permet de configurer le SDK android
**actions/setup-ruby@v1** permet de définir la version de ruby à utiliser
**actions/cache@v3** permet de mettre en place du cache sur les modules gradle.
```
- name: Write .env
shell: bash
run: |
echo "${{ secrets.DOTENV}}" > app/.env
- name: Write Google Cloud API Key
shell: bash
run: |
echo "${{ secrets.GOOGLE_CLOUD_API_KEY_B64}}" | base64 --decode > app/android/fastlane/google-cloud-api-key.json
- name: Write key properties
shell: bash
run: |
echo "${{ secrets.KEY_PROPERTIES}}" > app/android/key.properties
- name: Write key store
shell: bash
run: |
echo "${{ secrets.KEYSTORE_B64}}" | base64 --decode > app/android/app/my-upload-key.jks
- name: Install Fastlane
run: cd app/android && bundle install
- name: Install packages
run: cd app && yarn install
- name: Execute Fastlane command
run: cd app && yarn publish:android
```
La suite des étapes sont de simple run de commandes d'install de fastlane, d'install de modules node et des création de fichiers en utilisant des secrets.
### 3 - Ajouter les secrets
- Allez sur la page github de votre repo, allez dans le tab "settings" puis "secrets" > "actions".
- Vous pouvez créer de nouveau secret en cliquant sur "new repository secret" ou les update dans la liste.
Les secrets de github sont des "string", certains des éléments dont nous avons besoin vont donc devoir etre converti en base64 pour etre ajouté aux secret (ex: certificats).
Voici les commandes mac pour encoder ou décoder un fichier en base64:
- **Encoder un fichier:** encode distribution.p12 en base64 et créer le fichier distribution.p12.txt pour contenir le contenu base64.
```cmd
openssl base64 -in distribution.p12 -out distribution.p12.txt
```
- **Décoder un fichier:** decode distribution.p12.txt de base64 et recréer le fichier distribution.p12 non encodé.
```cmd
openssl base64 -d -in distribution.p12.txt -out distribution.p12
```
- **Durant les github actions, décoder un secret base64 et créer un fichier:** transforme un string base64, ici un secret, en fichier décodé.
```
echo "${{ secrets.GOOGLE_CLOUD_API_KEY_B64}}" | base64 --decode > app/android/fastlane/google-cloud-api-key.json
```
## Environnements multiples
Pour gérer différentes environnement ( dev, recette, prod,...) il faut à la fois donner des variables d'environnement adapaté pour le package js react-antive mais aussi aux parties native ios et android de l'app.
Pour cela le module [react-native-config](https://github.com/luggit/react-native-config) est idéal. Il demande quelques modifications dans les fichers natifs. Vous pouvez le mettre en place en suivant le guide suivant qui explique aussi comment gérer les multiples environnement des parties native:
[Guide pour gérer les environnement ios et android en react-native](https://medium.com/swlh/setting-up-multiple-environments-on-react-native-for-ios-and-android-c43f3128754f)
Une fois cela fait il faudra adapter les fastlane et github actions pour s'assurer d'avoir tous les .env (.env, .env.development, .env.production, ...) mais aussi les certificats necessaires et faire installer les certificats correspondant a votre cible de deploiement durant votre fastlane.