大多数浏览器和
Developer App 均支持流媒体播放。
-
Swift 中的二进制框架
Xcode 11 现充分支持通过 Swift 使用和创建二进制框架。了解如何利用新的 XCFramework 套装类型同时支持设备和模拟器,Swift 模块接口如何工作,以及如何长期管理您对框架的更改。
资源
相关视频
WWDC20
WWDC19
-
下载
大家下午好 我叫 Harlan 我非常高兴能和 你们讨论 Xcode 11 是如何允许 你们在 Swift 中创建和分发 二进制框架的
在讨论二进制框架之前 我想先花点时间 谈谈 Swift 包
借助 Xcode 11 中 对 Swift 包的新支持 你们可以轻松地在项目中 创建和使用它们并将其分发给其他人 Swift 包是 分发代码的好方法 因为 Xcode 知道如何 管理它们的依赖关系 它会自动找出 要使用的包版本 由于它们是以 源代码形式进行分发的 因此无需保持 与客户端的二进制兼容性 如果你有能力 提供项目的源代码 那么 Swift 包 真的很棒
但并不是每个人都有能力 发布其库的源代码 如果你没有这个能力
那么 Xcode 11 支持使用 新的 XC 框架格式 分发二进制库 因此在这次演讲中 我将向你介绍 XC 框架 这是一种受支持的 分发二进制框架的新方法 我还将讨论一些 客户在选择 使用第三方代码时 应该考虑的事情 接下来 我将讨论 XC 框中的内容 以及如何为项目 创建一个 XC 框架
最后我的同事 Jordan 会来和你们讨论 一些框架作者 应该考虑的事情 以便让他们的 框架尽可能的顺畅
XC 框架是一种新的方法 这个方法可以将 框架的多个变体捆绑在一起 使其能够在以后的 Xcode 版本中工作 单个 XC 框架可以 包含模拟器和设备的变体 还没有结束 因为单个 XC 框架 也可以包含 Xcode 支持的任何平台的变体 对于使用 AppKit 的 Mac App 你也可以有一个变体 对于使用 UIKit 的 Mac App 你也可以有一个变体 因此无论你的客户端 想要使用哪种 API 他们都能够有效地 使用你的框架 你不仅可以捆绑框架 还可以使用 XC 框架捆绑静态库及其 相应的头文件 Xcode 将自动设置 客户端的搜索板
而且当然 - XC 框架支持 基于 Swift 和 C 代码的 二进制分发 现在我想向 你们展示使用 XC 框架是多么容易
这里我有一个 非常简单的 iOS App 我将继续并单击 Run 以在 iPad 模拟器上运行它 你可以看到 它有一个很大的蓝色启动按钮 当你点击它时它什么都不做 这是因为它 连接到这个发射方法 它的主体是空的
我有一个很棒的 XC 框架 我想使用它 它的名字是 FlightKit
FlightKit 给了我 一些我想要在我 App 中呈现的 UI 因此为了能够实际使用 FlightKit XC 框架 我只需单击 项目导航栏中的项目 选择我的 Target 并确保选择了 General 选项卡
然后我将向下 滚动到 Frameworks, Libraries and Embedded Content
然后我将只是拖入我的 XC 框架 并且已经自动连接 为我的 Target 的依赖项
让我们回到代码 并开始使用它
就像你已经习惯 使用的任何框架一样 你要做的第一件事就是导入它
现在我想继续 使用 FlightKit 的一些 API 所以要么我可以 去查看文档 要么我可以按住 Command 单击 名称 FlightKit 然后单击 Jump to Definition 这会把我带到为 FlightKit 生成的接口 这显示了所有公共 API 每个公共类型 公共方法 我导入 FlightKit 时可以使用的所有内容 我可以看到 这有一个 LaunchViewController 它是 UIViewController 的子类 这似乎是我可能 希望展示的一小部分 UI
太好了 所以现在我需要知道 如何创建这些 我可以看到在界面 有一个初始化程序 需要构造一个 Spaceship Spaceship 也是 FlightKit 的一部分
如果我跳转到它的定义 它将进一步将我 代入到生成的界面中 并向我展示所有我可以 在 Spaceship 中使用的内容 我可以看到 有一个称为 name 的公共存储属性 并且还有一个输入 name 的公共 init 程序
好吧这样我就可以创建 一个太空船 并且我可以创建一个 LaunchViewController 然后我可以呈现它
那么让我们回到代码中 并准确地做到这一点
首先我要创建一个船
我可以看到 自动补全已经向我 暗示了所有在 FlightKit 中的成分 就像你已经习惯 使用的框架一样 我可以接受自动补全 然后我将为我的船 选择一个名字 好吧我已经有了 这一数组的船名 其中任何一个 都将是这艘船的好名字 我将从船名数组中 随机抽取一个元素 现在我将创建 一个 LaunchViewController 并将它传递给我刚刚创建的船 最后并显示 控制器自己作为发送者 在创建了一艘船和一些 UI 之后 我现在将进行展示
我将构建并在模拟器中运行我的程序 当我点击启 Launch 时 它会随机选择一个名字 然后启动 UI 如果我再次点击它 它会选择一个名字和另一个名字 你懂了吧
这就是如何在一个平台上 使用 XC 框架 但 XC 框架的一大优点是 可以将多个变体 放在同一个包中 因此只需将一个 XC 框架拖入其中 我不仅能够为 模拟器构建和运行 而且如果我选择 Generic iOS Device 那么我可以转到 Product Archive 并为 App Store 构建存档 从代码中使用 XC 框架 是多么容易啊
因此当你选择 使用框架时 了解你向第三方代码 提供哪些内容非常重要
重要的是 你希望确保信任框架的来源
你相信他们不会 给你的 App 带来漏洞或不稳定 你相信他们 会尊重你用户的隐私 例如如果你 已经为你的 App 授予了权限 并且你使用了一个框架 那么该框架也将被授予这些权限 以及那些许可也是一样 如果你的用户给了许可的话
此外如果你采用的框架 需要某种权限才能使用 那么你需要负责 将该权限添加到你的 App 中
关于使用框架 需要考虑的另一件事是 有时你会使用 一个带有自己依赖项的框架 这些依赖项可能也有自己的依赖项 你不仅有义务要 将所有这些添加到项目中 还要对它们每个部分 扩展同样的信任 现在值得注意的是 这种信任也扩展到了 使用 Swift 包 包相对于二进制框架的一个优点是 你可以检查代码 并且可以在调试时深入查看 如果你想了解 更多关于在 Xcode 中使用 Swift 包的信息 我向你推荐本周早些时候的会议 但无论你使用的 是包还是二进制框架 Xcode 11 都可以让你 轻松使用你信任的第三方代码
现在我想谈谈 如何创建一个 XC 框架
你要做的第一件事 就是有一些你 想要发布的源代码 让我们来看一下 早前 FlightKit 的一些源代码
这只是 FlightKit 中对象的子集 仅仅用来举例 但是你可以 看到我们之前看过的 Spaceship 类型
你还可以看到 一个名为 Speed 的枚举 它描述了事物在太空中移动的速度
你还会看到一个名为 Location 的结构体 用于描述对象在空间中的位置
太好了 我们有这个代码 现在我们将如何确保 我们构建此库 是用于分发? 在 Xcode 11 中 有一个新的构建设置 称为 Build Libraries for Distribution 它做的确实是这件事 它开启了所有构建库所需的特性 以便以一种可分发的方式构建库
现在我们来谈谈 其中一个特性
如果你以前尝试过 向某人发送已构建的 Swift 框架 那么你可能已经看到了这种错误的变体
已编译模块是由 较新版本的编译器创建的 这个错误到底意味着什么
当 Swift 编译器 导入一个模块时 它会为这个库 查找一个名为 Compiled Module 的文件
如果找到其中一个文件 它将读取可以调用的 公共 API 的 Manifest 并让你使用它们 现在这个已编译模块格式是二进制格式 基本上包含 内部编译器数据结构 由于它们只是内部数据结构 所以随着 Swift 编译器的每个版本 它们都可能发生变化 这意味着 如果一个人试图 用一个版本的 Swift 导入一个模块 而这个模块是由 另一个版本的 Swift 创建的 他们的编译器将无法理解这个模块 他们也无法使用这个模块
为了解决 这个版本锁定问题 Xcode 11 为 Swift 模块 引入了一种新的格式 称为 Swift 模块接口
就像已编译模块格式一样 它们列出了模块的所有公共 API 但使用的是 更像源代码的文本形式
由于它们的行为 类似于源代码 那么 Swift 编译器的未来版本 将能够导入 使用旧版本创建的模块接口 当你启用 Build Libraries for Distribution 时 你是在告诉编译器 在编译器构建框架时 去生成一个稳定的接口 那么这些接口 实际上是什么样的呢? 让我们再次看看 FlightKit 的源代码
这就是来自 FlightKit 的源代码 在右侧你将 看到 FlightKit 的模块接口 现在这有点多 而且它从屏幕上消失了 所以我们要一块一块地看 首先你会看到这部分元数据 这包括生成这个接口的编译器版本 但它也包含 命令行标记的子集 Swift 编译器需要 将其作为模块导入
接下来你将看到 这个框架导入的所有模块 然后我们将开始 查看作为该接口一部分的一些类型
这是 Spaceship 类的公共 API 现在我希望 你注意到这三件事 第一 公共 name 属性 包含在接口中 但是私有 currentLocation 属性不包含
它不是公共 API 的一部分 接下来 请注意接口中包含了公共初始化器 和 fly 方法
但是它们的主体 没有被包括进去 同样也是因为它们不是公共 API 的一部分
最后请注意 该类在接口中 有一个取消初始化程序 但是在原始源代码中 却没有进行写入 现在当你在 Swift 中编写类 并且没有提供显式取消初始化程序时 编译器将为你生成一个 这强调了模块接口 的一个基本原则 如果这种格式 在编译器的不同版本之间 应该是稳定的 那么编译器不应该对底层源代码做任何假设 因此我们将其包含在模块接口中 接下来让我们看一下 Speed 枚举 首先要看到的是 两个枚举都被包含了 这些是公共 API 的一部分 然而在接口中 对于哈希需要明确的遵守 我们列出了 遵循哈希和相等 所需的方法 这是因为在 Swift 中 如果你生成了一个 没有任何关联值的枚举 那么编译器就会隐式地 使其符合哈希和相等 并自动派生出所需的方法 因此本着明确的精神 它被包含在模块接口中
最后 Location 结构体 以现在方式包含在内 因为它只有 公共存储的属性 并且不声明任何遵循 以上就是 FlightKit 的模块接口
现在你已经了解了框架内部的内容 接下来让我们 讨论如何自己构建一个 可分发的二进制 XC 框架 构建框架的第一步 是构建存档 归档你的框架 将在发布模式下构建它 并将其打包以进行分发 你可以在管理器窗口中看到它
此外作为附加优势 此存档还将包含 与框架的该版本 对应的调试信息 这意味着 如果客户端有任何崩溃
他们将能够将其 发送给你 而你将能够查看符号并调试它 要存档框架 你可以使用 xcodebuild 存档命令
你将输入项目中 框架的 scheme
并列出要为其编译的目标 因此如果你正在为 iOS 构建 可以是一个用于模拟器 一个用于设备以及 一个用于运行 UIKit 的 Mac 你还需要通过 Skip Install 生成设置 并将其设置为 No 这告诉 xcodebuild 存档 在生成的存档中安装框架 因此通过执行此操作 你将构建框架的 每个变体的存档 这些存档 将在 Preference 窗口中的 Location 选项卡中的 Archive 目录可用 构建这些存档后 你可以提取框架 并将它们捆绑在 一个 XC 框架中 为此你将运行 xcodebuild -create-xcframework 命令
你将输入磁盘上每个框架的路径 然后提供你希望 输出 XC 框架输出到的路径 以上就是如何构建 XC 框架 总而言之请记住 你需要启用 Build Libraries for Distribution 以确保你的库是为了分发而构建的 你将运行 xcodebuild 归档 以构建框架的归档 最后运行 xcodebuild -create-xcframework 将其打包以便分发 然后你可以开始 将其发送给你的客户 然后他们可以开始采用它 这就是 XC 框架
现在我的同事 Jordan 将向你介绍作为一个框架作者 你应该考虑哪些内容 以使你的框架尽可能 顺畅地使用
谢谢 Harlan 好的 我们看到 将这些 XC 框架中的一个 引入作为框架客户端的 App 是多么容易 我们看到了生成 XC 框架所需的步骤 但这只是第一步 因为你是框架作者 并且你每年都在开发新功能 并为客户端做得更好 因此在这一节中 我将讨论 三件主要的事情 从不断的发布中 逐步发展你的框架 利用 Swift 提供的一些灵活性 来优化客户端 并帮助客户端 获得尽可能 平稳流畅的体验 因此请从发展你的框架开始 当我说要发展你的框架时 我是什么意思呢
好吧就像我说的 每次你发布新版本的框架时 它都会有新的功能 新的 API 可能还有一些漏洞修复 我们希望能够 在不破坏源代码 或二进制兼容性的情况下做到这一点 那么为什么二进制兼容性 在这里很重要呢
这是因为你 不一定知道 你的客户是谁 很多时候它只是一个 App Target 它们会使用你的框架 打包然后送到商店
但有时你的客户 本身就是二进制框架 要么来自你的公司 要么完全来自另一家公司 在这种情况下 你们两个可能 有不同的发布时间表 他们可能会 一直升级到 2.1 版 而你还在开发最新的版本 当你最终发布 1.1 版本时 他们不应该再为采用它 而付出任何额外的努力 你不希望陷入 两个二进制框架 彼此版本锁定的情况 因为使用它们的 App 可能 决定不更新 所以我在这里说 你的框架版本很重要 你不仅想 把它放在你的网站和你的文档上 而且你还应该 把它放在框架本身里 并且能这样做的地方是 框架的 Info.plist 中的 Bundle 版本字符串设置 这是人类可读版本号 你可以在这里与客户交流 自上次发布以来所做的更改 我们推荐的方法 是使用语义版本控制 如果你之前 没参加包讨论的话 我现在将快速回顾一下 什么是语义版本控制 最小的组成部分是 补丁版本 它表示何时对框架进行漏洞修复 或实现更改 而这些更改 不应该影响客户 中间组成部分用于 向后兼容的版本 新 API 或新功能 而主要的组成部分 是你必须做的 任何中断更改 不管是源代码中断 二进制中断 还是语义中断 在某种程度上 客户将不得不重新构建 甚至可能重做一些客户端代码 以采用新版本的框架 让我们看一下 FlightKit 模型对象 在实践中的效果 所以左边的情况 与我们之前的情况相同
现在在右边 我对这个框架进行了一系列更改
让我们逐个讨论它们 看看每个更改如何影响 框架的版本号
我们将从顶部开始
我已经为 Spaceship 船类 添加了一个新的私有属性 而我正在 Spaceship 的 初始化器中使用它
目前这些东西 都不会出现 在模块界面中 它们并不是你框架 的公共 API 的一部分
因此这种更改 只需要更新次要部分 或补丁版本部分
请记住 虽然我确实改变了 初始化程序的行为 如果之前记录了这种行为 那么这将是 一个语义突破的变化 客户必须考虑是否更新 因此我应该 更改主版本号 现在我在这里 做的下一个更改 是向 Spaceship 类添加一个新方法 这是一个新的公共方法 这意味着客户 将开始使用它并依赖它 因此正确的做法 是增加次要版本号 你会注意到 我还将补丁版本重置为零 最后我还在 fly 方法 中添加了一个新参数 我已经给了它一个默认值 这样大多数的使用站点 就不必更改了 但在 Swift 中 函数的名称和参数 是唯一标识的 参数标签和类型 所以这里我已经破坏了 源代码和二进制兼容性 所以这需要 更新主版本号 并要求任何客户端重新编译 也许我应该 做一个新的过载 现在这些都是 对 Spaceship 类的更改 但我也更改了 FlightKit 中的一些值类型 我在 Speed 枚举中添加了一个新案例
我已经使 Loacation 变得可哈希 这样客户端就可以拥有它们的集合 这是我最喜欢的更改 我在不破坏源代码 或二进制兼容性的情况下 向 Location 结构添加了 一个新的存储属性 现在在 Swift 中 所有这些更改 都是向后兼容的 所以我只需要修改次要版本号 现在这种灵活性 对如何设计框架的 API 有一些影响 最重要的是 从小处着手 如果你发现 你需要新功能 或者你的客户文件 反馈说需要更多的功能 那么添加新功能是很容易的 但是很难 删除某些东西 因为它很可能会破坏 至少一个客户的源代码 或二进制兼容性 对于那些你在事后 无法更改的东西 比如你的类型的名称 请确保你 预先仔细考虑过它们 这些名称不仅在 这个版本中有意义 而且在所有将来的版本中都有意义 最后不要过早地 添加可扩展性 你不需要在框架的 第一个版本中 将类设为开放 提供任意的回调 为什么这很重要 因为当你必须 考虑客户可能 同时在做什么时 对框架行为的推理 会变得更加困难
你总是可以在 将来开放类 你总是可以添加 表示额外回调的属性 但在默认情况下 不能删除 所添加的灵活性 那么这一切是如何运作的呢
间接 这仅仅只是一个单词而已 让我们现在来看一个例子 在左边这里 我有 Spaceship 类 这次剥离到它的模块接口 在右边我使用了 fly 方法
这是来自 FlightKit 框架外部的客户代码
运行时 客户端会问 哪个方法 是 fly 方法 框架会回应 是第二个 这就是 Swift 确保二进制兼容性的方式 即使在向类添加新方法时也是如此
它基本上 与 Objective-C 进行消息调度的方式相同 在从一个库到另一个库的调用中执行它 但 Swift 仅在你跨越此客户框架边界时执行此操作
还有另一种 间接的形式 当客户使用框架中 定义的结构体或枚举时
在本例中 fly 方法的一个参数 是来自 speed 枚举的 fast case 我之前说过 枚举可以在 不破坏二进制兼容性的情况下 添加新 case
这意味着 客户端不能假设 它知道枚举在内存中的大小
因此枚举的这种使用 要求客户端 询问框架有多大 框架回应它只有一个字节
这里的另一种可能性是 将来添加的新 case 之一 可能具有相关的值 那些相关的值 可能需要一些清理
因此客户端也会 要求框架在完成时 清除枚举值 并且框架也将这样做 此时观众中 的一些人 可能会变得有些烦躁 因为我们谈论的 是客户端和框架之间的 所有这些额外的通信
那是因为你有 对性能敏感的框架 这就是为什么下一节 是关于牺牲 Swift 提供的灵活性 来换取 给客户的优化
这是一个权衡 作为框架的作者 我们希望 能够在不破坏源代码 或二进制兼容性的情况下 灵活地更改 添加和改进
但是为了让编译器 尽可能快地 生成客户代码 它需要对框架中的内容做出假设 所以 Swift 需要同时 处理这两方面的问题 它的工作方式是 通过 Build Libraries for Distribution 的构建设置 Harlan 之前说过 除了生成模块接口文件之外 它还有多种效果 其中一种效果是 将默认值设置为偏向灵活性
但同样 Swift 需要 能够处理所有这些用例 因此在本节中 我将讨论一下 一旦你从外部 分析了框架的行为 并且看到你需要额外的性能 你可以做些什么 有三种方法 可以做到这一点 内联函数 冻结枚举和冻结结构 因此我们将从 内联函数开始 这是去年在 Swift 4.2 中引入的一个特性 在这个例子中 我有一个 cargoship 子类 这是我们之前看到 的 Spaceship 类的一个子类 它有一个方法 canCarry 它只决定货船 是否能够装载一些货物
我把它变成了内联的 因为我认为 这对我的客户 表现很重要
这将使这个方法 成为我的公共接口的一部分 不仅是它的声明 而且是它的主体
这样做的效果是 将主体复制到 模块接口文件中 如果你看得比较快 你还会看到这个方法 引用 CargoShip 类 的一个内部属性
这是可能的 因为我已将 该属性标记为可从内联使用
这可以让你 充分利用这两个世界 作为框架的公共接口的一部分 该属性是可用的 但仅对 可内联代码可用 它仍然受到保护 不受外部客户端 任意读取或写入 所以它仍然是内部的 但可以从内联中使用
值得注意的是 这是一个声明决定 此处的 currentCargo 属性 也是内部的 不包含在模块界面中
我们在模块接口中 有 canCarry 方法的主体 当客户端根据 该接口进行编译时 他们将能够将 该主体直接复制到自己的代码中 如果他们了解 正在检查的 货物的一些信息
还可能进一步优化它 但是如果框架所有者 更改了方法的主体 而客户没有重新编译 会发生什么呢 例如 如果有一条新规定说 货船不允许 装载放射性物质怎么办
在这种情况下 我们会遇到麻烦 因为现在程序的 两个不同部分 对这个方法应该做什么 有不同的想法 对于一些输入 它们仍然会同意 对于一些常规的货物 客户端和框架 都会说没问题 但是如果 我们试图测试放射性货物 那么客户端代码会说没问题 因为这是 它在编译模块 接口时看到的
虽然框架 具有该方法的新版本 但仍然将不允许它 这可能表明 程序中存在严重的逻辑错误
因此作为一个经验法则 如果你是一个框架作者 并且使一个函数可以内联 那么请确保 不要更改输出或可观察的行为
你可以添加 一个更好的算法 或者一些额外的快速填充 但是如果你 改变了函数的可观察行为 那么你最终 可能会遇到这些非常微妙的问题 这些问题只在运行时可见 而且可能只在某些输入下可见 如果你需要这样做 则需要重新编译所有客户端 接下来我想谈谈枚举
Swift 枚举很棒 我爱它们 我们在这里谈到的一件事是 你可以在 不破坏源代码或 二进制兼容性的情况下 将新 case 添加到枚举中 这对客户端意味着 当切换枚举时 它们总是必须有一个默认情况 在这个客户端中 他们决定使用 Swift 4.2 中引入的 未知默认语法 这意味着它们已经处理了 枚举中所有已知的情况 但是仍然会 处理将来添加的任何情况 这在切换 C 枚举 和构建在二进制框架中的枚举时是必要的 这就是我之前 谈到的另一个影响 客户端和框架 之间的这种交流 关于枚举的大小 以及是否需要进行任何清理 但我在这里选择 的例子是飞行计划 你只能乘坐单程 或往返航班
因此通过使用 冻结属性标记此枚举 我作为框架作者
可以保证 在框架的未来版本中不会添加新 case
这样做的第一个影响是 客户端不再需要 编写该默认情况 它可以自行消失
接下来编译器 可以更有效地编译它 客户端可以假设 这个枚举不会 有任何额外的情况 也不需要进行任何清理
这太好了 只是我忘了一件事 还有另一种飞行计划 多程航班
现在我们遇到了麻烦 因为客户端代码 不再具有默认情况 因此在冻结枚举 中添加新 case 既包括源代码 和二进制代码中断 并且需要迭代主要版本 并要求所有客户端重新编译 现在在冷冻枚举后 冷冻结构大致相同 默认情况下 二进制框架中的结构 可以添加新的存储属性 或者对现有的属性 进行重新排序 而不会有任何问题 但这确实会导致 相同类型的交流 以及客户端和框架之间的额外通信 因此为了避免这种情况 对于已知 具有冻结布局的结构 可以使用冻结属性 来保证存储的属性不会更改 它们不会被添加 重新排序或删除 这样做的另一件事是 要求存储的属性 都具有公共的类型 或者内联的可用类型 因为记住这里的目标是什么 我们希望编译器 在处理客户端代码时 能够直接操作 这个结构的存储属性 以便在客户端 生成更有效的代码 这还具有语义效应 即框架作者 现在可以编写可内联的初始化器 设置结构中的 所有存储属性 已经需要一个初始化器 但是现在编译器 可以确保 在框架的未来版本 中也会这样做 现在我想提醒你 出于某些原因灵活性是默认的 来结束这部分话题 其中最主要的一点是 中断更改对客户 来说非常不方便 客户可能会 重新考虑是否 采用新版本的框架 因为框架可能会以 某种方式破坏它们自身 当一个二进制框架 依赖于另一个二进制框架时 你也可能会遇到麻烦
同样值得提醒的是
这些属性只影响客户端代码 在你的框架中 你仍然可以获得编译器优化的全部功能
因此在使用冻结 或内联之前 请确保你已经 从外部描述了框架的行为 并证明你需要 额外的性能 否则保持灵活性 因为你可能需要它
现在我想谈的最后一部分 是确保客户的 体验是最好的 这与 Harlan 前半部分的 内容非常相似 我们将从授权开始 如果你的框架 具有完成其工作 所需的某些权利 那么让我们从基础开始 请你确保记录它们 以便任何潜在客户知道 成功采用你的框架 需要做什么 此外尽量减少 特定框架的授权请求 因为这意味着 它将适用于更多的上下文 你可以使用你的框架 获得更多客户 最后请记住 虽然框架和 App 都可以向用户 请求权限 但最终是否 授予权限是用户的选择
因此如果你被 拒绝了某个特定的权限 请确保你的框架 能够优雅地处理该拒绝 它不应该使 App 崩溃 也不应该停止工作 确保它仍然做 一些有用的事情 以便你的客户 可以使用框架而不必放弃
现在依赖关系 与权限有很多 相同的问题 因为就像权限一样 框架的依赖关系 变成了 App 的依赖关系
因此你应该 首先记录它们 以便潜在客户 知道他们注册了什么 而且你应该尽量 减少你的依赖关系 这样你对客户的要求就会更少 在扩展信任方面 你对客户的要求也要更少 甚至在实际问题上 比如依赖项占用的代码大小方面
最后 所有的依赖项都必须使用 Build Libraries for Distribution 构建设置来构建 以便获得我们 所讨论的二进制兼容性保证 这确实有一个特殊含义 即二进制 框架不能依赖于包
让我们看一个依赖关系图
几分钟前我说过 框架的依赖关系 成为 App 的依赖关系 但是当一个 App 构建一个包时 它必须选择一个特定的标签来执行此操作 这可能与你 构建框架的版本不匹配 它可能根本不兼容 除此之外 并非所有框架都必须 以与 Build Libraries for Distribution 兼容的模式构建 所以我们不支持这种配置 现在我想谈的最后一件事 是你们的 Objective-C 接口 是的你 Swift 框架的作者 你有一个 Objective-C 接口 很有可能因为 Xcode 的默认模板 是为一个混合源框架设置的 它有一个 Objective-C Umbrella Header 和一个生成的 Header 位于你的框架中 Swift 包含 的 Objective-C 部分 但是如果你的 Swift 代码没有任何它 试图发布的 Objective-C API 那么你根本不需要安装第二个 Header 这里有一个你可以直接关闭的 Install Objective-C Compatibility Header 构建设置 如果你的框架 没有提供任何 Objective-C API 那就没有理由 支持 Objective-C 导入语法 你也可以通过 Defines Module Build 设置关闭它 将其设置为 No 这将不再支持有效 的 Objective-C 代码
在你完成此操作后 你可以删除 Xcode 为你生成的 Umbrella Header
所以让我们总结一下 我们今天谈了很多 但最重要的是 XC 框架 它们是一种新的捆绑包格式 用于以一种用户 非常容易使用的方式 分发多个框架变体
为了构建 XC 框架 你需要打开 Build Libraries for Distribution 构建设置 这将激活你获得 正确的二进制兼容 框架所需的一切 作为框架所有者 请确保你了解你对客户的责任 以便你可以 为他们提供最好的服务 Harlan 和我将在 本节会议结束后 立即进入实验室 对于所有来到这里参会的人 非常感谢你们 让我们看看这些很棒的框架 [掌声和欢呼]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。