Movatterモバイル変換


[0]ホーム

URL:


Skip to main content

docs.flutter.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.

Learn more

Flutter 3.41 is live! Check out theFlutter 3.41 blog post!

Swift Package Manager for plugin authors

How to add Swift Package Manager compatibility to iOS and macOS plugins

Warning

Flutter is migrating toSwift Package Manager to manage iOS and macOS native dependencies. Flutter's support of Swift Package Manager is under development. If you find a bug in Flutter's Swift Package Manager support,open an issue. Swift Package Manager support isoff by default. Flutter continues to support CocoaPods.

Flutter's Swift Package Manager integration has several benefits:

  1. Provides access to the Swift package ecosystem. Flutter plugins can use the growing ecosystem ofSwift packages!
  2. Simplifies Flutter installation. Swift Package Manager is bundled with Xcode. In the future, you won’t need to install Ruby and CocoaPods to target iOS or macOS.

How to turn on Swift Package Manager

#

Flutter's Swift Package Manager support is turned off by default. To turn it on:

  1. Upgrade to the latest Flutter SDK:

    sh
    flutter upgrade
  2. Turn on the Swift Package Manager feature:

    sh
    flutter config --enable-swift-package-manager

Using the Flutter CLI to run an appmigrates the project to add Swift Package Manager integration. This makes your project download the Swift packages that your Flutter plugins depend on. An app with Swift Package Manager integration requires Flutter version 3.24 or higher. To use an older Flutter version, you will need toremove Swift Package Manager integration from the app.

Flutter falls back to CocoaPods for dependencies that do not support Swift Package Manager yet.

How to turn off Swift Package Manager

#
Plugin authors

Disabling Swift Package Manager causes Flutter to use CocoaPods for all dependencies. However, Swift Package Manager remains integrated with your project. To remove Swift Package Manager integration completely from your project, follow theHow to remove Swift Package Manager integration instructions.

Turn off for a single project

#

In the project'spubspec.yaml file, under theflutter section, setenable-swift-package-manager tofalse in theconfig subsection.

pubspec.yaml
yaml
# The following section is specific to Flutter packages.flutter:config:enable-swift-package-manager:false

This turns off Swift Package Manager for all contributors to this project.

Migrating from deprecated syntax

If you were previously usingdisable-swift-package-manager: true, update yourpubspec.yaml to use the newconfig section format shown above. The old syntax is deprecated and will produce an error in Flutter 3.38 and later.

Run the following command:

sh
flutter config --no-enable-swift-package-manager

This turns off Swift Package Manager for the current user.

If a project is incompatible with Swift Package Manager, all contributors need to run this command.

How to add Swift Package Manager support to an existing Flutter plugin

#

This guide shows how to add Swift Package Manager support to a plugin that already supports CocoaPods. This ensures the plugin is usable by all Flutter projects.

Flutter plugins should supportboth Swift Package Manager and CocoaPods until further notice.

Swift Package Manager adoption will be gradual. Plugins that don't support CocoaPods won't be usable by projects that haven't migrated to Swift Package Manager yet. Plugins that don't support Swift Package Manager can cause problems for projects that have migrated.

Replaceplugin_name throughout this guide with the name of your plugin. The example below usesios, replaceios withmacos/darwin as applicable.

  1. Turn on the Swift Package Manager feature.

  2. Start by creating a directory under theios,macos, and/ordarwin directories. Name this new directory the name of the platform package.

    • plugin_name/
      • ios/
        • plugin_name/
  3. Within this new directory, create the following files/directories:

    • Package.swift (file)
    • Sources (directory)
    • Sources/plugin_name (directory)

    Your plugin should look like:

    • plugin_name/
      • ios/
        • plugin_name/
          • Package.swift
          • Sources/
            • plugin_name/
  4. Use the following template in thePackage.swift file:

    Package.swift
    swift
    // swift-tools-version: 5.9// The swift-tools-version declares the minimum version of Swift required to build this package.importPackageDescriptionletpackage=Package(// TODO: Update your plugin name.name:"plugin_name",platforms:[// TODO: Update the platforms your plugin supports.// If your plugin only supports iOS, remove `.macOS(...)`.// If your plugin only supports macOS, remove `.iOS(...)`..iOS("13.0"),.macOS("10.15")],products:[// TODO: Update your library and target names.// If the plugin name contains "_", replace with "-" for the library name..library(name:"plugin-name",targets:["plugin_name"])],dependencies:[],targets:[.target(// TODO: Update your target name.name:"plugin_name",dependencies:[],resources:[// TODO: If your plugin requires a privacy manifest// (e.g. if it uses any required reason APIs), update the PrivacyInfo.xcprivacy file// to describe your plugin's privacy impact, and then uncomment this line.// For more information, see:// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files// .process("PrivacyInfo.xcprivacy"),// TODO: If you have other resources that need to be bundled with your plugin, refer to// the following instructions to add them:// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package])])
  5. Update thesupported platforms in yourPackage.swift file.

    Package.swift
    swift
    platforms:[// TODO: Update the platforms your plugin supports.// If your plugin only supports iOS, remove `.macOS(...)`.// If your plugin only supports macOS, remove `.iOS(...)`..iOS("13.0"),.macOS("10.15")],
  6. Update the package, library, and target names in yourPackage.swift file.

    Package.swift
    swift
    letpackage=Package(// TODO: Update your plugin name.name:"plugin_name",platforms:[.iOS("13.0"),.macOS("10.15")],products:[// TODO: Update your library and target names.// If the plugin name contains "_", replace with "-" for the library name.library(name:"plugin-name",targets:["plugin_name"])],dependencies:[],targets:[.target(// TODO: Update your target name.name:"plugin_name",dependencies:[],resources:[// TODO: If your plugin requires a privacy manifest// (e.g. if it uses any required reason APIs), update the PrivacyInfo.xcprivacy file// to describe your plugin's privacy impact, and then uncomment this line.// For more information, see:// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files// .process("PrivacyInfo.xcprivacy"),// TODO: If you have other resources that need to be bundled with your plugin, refer to// the following instructions to add them:// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package])])
    Note

    If the plugin name contains_, the library name must be a- separated version of the plugin name.

  7. If your plugin has aPrivacyInfo.xcprivacy file, move it toios/plugin_name/Sources/plugin_name/PrivacyInfo.xcprivacy and uncomment the resource in thePackage.swift file.

    Package.swift
    swift
    resources:[// TODO: If your plugin requires a privacy manifest// (e.g. if it uses any required reason APIs), update the PrivacyInfo.xcprivacy file// to describe your plugin's privacy impact, and then uncomment this line.// For more information, see:// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files.process("PrivacyInfo.xcprivacy"),// TODO: If you have other resources that need to be bundled with your plugin, refer to// the following instructions to add them:// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package],
  8. Move any resource files fromios/Assets toios/plugin_name/Sources/plugin_name (or a subdirectory). Add the resource files to yourPackage.swift file, if applicable. For more instructions, seehttps://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package.

  9. Move all files fromios/Classes toios/plugin_name/Sources/plugin_name.

  10. Theios/Assets,ios/Resources, andios/Classes directories should now be empty and can be deleted.

  11. If your plugin usesPigeon, update your Pigeon input file.

    pigeons/messages.dart
    dart
    kotlinOptions:KotlinOptions(),javaOut:'android/app/src/main/java/io/flutter/plugins/Messages.java',javaOptions:JavaOptions(),swiftOut:'ios/Classes/messages.g.swift',swiftOut:'ios/plugin_name/Sources/plugin_name/messages.g.swift',swiftOptions:SwiftOptions(),
  12. Update yourPackage.swift file with any customizations you might need.

    1. Open theios/plugin_name/ directory in Xcode.

    2. In Xcode, open yourPackage.swift file. Verify Xcode doesn't produce any warnings or errors for this file.

      Tip

      If Xcode doesn't show any files, quit Xcode (Xcode > Quit Xcode) and reopen.

      If Xcode doesn't update after you make a change, try clickingFile > Packages > Reset Package Caches.

    3. If yourios/plugin_name.podspec file hasCocoaPodsdependencys, add the correspondingSwift Package Manager dependencies to yourPackage.swift file.

    4. If your package must be linked explicitlystatic ordynamic (not recommended by Apple), update theProduct to define the type:

      Package.swift
      swift
      products:[.library(name:"plugin-name",type:.static,targets:["plugin_name"])],
    5. Make any other customizations. For more information on how to write aPackage.swift file, seehttps://developer.apple.com/documentation/packagedescription.

      Tip

      If you add targets to yourPackage.swift file, use unique names. This avoids conflicts with targets from other packages.

  13. Update yourios/plugin_name.podspec to point to new paths.

  14. Update loading of resources from bundle to useBundle.module.

    swift
    #ifSWIFT_PACKAGEletsettingsURL=Bundle.module.url(forResource:"image",withExtension:"jpg")#elseletsettingsURL=Bundle(for:Self.self).url(forResource:"image",withExtension:"jpg")#endif
    Note
  15. If your.gitignore doesn't include.build/ and.swiftpm/ directories, you'll want to update your.gitignore to include:

    .gitignore
    .build/.swiftpm/

    Commit your plugin's changes to your version control system.

  16. Verify the plugin still works with CocoaPods.

    1. Turn off Swift Package Manager.

      sh
      flutter config --no-enable-swift-package-manager
    2. Navigate to the plugin's example app.

      sh
      cd path/to/plugin/example/
    3. Ensure the plugin's example app builds and runs.

      sh
      flutter run
    4. Navigate to the plugin's top-level directory.

      sh
      cd path/to/plugin/
    5. Run CocoaPods validation lints.

      sh
      pod lib lint ios/plugin_name.podspec  --configuration=Debug --skip-tests --use-modular-headers --use-libraries
      sh
      pod lib lint ios/plugin_name.podspec  --configuration=Debug --skip-tests --use-modular-headers
  17. Verify the plugin works with Swift Package Manager.

    1. Turn on Swift Package Manager.

      sh
      flutter config --enable-swift-package-manager
    2. Navigate to the plugin's example app.

      sh
      cd path/to/plugin/example/
    3. Ensure the plugin's example app builds and runs.

      sh
      flutter run
      Note
    4. Open the plugin's example app in Xcode. Ensure thatPackage Dependencies shows in the leftProject Navigator.

  18. Verify tests pass.

Replaceplugin_name throughout this guide with the name of your plugin. The example below usesios, replaceios withmacos/darwin as applicable.

  1. Turn on the Swift Package Manager feature.

  2. Start by creating a directory under theios,macos, and/ordarwin directories. Name this new directory the name of the platform package.

    • plugin_name/
      • ios/
        • plugin_name/
  3. Within this new directory, create the following files/directories:

    • Package.swift (file)
    • Sources (directory)
    • Sources/plugin_name (directory)
    • Sources/plugin_name/include (directory)
    • Sources/plugin_name/include/plugin_name (directory)
    • Sources/plugin_name/include/plugin_name/.gitkeep (file)
      • This file ensures the directory is committed. You can remove the.gitkeep file if other files are added to the directory.

    Your plugin should look like:

    • plugin_name/
      • ios/
        • plugin_name/
          • Package.swift
          • Sources/plugin_name/include/plugin_name/
            • .gitkeep/
  4. Use the following template in thePackage.swift file:

    Package.swift
    swift
    // swift-tools-version: 5.9// The swift-tools-version declares the minimum version of Swift required to build this package.importPackageDescriptionletpackage=Package(// TODO: Update your plugin name.name:"plugin_name",platforms:[// TODO: Update the platforms your plugin supports.// If your plugin only supports iOS, remove `.macOS(...)`.// If your plugin only supports macOS, remove `.iOS(...)`..iOS("13.0"),.macOS("10.15")],products:[// TODO: Update your library and target names.// If the plugin name contains "_", replace with "-" for the library name.library(name:"plugin-name",targets:["plugin_name"])],dependencies:[],targets:[.target(// TODO: Update your target name.name:"plugin_name",dependencies:[],resources:[// TODO: If your plugin requires a privacy manifest// (e.g. if it uses any required reason APIs), update the PrivacyInfo.xcprivacy file// to describe your plugin's privacy impact, and then uncomment this line.// For more information, see:// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files// .process("PrivacyInfo.xcprivacy"),// TODO: If you have other resources that need to be bundled with your plugin, refer to// the following instructions to add them:// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package],cSettings:[// TODO: Update your plugin name..headerSearchPath("include/plugin_name")])])
  5. Update thesupported platforms in yourPackage.swift file.

    Package.swift
    swift
    platforms:[// TODO: Update the platforms your plugin supports.// If your plugin only supports iOS, remove `.macOS(...)`.// If your plugin only supports macOS, remove `.iOS(...)`..iOS("13.0"),.macOS("10.15")],
  6. Update the package, library, and target names in yourPackage.swift file.

    Package.swift
    swift
    letpackage=Package(// TODO: Update your plugin name.name:"plugin_name",platforms:[.iOS("13.0"),.macOS("10.15")],products:[// TODO: Update your library and target names.// If the plugin name contains "_", replace with "-" for the library name.library(name:"plugin-name",targets:["plugin_name"])],dependencies:[],targets:[.target(// TODO: Update your target name.name:"plugin_name",dependencies:[],resources:[// TODO: If your plugin requires a privacy manifest// (e.g. if it uses any required reason APIs), update the PrivacyInfo.xcprivacy file// to describe your plugin's privacy impact, and then uncomment this line.// For more information, see:// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files// .process("PrivacyInfo.xcprivacy"),// TODO: If you have other resources that need to be bundled with your plugin, refer to// the following instructions to add them:// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package],cSettings:[// TODO: Update your plugin name..headerSearchPath("include/plugin_name")])])
    Note

    If the plugin name contains_, the library name must be a- separated version of the plugin name.

  7. If your plugin has aPrivacyInfo.xcprivacy file, move it toios/plugin_name/Sources/plugin_name/PrivacyInfo.xcprivacy and uncomment the resource in thePackage.swift file.

    Package.swift
    swift
    resources:[// TODO: If your plugin requires a privacy manifest// (e.g. if it uses any required reason APIs), update the PrivacyInfo.xcprivacy file// to describe your plugin's privacy impact, and then uncomment this line.// For more information, see:// https://developer.apple.com/documentation/bundleresources/privacy_manifest_files.process("PrivacyInfo.xcprivacy"),// TODO: If you have other resources that need to be bundled with your plugin, refer to// the following instructions to add them:// https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package],
  8. Move any resource files fromios/Assets toios/plugin_name/Sources/plugin_name (or a subdirectory). Add the resource files to yourPackage.swift file, if applicable. For more instructions, seehttps://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package.

  9. Move any public headers fromios/Classes toios/plugin_name/Sources/plugin_name/include/plugin_name.

    • If you're unsure which headers are public, check yourpodspec file'spublic_header_files attribute. If this attribute isn't specified, all of your headers were public. You should consider whether you want all of your headers to be public.

    • ThepluginClass defined in yourpubspec.yaml file must be public and within this directory.

  10. Handlingmodulemap.

    Skip this step if your plugin does not have amodulemap.

    If you're using amodulemap for CocoaPods to create a Test submodule, consider removing it for Swift Package Manager. Note that this makes all public headers available through the module.

    To remove themodulemap for Swift Package Manager but keep it for CocoaPods, exclude themodulemap and umbrella header in the plugin'sPackage.swift file.

    The example below assumes themodulemap and umbrella header are located in theios/plugin_name/Sources/plugin_name/include directory.

    Package.swift
    swift
    .target(name:"plugin_name",dependencies:[],exclude:["include/cocoapods_plugin_name.modulemap","include/plugin_name-umbrella.h"],

    If you want to keep your unit tests compatible with both CocoaPods and Swift Package Manager, you can try the following:

    Tests/TestFile.m
    objc
    @importplugin_name;@importplugin_name.Test;#if __has_include(<plugin_name/plugin_name-umbrella.h>)@importplugin_name.Test;#endif

    If you would like to use a custommodulemap with your Swift package, refer toSwift Package Manager's documentation.

  11. Move all remaining files fromios/Classes toios/plugin_name/Sources/plugin_name.

  12. Theios/Assets,ios/Resources, andios/Classes directories should now be empty and can be deleted.

  13. If your header files are no longer in the same directory as your implementation files, you should update your import statements.

    For example, imagine the following migration:

    • Before:

      ios/Classes/├── PublicHeaderFile.h└── ImplementationFile.m
    • After:

      ios/plugin_name/Sources/plugin_name/└── include/plugin_name/   └── PublicHeaderFile.h└── ImplementationFile.m

    In this example, the import statements inImplementationFile.m should be updated:

    Sources/plugin_name/ImplementationFile.m
    objc
    #import "PublicHeaderFile.h"#import "./include/plugin_name/PublicHeaderFile.h"
  14. If your plugin usesPigeon, update your Pigeon input file.

    pigeons/messages.dart
    dart
    javaOptions:JavaOptions(),objcHeaderOut:'ios/Classes/messages.g.h',objcSourceOut:'ios/Classes/messages.g.m',objcHeaderOut:'ios/plugin_name/Sources/plugin_name/messages.g.h',objcSourceOut:'ios/plugin_name/Sources/plugin_name/messages.g.m',copyrightHeader:'pigeons/copyright.txt',

    If yourobjcHeaderOut file is no longer within the same directory as theobjcSourceOut, you can change the#import usingObjcOptions.headerIncludePath:

    pigeons/messages.dart
    dart
    javaOptions:JavaOptions(),objcHeaderOut:'ios/Classes/messages.g.h',objcSourceOut:'ios/Classes/messages.g.m',objcHeaderOut:'ios/plugin_name/Sources/plugin_name/include/plugin_name/messages.g.h',objcSourceOut:'ios/plugin_name/Sources/plugin_name/messages.g.m',objcOptions:ObjcOptions(headerIncludePath:'./include/plugin_name/messages.g.h',),copyrightHeader:'pigeons/copyright.txt',

    Run Pigeon to re-generate its code with the latest configuration.

  15. Update yourPackage.swift file with any customizations you might need.

    1. Open theios/plugin_name/ directory in Xcode.

    2. In Xcode, open yourPackage.swift file. Verify Xcode doesn't produce any warnings or errors for this file.

      Tip

      If Xcode doesn't show any files, quit Xcode (Xcode > Quit Xcode) and reopen.

      If Xcode doesn't update after you make a change, try clickingFile > Packages > Reset Package Caches.

    3. If yourios/plugin_name.podspec file hasCocoaPodsdependencys, add the correspondingSwift Package Manager dependencies to yourPackage.swift file.

    4. If your package must be linked explicitlystatic ordynamic (not recommended by Apple), update theProduct to define the type:

      Package.swift
      swift
      products:[.library(name:"plugin-name",type:.static,targets:["plugin_name"])],
    5. Make any other customizations. For more information on how to write aPackage.swift file, seehttps://developer.apple.com/documentation/packagedescription.

      Tip

      If you add targets to yourPackage.swift file, use unique names. This avoids conflicts with targets from other packages.

  16. Update yourios/plugin_name.podspec to point to new paths.

  17. Update loading of resources from bundle to useSWIFTPM_MODULE_BUNDLE:

    Note
  18. If yourios/plugin_name/Sources/plugin_name/include directory only contains a.gitkeep, you'll want update your.gitignore to include the following:

    .gitignore
    !.gitkeep

    Runflutter pub publish --dry-run to ensure theinclude directory is published.

  19. Commit your plugin's changes to your version control system.

  20. Verify the plugin still works with CocoaPods.

    1. Turn off Swift Package Manager:

      sh
      flutter config --no-enable-swift-package-manager
    2. Navigate to the plugin's example app.

      sh
      cd path/to/plugin/example/
    3. Ensure the plugin's example app builds and runs.

      sh
      flutter run
    4. Navigate to the plugin's top-level directory.

      sh
      cd path/to/plugin/
    5. Run CocoaPods validation lints:

      sh
      pod lib lint ios/plugin_name.podspec  --configuration=Debug --skip-tests --use-modular-headers --use-libraries
      sh
      pod lib lint ios/plugin_name.podspec  --configuration=Debug --skip-tests --use-modular-headers
  21. Verify the plugin works with Swift Package Manager.

    1. Turn on Swift Package Manager:

      sh
      flutter config --enable-swift-package-manager
    2. Navigate to the plugin's example app.

      sh
      cd path/to/plugin/example/
    3. Ensure the plugin's example app builds and runs.

      sh
      flutter run
      Note
    4. Open the plugin's example app in Xcode. Ensure thatPackage Dependencies shows in the leftProject Navigator.

  22. Verify tests pass.

How to update unit tests in a plugin's example app

#

If your plugin has native XCTests, you might need to update them to work with Swift Package Manager if one of the following is true:

  • You're using a CocoaPod dependency for the test.
  • Your plugin is explicitly set totype: .dynamic in itsPackage.swift file.

To update your unit tests:

  1. Open yourexample/ios/Runner.xcworkspace in Xcode.

  2. If you were using a CocoaPod dependency for tests, such asOCMock, you'll want to remove it from yourPodfile file.

    ios/Podfile
    ruby
    target'RunnerTests'doinherit!:search_pathspod'OCMock','3.5'end

    Then in the terminal, runpod install in theplugin_name_ios/example/ios directory.

  3. Navigate toPackage Dependencies for the project.

    The project's package dependencies

    The project's package dependencies

  4. Click the+ button and add any test-only dependencies by searching for them in the top right search bar.

    Search for test-only dependencies

    Search for test-only dependencies

    Note

    OCMock uses unsafe build flags and can only be used if targeted by commit.fe1661a3efed11831a6452f4b1a0c5e6ddc08c3d is the commit for the 3.9.3 version.

  5. Ensure the dependency is added to theRunnerTests Target.

    Ensure the dependency is added to the `RunnerTests` target

    Ensure the dependency is added to theRunnerTests target

  6. Click theAdd Package button.

  7. If you've explicitly set your plugin's library type to.dynamic in itsPackage.swift file (not recommended by Apple), you'll also need to add it as a dependency to theRunnerTests target.

    1. EnsureRunnerTestsBuild Phases has aLink Binary With Libraries build phase:

      The `Link Binary With Libraries` Build Phase in the `RunnerTests` target

      TheLink Binary With Libraries Build Phase in theRunnerTests target

      If the build phase doesn't exist already, create one. Click theadd button and then clickNew Link Binary With Libraries Phase.

      Add `Link Binary With Libraries` Build Phase

      AddLink Binary With Libraries Build Phase

    2. Navigate toPackage Dependencies for the project.

    3. Click theadd button.

    4. In the dialog that opens, click theAdd Local... button.

    5. Navigate toplugin_name/plugin_name_ios/ios/plugin_name_ios and click theAdd Package button.

    6. Ensure that it's added to theRunnerTests target and click theAdd Package button.

  8. Ensure tests passProduct > Test.

Was this page's content helpful?

Unless stated otherwise, the documentation on this site reflects Flutter 3.38.6. Page last updated on 2025-12-08.View source orreport an issue.


[8]ページ先頭

©2009-2026 Movatter.jp