在现有 xcode 项目上使用 swift 包管理器

Use swift package manager on existing xcode project

我是 swift 和 xcode 世界的新手,所以我在尝试将包集成到我的项目时遇到了问题。

我想添加 Alamofire 依赖,使用以下命令:

在我的根项目文件夹中:

swift init

这会创建 Package.swift 文件,我在里面添加依赖项,运行 然后:

swift build

一切似乎都很好,但是当我尝试导入我的库时我的项目是:

import Alamofire

我收到一个错误,它说模块无法识别。 所以我的问题是,在不崩溃的情况下集成包管理器和对现有项目的依赖的正确步骤是什么。

更新:

swift build

输出:

Resolved version: 4.3.0
Compile Swift Module 'Alamofire' (17 sources)
Compile Swift Module 'Sample' (1 sources)

而我的 Package.swift 是:

import PackageDescription

let package = Package(
    name: "Sample",
    dependencies: [
        .Package(url: "https://github.com/Alamofire/Alamofire.git", majorVersion: 4)
    ]
)

Swift Package Manager 是一个独立的工具,它允许在没有 Xcode 的情况下管理依赖项和构建项目。它可以为您生成 Xcode 个项目 swift package generate-xcodeproj

但是,目前 Swift 包管理器仅支持为 macOS 和 Linux 平台构建项目。为 iOS、tvOS 和 watchOS 构建项目的唯一方法是使用 Xcode,其中包括这些平台所需的 SDK。

有一些方法可以使用 Swift 包管理器来管理 iOS/tvOS/watchOS 的依赖项,但这并不容易,需要手动操作。有兴趣的可以看看https://github.com/j-channings/swift-package-manager-ios

除此之外,我建议使用 Carthage or CocoaPods

更新 Xcode 11

Swift 包管理器现已集成到 Xcode 11。您可以通过转到 "File" 然后 "Swift Packages" 然后 "Add Package Dependency..." 粘贴您的包存储库的 URL 进入上面的字段,然后单击 "next"。 Xcode 将引导您完成其余步骤。您可以在 this WWDC talk.

了解更多信息

Swift 程序包管理器 (SPM)

[iOS Dependency manager]

消费

Produce:如果你正在开发library/module(模块化)你应该注意支持它

Package.swift - 清单文件。

  • 这是一个硬编码名称。
  • 应放在同层或更高层,其他情况:
target '<target_name>' in package '<package_name>' is outside the package root

Package.swift 例子

// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
 
let package = Package(

    name: "PackageName1",

    //Supported platforms
    platforms: [
        .iOS(.v11)
    ],
    
    //Product list - executable binary
    products: [
        .library(
            name: "LibraryName1",
            targets: ["TargetName1"]),
    ],

    //Additional SPM dependencies declaration(packages) which are used in targets
    dependencies: [

        //Local package path
        .package(name: "PackageName2", path: "../Feature1")

        //Local package URL
        .package(name: "PackageName2", url: "file:///some_local_path", .branch("master"))

        //Remote package URL
        .package(name: "PackageName2", url: "https://github.com/user/repo", .branch("master")),
    ],

    targets: [
        //Source code location. implicitly `Sources/<target_name>`(Sources/TargetName1) or explicitly `path:`
        .target(
            name: "TargetName1",
            dependencies: [
                //using dependencies from package.targets and package.dependencies

                //package.targets
                "LibraryName2"

                //package.dependencies
                .product(name: "PM2LibraryName1", package: "PackageName2")
            ]),
            path: "Sources/TargetName1"
    ]
)

观察 Swift 依赖性

  • == package.targets.target.name
  • package.products.library.name仅用于Xcode表示
  • 图书馆被使用[About]
  • 当目标依赖于另一个目标时,源代码将被包含到 single 库中,其中有一种来自 .modulemap[=34= 的 explicit multi module ]和access可以认为
import Module1
import Module2
  • Swift 库转换为单个 .o format file and .swiftmodule
  • Swift 库公开了 .modulemap umbrella.h[About] 用于公开 Objective-C 消费者思想的模块 @import SomeModule;
- You are able to work with `Package.swift` in Xcode if double click on it
.swiftpm/xcode with .xcworkspace will be generated 
- When you work with `Package.swift` you are able to check it, just save this file
- When you work with `Package.swift` you should specify schema and device(platform)
- When you build `Package.swift` 
  - library and .swiftmodule is located:
<path_to_derived_data>/DerivedData/<folder_name_where_Package.swift_located>-<randomizer>/Build/Products/<platform>
//e.g.
/Users/alex/Library/Developer/Xcode/DerivedData/someFolder-ccivqbbjujxuvdcxtuydyqfeepfx/Build/Products/Debug-iphonesimulator
  - .modulemap and umbrella.header is located:
<path_to_derived_data>/DerivedData/<folder_name_where_Package.swift_located>-<randomizer>/Build/Intermediates.noindex/<project_name>.build/<platform>/<target_name>.build/<.modulemap> and plus /Objects-normal/<arch>/<tarhet_name-Swift.h>

- When you build consumer with `Package.swift` results files will be located:
<path_to_derived_data>/DerivedData/<target_name>-<randomizer>/Build/Products/<platform>

- When you work with consumer of `Package.swift` SPM clones it into
<path_to_derived_data>/DerivedData/<target_name>-<randomizer>/SourcePackages/checkouts

package.products.library.targets

您可以指定多个目标。这意味着可以使用单个可执行二进制文件(一种伞形库)中的多个模块

producer:
package.products.library.targets: ["TargetName1", "TargetName2"]

consumer: 
1. adds single library
2. several imports

import TargetName1
import TargetName2

package.targets.target.dependencies

如果你的目标有依赖性。你也会有同样的效果-伞库。

1.Add 来自同一包的另一个 目标

例如使用Explicit Dependency[About]。重要:使用相同的名称(模块和 SPM 目标)。如果您不在 package.targets.target.dependencies 处设置依赖项,则会出现下一个错误

Undefined symbol

2.Add product 来自另一个包。来自其他包的所有目标都将公开

2.1 本地包路径

您不能在消费者端使用。但至少能让你出道

package <package_name_1> is required using a revision-based requirement and it depends on local package <package_name_2>, which is not supported

2.2本地包URL

不要在路径中使用 space( ) 否则你会得到

The URL file:///hello world/some_local_path is invalid

如果你不指定 // swift-tools-version:<version> 你会得到:

package at '<some_path>' is using Swift tools version 3.1.0 which is no longer supported; consider using '// swift-tools-version:5.3' to specify the current tools version

*不要忘记在测试之前提交您的更改和更新

如果您使用的是 Xcode 项目,则不需要(也不应该使用)Package.swift,只需单击 Swift 中的包中的加号图标Xcode,并添加Swift包的GitHub URL,库也会自动添加到你的目标中(按照下面的GIF,或点击添加图标图片 here):

额外信息

  • 不一致问题:您不能为相同的目标同时维护 Xcode 项目和 Swift.package。它们不同步,并且会变得不一致,因此根据使用的工具,您将获得不同的构建:令人困惑。您过去可以使用 swift package generate-xcodeproj 创建基于 Package.swift 的 xcodeproj,但这已被弃用。您对此 Xcodeproj 所做的更改未反映在原始 Package.swift) 中。
  • xcodebuild vs. swift build:方便的是,如果与 Package.swift 相同的目录中没有 xcodeprojxcodebuild 将自动生成方案供您使用,因此您不必使用swift build。例如,运行 xcodebuild -list 查看从您的 Package.swift 文件生成的方案列表,然后使用这些方案之一。不方便的是,没有办法/配置让 xcodebuild 使用 Package.swift.