翻译:Swift 5创建和使用Framework, XCFramework 从入门到精通

说明

了解如何构建iOS框架,该框架可让您在应用程序之间共享代码,模块化代码或将其分发为第三方库。
下载代码

更新说明:本教程已由Emad Ghorbaninia更新到iOS 14,Xcode 12和Swift 5.3。原始教程由Sam Davies撰写。

您是否曾经想在两个应用程序之间共享大量代码,或者想与其他开发人员共享程序的一部分?

也许您想对代码进行模块化,就像iOS SDK通过功能将其API分开一样。或者,您可能希望像流行的第三方库一样分发代码。

在本教程中,您将把在为iOS创建自定义CalendarControl中开发的CalendarControl提取到一个单独的可重用框架中。一路上,您将:

  • 为CalendarControl创建一个新框架Framework。
  • 迁移现有代码。
  • 将所有内容导入回应用程序。
  • 构建一个二进制框架XCFramework。
  • 将其打包为超级便携式Swift软件包。
  • 为您的Swift软件包设置一个存储库并发布它。

待您完成时,该应用程序将像以前一样使用您开发的便携式XCFramework进行操作!

入门

使用本教程顶部或底部的“下载材料”按钮,下载入门项目和最终项目。查找入门项目文件夹。找到1-RWCalendarPickerUI并打开RWCalendarPicker.xcodeproj。

RWCalendarPicker是一款类似于提醒的清单应用程序,可让用户创建任务并设置截止日期。

构建并运行以了解其工作原理。
在这里插入图片描述
查看RWCalendarPicker中的文件,以熟悉该项目。CalendarControl的代码分为几个类:

  • Day.swift:一个数据模型,其中包含每个日对象的数据。
  • MonthMetadata.swift:几个月的数据模型。
  • CalendarDateCollectionViewCell.swift:使用集合视图中的单元格显示一个月中的几天。每个单元格都在此处自定义。
  • CalendarPickerFooterView.swift:允许用户选择不同的月份。
  • CalendarPickerHeaderView.swift:显示当前月份和年份,让用户关闭选择器并显示工作日标签。
  • CalendarPickerViewController.swift:日历的主体,所有相关视图在此合并。

CalendarPicker非常方便。在此应用程序之外的多个应用程序中使用它会不会很好?救援框架Framework!

什么是框架?

框架是独立的,可重用的代码和资源块,您可以将其导入许多应用程序中。您甚至可以在iOS,tvOS,watchOS和macOS应用程序之间共享它们。与Swift的访问控制结合使用时,框架可帮助定义代码模块之间强大的,可测试的接口。

框架具有三个主要目的:

  • 封装代码
  • 模块化代码
  • 重用代码

如果您使用其他语言编程,则可能听说过node modules, packages, gems or jars。Frameworks与Apple生态系统中的框架相同。iOS SDK中常见框架的一些示例包括Foundation,UIKit,SwiftUI,CloudKit和Combine。

用Swift的话来说,模块是分发在一起的一组编译后的代码。框架是模块的一种,而应用程序是另一种。

注意:如果您想了解有关框架的更多信息,请阅读什么是框架?。

创建框架

苹果在Xcode 6中引入了Cocoa Touch Framework,最近又将其更改为Framework。创建框架从未如此简单。首先,您将为框架创建项目。

在Xcode中,选择File▸New▸Project…。然后选择iOS▸框架和库▸框架。
在这里插入图片描述
单击下一步。然后将产品名称设置为CalendarControl。使用您自己的组织名称和组织标识符。
在这里插入图片描述单击下一步。在文件选择器中,选择在2-Framework创建项目。然后点击创建。

现在您有一个项目,尽管很无聊,但却创建了一个框架!

将源代码添加到框架

您当前的状态是一个没有代码的框架。这和不加糖的纯巧克力一样诱人。在本节中,您将通过将现有文件添加到框架中来介绍代码。

从RWCalendarPicker源目录中,将Day.swift拖动 到Xcode中的CalendarControl项目中。确保根据需要选中“复制项目”,以便将文件复制到新项目中,而不是添加引用。框架需要自己的代码(而不是引用)才能独立。
在这里插入图片描述仔细检查Day.swift在CalendarControl中是否具有目标成员身份,以确保它出现在最终框架中。通过选择此文件并确保在“文件”检查器的“目标成员资格”区域中选择了CalendarControl来进行验证。

现在,按照上述步骤将这些文件添加到您的项目中:

  • MonthMetadata.swift
  • CalendarDateCollectionViewCell.swift
  • CalendarPickerFooterView.swift
  • CalendarPickerHeaderView.swift
  • CalendarPickerViewController.swift

在这里插入图片描述

注意:将类划分到各自的文件夹组中并不是绝对必要的,但这是组织代码的良好实践。

在“项目”导航器中选择您的项目,然后在“目标”中选择“ CalendarControl”。打开构建设置。然后将“构建要分发的库”设置为“是”。这将产生一个模块接口文件,当有人跳转到Xcode中的模块定义时,该文件将显示您的公共API 。
在这里插入图片描述
生成框架项目。确保您成功完成构建,没有构建警告或错误。

向项目添加框架

关闭CalendarControl。返回到RWCalendarPicker。现在,您已经将日历框架组装到框架中,在主项目中不再需要迁移的文件。删除以下文件。在确认对话框中选择移至垃圾箱。

  • Day.swift
  • MonthMetadata.swift
  • CalendarDateCollectionViewCell.swift
  • CalendarPickerFooterView.swift
  • CalendarPickerHeaderView.swift
  • CalendarPickerViewController.swift
    在这里插入图片描述生成项目。您将看到几个可预测的错误,其中Xcode抱怨不知道到底CalendarPickerViewController是什么。具体来说,您会在范围错误消息中看到“找不到CalendarPickerViewController”。

您将通过添加CalendarControl框架项目来解决这些问题。

嵌入您的二进制文件

现在,右键单击项目导航器中的根RWCalendarPicker节点。单击添加文件到“ RWCalendarPicker”。

在文件选择器中,导航到2-Framework / CalendarControl并选择CalendarControl.xcodeproj。然后单击“添加”将其添加为子项目。
在这里插入图片描述

注意:并非必须将框架项目添加到应用程序项目中。您可以添加CalendarControl.framework输出。
但是,将项目组合在一起可以更轻松地同时开发框架和应用程序。您对框架项目所做的任何更改都会自动传播到应用程序。这也使Xcode更容易解析路径并知道何时重建项目。

生成并运行。您会看到相同的编译错误!

在这里插入图片描述
即使两个项目现在在一起,RWCalendarPicker仍然没有得到CalendarControl。就像他们坐在同一个房间里一样,但是RWCalendarPicker无法看到新框架。

请按照以下步骤解决问题:

  1. 将方案更改为CalendarControl并进行构建。
  2. 然后,展开CalendarControl项目以查看“产品”文件夹。
  3. 在其下面查找CalendarControl.framework。该文件是框架项目的输出,该项目打包了二进制代码,标头,资源和元数据。
  4. 然后选择顶层RWCalendarPicker节点以打开项目编辑器。
  5. 单击RWCalendarPicker目标。然后转到“常规”选项卡。
  6. 向下滚动到“框架,库和嵌入式内容”部分。
  7. 拖动CalendarControl.framework从产品文件夹的CalendarControl.xcodeproj到这一部分。
    在这里插入图片描述您已在Frameworks,Libraries和Embedded Content中为该框架添加了一个条目。

现在,该应用程序知道了该框架以及在何处可以找到它。这样就足够了吧?

切换到RWCalendarPicker方案并构建项目。更多相同的错误。
在这里插入图片描述
您错过了框架开发的重要部分:访问控制。

访问控制

尽管框架是项目的一部分,但是项目的代码对此并不了解。眼不见,心不烦。

转到ItemDetailViewController.swift,并将以下行添加到文件顶部的导入列表中:

import CalendarControl

至关重要的是,此包含仍然不能解决构建错误,因为Swift使用访问控制来让您确定结构是否对其他文件或模块可见。

默认情况下,Swift使所有内容internal—仅在其自己的模块中可见。

要恢复该应用程序的功能,您必须更新CalendarControl类上的访问控制。

尽管有点乏味,但是更新访问控制的过程通过隐藏不想出现在框架外部的代码来提高模块化。您可以通过使某些函数不具有访问修饰符或显式声明它们来实现此目的internal。

Swift具有五个级别的访问控制。创建自己的框架时,请遵循以下经验法则:

  • Open and public开放和公开:适用于应用或其他框架(例如自定义视图)调用的代码。
  • Internal内部:用于在框架内的函数和类之间使用的代码,例如该视图中的自定义层。
  • Fileprivate:用于单个文件中使用的代码,例如用于计算布局高度的辅助函数。
  • Private私有:用于封闭声明中使用的代码,例如单个文件的class块以及该声明在同一文件中的扩展名。

当CalendarControl成为RWCalendarPicker应用程序的一部分时,内部访问就不成问题。现在,它在一个单独的模块中,您必须将其公开,以供应用使用。您将在下一部分中进行操作。

注:如果您想了解更多关于访问控制和理解之间的区别open和public,看一看的访问控制文件

更新框架访问级别

打开CalendarPickerViewController.swift。通过将public关键字添加到类定义中来公开类,如下所示:

public class CalendarPickerViewController: UIViewController  {
    
    

现在CalendarPickerViewController对导入CalendarControl框架的任何应用程序文件都是可见的。

接下来,将public关键字添加到:

  • CalendarPickerViewController.init(baseDate:selectedDateChanged:)
  • CalendarPickerViewController.init(coder:)
  • CalendarPickerViewController.viewDidLoad()
  • CalendarPickerViewController.viewWillTransition(to:with:)
  • CalendarPickerViewController.collectionView(_:numberOfItemsInSection:)
  • CalendarPickerViewController.collectionView(_:cellForItemAt:)
  • CalendarPickerViewController.collectionView(_:didSelectItemAt:)
  • CalendarPickerViewController.collectionView(_:layout:sizeForItemAt:)

注意:您可能想知道为什么必须声明init为public。Apple在其访问控制文档中解释了访问控制的这一点和其他一些要点。

生成并运行。现在,您获得了CalendarControl。

恭喜你!现在,您有了一个有效的独立框架以及使用该框架的应用程序!
在这里插入图片描述

发布XCFramework

您可能在WWDC 2019期间听说过XCFramework。是的,您是对的:这是可以使用Xcode生成的二进制框架的名称。

在2019年之前,您只有一个机会来制作自己的二进制框架:通用静态库(Universal Static Library),也称为Fat Framework。

为了支持多种架构,例如模拟器和设备,您必须将它们组合到fat框架中的一个库下。但是,在本文之后,您的框架不必再胖了。

归档您的框架
在本节中,您将与老朋友Terminal一起工作。oo!

打开您的终端,并使用以下命令导航到framework文件夹。或者,您可以在cd命令后将项目文件夹拖到终端:

cd "CreateFrameworkForiOS/starter/2-Framework"

接下来,开始为以下目标归档您的框架:

  • iOS
  • Simulator
  • macOS

从iOS开始。在终端中输入以下命令:

xcodebuild archive \
-scheme CalendarControl \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath './build/CalendarControl.framework-iphoneos.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

该命令将使用以下列表作为输入来生成您的框架的存档:

  1. -scheme CalendarControl:它将使用此方案进行归档。
  2. -configuration Release:它将使用发布配置进行构建。
  3. -destination’generic / platform = iOS’:这是架构类型。
  4. -archivePath:它将归档文件以给定名称保存到该文件夹​​路径中。
  5. SKIP_INSTALL:设置为NO即可将框架安装到存档中。
  6. BUILD_LIBRARIES_FOR_DISTRIBUTION:确保构建了用于分发的库并创建了接口文件。

接下来,目标模拟器。通过将此命令添加到终端来进行归档:

xcodebuild archive \
-scheme CalendarControl \
-configuration Release \
-destination 'generic/platform=iOS Simulator' \
-archivePath './build/CalendarControl.framework-iphonesimulator.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

这些命令选项与iOS的选项相同,不同之处在于:

  1. -destination’generic / platform = iOS Simulator’:在此处设置体系结构类型。
  2. -archivePath:这会将存档生成到具有给定名称的文件夹路径中。

最后,为macOS生成一个新的存档。在终端中添加以下命令:

xcodebuild archive \
-scheme CalendarControl \
-configuration Release \
-destination 'platform=macOS,arch=x86_64,variant=Mac Catalyst' \
-archivePath './build/CalendarControl.framework-catalyst.xcarchive' \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

除了以下区别外,此命令与其他命令相同:

  1. -destination’platform = macOS,arch = x86_64,variant = Mac Catalyst’:这是您指示体系结构类型的位置。
  2. -archivePath:这会将存档生成到具有给定名称的文件夹路径中。
    正如您在finder和下面的屏幕快照中所看到的,您从框架中生成了三个不同的存档文件。
    在这里插入图片描述

生成XCFramework

现在,制作二进制框架XCFramework。将以下命令添加到终端:

xcodebuild -create-xcframework \
-framework './build/CalendarControl.framework-iphonesimulator.xcarchive/Products/Library/Frameworks/CalendarControl.framework' \
-framework './build/CalendarControl.framework-iphoneos.xcarchive/Products/Library/Frameworks/CalendarControl.framework' \
-framework './build/CalendarControl.framework-catalyst.xcarchive/Products/Library/Frameworks/CalendarControl.framework' \
-output './build/CalendarControl.xcframework'

此命令使用之前生成的档案将XCFramework添加到build文件夹。

检查构建文件夹以查看XCFramework包含的内容。
在这里插入图片描述
嘘!现在,您已经完成了第一个XCFramework。

在这里插入图片描述

将XCFramework集成到您的项目中

现在是时候从RWCalendarPicker项目中删除CalendarControl引用了,就像这样:
在这里插入图片描述
这样做是因为您不再需要访问框架的源代码。将XCFramework拖到项目目标的“框架,库和嵌入式内容”部分:
在这里插入图片描述
生成并运行。您将可以访问与以前相同的类,但是这次您的框架只是二进制的。

将XCFramework作为Swift软件包分发

在WWDC 2020上,Apple宣布您可以轻松地在Swift Packages中分发XCFramework。那不是很棒吗?

注意:如果您不熟悉Swift Packages或Swift Package Manager,可以通过阅读iOS的Swift Package Manager来了解更多信息。

您应该具有用于​​分发XCFramework的Swift软件包。您将在下一部分中创建一个。然后,您可以通过在GitHub上发布框架来共享您的框架。

准备Swift包

在入门项目文件中,您已经有一个简单的Swift软件包。导航到/ starter / 3-SwiftPackage / CalendarControl并打开Package.swift
在这里插入图片描述
此类是您的Swift软件包的清单。您需要对其进行修改,以使CalendarControl成为Swift软件包。

请按照下列步骤,并用正确的值填充清单:

  1. Platforms:
platforms: [
  .macOS(.v10_15), .iOS(.v14), .tvOS(.v14)
],

此代码指示它可以在哪些平台上运行。

  1. Product
products: [
  .library(
    name: "CalendarControl",
    targets: ["CalendarControl"]),
],

这些是包装提供的产品。这些可以是库(您可以将其导入其他Swift项目中的代码)或可执行文件(可以由操作系统运行)的代码。一个产品是可以对其他包导出到使用的目标。
3. Targets

targets: [
  .binaryTarget(
    name: "CalendarControl",
    path: "./Sources/CalendarControl.xcframework")
]

目标是独立构建的代码模块。在这里,您可以为XCFramework添加路径。

注意:清单的第一行必须包含格式化的注释,该注释告诉Swift软件包管理器构建软件包所需的最低Swift编译器版本。

最后,将XCFramework添加到项目中并将其放在Sources下:
在这里插入图片描述
恭喜你!您的Swift软件包已准备好分发。
在这里插入图片描述

大二进制和计算校验和

尽管并非如此CalendarControl,但特别庞大的框架将需要格外小心。如果您想了解更多有关处理较大的二进制文件的信息,请打开下面的扰流板。

如果您有一个大型的二进制框架(如Apple所建议的),则不应将其添加到存储库中。相反,您可以将其上传到主机,并在清单目标中添加一个URL,如下所示:

targets: [
  .binaryTarget(
    name: "CalendarControl",
    url: "https://example.com/CalendarControl.xcframework.zip",
    checksum: "4d4053074fd8b92f9f2f339c48980b99")
]

在这里,您有三个输入:

  1. 名称:这是您的包裹名称。
  2. URL:您的XCFramework压缩文件URL。
  3. 校验和:您的Swift软件包将确保框架zip文件与通过检查此校验和所生成的压缩文件相同。

请按照以下步骤计算校验和:
在这里插入图片描述

  1. 压缩您的框架,然后将zip文件复制到Swift Package文件夹中。
  2. 在终端中,导航到Swift Package文件夹。
  3. 运行以下命令并生成校验和。
swift package compute-checksum CalendarControl.xcframework.zip

您的XCFramework校验和在这里。您可以将此复制到清单中。

发布您的Swift软件包

Xcode使发布软件包变得容易。接下来,您将发布您创建的CalendarControl Swift软件包。

使用Xcode,打开Swift Package项目。然后从菜单栏中选择Source Control▸New Git Repositories…。
在这里插入图片描述
这将在您的计算机上创建一个Git存储库,并首次提交您的代码。

必须先将其公开发布,然后才能发布您的软件包供他人使用。最简单的方法是发布到GitHub。

如果您没有GitHub帐户,则可以在github.com上免费创建一个。然后,如果还没有这样做,请通过在Xcode菜单中选择Xcode▸Preferences将GitHub帐户添加到Xcode 。选择帐户。

现在,单击+添加一个新帐户。选择GitHub并按要求填写您的凭据。
在这里插入图片描述
打开源代码管理导航器,然后选择CalendarControl程序包。然后,通过右键单击或按住Control键单击打开上下文菜单。

接下来,选择New“ CalendarControl” Remote…。您可以将可见性更改为“私人”或接受默认设置。然后点击创建。

在这里插入图片描述
这会在GitHub上创建一个新的存储库,并自动为您推送代码。

接下来,通过为包创建标签来设置框架的版本。在上下文菜单中,选择“标记主要…”。将其标记为1.0.0版,然后点击创建。
在这里插入图片描述
最后,从Xcode菜单栏中选择Source Control▸Push…。确保选择了包括标签。然后单击“推”。

这会将标签推送到SwiftPM可以读取它的GitHub。您的软件包的1.0.0版现已发布。:]
在这里插入图片描述

使用Swift包

现在是时候在RWCalendarPicker项目中使用您的Swift软件包了。

再次打开RWCalendarPicker。从项目目标中删除导入的CalendarControl框架:
在这里插入图片描述
接下来,您将学习如何使用Swift Package Manager将Swift Package添加到项目中。

使用SPM添加程序包依赖性

选择文件▸斯威夫特包▸添加包依赖…。粘贴Git存储库URL。单击下一步。

根据您的GitHub设置,您可能需要在此处验证SSH密钥。然后,在“规则”下,确保为版本1.0.0选择了“至下一专业”。单击下一步。

如果您想了解有关主要和次要版本控制的更多信息,请访问semver.org。Xcode提取包后,请确保已选择CalendarControl产品并将其添加到RWCalendarPicker目标。然后选择完成。
在这里插入图片描述
生成并运行。确保一切都像以前一样运行。
在这里插入图片描述
极好的!现在,您有一个在项目内部使用的远程Swift软件包。

在这里插入图片描述

然后去哪儿?

您可以使用本教程顶部或底部的“下载材料”按钮下载项目的完整版本。

在本教程中,您学习了如何:

  1. 从RWCalendarPicker中提取CalendarControl并创建一个新框架。
  2. 在RWCalendarPicker中使用CalendarControl框架。
  3. 建立一个二进制框架,并在RWCalendarPicker中使用该XCFramework。
  4. 发布一个Swift软件包,并在RWCalendarPicker中使用它。

干得好!

从这里,观看有关此主题的WWDC 2019和2020视频:

#pic_center =600x

参考

https://www.raywenderlich.com/17753301-creating-a-framework-for-ios

https://developer.apple.com/documentation/xcode/creating_a_standalone_swift_package_with_xcode

猜你喜欢

转载自blog.csdn.net/zgpeace/article/details/115057441