メインコンテンツへスキップ

Capacitor 8 で SPM Package Traits を使う方法

Capacitor 8 で SPM package traits を使う: packageTraits でオプションのプラグイン機能を有効化し、swiftToolsVersion 6.1 を設定して、独自のプラグインに traits を追加します。

Capacitor iOS プロジェクトでの Swift Package Manager 設定のイメージ図

Capacitor 8 で SPM package traits を使用するには、 experimental.ios.spm.swiftToolsVersion まで "6.1" を設定し、各プラグインの traits を experimental.ios.spm.packageTraits を Capacitor の設定に記述し、次に bunx cap sync iosを実行します。CLI は、これらの traits を生成される CapApp-SPM/Package.swiftに書き込み、SwiftPM は対応するオプションの依存関係と code パスを使ってプラグインをビルドします。これには Capacitor CLI 8.3.0 以降が必要で、Swift Package Manager を使用する iOS プロジェクトにのみ適用されます。

Traits は、プラグインにおける SPM と CocoaPods の最後の大きな機能差を埋めます。それは、以前は podspec の subspec だったオプションのネイティブ依存関係です。このガイドでは、アプリ側、プラグイン作者側、そして現在の実験的サポートの制限事項を説明します。

Package traits とは

Package traits は、Swift Evolution の提案 SE-0450で、Swift 6.1 (Xcode 16.3 以降) で実装されました。パッケージは、その Package.swift。利用側は、パッケージに依存する際に有効にする trait を選べます。trait では次のことができます:

  • 依存関係をオプションにする(condition: .when(traits: [...]) ターゲット依存関係に対して)、
  • code パスを有効にする(有効化した trait はすべてコンパイル条件として使えるため)、#if TraitName),
  • define やリンカフラグなどのビルド設定を切り替える、
  • 他の trait を有効にする。

パッケージは trait をデフォルトに指定することもできます。利用側が明示的なリストを渡さない限り、それらは有効です。

CocoaPods の subspec や Rust の Cargo features を知っていれば、同じ考え方です。

Capacitor で重要な理由

Capacitor はアプリの Package.swift を生成するので、trait を渡すために依存関係の行を手で編集することはできません。CLI 8.3 より前は、オプションのネイティブ SDK を持つプラグイン作者には SPM で 2 つの悪い選択肢がありました。常に SDK をリンクしてサイズを増やし、プライバシーや輸出コンプライアンス対応が増えることもあるか、2 つ目のプラグインを公開するかです。よくあるケース:

  • 暗号化 SQLite とプレーン SQLite(SQLCipher)、
  • 広告識別子の収集あり/なしの analytics SDK、
  • 決済またはログインプロバイダー1社向けのオプションのベンダー SDK、
  • デバッグ専用ツール。

アプリで traits を有効にする

1. バージョンを確認する

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

プロジェクトで SPM を使用している必要があります: ios/App/CapApp-SPM が存在します。CocoaPods を使用している場合は、 Capacitor アプリを SPM に移行する方法.

2. プラグインの trait 名を特定する

プラグインの Package.swift における node_modules を探してください traits: 配列、またはその README を確認してください。Trait 名は大文字小文字を区別します。

3. 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;

キーはプラグインの npm パッケージ名です。値は有効にする Trait のリストです。

4. 同期して出力を確認する

bunx cap sync ios

生成された ios/App/CapApp-SPM/Package.swift は以下で始まります // swift-tools-version: 6.1 プラグインの依存関係行には Trait が含まれます:

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

CLI は .defaults (または defaults, .default, default いずれの場合も) を SwiftPM の .defaults 値として書き、他のすべての名前は引用符付きの文字列として書き込みます。

Xcode でビルドします。Xcode がまだ古いグラフを表示している場合は、 File > Packages > Reset Package Caches.

CLI が適用するルール

Capacitor CLI は、同期時に設定を検証します:

  • いずれかのプラグインが空でないトレイトリストを持ち、 swiftToolsVersion が欠落している場合、同期は「Package traits require an explicit Swift tools version of 6.1 or higher.」で停止します。
  • もし swiftToolsVersion が 6.1 未満の場合、同期は停止し、バージョンが低すぎると通知します。
  • swiftToolsVersion は次の形式である必要があります 6.1 または 6.1.0.
  • 空の配列を持つプラグインは、リストにないものとして扱われます。

デフォルト traits を残すか削除する

トレイトを列挙すると、デフォルトが置き換わります。比較:

設定値 実績
未記載 プラグインのデフォルト traits
['SQLCipher'] のみ SQLCipher、デフォルトでオフ
['.defaults', 'SQLCipher'] デフォルトに追加 SQLCipher

デフォルトを削除する前にプラグインのドキュメントを確認してください。標準バックエンドがデフォルト trait に含まれている場合があります。

自作プラグインに traits を追加する

オプションの SDK を持つプラグインをメンテナンスしている場合、完全な Package.swiftです。パッケージ名は、Capacitor が CLI から npm 名を導出するものと一致する必要があります(@acme/capacitor-db に変わります AcmeCapacitorDb)。参照: Capacitor プラグインを SPM に移行する ルールについて。

// 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]
)

コピーする前に、SDK のリポジトリで現在のパッケージURL、製品名、バージョンを確認してください。

見落としやすいポイント:

  • Tools バージョン 6.x では、デフォルトの言語モードが Swift 6 に変更されます ターゲットに対して。Capacitor はまだ Swift 6 を公式にサポートしていないため、 swiftLanguageModes: [.v5] code が厳密な並行処理に対応するまで、このままにしてください。
  • プラグインの Tools バージョンを 6.1 に上げると、利用者は Xcode 16.3 以上が必要になります。 Capacitor 8 のアプリはすでに Xcode 26 を要求しているため、これは新しい制約ではありません。

code で trait を使用する

有効化された traits は、パッケージのターゲットにおけるコンパイル条件です:

#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
}

機能がオフの場合、そのトレイト名を明示した明確なエラーを返してください。そうしないと、アプリ開発者はサイレントな失敗に遭遇し、プラグインのせいにします。

prefixed な名前を好む場合は、独自のフラグを以下のように定義できます。 swiftSettings: [.define("ACME_SQLCIPHER", .when(traits: ["SQLCipher"]))] prefixed な名前を好む場合は、

traits を追加可能な形で設計する

SwiftPM は依存関係グラフ全体でトレイトを統一します。2つのパッケージが異なるトレイトであなたのプラグインに依存している場合、それらの和集合が有効になります。つまり:

  • トレイトを有効にすると、API を削除したりデフォルトを変更したりするのではなく、機能が追加されるべきです。
  • 相互排他的なトレイトは避けてください。避けられない場合は、ビルドを明確に失敗させます:
#if TraitA && TraitB
#error("TraitA and TraitB cannot be enabled together")
#endif

すべての組み合わせをテストする

swift build 単体では Mac 向けにビルドされ、Capacitor に依存するプラグインは iOS 向けにのみビルドされるため、iOS シミュレータ向けにビルドされた Capacitor テストアプリを通じてトレイトをテストしてください。各組み合わせ(デフォルトトレイトのエントリなし、 ['SQLCipher'], ['.defaults', 'SQLCipher'] など)について、 packageTraits テストアプリの設定を変更し、同期してビルドします:

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

各組み合わせを CI に独立したジョブとして追加してください。

CocoaPods ユーザーもカバー

Traits は SPM にのみ存在します。プラグインが podspec も同梱している場合は、subspec として同じ選択肢を提供してください:

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

subspec に同じコンパイル条件名を設定すれば、1 つの #if SQLCipher code パスを共有できます。CocoaPods アプリでは Podfile で subspec を選択します。Capacitor CLI は、 pod プラグインごとに 1 行を内部へ capacitor_pods書き込むため、README に追加の Podfile 行を記載してください。 Capacitor 8 で CocoaPods を使う方法 カスタム pod 行をどこに書くかを示しています。

制限事項

  • 実験的機能。 オプションは以下にあり、 experimental 別の場所に移動する可能性があります。 ios.spm.* 将来のメジャーバージョンで。いずれ設定名が変更される予定です。
  • Swift 6 は公式にサポートされていません。 CLI 自身のドキュメントでも、 swiftToolsVersion を 6.0 以上に設定すると問題が発生する可能性があるとの警告があります。プラグイン(特にバイナリ xcframework を同梱しているもの)を含むアプリ全体をテストしてください。
  • iOSのみ。 Android には Capacitor に相当するものはありません。プラグインは、 variables.gradle 内の Gradle 変数または個別のアーティファクトで任意の Android SDK を処理します。
  • プラグインはオプトインが必要です。 ほとんどのプラグインはまだ traits を定義していません。利用を計画する前に確認してください。

トラブルシューティング

「Package traits require an explicit Swift tools version of 6.1 or higher」エラーで同期が失敗します。 追加 swiftToolsVersion: '6.1' の横にある packageTraits.

SwiftPMが不明なtraitを報告します。 trait名は大文字小文字を区別し、プラグインの Package.swift にインストールされたバージョンで存在する必要があります。

traitを有効にしても機能がまだ見つからない。 Xcodeでパッケージキャッシュをリセットし、buildフォルダをクリーンアップして、生成された CapApp-SPM/Package.swift に traits: サフィックスがあることを確認してください。このファイルを直接編集しても、CLIがすべてのsync時に書き換えるため、変更は保持されません。

toolsバージョンを上げた後のSwift code でのエラー。 これは、あなたが管理するパッケージでのSwift 6言語モードです。 swiftLanguageModes: [.v5].

プラグイン間の名前衝突。 CLI 8.4以降、 experimental.ios.spm.packageOptions 設定できます symlink または moduleAliases プラグイン単位で。詳細は Capacitor iOSトラブルシューティングガイド.

SPMの全体像については、 Capacitor の SPM と CocoaPods 比較。SPMプロジェクトで最新のXcodeが使えるクラウドビルドが必要なら、 Capgo のビルド.

Capacitor アプリ向けの Live Updates

Web レイヤーのバグが本番で発生したら、App Store の審査を何日も待たずに Capgo で修正を配信しましょう。ネイティブの変更は通常の審査フローに残したまま、ユーザーはバックグラウンドでアップデートを受け取れます。

最新のブログ記事

Capgoは、真にプロフェッショナルなモバイルアプリを作るために必要な最高のインサイトを提供します。