跳到主内容

Swift Package Manager 插件作者指南

如何为 iOS 和 macOS 插件添加 Swift Package Manager 兼容性

Flutter 的 Swift Package Manager 集成具有多种优势

  1. 提供对 Swift 包生态系统的访问。Flutter 插件可以使用不断增长的 Swift 包 生态系统!
  2. 简化 Flutter 安装。Swift Package Manager 与 Xcode 捆绑在一起。将来,您无需安装 Ruby 和 CocoaPods 即可定位 iOS 或 macOS。

如何启用 Swift Package Manager

#

Flutter 的 Swift Package Manager 支持默认情况下是关闭的。要启用它

  1. 升级到最新的 Flutter SDK

    sh
    flutter upgrade
    
  2. 启用 Swift Package Manager 功能

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

使用 Flutter CLI 运行应用 迁移项目 以添加 Swift Package Manager 集成。这将使您的项目下载 Flutter 插件所依赖的 Swift 包。使用 Swift Package Manager 集成的应用需要 Flutter 版本 3.24 或更高版本。要使用旧版本的 Flutter,您需要 删除 Swift Package Manager 集成

对于尚未支持 Swift Package Manager 的依赖项,Flutter 将回退到 CocoaPods。

如何禁用 Swift Package Manager

#

禁用 Swift Package Manager 将导致 Flutter 为所有依赖项使用 CocoaPods。但是,Swift Package Manager 仍然集成到您的项目中。要完全从项目中删除 Swift Package Manager 集成,请按照 如何删除 Swift Package Manager 集成 说明进行操作。

为单个项目禁用

#

在项目的 pubspec.yaml 文件中,在 flutter 部分下,在 config 子部分中将 enable-swift-package-manager 设置为 false

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

这会为该项目的所有贡献者禁用 Swift Package Manager。

为所有项目全局禁用

#

运行以下命令

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

这会为当前用户禁用 Swift Package Manager。

如果项目与 Swift Package Manager 不兼容,所有贡献者都需要运行此命令。

如何将 Swift Package Manager 支持添加到现有的 Flutter 插件

#

本指南介绍了如何将 Swift Package Manager 支持添加到已经支持 CocoaPods 的插件。这可确保插件可供所有 Flutter 项目使用。

在进一步通知之前,Flutter 插件应同时支持 Swift Package Manager 和 CocoaPods。

Swift Package Manager 的采用将是渐进的。不支持 CocoaPods 的插件将无法被尚未迁移到 Swift Package Manager 的项目使用。不支持 Swift Package Manager 的插件可能会给已迁移的项目带来问题。

在整个指南中,将 plugin_name 替换为您的插件名称。下面的示例使用 ios,请根据需要将 ios 替换为 macos/darwin

  1. 启用 Swift Package Manager 功能.

  2. 首先在 iosmacos 和/或 darwin 目录中创建一个目录。将此新目录命名为平台包的名称。

    • plugin_name/
      • ios/
        • plugin_name/
  3. 在此新目录中,创建以下文件/目录

    • Package.swift (文件)
    • Sources (目录)
    • Sources/plugin_name (目录)

    您的插件应如下所示

    • plugin_name/
      • ios/
        • plugin_name/
          • Package.swift
          • Sources/
            • plugin_name/
  4. Package.swift 文件中使用以下模板

    Package.swift
    swift
    // swift-tools-version: 5.9
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = 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. 更新 Package.swift 文件中的 支持的平台

    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. 更新 Package.swift 文件中的包、库和目标名称。

    Package.swift
    swift
    let package = 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
                ]
            )
        ]
    )
    
  7. 如果您的插件具有 PrivacyInfo.xcprivacy 文件,请将其移动到 ios/plugin_name/Sources/plugin_name/PrivacyInfo.xcprivacy 并取消注释 Package.swift 文件中的资源。

    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. 将任何资源文件从 ios/Assets 移动到 ios/plugin_name/Sources/plugin_name(或子目录)。如果适用,将资源文件添加到您的 Package.swift 文件中。有关更多说明,请参阅 https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package

  9. 将所有文件从 ios/Classes 移动到 ios/plugin_name/Sources/plugin_name

  10. ios/Assetsios/Resourcesios/Classes 目录现在应该为空,并且可以删除。

  11. 如果您的插件使用 Pigeon,请更新您的 Pigeon 输入文件。

    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. 使用您可能需要的任何自定义更新您的 Package.swift 文件。

    1. 在 Xcode 中打开 ios/plugin_name/ 目录。

    2. 在 Xcode 中,打开您的 Package.swift 文件。验证 Xcode 是否未对此文件产生任何警告或错误。

    3. 如果您的 ios/plugin_name.podspec 文件具有 CocoaPods dependency,请将相应的 Swift Package Manager 依赖项添加到您的 Package.swift 文件中。

    4. 如果您的包必须显式链接 staticdynamic不推荐由 Apple 使用),请更新 Product 以定义类型

      Package.swift
      swift
      products: [
          .library(name: "plugin-name", type: .static, targets: ["plugin_name"])
      ],
      
    5. 进行任何其他自定义。有关如何编写 Package.swift 文件的更多信息,请参阅 https://developer.apple.com/documentation/packagedescription

  13. 更新您的 ios/plugin_name.podspec 以指向新的路径。

    ios/plugin_name.podspec
    ruby
    s.source_files = 'Classes/**/*.swift'
    s.resource_bundles = {'plugin_name_privacy' => ['Resources/PrivacyInfo.xcprivacy']}
    s.source_files = 'plugin_name/Sources/plugin_name/**/*.swift'
    s.resource_bundles = {'plugin_name_privacy' => ['plugin_name/Sources/plugin_name/PrivacyInfo.xcprivacy']}
    
  14. 更新从 bundle 加载资源以使用 Bundle.module

    swift
    #if SWIFT_PACKAGE
         let settingsURL = Bundle.module.url(forResource: "image", withExtension: "jpg")
    #else
         let settingsURL = Bundle(for: Self.self).url(forResource: "image", withExtension: "jpg")
    #endif
    
  15. 如果您的 .gitignore 不包含 .build/.swiftpm/ 目录,您需要更新您的 .gitignore 以包含

    .gitignore
    .build/
    .swiftpm/
    

    提交您的插件更改到您的版本控制系统。

  16. 验证插件是否仍然适用于 CocoaPods。

    1. 禁用 Swift Package Manager。

      sh
      flutter config --no-enable-swift-package-manager
      
    2. 导航到插件的示例应用。

      sh
      cd path/to/plugin/example/
      
    3. 确保插件的示例应用可以构建和运行。

      sh
      flutter run
      
    4. 导航到插件的顶级目录。

      sh
      cd path/to/plugin/
      
    5. 运行 CocoaPods 验证 lint。

      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. 验证插件是否适用于 Swift Package Manager。

    1. 启用 Swift Package Manager。

      sh
      flutter config --enable-swift-package-manager
      
    2. 导航到插件的示例应用。

      sh
      cd path/to/plugin/example/
      
    3. 确保插件的示例应用可以构建和运行。

      sh
      flutter run
      
    4. 在 Xcode 中打开插件的示例应用。确保左侧 项目导航器 中显示 包依赖项

  18. 验证测试是否通过。

在整个指南中,将 plugin_name 替换为您的插件名称。下面的示例使用 ios,请根据需要将 ios 替换为 macos/darwin

  1. 启用 Swift Package Manager 功能.

  2. 首先在 iosmacos 和/或 darwin 目录中创建一个目录。将此新目录命名为平台包的名称。

    • plugin_name/
      • ios/
        • plugin_name/
  3. 在此新目录中,创建以下文件/目录

    • Package.swift (文件)
    • Sources (目录)
    • Sources/plugin_name (目录)
    • Sources/plugin_name/include (目录)
    • Sources/plugin_name/include/plugin_name (目录)
    • Sources/plugin_name/include/plugin_name/.gitkeep (文件)
      • 此文件可确保提交该目录。如果向该目录添加了其他文件,您可以删除 .gitkeep 文件。

    您的插件应如下所示

    • plugin_name/
      • ios/
        • plugin_name/
          • Package.swift
          • Sources/plugin_name/include/plugin_name/
            • .gitkeep/
  4. Package.swift 文件中使用以下模板

    Package.swift
    swift
    // swift-tools-version: 5.9
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = 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. 更新 Package.swift 文件中的 支持的平台

    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. 更新 Package.swift 文件中的包、库和目标名称。

    Package.swift
    swift
    let package = 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")
                ]
            )
        ]
    )
    
  7. 如果您的插件具有 PrivacyInfo.xcprivacy 文件,请将其移动到 ios/plugin_name/Sources/plugin_name/PrivacyInfo.xcprivacy 并取消注释 Package.swift 文件中的资源。

    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. 将任何资源文件从 ios/Assets 移动到 ios/plugin_name/Sources/plugin_name(或子目录)。如果适用,将资源文件添加到您的 Package.swift 文件中。有关更多说明,请参阅 https://developer.apple.com/documentation/xcode/bundling-resources-with-a-swift-package

  9. 将任何公共头文件从 ios/Classes 移动到 ios/plugin_name/Sources/plugin_name/include/plugin_name

    • 如果您不确定哪些头文件是公共的,请检查您的 podspec 文件中的 public_header_files 属性。如果未指定此属性,则所有头文件都是公共的。您应该考虑是否希望所有头文件都是公共的。

    • 在您的 pubspec.yaml 文件中定义的 pluginClass 必须是公共的并且位于此目录中。

  10. 处理 modulemap

    如果您的插件没有 modulemap,请跳过此步骤。

    如果您正在使用 modulemap 来创建 CocoaPods 的 Test 子模块,请考虑将其删除以用于 Swift Package Manager。请注意,这将使所有公共头文件通过模块可用。

    要删除 Swift Package Manager 的 modulemap 但保留 CocoaPods 的 modulemap,请在插件的 Package.swift 文件中排除 modulemap 和 umbrella header。

    下面的示例假定 modulemap 和 umbrella header 位于 ios/plugin_name/Sources/plugin_name/include 目录中。

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

    如果您希望您的单元测试与 CocoaPods 和 Swift Package Manager 兼容,可以尝试以下方法

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

    如果您想为您的 Swift 包使用自定义 modulemap,请参阅 Swift Package Manager 的文档

  11. ios/Classes 中的所有剩余文件移动到 ios/plugin_name/Sources/plugin_name

  12. ios/Assetsios/Resourcesios/Classes 目录现在应该为空,并且可以删除。

  13. 如果您的头文件不再与您的实现文件位于同一目录中,您应该更新您的导入语句。

    例如,想象以下迁移

    • 之前

      ios/Classes/
      ├── PublicHeaderFile.h
      └── ImplementationFile.m
      
    • 之后

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

    在此示例中,ImplementationFile.m 中的导入语句应进行更新

    Sources/plugin_name/ImplementationFile.m
    objc
    #import "PublicHeaderFile.h"
    #import "./include/plugin_name/PublicHeaderFile.h"
    
  14. 如果您的插件使用 Pigeon,请更新您的 Pigeon 输入文件。

    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',
    

    如果您的 objcHeaderOut 文件不再与 objcSourceOut 位于同一目录中,您可以使用 ObjcOptions.headerIncludePath 更改 #import

    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',
    

    运行 Pigeon 以使用最新的配置重新生成其代码。

  15. 使用您可能需要的任何自定义更新您的 Package.swift 文件。

    1. 在 Xcode 中打开 ios/plugin_name/ 目录。

    2. 在 Xcode 中,打开您的 Package.swift 文件。验证 Xcode 是否未对此文件产生任何警告或错误。

    3. 如果您的 ios/plugin_name.podspec 文件具有 CocoaPods dependency,请将相应的 Swift Package Manager 依赖项添加到您的 Package.swift 文件中。

    4. 如果您的包必须显式链接 staticdynamic不推荐由 Apple 使用),请更新 Product 以定义类型

      Package.swift
      swift
      products: [
          .library(name: "plugin-name", type: .static, targets: ["plugin_name"])
      ],
      
    5. 进行任何其他自定义。有关如何编写 Package.swift 文件的更多信息,请参阅 https://developer.apple.com/documentation/packagedescription

  16. 更新您的 ios/plugin_name.podspec 以指向新的路径。

    ios/plugin_name.podspec
    ruby
    s.source_files = 'Classes/**/*.{h,m}'
    s.public_header_files = 'Classes/**/*.h'
    s.module_map = 'Classes/cocoapods_plugin_name.modulemap'
    s.resource_bundles = {'plugin_name_privacy' => ['Resources/PrivacyInfo.xcprivacy']}
    s.source_files = 'plugin_name/Sources/plugin_name/**/*.{h,m}'
    s.public_header_files = 'plugin_name/Sources/plugin_name/include/**/*.h'
    s.module_map = 'plugin_name/Sources/plugin_name/include/cocoapods_plugin_name.modulemap'
    s.resource_bundles = {'plugin_name_privacy' => ['plugin_name/Sources/plugin_name/PrivacyInfo.xcprivacy']}
    
  17. 更新从 bundle 加载资源的方式,以使用 SWIFTPM_MODULE_BUNDLE

    objc
    #if SWIFT_PACKAGE
       NSBundle *bundle = SWIFTPM_MODULE_BUNDLE;
     #else
       NSBundle *bundle = [NSBundle bundleForClass:[self class]];
     #endif
     NSURL *imageURL = [bundle URLForResource:@"image" withExtension:@"jpg"];
    
  18. 如果您的 ios/plugin_name/Sources/plugin_name/include 目录仅包含一个 .gitkeep 文件,您需要更新您的 .gitignore 文件以包含以下内容

    .gitignore
    !.gitkeep
    

    运行 flutter pub publish --dry-run 以确保 include 目录已发布。

  19. 提交您的插件更改到您的版本控制系统。

  20. 验证插件是否仍然适用于 CocoaPods。

    1. 关闭 Swift Package Manager

      sh
      flutter config --no-enable-swift-package-manager
      
    2. 导航到插件的示例应用。

      sh
      cd path/to/plugin/example/
      
    3. 确保插件的示例应用可以构建和运行。

      sh
      flutter run
      
    4. 导航到插件的顶级目录。

      sh
      cd path/to/plugin/
      
    5. 运行 CocoaPods 验证 lint

      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. 验证插件是否适用于 Swift Package Manager。

    1. 开启 Swift Package Manager

      sh
      flutter config --enable-swift-package-manager
      
    2. 导航到插件的示例应用。

      sh
      cd path/to/plugin/example/
      
    3. 确保插件的示例应用可以构建和运行。

      sh
      flutter run
      
    4. 在 Xcode 中打开插件的示例应用。确保左侧 项目导航器 中显示 包依赖项

  22. 验证测试是否通过。

如何更新插件示例应用中的单元测试

#

如果您的插件具有本地 XCTests,如果满足以下条件之一,您可能需要更新它们以使其与 Swift Package Manager 协同工作

  • 您正在为测试使用 CocoaPod 依赖项。
  • 您的插件在 Package.swift 文件中显式设置为 type: .dynamic

要更新您的单元测试

  1. 在 Xcode 中打开您的 example/ios/Runner.xcworkspace

  2. 如果您正在为测试使用 CocoaPod 依赖项,例如 OCMock,您需要将其从 Podfile 文件中删除。

    ios/Podfile
    ruby
    target 'RunnerTests' do
      inherit! :search_paths
    
      pod 'OCMock', '3.5'
    end
    

    然后在终端中,在 plugin_name_ios/example/ios 目录中运行 pod install

  3. 导航到项目的 Package Dependencies(包依赖项)。

    The project's package dependencies

    项目的包依赖项

  4. 单击 + 按钮,并通过在右上角的搜索栏中搜索来添加任何仅用于测试的依赖项。

    Search for test-only dependencies

    搜索仅用于测试的依赖项

  5. 确保将依赖项添加到 RunnerTests Target(目标)。

    Ensure the dependency is added to the `RunnerTests` target

    确保将依赖项添加到 RunnerTests 目标

  6. 单击 Add Package(添加包)按钮。

  7. 如果您已在 Package.swift 文件中将插件的库类型显式设置为 .dynamicApple 不推荐),您还需要将其作为依赖项添加到 RunnerTests 目标。

    1. 确保 RunnerTests Build Phases(构建阶段)具有 Link Binary With Libraries(链接二进制文件与库)构建阶段

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

      RunnerTests 目标的 Link Binary With Libraries 构建阶段

      如果构建阶段尚不存在,请创建一个。单击 add 按钮,然后单击 New Link Binary With Libraries Phase(新建链接二进制文件与库阶段)。

      Add `Link Binary With Libraries` Build Phase

      添加 Link Binary With Libraries 构建阶段

    2. 导航到项目的 Package Dependencies(包依赖项)。

    3. 单击 add 按钮。

    4. 在打开的对话框中,单击 Add Local...(添加本地...)按钮。

    5. 导航到 plugin_name/plugin_name_ios/ios/plugin_name_ios,然后单击 Add Package(添加包)按钮。

    6. 确保将其添加到 RunnerTests 目标,然后单击 Add Package(添加包)按钮。

  8. 确保测试通过 Product > Test(产品 > 测试)。