库的相关问题(一) —— iOS Framework的创建的简单示例(一)

版本记录

版本号 时间
V1.0 2021.01.25 星期一

前言

iOS中有很多库,包括系统库还有我们使用的三方封装库,这个专题我们就一起看学习一下相关库的知识。

开始

首先看下主要内容:

了解如何构建iOS框架,该框架可让您在应用之间共享代码,模块化代码或将其作为第三方库分发。内容来自翻译。

下面看下写作环境:

Swift 5, iOS 14, Xcode 12

接着就是正文啦。

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

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

在本教程中,您将把在 Creating a Custom CalendarControl for iOS的CalendarControl提取到一个单独的可重用框架中。 在此过程中,您将:

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

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

查找入门项目文件夹。 找到1-RWCalendarPickerUI并打开RWCalendarPicker.xcodeproj

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

构建并运行以了解其工作原理。

查看RWCalendarPicker中的文件以熟悉该项目。 CalendarControl的代码分为几类:

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

CalendarPicker非常方便。 在此应用程序之外的多个应用程序中使用它会不会很好? 框架就是可以做到!


What is a Framework?

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

框架具有三个主要目的:

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

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

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

注意:如果要了解有关框架的更多信息,请阅读What are Frameworks?。

1. Creating a Framework

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

在Xcode中,选择File ▸ New ▸ Project…。 然后选择iOS ▸ Framework & Library ▸ Framework

点击Next。 然后将Product Name设置为CalendarControl。 使用您自己的Organization NameOrganization Identifier

点击下一步。 在文件选择器中,选择在2-Framework处创建项目。 然后单击Create

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

2. Adding the Source Code to the Framework

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

RWCalendarPicker源目录中,将Day.swift拖动到Xcode中的CalendarControl项目中。 确保根据需要选中Copy items if needed ,以便将文件复制到新项目中,而不是添加引用。 框架需要自己的代码(而不是引用)才能独立。

仔细检查Day.swiftCalendarControl中是否具有Target Membership,以确保它出现在最终框架中。 通过选择此文件并确保在File inspectorTarget Membership区域中选择了CalendarControl来验证这一点。

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

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

注意:严格来说,将类划分为各自的文件夹组不是必须的,但是这是组织代码的一种很好的做法。

在“项目”导航器中选择项目,然后在Targets中选择CalendarControl。 打开Build Settings。 然后将Build Libraries for Distribution设置为yes。 这将产生一个模块接口文件,当有人跳转到Xcode中的模块定义时,该文件将显示您的公共API。

构建框架项目。 确保您没有任何构建警告或错误的情况下获得Build Succeeded

3. Adding Framework to the Project

关闭CalendarControl。 返回到RWCalendarPicker。 现在,您已经将calendar framework组装到框架framework中,您不再需要在主项目中迁移文件。 删除以下文件。 在确认对话框中选择Move to Trash

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

构建项目。 您会看到几个可预测的错误,其中Xcode报警不知道CalendarPickerViewController到底是什么。 具体来说,您会在范围错误消息中看到Cannot find ‘CalendarPickerViewController’ in scope

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

4. Embedding Your Binary

现在,右键单击项目导航器中的根RWCalendarPicker节点。 单击Add Files to “RWCalendarPicker”

在文件选择器中,导航到2-Framework / CalendarControl,然后选择CalendarControl.xcodeproj。 然后单击添加将其添加为子项目。

注意:并非必须将框架项目添加到应用程序项目中。 您可以添加CalendarControl.framework输出。

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

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

即使两个项目现在在一起,RWCalendarPicker仍然无法获得CalendarControl。 就像他们坐在同一个房间里一样,但是RWCalendarPicker无法看到新框架。

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

  • 1) 将scheme更改为CalendarControl并进行构建。
  • 2) 然后,展开CalendarControl项目以查看Products文件夹。
  • 3) 在其下面查找CalendarControl.framework。 该文件是框架项目的输出,该项目打包了二进制代码,header,资源和元数据。
  • 4) 然后选择顶层RWCalendarPicker节点以打开项目编辑器。
  • 5) 单击RWCalendarPicker target。 然后转到General选项卡。
  • 6) 向下滚动到Frameworks, Libraries and Embedded Content部分。
  • 7) 将CalendarControl.frameworkCalendarControl.xcodeprojProducts文件夹中拖到此部分。

您在Frameworks, Libraries and Embedded Content中为框架添加了一个条目entry

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

切换到RWCalendarPicker scheme并构建项目。 更多相同的错误。

您错过了框架开发的重要部分:Access Control


Access Control

尽管框架是项目的一部分,但是项目的代码对此并不了解。 看不见,也想不到。

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

import CalendarControl

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

默认情况下,Swift将所有内容内部化(internal)-仅在其自己的模块中可见。

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

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

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

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

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

注意:如果要了解有关访问控制的更多信息并了解openpublic之间的区别,请查看 Access Control Documentation。

1. Updating the Framework Access Level

打开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在其Access Control Documentation中解释了访问控制的这一点和其他一些要点。

构建并运行。 现在,您获得了CalendarControl

恭喜你! 现在,您有了一个有效的独立框架和使用该框架的应用程序!


Publishing the XCFramework

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

2019年之前,您只有一个机会来制作自己的二进制框架:Universal Static Library,也称为Fat Framework

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

1. Archiving Your Framework

在本部分中,您将与老朋友Terminal一起工作。 hoo!

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

cd "CreateFrameworkForiOS/starter/2-Framework"

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

  • 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:它将使用此scheme进行archiving
  • 2) -configuration Release:它将使用发布配置进行构建。
  • 3) -destination“ generic / platform = iOS”:这是架构类型。
  • 4) -archivePath:它将archives以给定名称保存到该文件夹路径中。
  • 5) SKIP_INSTALL:设置为NO即可将框架安装到archive中。
  • 6) BUILD_LIBRARIES_FOR_DISTRIBUTION:确保为分发而构建您的库并创建接口文件。

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

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:这会将archive生成到具有给定名称的文件夹路径中。

最后,为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:这会将archive生成到具有给定名称的文件夹路径中。

如您在查找器和以下屏幕截图中所见,您从框架中生成了三个不同的存档文件。

2. Generating the 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'

此命令使用您生成的先前archivesXCFramework添加到build文件夹。

检查构建文件夹以查看XCFramework包含的内容。

嘘! 现在,您已经完成了第一个XCFramework

3. Integrating XCFramework Into Your Project

现在该从RWCalendarPicker项目中删除CalendarControl引用,如下所示:

这样做是因为您不再需要访问框架源代码。 将XCFramework拖到项目targetFrameworks, Libraries and Embedded Content

构建并运行。 您将拥有与以前相同的类的访问权限,但是这次您的框架仅是二进制的。


Distributing XCFramework as a Swift Package

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

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

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

1. Preparing the Swift Package

在入门项目文件中,您已经有一个简单的Swift Package。 导航到/ starter / 3-SwiftPackage / CalendarControl并打开Package.swift

此类是您的Swift Package的清单。 您需要对其进行修改,以使CalendarControl成为Swift Package

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

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

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

  • 2) Products
products: [
  .library(
    name: "CalendarControl",
    targets: ["CalendarControl"]),
],

这些是包装提供的产品。 这些可以是库(可以导入其他Swift项目中的代码)或可执行文件(可以由操作系统运行)。 product是您可以导出以供其他软件包使用的target

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

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

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

最后,将XCFramework添加到项目中并将其放在Sources下:

恭喜你! 您的Swift Package已准备好分发。

2. Large Binary and Compute Check-Sum

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

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

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

这里有三个输入:

  • 1) Name:这是您的包名称。
  • 2) URL:您的XCFramework压缩文件URL
  • 3) Checksum:您的Swift Package将确保框架zip文件与通过检查此checksum和所生成的压缩文件相同。

请按照以下步骤计算校验和checksum

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

您的XCFramework校验和在这里。 您可以将其复制到manifest

3. Publishing Your Swift Package

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

使用Xcode打开Swift Package项目。 然后从菜单栏中选择Source Control ▸ New Git Repositories…

这将在您的计算机上创建一个Git存储库,并首次提交代码。

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

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

现在,单击+添加一个新帐户。 选择GitHub并按要求填写您的凭据。

打开Source Control navigator,然后选择CalendarControl程序包。 然后,通过右键单击或按住Control键单击打开上下文菜单。

接下来,选择New “CalendarControl” Remote…。 您可以将可见性更改为Private或接受默认设置。 然后单击Create

这将在GitHub上创建一个新的存储库,并自动为您推送代码。

接下来,通过为包创建标签来设置框架的版本。 在上下文菜单中,选择Tag main…。 将其标记为1.0.0版本,然后单击Create

最后,从Xcode菜单栏中选择Source Control▸Push…。 确保选择了Include tags。 然后单击Push

这会将标签推送到SwiftPM可以读取它的GitHub。 您的软件包的1.0.0版现已发布。


Using Swift Package

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

再次打开RWCalendarPicker。 从项目target中删除导入的CalendarControl框架:

接下来,您将学习如何使用Swift Package ManagerSwift Package添加到项目中。

1. Adding Package Dependency Using SPM

选择File ▸ Swift Packages ▸ Add Package Dependency…。 粘贴Git Repository URL。 单击下一步。

根据您的GitHub设置,您可能需要在此处验证SSH密钥。 然后,在Rules下,确保为1.0.0版本选择了Up to Next Major。 点击Next

如果您想了解有关主要和次要版本控制的更多信息,请访问semver.org。 Xcode提取包后,请确保已选择CalendarControl产品并将其添加到RWCalendarPicker target。 然后选择Finish

构建并运行。 确保一切都像以前一样运行。

太棒了! 现在,您有一个在项目内部使用的远程Swift软件包。

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

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

干得好!

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

  • Distribute Binary Frameworks as Swift Packages
  • Binary Frameworks in Swift

后记

本篇主要讲述了iOS Framework的创建的简单示例,感兴趣的给个赞或者关注~~~

你可能感兴趣的:(库的相关问题(一) —— iOS Framework的创建的简单示例(一))