Aller au contenu principal
CI/CD

Build iOS Capacitor automatique avec GitHub Actions et certificat

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

Illustration de blog : build iOS Capacitor automatique avec les actions GitHub et le certificat Capgo

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 est conservé pour les équipes qui maintiennent des pipelines GitHub Actions existants, mais les nouveaux builds iOS doivent utiliser le Capgo CLI pour ne pas avoir à maintenir vous-même Fastlane, les runners Xcode, les certificats et les scripts d'upload.

Capgo Build pour CI/CD par Capgo

Évitez la maintenance de Fastlane, des runners Xcode, des certificats, des profils de provisionnement et des 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 ainsi de gérer les runners macOS, les images Xcode ou les lanes Fastlane.
  • 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 :

Livraison continue pour iOS avec Fastlane, les Actions GitHub et le certificat

Prerequisites

Avant de poursuivre le tutoriel :

  • Assurez-vous d’avoir Fastlane installé sur votre machine de développement.
  • Assurez-vous d’être membre du programme de développement iOS.

Informations importantes sur le prix

Prix de l'action GitHub

https://github.com/features/actions

Le service est «gratuit » jusqu’à la limite, selon 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 passés en revue, continuons.

Note : dans cet article, je pars du principe que vous avez créé l’application dans App Store Connect. Les informations importantes seront copiées par Fastlane !

Ce que vous allez apprendre dans ce tutoriel

Étapes à suivre dans l'article

  1. Utiliser App Store Connect API avec Fastlane
    • Prérequis :
      • Créer une clé API App Store Connect
      • Utiliser une clé API App Store Connect
  2. Copier les fichiers Fastlane
  3. Configurer les Actions GitHub

1. Utiliser API d'App Store Connect avec Fastlane

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

Prérequis

Pour que Fastlane puisse utiliser App Store Connect API afin d’envoyer votre application, vous devez fournir les éléments suivants trois éléments :

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

Obtenir une clé API App Store Connect

Pour générer des clés, vous devez disposer des permissions Admin dans App Store Connect. Si vous n’avez pas cette permission, vous pouvez orienter la personne concernée vers cet article.

  1. Se connecter à 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

  1. Cliquez sur Générer une clé API ou sur le bouton Ajouter (+).

Création de clés API App Store Connect

  1. Saisissez un nom pour la clé. Ce nom sert uniquement de référence et ne fait pas partie de la clé.

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.

  1. Cliquez sur Générer.

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'émetteur. (APPLE_ISSUER_ID secret)
<2> ID de la clé. (APPLE_KEY_ID secret)
<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 (fichier p8 à télécharger), l’ID de clé et l’ID d’émetteur sont requis pour créer le token JWT d’autorisation. Il existe plusieurs façons de transmettre ces informations à Fastlane. J’ai choisi d’utiliser 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.

Veuillez convertir le fichier p8 téléchargé en Base64 et le stocker en tant que secret (APPLE_KEY_CONTENT).

base64 -i APPLE_KEY_CONTENT.p8 | pbcopy

Nous pouvons maintenant gérer App Store Connect avec Fastlane à l’aide de la clé API, super !

2. Certificats

Ouvrez Xcode et allez dans Paramètres > Comptes > Apple ID > Équipes et sélectionnez votre équipe.

Identités de signature Code

Cliquez sur Gérer les certificats.

Si vous n’avez pas encore créé de certificat, vous pouvez en créer un nouveau.

Cliquez sur + et sélectionnez Distribution Apple

Distribution Apple

Ensuite, vous devez vous rendre dans le trousseau pour télécharger le certificat en tant que .p12 fichier.

Pour ce faire, allez dans le trousseau et basculez sur le session trousseau, puis sur l'onglet Mes certificats.

Mes certificats

Vous pouvez ensuite sélectionner le certificat que vous souhaitez télécharger. (Recherchez par date de validité du certificat)

Faites ensuite un clic droit sur la clé privée du certificat et sélectionnez Exporter.

Choisir le format de fichier Échange d'informations personnelles (.p12).

Cela téléchargera le certificat sous forme de .p12 fichier.

Veuillez ouvrir le fichier dans un terminal et utiliser la commande suivante pour le convertir en Base64 :

base64 -i BUILD_CERTIFICATE.p12 | pbcopy

Ceci deviendra votre BUILD_CERTIFICATE_BASE64 secret. De plus, lorsqu'on vous le demandera, veuillez saisir le mot de passe du certificat. Ce mot de passe sera votre P12_PASSWORD secret.

3. Profils de provisionnement

Ouvrez Apple Developer et sélectionnez la bonne équipe.

Ensuite, créez un nouveau profil en cliquant sur +

Créer un nouveau profil

Et sélectionnez App Store Connect.

Sélectionner App Store Connect

Ensuite, vous devez sélectionner la bonne application. Attention, vous ne pouvez pas utiliser de joker, sinon la signature échouera.

Sélectionnez la bonne application

Sélectionnez le certificat que vous avez créé précédemment (vérifiez la date d'expiration : elle doit tomber le même jour et le même mois qu'aujourd'hui) et cliquez sur Continuer.

Sélectionnez le bon certificat

Enfin, saisissez le nom du profil et cliquez sur Générer.

Le nom servira à identifier le profil dans Fastlane, sous la valeur de APPLE_PROFILE_NAME.

Générer le profil

Vous pouvez télécharger le profil en tant que .mobileprovision fichier.

Télécharger le profil

Convertissez le profil en Base64 et stockez-le comme secret (BUILD_PROVISION_PROFILE_BASE64).

base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy

4. 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 le dossier Fastlane à la racine de votre projet Capacitor/Ionic et ajoutez-y le Fastfile :

  • Dossier : <project-root>/fastlane/
  • Fichier : <project-root>/fastlane/Fastfile

C'est au même niveau que package.json, capacitor.config.*, et le ios/ le dossier. Ne le créez pas à l'intérieur ios/App/.

platform :ios do
  desc 'Export ipa and submit to TestFlight'
  lane :beta do
    keychain_info = { keychain_name: "ios-build-#{Time.now.to_i}.keychain", keychain_password: SecureRandom.uuid }
    
    begin
      setup_signing(keychain_info)
      bump_build_number
      build_app_with_signing(keychain_info)
      submit_to_testflight
    ensure
      cleanup_keychain(keychain_info)
    end
  end

  private_lane :setup_signing do |options|
    create_keychain(
      name: options[:keychain_name],
      password: options[:keychain_password],
      unlock: true,
      timeout: 0,
      lock_when_sleeps: false, 
      add_to_search_list: true
    )
    import_cert(options)
    install_profile
    update_project_settings
  end

  lane :bump_build_number do
		file = File.read('../package.json')
		data_hash = JSON.parse(file)
		api_key = app_store_connect_api_key(
      key_id: ENV['APPLE_KEY_ID'],
      issuer_id: ENV['APPLE_ISSUER_ID'],
      key_content: ENV['APPLE_KEY_CONTENT'],
      is_key_content_base64: true,
      duration: 1200,
      in_house: false
    )
		build_num = app_store_build_number(
      api_key: api_key,
			app_identifier: ENV['BUNDLE_IDENTIFIER'],
			live: false
    )
		build_num = build_num + 1
		UI.message("Bumped build number to #{build_num}")
		increment_build_number(
			build_number: build_num,
			xcodeproj: "./ios/App/App.xcodeproj",
			skip_info_plist: true
		)
	end

  private_lane :import_cert do |options|
    cert_path = "#{Dir.tmpdir}/build_certificate.p12"
    File.write(cert_path, Base64.decode64(ENV['BUILD_CERTIFICATE_BASE64']))
    import_certificate(
      certificate_path: cert_path,
      certificate_password: ENV['P12_PASSWORD'] || "",
      keychain_name: options[:keychain_name],
      keychain_password: options[:keychain_password],
      log_output: true
    )
    File.delete(cert_path)
  end  
  
  private_lane :cleanup_keychain do |options|
    delete_keychain(
      name: options[:keychain_name]
    )
  end  

  private_lane :install_profile do
    profile_path = "#{Dir.tmpdir}/build_pp.mobileprovision"
    File.write(profile_path, Base64.decode64(ENV['BUILD_PROVISION_PROFILE_BASE64']))
    UI.user_error!("Failed to create provisioning profile at #{profile_path}") unless File.exist?(profile_path)
    ENV['PROVISIONING_PROFILE_PATH'] = profile_path
    install_provisioning_profile(path: profile_path)
    File.delete(profile_path)
  end

  private_lane :update_project_settings do
    update_code_signing_settings(
      use_automatic_signing: false,
      path: "./ios/App/App.xcodeproj",
      code_sign_identity: "iPhone Distribution",
      profile_name: ENV['APPLE_PROFILE_NAME'],
      bundle_identifier: ENV['BUNDLE_IDENTIFIER'],
      team_id: ENV['APP_STORE_CONNECT_TEAM_ID']
    )
    update_project_team(
      path: "./ios/App/App.xcodeproj",
      teamid: ENV['APP_STORE_CONNECT_TEAM_ID']
    )
  end

  private_lane :build_app_with_signing do |options|
    unlock_keychain(
      path: options[:keychain_name],
      password: options[:keychain_password],
      set_default: false
    )
    build_app(
      workspace: "./ios/App/App.xcworkspace",
      scheme: "App",
      configuration: "Release",
      export_method: "app-store",
      output_name: "App.ipa",
      export_options: {
        provisioningProfiles: {
          ENV['BUNDLE_IDENTIFIER'] => ENV['APPLE_PROFILE_NAME']
        }
      },
      xcargs: "-verbose",
      buildlog_path: "./build_logs",
      export_xcargs: "-allowProvisioningUpdates",
    )
  end   

  private_lane :submit_to_testflight do
    api_key = app_store_connect_api_key(
      key_id: ENV['APPLE_KEY_ID'],
      issuer_id: ENV['APPLE_ISSUER_ID'],
      key_content: ENV['APPLE_KEY_CONTENT'],
      is_key_content_base64: true,
      duration: 1200,
      in_house: false
    )
    pilot(
      api_key: api_key,
      skip_waiting_for_build_processing: true,
      skip_submission: true,
      distribute_external: false,
      notify_external_testers: false,
      ipa: "./App.ipa"
    )
  end
end

5. Configuration des secrets

GitHub Actions utilise les secrets du dépôt que vous configurez à l'étape suivante. Vous n'avez besoin d'un fichier local .env que si vous souhaitez exécuter ou tester Fastlane depuis votre propre machine.

Pour tester en local, créez <project-root>/fastlane/.env à côté du Fastfile. Ne commitez pas ce fichier. Ajoutez fastlane/.env vers votre .gitignore d'abord (ou vérifiez qu'il est déjà ignoré). Voici un exemple :

APP_STORE_CONNECT_TEAM_ID=UVTJ336J2D
BUNDLE_IDENTIFIER=ee.forgr.testfastlane
# See previous section for these secrets
BUILD_CERTIFICATE_BASE64=
BUILD_PROVISION_PROFILE_BASE64=
APPLE_KEY_ID=
APPLE_ISSUER_ID=
APPLE_KEY_CONTENT=
P12_PASSWORD=
APPLE_PROFILE_NAME=

Récupérer l'APP_STORE_CONNECT_TEAM_ID

Accéder à Centre développeur et faites défiler jusqu'à Membership details section. Le Team ID est la valeur que vous devez configurer dans le APP_STORE_CONNECT_TEAM_ID secret.

app-store-connect-team-id

Récupérer le BUNDLE_IDENTIFIER

  1. Ouvrez Xcode
  2. Double-cliquez sur le App dans le navigateur de projet
  3. Puis cliquez sur l'onglet Signing and Capabilities
  4. Copiez la valeur de Bundle identifier. C’est la valeur à définir dans le BUNDLE_IDENTIFIER secret.
bundle-identifier-xcode

6. Traitement du build

Dans les Actions GitHub, la facturation se fait selon les minutes que vous avez utilisé pour exécuter votre workflow CI/CD. D’après mon expérience, il faut compter environ 10 à 15 minutes avant qu’un build ne soit 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 $, voire plus, selon la configuration et les dépendances de votre projet.

Si les coûts des projets privés vous inquiètent, vous pouvez définir skip_waiting_for_build_processing vers true. Cela permet d'économiser des minutes de build en évitant d'attendre la fin du traitement du build par App Store Connect.

Cependant, il y a une contrepartie : vous devrez mettre à jour manuellement les informations de conformité de votre application dans App Store Connect avant de pouvoir distribuer le build aux utilisateurs.

Cette optimisation est surtout utile pour les projets privés où les minutes de build sont facturées. Pour les projets publics/gratuits, les minutes de build sont offertes, il n’est donc pas nécessaire d’activer ce paramètre. Voir GitHub’s page des tarifs pour plus de détails.

7. Configurer les GitHub Actions

Configurer les secrets GitHub

Copiez les secrets depuis le .env fichier et collez-les dans les secrets du dépôt GitHub.

Accéder à Paramètres > Secrets et variables > Actions > Nouveau secret de dépôt

github-secrets

2. BUILD_CERTIFICATE_BASE64 - Certificat encodé en Base64.

3. BUILD_PROVISION_PROFILE_BASE64 - Profil de provisionnement encodé en Base64.

4. BUNDLE_IDENTIFIER - l'identifiant de bundle de votre application.

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

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

7. APPLE_KEY_CONTENT — Clé App Store Connect API 🔺 Contenu de la clé .p8, vérifiez-la

8. 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: '3.0'
          bundler-cache: true
      - uses: maierj/fastlane-action@v3.1.0
        env:
          APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
          BUNDLE_IDENTIFIER: ${{ secrets.BUNDLE_IDENTIFIER }}
          BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
          BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
          APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
          APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
          APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
          P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
          APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }}
        with:
          lane: ios beta
      - name: Upload release bundle
        uses: actions/upload-artifact@v6
        with:
          name: ios-release
          path: ./App.ipa
          retention-days: 10

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.

8. 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

9. Puis-je déployer depuis ma machine locale ?

Oui, c'est possible et sans effort.

Vous pouvez utiliser Xcode pour compiler et signer votre app, comme d'habitude.

Guides de configuration CI/CD

Alternatives aux plateformes CI/CD

Live Updates et déploiement

Merci

Cet article s'appuie sur les articles suivants :

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

Si vous utilisez Build iOS Capacitor automatique avec GitHub Actions et certificat 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.