Aller au contenu principal
CI/CD

Build iOS automatique Capacitor avec les actions GitHub via match

Comment configurer un pipeline CI/CD pour votre application Ionic iOS avec fastlane et les GitHub Actions en 5 min (2022)

Build iOS automatique Capacitor avec des actions GitHub via match Capgo, illustration du blog

Builds iOS automatiques avec des actions GitHub via Match

Configurer la CI/CD pour les apps Capacitor peut être complexe et chronophage. Voici ce qu'il faut savoir :

Nous recommandons désormais d'utiliser Capgo Build avec le Capgo CLI pour les builds natifs Capacitor. Ce guide Fastlane Match est conservé pour les équipes qui maintiennent des pipelines GitHub Actions existants, mais les nouveaux builds iOS devraient passer par Capgo CLI pour ne pas avoir à maintenir vous-même Fastlane, les dépôts Match, les runners Xcode, les certificats et les scripts d'upload.

Capgo Build pour CI/CD par Capgo

Zéro maintenance Fastlane Match, runners Xcode, certificats, profils de provisionnement et scripts d'upload. Build Capgo exécute des builds iOS natifs signés depuis votre pipeline CI/CD existant :

  • Compatible avec votre pipeline: Déclenchez Capgo Build depuis GitHub Actions, GitLab CI, Jenkins ou des scripts locaux après votre build web et npx cap sync.
  • Signature via les secrets CI: Conservez vos clés App Store Connect, certificats, profils de provisionnement, mots de passe et IDs d'équipe dans vos propres secrets CI.
  • Aucune maintenance de runner natif: Capgo Build fournit des environnements de build Apple maintenus, vous évitant de gérer les runners macOS, les images Xcode, Fastlane ou les dépôts Match.
  • Artifacts et soumission: Téléchargez des artifacts signés pour la QA ou soumettez des builds de release via Capgo CLI.

Tarifs

  • Les plans Capgo démarrent à 12 $/mois
  • Inclut les mises à jour OTA et environ 15 builds natifs par mois
  • Les minutes de build supplémentaires sont facturées à la minute via des crédits

Configurez Capgo Build dans votre CI/CD

Guide de configuration manuelle

Voici ce que vous devez faire :

Continuous Delivery pour iOS via Fastlane et GitHub Actions avec match

Prerequisites

Avant de poursuivre le tutoriel…

  • Assurez-vous d’avoir Fastlane installé sur votre machine de développement.
  • Une adhésion au programme développeur iOS.
  • L’envie de lire 😆…
  • Une équipe de plusieurs devs, sinon nous recommandons d’utiliser fastlane cert pour des workflows plus simples.

Note importante sur le prix

Prix de l'action GitHub

https://github.com/features/actions

Le service est « gratuit » jusqu'à la limite, en fonction de la machine choisie.
Nous allons utiliser une machine macOS dont vous pouvez voir le prix et les limites sur la capture d'écran (tarifs au moment de la création du tutoriel, susceptibles d'évoluer)

🔴 Une fois les prérequis et les tarifs présentés, si vous le souhaitez, nous continuons…

📣 Dans cet article, nous partons du principe que l'app est créée dans iTunes Connect et que nous disposons des certificats de l'écosystème Apple ; tout sera copié par Fastlane !

Plongeons dans le vif du sujet 🤿

Étapes à suivre dans l'article

  1. Utiliser App Store Connect API avec Fastlane Match
  2. Prérequis
  3. Créer une clé API App Store Connect
  4. Utiliser une clé API App Store Connect
  5. Copier les fichiers Fastlane
  6. Configurez Fastlane match

1. Utiliser API d'App Store Connect avec Fastlane Match

Depuis février 2021, l'authentification à deux facteurs ou la vérification en deux étapes est obligatoire pour que tous les utilisateurs puissent se connecter à App Store Connect. Cette couche de sécurité supplémentaire pour votre identifiant Apple garantit que vous êtes la seule personne à pouvoir accéder à votre compte.
Depuis Support Apple

Pour commencer avec match, vous devrez révoquer vos certificats actuels. Pas d'inquiétude, vous recevrez directement les nouveaux.

Prérequis

Pour pouvoir utiliser API d'App Store Connect, Fastlane a besoin de trois choses.

  1. ID de l’émetteur.
  2. ID de la clé.
  3. Fichier de clé ou contenu de la clé.

Créer une clé API App Store Connect

Pour générer des clés, vous devez disposer de la permission Admin dans App Store Connect. Si vous ne l'avez pas, vous pouvez transmettre cet article à la personne concernée et lui demander de suivre les instructions ci-dessous.

1 — Connectez-vous à App Store Connect.

2 — Sélectionnez Utilisateurs et accès.

Accès utilisateur à App Store Connect

3 — Sélectionnez l'onglet Intégration.

Intégration API App Store Connect

4 — Cliquez sur Generate API Key ou sur le bouton Add (+).

Création de clés API App Store Connect

5 — Saisissez un nom pour la clé. Ce nom sert uniquement de référence et ne fait pas partie de la clé elle-même.

Nom de création des clés API App Store Connect

6 — Sous Accès, sélectionnez le rôle de la clé. Les rôles applicables aux clés sont les mêmes que ceux des utilisateurs de votre équipe. Voir permissions de rôle. Nous recommandons de sélectionner Gestionnaire d'app.

7 — Cliquez sur Generate.

L'accès à une clé API ne peut pas être limité à des apps spécifiques.

Le nom de la nouvelle clé, son ID, un lien de téléchargement et d'autres informations s'affichent sur la page.

Clés de téléchargement App Store Connect

Vous pouvez récupérer ici les trois informations nécessaires.
<1> ID de l'issue.
<2> ID de la clé.
<3> Cliquez sur « Download API Key » pour télécharger votre clé privée API. Le lien de téléchargement n'apparaît que si la clé privée n'a pas encore été téléchargée. Apple ne conserve pas de copie de la clé privée. Vous ne pouvez donc la télécharger qu'une seule fois.

🔴 Stockez votre clé privée dans un endroit sûr. Vous ne devez jamais partager vos clés, les stocker dans un dépôt code ou les inclure dans du code côté client.

Utiliser une clé API App Store Connect

Le fichier API Key (le fichier p8 que vous téléchargez), l'ID de la clé et l'ID de l'émetteur sont nécessaires pour créer le token JWT d'autorisation. Il existe plusieurs façons de renseigner ces informations dans Fastlane avec la nouvelle action de Fastlane, app_store_connect_api_key. Vous pouvez découvrir d'autres méthodes dans la documentation Fastlane. Je présente cette méthode car je pense que c'est la plus simple pour la plupart des CI actuelles, où vous pouvez configurer des variables d'environnement.

Nous pouvons maintenant gérer Fastlane avec la clé API d'App Store Connect, super !

2. Copier les fichiers Fastlane

Fastlane est une bibliothèque Ruby créée pour automatiser les tâches courantes du développement mobile. Avec Fastlane, vous pouvez configurer des « lanes » personnalisées qui regroupent une série d'« actions » pour effectuer les tâches que vous feriez normalement via Android Studio. Vous pouvez faire énormément de choses avec Fastlane, mais pour ce tutoriel, nous n'utiliserons que quelques actions de base.

Créez un dossier Fastlane à la racine de votre projet et copiez les fichiers suivants : Fastfile

default_platform(:ios)

DEVELOPER_APP_IDENTIFIER = ENV["DEVELOPER_APP_IDENTIFIER"]
DEVELOPER_APP_ID = ENV["DEVELOPER_APP_ID"]
PROVISIONING_PROFILE_SPECIFIER = ENV["PROVISIONING_PROFILE_SPECIFIER"]
TEMP_KEYCHAIN_USER = ENV["TEMP_KEYCHAIN_USER"]
TEMP_KEYCHAIN_PASSWORD = ENV["TEMP_KEYCHAIN_PASSWORD"]
APPLE_ISSUER_ID = ENV["APPLE_ISSUER_ID"]
APPLE_KEY_ID = ENV["APPLE_KEY_ID"]
APPLE_KEY_CONTENT = ENV["APPLE_KEY_CONTENT"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]

def delete_temp_keychain(name)
  delete_keychain(
    name: name
  ) if File.exist? File.expand_path("~/Library/Keychains/#{name}-db")
end

def create_temp_keychain(name, password)
  create_keychain(
    name: name,
    password: password,
    unlock: false,
    timeout: 0
  )
end

def ensure_temp_keychain(name, password)
  delete_temp_keychain(name)
  create_temp_keychain(name, password)
end

platform :ios do
  lane :build do
    build_app(
      configuration: "Release",
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      export_method: "app-store",
      export_options: {
        provisioningProfiles: { 
            DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
        }
      }
    )
  end
  lane :refresh_profiles do
    match(
      type: "development",
      force: true)
    match(
      type: "adhoc",
      force: true)
  end
  desc "Register new device"
  lane :register_new_device do  |options|
      device_name = prompt(text: "Enter the device name: ")
      device_udid = prompt(text: "Enter the device UDID: ")
      device_hash = {}
      device_hash[device_name] = device_udid
      register_devices(
                       devices: device_hash
                       )
    refresh_profiles
  end
  lane :closed_beta do
    keychain_name = TEMP_KEYCHAIN_USER
    keychain_password = TEMP_KEYCHAIN_PASSWORD
    ensure_temp_keychain(keychain_name, keychain_password)

    api_key = app_store_connect_api_key(
      key_id: APPLE_KEY_ID,
      issuer_id: APPLE_ISSUER_ID,
      key_content: APPLE_KEY_CONTENT,            
      duration: 1200,            
      in_house: false
    )

    match(
      type: 'appstore',
      git_basic_authorization: Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"),
      readonly: true,
      keychain_name: keychain_name,
      keychain_password: keychain_password,
      api_key: api_key
    )

    gym(
      configuration: "Release",
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      export_method: "app-store",
      export_options: {
        provisioningProfiles: { 
            DEVELOPER_APP_ID => "#{PROVISIONING_PROFILE_SPECIFIER}"
        }
      }
    )

    pilot(
      apple_id: "#{DEVELOPER_APP_ID}",
      app_identifier: "#{DEVELOPER_APP_IDENTIFIER}",
      skip_waiting_for_build_processing: true,
      skip_submission: true,
      distribute_external: false,
      notify_external_testers: false,
      ipa: "./App.ipa"
    )

    delete_temp_keychain(keychain_name)
  end
  lane :submit_review do
    version = ''
    Dir.chdir("..") do
      file = File.read("package.json")
      data = JSON.parse(file)
      version = data["version"]
    end
    deliver(
      app_version: version,
      submit_for_review: true,
      automatic_release: true,
      force: true, # Skip HTMl report verification
      skip_metadata: false,
      skip_screenshots: false,
      skip_binary_upload: true
    )
  end
end

Appfile

app_identifier(ENV["DEVELOPER_APP_IDENTIFIER"])
apple_id(ENV["FASTLANE_APPLE_ID"])
itc_team_id(ENV["APP_STORE_CONNECT_TEAM_ID"])
team_id(ENV["DEVELOPER_PORTAL_TEAM_ID"])

Configurez Fastlane match

Fastlane match est une nouvelle approche de la signature de code sur iOS. Fastlane match permet aux équipes de gérer facilement les certificats et les profils de provisionnement requis pour vos apps iOS.

Créez un nouveau dépôt privé nommé certificates, par exemple sur votre compte personnel GitHub ou votre organisation.

Initialisez Fastlane match pour votre app iOS.

fastlane match init

Sélectionnez ensuite l'option n° 1 (Git Storage).

[01:00:00]: fastlane match supports multiple storage modes, please select the one you want to use:1. git2. google_cloud3. s3?

Indiquez l'URL du dépôt fraîchement créé.

[01:00:00]: Please create a new, private git repository to store the certificates and profiles there[01:00:00]: URL of the Git Repo: <YOUR_CERTIFICATES_REPO_URL>

Vous avez maintenant dans votre dossier Fastlane un fichier nommé Matchfile et _git_url_doit être configuré avec l'URL HTTPS du dépôt de certificats. Vous pouvez aussi utiliser SSH, mais cela nécessite une étape supplémentaire.

# ios/Matchfilegit_url("https://github.com/gitusername/certificates")storage_mode("git")type("appstore")

Ensuite, nous générons les certificats et vous saisissez vos identifiants lorsque Fastlane Match vous le demande.

Un prompt vous demandera de saisir une passphrase. Retenez-la bien, car elle sera utilisée plus tard par les GitHub Actions pour décrypter votre dépôt de certificats.

fastlane match appstore

Si tout s'est bien passé, vous devriez voir quelque chose comme ceci :

[01:40:52]: All required keys, certificates and provisioning profiles are installed 🙌

Si vous avez rencontré un problème avec GitHub et les permissions nécessaires, peut-être que cet article vous aidera à générer des tokens d'authentification pour git.

Les certificats et profils de provisionnement générés sont envoyés dans les ressources du dépôt de certificats

Certificats App Store Connect

Enfin, ouvrez votre project dans Xcode, et mettez à jour le profil de provisionnement pour la configuration release de votre application.

Certificats Xcode

Quelques points à noter 💡

Match

Pour que la CI/CD puisse importer les certificats et les profils de provisionnement, elle doit avoir accès au dépôt de certificats. Pour cela, générez un personal access token (à créer au préalable) disposant du scope permettant d'accéder aux dépôts privés ou de les lire.

Dans GitHub, allez dans Paramètres → Paramètres développeur → Tokens d'accès personnels → cliquez sur Generate New Token → cochez la repo portée → puis cliquez sur Generate token.

Créer un token d'accès personnel

Gardez une copie du token d'accès personnel généré. Vous l'utiliserez plus tard pour la variable d'environnement GIT_TOKEN.

Ensuite, remplacez votre fichier match généré dans le dossier Fastlane par Matchfile

CERTIFICATE_STORE_URL = ENV["CERTIFICATE_STORE_URL"]
GIT_USERNAME = ENV["GIT_USERNAME"]
GIT_TOKEN = ENV["GIT_TOKEN"]
FASTLANE_APPLE_ID = ENV["FASTLANE_APPLE_ID"]

git_url(CERTIFICATE_STORE_URL)
storage_mode("git")
type("appstore")
git_basic_authorization(Base64.strict_encode64("#{GIT_USERNAME}:#{GIT_TOKEN}"))
username(FASTLANE_APPLE_ID)

Ceci sera utilisé par les Actions GitHub pour importer les certificats et les profils de provisionnement. La variable sera définie dans les Secrets GitHub, au lieu d'être codée en dur dans le fichier.

Traitement du build

Dans les Actions GitHub, la facturation se fait selon les minutes que vous avez utilisées pour exécuter votre workflow CI/CD. D'après notre expérience, il faut environ 10 à 15 minutes avant qu'un build puisse être traité dans App Store Connect.

Pour les projets privés, le coût estimé par build peut atteindre 0,08 $/min x 15 min = 1,20 $, ou plus, selon la configuration ou les dépendances de votre projet.

Si vous partagez les mêmes préoccupations que moi concernant les tarifs pour les projets privés, vous pouvez garder le skip_waiting_for_build_processing vers true.

Quel est le piège ? Vous devez mettre à jour manuellement la conformité de votre application dans App Store Connect une fois le build traité, pour pouvoir distribuer ce build à vos utilisateurs.

Il s'agit simplement d'un paramètre optionnel à mettre à jour si vous voulez économiser des minutes de build sur vos projets privés. Pour les projets gratuits, cela ne devrait poser aucun problème. Voir tarifs.

3. Configurer les GitHub Actions

Configurer les secrets GitHub

Vous vous demandez d'où viennent les valeurs de ENV ? Eh bien, ce n'est plus un secret : elles viennent des secrets de votre projet. 🤦

Définir les secrets GitHub

1. APP_STORE_CONNECT_TEAM_ID - l'ID de votre équipe App Store Connect si vous faites partie de plusieurs équipes.

2. DEVELOPER_APP_ID - dans App Store Connect, allez sur l'app → Informations sur l'application → Faites défiler jusqu'à la General Information section de votre application et cherchez Apple ID.

3. DEVELOPER_APP_IDENTIFIER - l'identifiant de bundle de votre application.

4. DEVELOPER_PORTAL_TEAM_ID - l'ID de votre équipe Developer Portal si vous êtes dans plusieurs équipes.

5. FASTLANE_APPLE_ID - l'Apple ID ou l'e-mail développeur que vous utilisez pour gérer l'application.

6. GIT_USERNAME & GIT_TOKEN - Votre nom d'utilisateur git et votre personal access token.

7. MATCH_PASSWORD - la passphrase définie lors de l'initialisation de match, qui servira à déchiffrer les certificats et les profils de provisionnement.

8. PROVISIONING_PROFILE_SPECIFIER - match AppStore <YOUR_APP_BUNDLE_IDENTIFIER>, par ex. match AppStore com.domain.blabla.demo.

9. TEMP_KEYCHAIN_USER & TEMP_KEYCHAIN_PASSWORD - assignez un utilisateur et un mot de passe keychain temporaires pour votre workflow.

10. APPLE_KEY_ID — Clé App Store Connect API 🔺Key ID.

11. APPLE_ISSUER_ID — Clé App Store Connect API 🔺Issuer ID.

12. APPLE_KEY_CONTENT — Clé App Store Connect API 🔺 Fichier de clé ou contenu de la clé .p8, vérifiez-la

13. CERTIFICATE_STORE_URL — L'URL du dépôt de vos clés Match (ex. : https://github.com/***/fastlane_match.git)

4. Configurer le fichier de workflow GitHub

Créez un répertoire de workflow GitHub.

cd .github/workflows

Dans le workflow créez un fichier nommé build-upload-ios.ymlet ajoutez le contenu suivant.

name: Build source code on ios

on:
  push:
    tags:
      - '*'

jobs:
  build_ios:
    runs-on: macOS-latest
    steps:
      - uses: actions/checkout@v6
      - name: set Node.js
        uses: actions/setup-node@v6
        with:
          node-version: '24'
          cache: npm
      - name: Install dependencies
        id: install_code
        run: npm ci
      - name: Build
        id: build_code
        run: npm run build
      - uses: actions/cache@v5
        with:
          path: ios/App/Pods
          key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-pods-
      - name: Sync
        id: sync_code
        run: npx cap sync
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 2.7.2
      - uses: maierj/fastlane-action@v2.3.0
        env:
          DEVELOPER_APP_IDENTIFIER: ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
          DEVELOPER_APP_ID: ${{ secrets.DEVELOPER_APP_ID }}
          PROVISIONING_PROFILE_SPECIFIER: match AppStore ${{ secrets.DEVELOPER_APP_IDENTIFIER }}
          TEMP_KEYCHAIN_USER: ${{ secrets.TEMP_KEYCHAIN_USER }}
          TEMP_KEYCHAIN_PASSWORD: ${{ secrets.TEMP_KEYCHAIN_PASSWORD }}
          APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
          APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
          APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
          CERTIFICATE_STORE_URL: https://github.com/${{ secrets.CERTIFICATE_STORE_REPO }}.git
          GIT_USERNAME: ${{ secrets.GIT_USERNAME }}
          GIT_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
          FASTLANE_APPLE_ID: ${{ secrets.FASTLANE_APPLE_ID }}
          MATCH_USERNAME: ${{ secrets.FASTLANE_APPLE_ID }}
          MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
          APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
          DEVELOPER_PORTAL_TEAM_ID: ${{ secrets.DEVELOPER_PORTAL_TEAM_ID }}
        with:
          lane: closed_beta
      - name: Upload release bundle
        uses: actions/upload-artifact@v2
        with:
          name: ios-release
          path: ./App.ipa
          retention-days: 60

Ce workflow doit être déclenché après chaque GitHub balise, si vous souhaitez automatiser les tags, veuillez vous référer à Build et release automatiques avec les actions GitHub d'abord.

Ensuite, ce workflow récupère vos dépendances NodeJS, les installe et compile votre application JavaScript.

À chaque nouveau commit, une release sera générée dans TestFlight.

Votre application n'a pas besoin d'utiliser Ionic, seule la base Capacitor est obligatoire. Elle peut contenir d'anciens modules Cordova, mais l'utilisation du plugin JS Capacitor est recommandée.

5. Déclencher le workflow

Créer un commit

Effectuez un commit, vous devriez voir le workflow actif dans le dépôt.

Déclencher le workflow

Pousser les nouveaux commits sur la branche main ou development pour déclencher le workflow.

Lancé avec le commit

Après quelques minutes, le build devrait être disponible dans votre dashboard App Store Connect.

Dashboard TestFlight

Déploiement possible depuis une machine locale ?

Oui, c'est possible et sans effort.

Imaginez que vous ayez un dépôt privé, que vous ayez épuisé les minutes du plan gratuit et que vous ne vouliez pas payer pour de nouvelles releases, ou que vous préfériez soumettre l’application manuellement.

C’est parti

Ok, d’abord il faut créer dans my_project_path/fastlane un fichier nommé .env, dans le même chemin que Fastfile, pour pouvoir créer les mêmes secrets que ceux présents dans notre _GitHub, comme ci-dessous :

Fichier .env pour déployer depuis votre machine locale

Maintenant, vous pouvez ouvrir le terminal et lancez le Fastlane depuis votre machine :

fastlane closed_beta

❌ Point essentiel concernant le fichier .env , car nous préférons ne pas exposer ces données, nous devons l’ajouter à notre .gitignore, par exemple : ❌

fastlane/*.env

Cela devrait fonctionner de la même manière qu’avec les Actions GitHub sur la machine distante, mais sur notre machine locale. 🍻

Exécution locale de Fastlane

Exécution dans le terminal : $ Fastlane closed_beta

Si vous êtes arrivé jusqu’ici, félicitations : vous disposez désormais d’un processus entièrement automatisé pour vos applications iOS avec Fastlane et les GitHub Actions.

Chaque fois que vous envoyez un nouveau commit, une release est compilée dans la console Google Play, sur le canal bêta. J’améliorerai ce blog grâce à vos retours. Si vous avez des questions ou des suggestions, n’hésitez pas à me contacter par e-mail. martin@capgo.app

Compilez sur votre appareil

Si vous devez encore compiler sur votre appareil, vous devez les ajouter manuellement au profil de provisionnement. Connectez votre appareil à votre Mac et ouvrez le menu des appareils trouver le menu des appareils iOS Copiez ensuite votre identifiant trouver l'identifiant iOS Puis lancez la commande : fastlane register_new_device il vous demandera de définir un nom d'appareil et l'identifiant : définir l'identifiant iOS

si vous rencontrez des problèmes

Si vous avez des problèmes avec un appareil de dev impossible à tester, etc., cela règle généralement le souci.

Voici une commande magique qui peut vous sauver :

fastlane match nuke development
fastlane match development

Ensuite : Nettoyez le projet en maintenant Shift(⇧)+Command(⌘)+K ou en sélectionnant Product > Clean (il peut s'intituler « Clean Build Folder »)

Ensuite, essayez de relancer l'app sur votre appareil.

Merci

Cet article s'appuie sur les articles suivants :

Continuez avec le build iOS automatique Capacitor via les actions GitHub avec match

Si vous utilisez Build iOS automatique Capacitor avec les actions GitHub via match pour planifier l'automatisation CI/CD, et le connecter avec CI/CD Capgo pour le workflow produit dans le CI/CD de Capgo, Capgo Native Build pour le workflow produit dans les Native Builds de Capgo, Intégrations Capgo pour le workflow produit dans les intégrations de Capgo, Intégration CI/CD pour le détail d'implémentation dans l'intégration CI/CD, et Intégration GitHub Actions pour les détails d'implémentation de l'intégration GitHub Actions.

Live updates pour les apps Capacitor

Lorsqu'un bug de la couche web est en ligne, déployez le correctif via Capgo au lieu d'attendre des jours l'approbation des stores. Les utilisateurs reçoivent la mise à jour en arrière-plan, tandis que les changements natifs suivent le circuit de validation habituel.

Les derniers articles du blog

Capgo vous offre les meilleures informations pour créer une application mobile vraiment professionnelle.