swift package 技巧及混编兼容问题详解-kb88凯时官网登录

来自:网络
时间:2023-06-25
阅读:
免费资源网 - https://freexyz.cn/
目录

创建 package

mkdir somepath
cd somepath
swift package init (--type library/executable/empty/system module)

其中,type 的四种类型分别对应:

  • library: 库(默认)
  • executable: 可执行文件
  • empty: 空项目
  • system module: 系统模板项目

一般情况下默认即可

创建 package 之后,还可以使用 swift package generate-xcodeproj 创建一个xcode项目来编译和调试代码

使用 package

在 xcode 菜单栏中,选择 file -> add packages

可以指定 package 的版本规则

维护 package

版本控制

在 package 路径下,使用 git init 来创建一个仓库。之后上传至远端即可

本地调试修改

对于通过 cocoapods 引入的库,如果想在本地修改该库并提交的话,需要在 podfile 里面把路径改成本地的,然后再 pod install 一下,比较麻烦

但是修改 swift package 引入的库就很方便了,直接把 package 的文件目录拖到工程目录下即可。修改好提交到远端之后,右键 delete -> remove reference (move to trash 会删掉本地文件)

然后 file -> packages -> update to latest,即可更新到最新的版本

package 之间的依赖

在每个 swift package 的目录下都有个 package.swift 文件。内容如下:

// swift-tools-version:5.5
// the swift-tools-version declares the minimum version of swift required to build this package.
import packagedescription
let package = package(
    name: "some name",
    products: [
        // products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "some name",
            targets: ["some name"]),
    ],
    dependencies: [
        // dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // targets are the basic building blocks of a package. a target can define a module or a test suite.
        // targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "some name",
            dependencies: []),
        .testtarget(
            name: "some name",
            dependencies: ["some name"]),
    ]
)

其中的字段分别表示:

  • name: 库/项目名字
  • products: 库/项目生成的东西,可以是 library 或者 executable. 同一个库/项目可以生成多个 library 或者 executable
  • dependencies: 此库/项目所依赖的库,及依赖库的 url 和版本等信息。如果依赖本地库的话,可以添加 .package(path:"local path")
  • targets: 库/项目生成的目标

相较于 cocoapods,swift package 还是更加方便点的,而且是苹果自家的产品。但是目前很多三方库都在 cocoapods 上,swift package 的大面积普及还需要一段时间

混编问题

target 拆分

apple 官方文档里说:

targets can contain swift, objective-c/c , or c/c code, but an individual target can’t mix swift with c-family languages. for example, a swift package can have two targets, one that contains objective-c, objective-c , and c code, and a second one that contains swift code.

也就是说,spm 是支持 objc 以及 c 系代码的。但是同一个 target 里面只能有一种语言,swift 文件不能和 objc 文件放到一个 target 里。

如果我们想要在一个 spm 仓库里面同时放置两种语言的代码的话,就需要将仓库拆分为两个 target:

let package = package(
    name: "mymodule",
    platforms: [.ios(.v11),
                .macos(.v11)],
    products: [
        // products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "mymodule",
            targets: ["mymodule", "mymodule_objc"])
    ],
    dependencies: [
        // dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // targets are the basic building blocks of a package. a target can define a module or a test suite.
        // targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "mymodule_objc",
            dependencies: [],
            publicheaderspath: "include",
            csettings: [.headersearchpath(".")],
            cxxsettings: [.headersearchpath(".")]
        ),
        .target(
            name: "mymodule",
            dependencies: ["mymodule_objc"],
            path: "sources/mymodule",
            swiftsettings: [.define("spm_mode")]
        ),
        .testtarget(
            name: "mymoduletests",
            dependencies: ["mymodule"]),
    ]
)

其中,仓库文件结构应该为:

- mymodule
  |
  |-readme.md
  |
  |-package.swift
  |
  |-sources
    |
    |-mymodule
    | |
    | |- mypackage.swift  
    |
    |-mymodule_objc
      |
      |-include
      | |
      | |- myobjcclass.h
      |
      |- myobjcclass.m

sources 文件夹拆分为两个子文件夹,分别是两个 target 的路径。swift target 依赖 objc 的 target, objc 的 target 可以设置公开 header 的路径。

这样,objc 以及 c/c 这些 c 系的文件都放在 mymodule_objc 文件夹下,swift 文件放到 mymodule 文件夹下,就可以在同一个 spm 仓库下实现混编了。

引用以及和 cocoapods 的兼容问题

在上面的 package 设置里面可以看到一行预处理宏的定义:

swiftsettings: [.define("spm_mode")]

这个设置是用来标识当前库是通过 spm 方式引入的。根据上文,spm 模式下,当前库的 swift 和 objc 是两个 target。因此,同一个库的 swift 文件想要调用 objc 文件的话,必须引入 objc 的 target:

import mymodule_objc
// your code...

但是,我们的库一般情况下还是要支持 cocoapods 的。在 cocoapods 模式下,同一个仓库的 swift 和 objc 文件是不需要拆分为两个 target 的,pod 是通过桥接文件等来实现两者之间相互调用的。

那么问题就来了,当使用 cocoapods 引入当前库时,import mymodule_objc 是肯定会报错的,因为 pod 并不会生成 mymodule_objc

这时候,我们在 package 文件里预先定义的宏就派上用场了:

#if spm_mode
import foundationx_objc
#endif

只有在 spm 模式下,才会 import mymodule_objc,这样就解决了与 cocoapods 的兼容问题。

以上就是swift package 技巧及混编兼容问题详解的详细内容,更多关于swift package混编兼容的资料请关注其它相关文章!

免费资源网 - https://freexyz.cn/
返回顶部
顶部
网站地图