Passer à la navigation principale
CI/CD

Automatisation de la construction IOS automatique avec des actions de Capacitor et des certificats avec GitHub

Comment configurer une chaîne de CI/CD pour votre application IOS Ionic en utilisant fastlane et des actions de GitHub en 5 minutes (2024)

Crédits de l'article

Martin Donadieu

Auteur

Valeria

Réviseur

Jordan

Éditeur

Création automatique d'Capacitor IOS avec des GitHub actions avec certificat

La mise en place de CI/CD pour les applications Capacitor peut être complexe et fastidieuse. Voici ce qu'il faut savoir :

Nous recommandons maintenant d'utiliser Capgo Build avec le Capgo CLI pour les constructions natives Capacitor. Cette guide Fastlane est conservé pour les équipes qui maintiennent des pipelines d'actions GitHub existants, mais les nouvelles constructions iOS devraient utiliser le Capgo CLI afin que vous ne deviez pas maintenir Fastlane, les exécutants Xcode, les certificats, les profils de provisionnement et les scripts d'envoi.

Capgo Build pour CI/CD par Capgo

Évitez la maintenance de Fastlane, de l'exécutant Xcode, du certificat, du profil de provisionnement et du script d'envoi. Capgo Build exécute des constructions natives iOS signées à partir de votre pipeline CI/CD existant :

  • Fonctionne avec votre pipeline : Déclenchez la construction de Capgo à partir de GitHub Actions, GitLab CI, Jenkins ou scripts locaux après votre construction web et npx cap sync.
  • Signer à partir de secrets CI : Gardez les clés App Store Connect, les certificats, les profils de provisionnement, les mots de passe et les identifiants d'équipe dans vos propres secrets CI.
  • Pas de maintenance de l'exécuteur natif : Capgo Construction fournit des environnements de construction Apple maintenus, vous n'avez donc pas à gérer les exécutants macOS, les images Xcode ou les voies Fastlane.
  • Artéfacts et soumission : Téléchargez les artefacts signés pour les tests ou soumettez les versions de production à travers le Capgo CLI.

Tarification

  • : Les plans Capgo commencent à 12 $/mois
  • : Inclut les mises à jour OTA et environ 15 constructions natives par mois
  • : Les minutes de construction supplémentaires sont facturées par minute à l'aide de crédits

Configurez Capgo Build dans CI/CD

Guide de configuration manuelle

Voici ce que vous devez faire :

Livraison continue pour iOS à l'aide de Fastlane et d'actions GitHub et de certificat

Prérequis

Avant de poursuivre avec le tutoriel :

  • Assurez-vous d'avoir Fastlane installé sur votre poste de développement.
  • Vérifiez que vous êtes membre du programme de développeur iOS.

Informations importantes 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.
On va utiliser une machine macOS, vous pouvez voir dans l'écran d'aperçu son prix et ses limites (tarifs valables à la création de ce tutoriel, ils pourraient subir des changements à l'avenir). Une fois averti des exigences et des prix, continuons. Remarque : Dans l'article, je suppose que vous avez créé l'application dans App Store Connect. L'information importante sera copiée par Fastlane !

Qu'est-ce que vous allez apprendre dans ce tutoriel ?

Étapes à suivre dans cet article

Utilisation d'App Store Connect __CAPGO_KEEP_0__ avec Fastlane

machine

  1. Using App Store Connect API with Fastlane
    • Exigences :
      • Créer une clé App Store Connect API
      • Utiliser une clé App Store Connect API
  2. Copier les fichiers Fastlane
  3. Configurer les actions GitHub

1. Utiliser App Store Connect API avec Fastlane

À partir de février 2021, la deuxième authentification factorielle ou la vérification à deux étapes est obligatoire pour tous les utilisateurs pour se connecter à App Store Connect. Cette couche supplémentaire de sécurité pour votre identifiant Apple vous aide à vous assurer que vous êtes la seule personne qui peut accéder à votre compte.
De Support Apple

Exigences

Pour que Fastlane puisse utiliser App Store Connect API pour télécharger votre application, vous devez fournir les éléments suivants trois choses :

  1. Identifiant de l'émetteur
  2. Identifiant de clé
  3. Clé de fichier ou contenu de clé

Obtenir une clé d'App Store Connect API

Pour générer des clés, vous devez avoir les droits d'administrateur dans App Store Connect. Si vous n'avez pas ces droits, vous pouvez inviter la personne concernée à consulter cet article.

  1. Se connecter à App Store Connect.

  2. Sélectionner Utilisateurs et accès.

Accès à l'utilisateur App Store Connect

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

App Store Connect API Intégration

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

Les clés App Store Connect API créent

  1. Entrez un nom pour la clé. Le nom est uniquement à des fins de référence et n'est pas partie intégrante de la clé elle-même.

Les clés App Store Connect API créent un nom

6 — Dans l'accès, sélectionnez le rôle pour la clé. Les rôles qui s'appliquent aux clés sont les mêmes rôles qui s'appliquent aux utilisateurs de votre équipe. Voir les permissions de rôle. Nous recommandons de sélectionner Gestionnaire d'applications.

  1. Cliquez sur Générer.

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

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

Téléchargement des clés App Store Connect

Vous pouvez récupérer toutes les informations nécessaires ici.
<1> ID de l'incident. (APPLE_ISSUER_ID secret)
<2> ID de la clé. (APPLE_KEY_ID secret)
<3> Cliquez sur « Télécharger la clé API » pour télécharger votre API clé privée. 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 pouvez donc la télécharger qu'une seule fois.

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

Utilisation d'une clé App Store Connect API

Le fichier de clé API (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 jeton JWT d'autorisation. Il existe plusieurs façons de passer ces informations dans Fastlane. J'ai choisi d'utiliser l'action nouvelle de Fastlane app_store_connect_api_keyVous pouvez apprendre d'autres façons dans documentation de Fastlane. Je montre cette méthode car je pense qu'il s'agit de la façon la plus facile de travailler avec la plupart des CI, où vous pouvez définir des variables d'environnement.

Veuillez convertir le fichier p8 que vous téléchargez en Base64 et le stocker comme un secret (APPLE_KEY_CONTENT).

base64 -i APPLE_KEY_CONTENT.p8 | pbcopy

Maintenant, nous pouvons gérer Apple App Store Connect avec Fastlane à l'aide de la clé API, c'est génial !

2. Certificats

Ouvrez XCode et allez à Paramètres > Comptes > Identité Apple > Équipes et sélectionnez votre équipe.

Code identités de signature

Cliquez sur Gérer les certificats.

Si vous n'avez pas déjà créé de certificat, vous pouvez créer un nouveau certificat.

Cliquez sur + et sélectionnez Distribution Apple

Distribution Apple

Ensuite, vous devez vous rendre dans le cléchain pour télécharger le certificat sous forme de .p12 fichier.

Pour ce faire, vous devez vous rendre dans le cléchain, passer à la vue et sélectionner connexion le cléchain et puis la fenêtre Mes Certificats.

Mes Certificats

Choisissez ensuite le certificat que vous souhaitez télécharger. (Recherchez par la date du certificat)

Cliquez ensuite avec le bouton droit sur la clé privée du certificat et sélectionnez Exporter.

Choisissez le format de fichier Échange de données personnelles (.p12).

Cela téléchargera le certificat sous la forme d'un .p12 fichier.

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

base64 -i BUILD_CERTIFICATE.p12 | pbcopy

Cela deviendra votre BUILD_CERTIFICATE_BASE64 secret. De plus, lorsque vous y êtes invité, veuillez fournir le mot de passe du certificat. Ce mot de passe sera votre P12_PASSWORD secret.

3. Profils de provisionnement

Ouvrir Apple Developer et sélectionnez l'équipe appropriée.

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

Créer un nouveau profil

Et sélectionnez App Store Connect.

Sélectionnez App Store Connect

Ensuite, vous devez sélectionner l'application appropriée, soyez prudent, vous ne pouvez pas utiliser les caractères génériques sinon la signature échouera.

Sélectionnez l'application appropriée

Sélectionnez le bon certificat que vous avez créé avant (cherchez la date d'expiration, elle doit être la même journée et mois que la date actuelle) et cliquez sur Continuez.

Sélectionnez le bon certificat

Enfin, entrez le nom du profil et cliquez sur Générez le profil.

Le nom sera utilisé pour identifier le profil dans Fastlane, sous la valeur de APPLE_PROFILE_NAME.

Générez le profil

Vous pouvez télécharger le profil sous forme de .mobileprovision fichier.

Téléchargez le profil

Veuillez convertir le profil en Base64 et le stocker en tant que secret (BUILD_PROVISION_PROFILE_BASE64).

base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy

4. Copiez les fichiers Fastlane

Fastlane est une bibliothèque Ruby créée pour automatiser les tâches de développement mobile courantes. En utilisant Fastlane, vous pouvez configurer des « voies » personnalisées qui rassemblent une série d'« actions » qui exécutent des tâches que vous effectueriez normalement à l'aide d'Android Studio. Vous pouvez faire beaucoup avec Fastlane, mais pour les besoins de ce tutoriel, nous utiliserons uniquement une poignée d'actions de base.

Créez le dossier Fastlane au niveau de racine de votre projet Capacitor/Ionic et ajoutez-y le fichier Fastfile :

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

C'est au même niveau que package.json, capacitor.config.*, et le ios/ dossier. N'oubliez pas de ne pas le créer à l'intérieur de 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

Les GitHub Actions utilisent les secrets de votre référentiel que vous configurez dans l'étape suivante. Vous n'avez besoin d'un fichier local que si vous souhaitez exécuter ou tester Fastlane à partir de votre propre machine. .env 6. Copiez les fichiers Fastlane

Pour les tests locaux, créez <project-root>/fastlane/.env à côté de FastfileN'oubliez pas de ne pas le commiter. Ajoutez fastlane/.env à votre .gitignore premier (ou vérifiez s'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'ID d'équipe d'APP_STORE_CONNECT

Allez à Centre de développement et descendez jusqu'à Membership details section. La Team ID est la valeur que vous devez saisir dans le APP_STORE_CONNECT_TEAM_ID secret.

app-store-connect-team-id

Obtenir l'identifiant de l'application

  1. Ouvrez Xcode
  2. Double-cliquez sur le App en navigateur de projet
  3. Ensuite, cliquez sur l'onglet Signing and Capabilities
  4. Copiez la valeur de la Bundle identifier. C'est la valeur que vous devez saisir dans le BUNDLE_IDENTIFIER secret.
identifiant-de-l-application-xcode

6. Traitement de la construction

Dans GitHub Actions, Vous êtes facturés en fonction des minutes Vous avez utilisées pour exécuter votre flux de CI/CD. D'après mon expérience, il faut environ 10–15 minutes avant que le build ne soit traité dans App Store Connect.

Pour les projets privés, le coût estimé par build peut aller jusqu'à $0,08/min x 15 min = $1,2, ou plus, en fonction de la configuration et des dépendances de votre projet.

Si vous vous inquiétez des coûts pour les projets privés, vous pouvez configurer skip_waiting_for_build_processing à trueCe faisant, vous économiserez des minutes de build en ne pas attendre que App Store Connect termine le traitement du build.

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

This optimization is mainly useful for private projects where build minutes cost money. For public/free projects, the build minutes are free so there’s no need to enable this setting. See GitHub’s page de tarification pour plus de détails.

7. Configuration GitHub Actions

Configurez GitHub secrets

Veuillez copier les secrets du fichier et les coller dans les secrets de l'organisation __CAPGO_KEEP_0__. .env file and paste them into the GitHub repository secrets.

Paramètres &gt; Secrets et variables &gt; Actions &gt; Nouveau secret de l'organisation New repository secret

github-secrets

2. BUILD_CERTIFICATE_BASE64 - Certificat Base64 codé.

3. BUILD_PROVISION_PROFILE_BASE64 - Profil de provisionnement Base64 codé.

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

5. APPLE_KEY_ID — Clé d'App Store Connect API — ID de clé.

6. APPLE_ISSUER_ID — Clé d'App Store Connect API — ID émetteur.

7. APPLE_KEY_CONTENT — Clé d'App Store Connect API — Contenu de la clé. .p8, Vérifiez-le.

8. Configurez le fichier de flux GitHub

Créez un répertoire de flux GitHub

cd .github/workflows

Dans le workflow répertoire, créez un fichier nommé build-upload-ios.ymlet ajoutez les éléments suivants.

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

Cette workflow devrait être déclenchée après chaque GitHub étiquette, si vous avez besoin d'automatiser l'étiquetage, veuillez vous référer à Automatic build and release avec GitHub actions en premier lieu.

Ensuite, cette workflow tirera vos dépendances NodeJS, les installera et construira votre application JavaScript.

Chaque fois que vous envoyez un nouveau commit, une mise à jour sera construite dans TestFlight.

Votre application n'a pas besoin d'utiliser Ionic, la base Capacitor est obligatoire, elle peut avoir des anciens modules Cordova, mais les Capacitor plugins JavaScript sont préférés.

8. Déclenchez la workflow

Créez un Commit

Créez un commit, vous devriez voir le flux de travail actif dans le dépôt.

Déclenchez le flux de travail

Pusher les nouveaux commits vers la branche main ou development context : Fragment de texte HTML d'une chaîne de dialogue Capgo plus longue (clé parente `alternatives_cta_questions`). Page/zone : page de comparaison de alternatives de mise à jour en direct de Capacitor. Rôle : Paragraphe marketing ou juridique long. Vu dans : page alternatives.astro. Conservez les termes de produit et de marque Capgo ainsi que les termes de développeur exactement. Clé de message `alternatives_cta_questions` (Questions de CTA alternatives). | Fragment de texte HTML d'une chaîne de dialogue Capgo plus longue (clé parente `appflow_cta_questions`). Page/zone : page de comparaison/migration de marketing de Appflow. Rôle : Paragraphe marketing ou juridique long. Vu dans : page ionic-appflow.astro. Conservez les termes de produit et de marque Capgo ainsi que les termes de développeur exactement. Clé de message `appflow_cta_questions` (Questions de CTA Appflow). | Fragment de texte HTML d'une chaîne de dialogue Capgo plus longue (clé parente `capwesome_cta_questions`). Page/zone : page de comparaison de Capawesome. Rôle : Paragraphe marketing ou juridique long. Vu dans : page capwesome.astro. Conservez les termes de produit et de marque Capgo ainsi que les termes de développeur exactement. Clé de message `capwesome_cta_questions` (Questions de CTA Capwesome). | Fragment de texte HTML d'une chaîne de dialogue Capgo plus longue (clé parente `consulting_faq_subtitle`). Page/zone : page de services de consulting. Rôle : Sous-titre ou tagline de section. Vu dans : page consulting.astro. Conservez les termes de produit et de marque Capgo ainsi que les termes de développeur exactement. Clé de message `consulting_faq_subtitle` (Sous-titre FAQ de consulting). | Page/zone : page de comparaison/migration de marketing de Appflow. Rôle : Étiquette de navigation ou élément de navigation court. Vu dans : page ionic-appflow.astro, page ionic-enterprise-plugins.astro, page solutions/ionic-enterprise-plugins.astro. Clé de message `appflow_plugins_or` (Appflow Plugins ou).

pour déclencher le flux de travail.

Démarré avec commit

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

Tableau de bord Testflight

9. Puis-je déployer depuis l'ordinateur local ?

Vous pouvez utiliser Xcode pour construire et signer votre application, comme toujours.

Guides de configuration CI/CD

Plateformes CI/CD alternatives

Mises à jour en temps réel &amp; Déploiement

Merci

Cet article est basé sur les articles suivants :

Keep going from Automatic Capacitor IOS build with GitHub actions with certificate

Si vous utilisez Automatic Capacitor IOS build with GitHub actions with certificate pour planifier l'automatisation de CI/CD, connectez-l’à Capgo CI/CD pour le flux de workflow du produit dans Capgo CI/CD, Capgo Builds natifs pour le flux de workflow du produit dans Capgo Builds natifs, Capgo Intégrations for the product workflow in Capgo Integrations, Intégration CI/CD context GitHub Actions Integration for the implementation detail in GitHub Actions Integration.

Mises à jour en temps réel pour les applications Capacitor

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

Lorsqu'un bug de la couche web est en ligne, expédiez la correction par __CAPGO_KEEP_0__ au lieu de attendre des jours pour l'approbation de la boutique d'applications. Les utilisateurs reçoivent la mise à jour en arrière-plan tandis que les modifications natives restent dans le chemin de revue normal.

context : Page/zone : Site web de marketing Capgo. Rôle : Paragraphe de description ou de description de métadonnées de soutien. Vu dans : composant GetStarted.astro. Préservez les termes de produit/marque et les termes de développeur exactement. Clé de message `instant_updates_for_capacitor_apps_description` (Description de mises à jour instantanées pour les applications Capacitor).

Support humain de Martin

Capgo gives you the best insights you need to create a truly professional mobile app.