Aller au contenu principal

Comment utiliser les traits de package SPM dans Capacitor 8

Utilisez les traits de package SPM dans Capacitor 8 : activez des fonctionnalités de plugin optionnelles avec packageTraits, définissez swiftToolsVersion 6.1 et ajoutez des traits à votre propre plugin.

Illustration de la configuration de Swift Package Manager dans les projets iOS Capacitor

To use SPM package traits in Capacitor 8, set experimental.ios.spm.swiftToolsVersion vers "6.1" et listez les traits par plugin sous experimental.ios.spm.packageTraits dans votre config Capacitor, puis lancez bunx cap sync ios. CLI écrit ces traits dans le fichier généré CapApp-SPM/Package.swiftgénéré, et SwiftPM compile le plugin avec les dépendances optionnelles et les chemins code correspondants. Cela nécessite Capacitor CLI 8.3.0 ou version ultérieure et ne s'applique qu'aux projets iOS utilisant Swift Package Manager.

Les traits comblent le dernier grand écart entre SPM et CocoaPods pour les plugins : les dépendances natives optionnelles qui étaient auparavant des subspecs podspec. Ce guide couvre le côté application, le côté auteur de plugin et les limites du support expérimental actuel.

Ce que sont les package traits

Les package traits viennent de la proposition Swift Evolution SE-0450, implémentée dans Swift 6.1 (Xcode 16.3 et versions ultérieures). Un package déclare des traits nommés dans son Package.swift. Les consommateurs choisissent ceux à activer lorsqu'ils dépendent du package. Un trait peut :

  • rendre une dépendance optionnelle (condition: .when(traits: [...]) sur une dépendance de cible),
  • activez les chemins code, car chaque trait activé est disponible sous forme de condition de compilation (#if TraitName),
  • basculez les paramètres de build comme les defines ou les linker flags,
  • activez d'autres traits.

Un package peut également définir des traits par défaut. Ils sont activés, sauf si le consommateur passe une liste explicite.

Si vous connaissez les subspecs CocoaPods ou les features Cargo en Rust, c'est le même principe.

Pourquoi c'est important dans Capacitor

Capacitor génère l’application Package.swift de l’app pour vous, vous ne pouvez donc pas modifier à la main les lignes de dépendance pour passer des traits. Avant CLI 8.3, les auteurs de plugins avec un SDK natif optionnel avaient deux mauvais choix sur SPM : toujours lier le SDK, ce qui augmentait la taille et ajoutait parfois du travail de conformité à l’export ou en matière de confidentialité, ou publier un second plugin. Cas courants :

  • SQLite chiffré vs non chiffré (SQLCipher),
  • SDKs d'analytics avec ou sans collecte d'identifiant publicitaire,
  • un SDK tiers optionnel pour un seul fournisseur de paiement ou de connexion,
  • outils de debug uniquement.

Activez les traits dans votre app

1. Vérifiez les versions

bunx cap --version      # 8.3.0 or later
xcodebuild -version     # Xcode 26 (required by Capacitor 8 anyway)

Le projet doit utiliser SPM : ios/App/CapApp-SPM existe. Si vous utilisez CocoaPods, consultez comment migrer votre app Capacitor vers SPM.

2. Trouvez les noms de traits du plugin

Ouvrez le plugin Package.swift dans node_modules et cherchez l' traits: array, ou consultez son README. Les noms de traits sont sensibles à la casse.

3. Configurez Capacitor

import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'Example',
  webDir: 'dist',
  experimental: {
    ios: {
      spm: {
        swiftToolsVersion: '6.1',
        packageTraits: {
          '@acme/capacitor-db': ['.defaults', 'SQLCipher'],
        },
      },
    },
  },
};

export default config;

La clé est le nom du package npm du plugin. La valeur est la liste des traits à activer.

4. Synchronisez et vérifiez le résultat

bunx cap sync ios

Le code généré ios/App/CapApp-SPM/Package.swift commence désormais par // swift-tools-version: 6.1 et la ligne de dépendance du plugin contient les traits :

.package(name: "AcmeCapacitorDb", path: "../../../node_modules/@acme/capacitor-db", traits: [.defaults, "SQLCipher"])

Le CLI écrit .defaults (ou defaults, .default, default dans tous les cas) comme le SwiftPM .defaults valeur, et tous les autres noms sous forme de chaîne entre guillemets.

Lancez le build dans Xcode. Si Xcode affiche toujours l'ancien graphe, utilisez File > Packages > Reset Package Caches.

Les règles que le CLI impose

Le Capacitor CLI valide la config lors de la synchronisation :

  • Si un plugin a une liste de traits non vide et swiftToolsVersion est manquant, la synchronisation s’arrête avec « Package traits require an explicit Swift tools version of 6.1 or higher. »
  • Si swiftToolsVersion est inférieure à 6,1, la synchronisation s’arrête et vous indique que la version est trop basse.
  • swiftToolsVersion doit ressembler à 6.1 ou 6.1.0.
  • Les plugins avec un tableau vide sont traités comme s’ils n’étaient pas listés.

Conserver ou supprimer les traits par défaut

Lister des traits remplace les valeurs par défaut. Comparez :

Valeur de configuration Résultat
non répertorié traits par défaut du plugin
['SQLCipher'] uniquement SQLCipher, désactivés par défaut
['.defaults', 'SQLCipher'] Traits par défaut + SQLCipher

Lisez la doc du plugin avant de retirer les traits par défaut. Un plugin peut mettre son backend standard derrière un trait par défaut.

Ajouter des traits à votre propre plugin

Si vous maintenez un plugin avec un SDK optionnel, voici un exemple complet Package.swift. Le nom du package doit correspondre à celui que le Capacitor CLI dérive de votre nom npm (@acme/capacitor-db devient AcmeCapacitorDb). Consultez migrer un plugin Capacitor vers SPM pour connaître la règle.

// swift-tools-version: 6.1
import PackageDescription

let package = Package(
    name: "AcmeCapacitorDb",
    platforms: [.iOS(.v15)],
    products: [
        .library(name: "AcmeCapacitorDb", targets: ["DbPlugin"])
    ],
    traits: [
        .trait(name: "SQLCipher", description: "Link SQLCipher and enable encrypted databases."),
        .default(enabledTraits: [])
    ],
    dependencies: [
        .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0"),
        .package(url: "https://github.com/sqlcipher/SQLCipher.swift.git", from: "4.10.0")
    ],
    targets: [
        .target(
            name: "DbPlugin",
            dependencies: [
                .product(name: "Capacitor", package: "capacitor-swift-pm"),
                .product(name: "Cordova", package: "capacitor-swift-pm"),
                .product(
                    name: "SQLCipher",
                    package: "SQLCipher.swift",
                    condition: .when(traits: ["SQLCipher"])
                )
            ],
            path: "ios/Sources/DbPlugin"
        )
    ],
    swiftLanguageModes: [.v5]
)

Consultez le dépôt de SDK pour vérifier l’URL du package, le nom du produit et la version actuels avant de copier ceci.

Points faciles à oublier :

  • La version 6.x des outils change le mode de langage par défaut en Swift 6 pour vos cibles. Capacitor ne prend pas encore officiellement en charge Swift 6, donc conservez swiftLanguageModes: [.v5] sauf si votre code est prêt pour la concurrence stricte.
  • Passer la version des outils de votre plugin à 6.1 impose Xcode 16.3+ aux utilisateurs. Les apps Capacitor 8 exigent déjà Xcode 26, ce n’est donc pas une nouvelle contrainte.

Utilisez le trait dans code

Les traits activés sont des conditions de compilation dans les cibles de votre package :

#if SQLCipher
import SQLCipher
#endif

@objc func open(_ call: CAPPluginCall) {
    let key = call.getString("encryptionKey")
    #if SQLCipher
    // open with key
    #else
    if key != nil {
        call.unavailable("Encryption requires the SQLCipher trait. Enable it in experimental.ios.spm.packageTraits.")
        return
    }
    #endif
    // open without encryption
}

Retournez une erreur claire indiquant le nom du trait lorsqu’une fonctionnalité est désactivée. Sinon, les développeurs d’applications voient un échec silencieux et blâment le plugin.

Vous pouvez également définir votre propre flag avec swiftSettings: [.define("ACME_SQLCIPHER", .when(traits: ["SQLCipher"]))] si vous préférez un nom préfixé.

Concevez des traits additifs

SwiftPM unifie les traits dans tout le graphe de dépendances. Si deux packages dépendent de votre plugin avec des traits différents, l’union est activée. Donc :

  • Activer un trait doit ajouter des capacités, pas supprimer API ni modifier les valeurs par défaut.
  • Évitez les traits mutuellement exclusifs. Si vous ne pouvez pas, faites échouer le build bruyamment :
#if TraitA && TraitB
#error("TraitA and TraitB cannot be enabled together")
#endif

Testez chaque combinaison

swift build seul se compile pour Mac, et un plugin qui dépend de Capacitor ne se compile que pour iOS, testez donc les traits via une app de test Capacitor compilée pour un simulateur iOS. Pour chaque combinaison (aucune entrée pour les traits par défaut, ['SQLCipher'], ['.defaults', 'SQLCipher'] et ainsi de suite), modifiez packageTraits dans la config de l’app de test, puis synchronisez et compilez :

bunx cap sync ios
xcodebuild build \
  -project ios/App/App.xcodeproj \
  -scheme App \
  -destination 'generic/platform=iOS Simulator' \
  CODE_SIGNING_ALLOWED=NO

Ajoutez chaque combinaison à la CI en tant que job distinct.

Garder les utilisateurs de CocoaPods couverts

Les traits n'existent que dans SPM. Si votre plugin fournit également un podspec, offrez le même choix que les subspecs :

s.default_subspec = 'Core'

s.subspec 'Core' do |core|
  core.source_files = 'ios/Sources/DbPlugin/**/*.swift'
  core.dependency 'Capacitor'
end

s.subspec 'SQLCipher' do |sc|
  sc.dependency 'AcmeCapacitorDb/Core'
  sc.dependency 'SQLCipher', '~> 4.10'
  sc.pod_target_xcconfig = { 'SWIFT_ACTIVE_COMPILATION_CONDITIONS' => '$(inherited) SQLCipher' }
end

Définir le même nom de condition de compilation dans le subspec permet de partager un #if SQLCipher chemin code. Les applications CocoaPods sélectionnent alors le subspec dans leur Podfile. Le Capacitor CLI écrit une pod ligne par plugin dans capacitor_pods, documentez donc la ligne Podfile supplémentaire dans votre README. Comment utiliser CocoaPods avec Capacitor 8 indique où placer les lignes de pod personnalisées.

Limites

  • Expérimental. Les options se trouvent sous experimental et peuvent être déplacées vers ios.spm.* in a future major. Expect a config rename at some point.
  • Swift 6 non officiellement pris en charge. The CLI’s own docs warn that setting swiftToolsVersion à 6.0 ou supérieur peut provoquer des problèmes. Testez l’application complète, en particulier les plugins qui livrent des xcframeworks binaires.
  • iOS uniquement. Android n’a pas d’équivalent dans Capacitor. Les plugins gèrent les SDK Android optionnels avec des variables Gradle dans variables.gradle ou des artefacts séparés.
  • Les plugins doivent opt in. La plupart des plugins ne définissent pas encore de traits. Vérifiez avant de vous y mettre.

Troubleshooting

La synchro échoue avec « Package traits require an explicit Swift tools version of 6.1 or higher ». Ajoutez swiftToolsVersion: '6.1' à côté de packageTraits.

SwiftPM signale un trait inconnu. Les noms de traits sont sensibles à la casse et doivent exister dans le Package.swift de la version installée.

Fonctionnalité toujours absente après activation du trait. Réinitialisez les caches des paquets dans Xcode, nettoyez le dossier de build et vérifiez le CapApp-SPM/Package.swift a traits: . Modifier ce fichier à la main n’a pas d’effet, car CLI le réécrit à chaque synchronisation.

Erreurs dans Swift code après augmentation de la version des outils. Il s’agit du mode langage Swift 6 dans un paquet que vous contrôlez. Ajoutez swiftLanguageModes: [.v5].

Conflits de noms entre plugins. Depuis CLI 8,4, experimental.ios.spm.packageOptions vous permet de définir symlink ou moduleAliases par plugin. Plus de détails dans l’ guide de dépannage iOS de Capacitor.

Pour une vue d’ensemble de SPM, lisez SPM vs CocoaPods pour Capacitor. Pour des builds cloud qui tournent déjà sur la version actuelle de Xcode pour les projets SPM, consultez Build Capgo.

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.