通过Cocoapods分发编译的Swift框架

这是 通过Cocoapods分发Swift框架 的后续文章

在我以前的文章中,我们学习了如何使用Cocoapods分发Swift框架。 简而言之,我们通过告诉Cocoapods将哪些源代码包装到框架中来实现这一目标。 然后,Cocoapods包装了源代码并将其与集成商项目链接。

我们发现此解决方案有两个潜在问题。

  1. 源代码泄漏给了集成商。 允许他们查看和修改我们的代码。
  2. 在集成商应用程序的每次干净构建上,框架都将随之编译。 与框架无关的更改要求重新编译框架。

那么有办法解决这两个问题吗? 🤔是的! 解决方案是编译框架,然后分发它。 但这说起来容易做起来难。

在这篇文章中,我们将介绍

  • 什么是编译框架。
  • 为什么要分发已编译的框架。
  • 分发编译框架

我们不会介绍如何创建Swift框架。 如果您想回顾一下如何创建Swift框架,请查看我的文章《使用Swift框架重用代码》。

我们不会深入研究Cocoapods是什么以及它如何工作。 确保已安装Cocoapods。 您还可以查看我以前的文章《通过Cocoapods分发Swift框架》,以了解有关Cocoapods的更多信息。

同样,我们不会在这篇文章中介绍git。 我在这里假设您已经熟悉它。

本指南使用Xcode 10.1和Swift 4.2。

什么是编译框架?

Swift源代码是iOS开发人员可以理解和编写的形式的代码。 它是人类可读的形式。 但是iOS无法理解Swift。 它了解二进制。 那么iOS如何运行我们的Swift代码?

我们将Swift代码转换为二进制代码。 翻译过程称为编译,而最终的翻译形式称为编译代码或二进制。

然后,iOS可以执行代码的二进制形式。

为什么要分发编译后的代码?

在我以前的文章中,我们通过Cocoapods分发了框架的源代码。 然后,Cocoapods将源代码包装到集成商端的框架中。 每次集成商清理构建其应用程序时,都会随之构建框架。 即使他们没有更改框架源代码,也是如此。 编译代码需要时间。

此外,集成商还可以访问我们的源代码。 他们能够查看和修改我们的代码。

通过分发编译后的代码,我们:

  • 保密我们的代码
  • 在应用编译过程中节省时间

分发编译框架

在本节中,我们将介绍编译iOS框架,然后通过Cocoapods分发它的步骤。

大纲:

  • 通过Xcode编译Swift框架
  • 通过Cocoapods分发编译的框架
  • 消耗编译的框架
  • 构建和分发通用iOS框架

在以下步骤中,我们将非常频繁地使用终端运行命令。 确保在任何时候都方便。

通过Xcode编译Swift框架

在开始之前,让我们获取一个包含框架目标的项目。 运行以下命令:

 光盘〜 
curl -o MyFramework.zip -L https://www.dropbox.com/s/5vykpag4xb5vh51/MyFramework.zip -s
解压-q MyFramework.zip

上面的命令获取本指南中将要使用的框架项目。

编译Swift框架的最简单形式是通过Xcode用户界面。 让我们在Xcode中打开MyFramework项目。 运行以下命令:

 打开-Xcode〜/ MyFramework / MyFramework.xcodeproj 

打开Xcode后,从设备列表中选择“ Generic iOS Device ”。 最后,通过从菜单Product > Build中选择来构建框架。

构建过程完成后,您将在项目导航器的Products文件夹(或在Xcode🤯中混淆性地称为“ Groups”)中找到已构建的框架。 右键单击MyFramework.framework ,然后单击在Finder中显示 选项。 生成的框架的路径可能会更改,因此,让我们使用“ 在Finder中显示”选项可以轻松地找到生成的框架。 在Finder中将看到一个名为MyFramework.framework的目录, MyFramework.framework包含已编译的MyFramework二进制文件以及使用该框架所需的其他内容。

将Finder窗口与我们已编译的框架保持在一起,将在下一部分中使用它。

通过Cocoapods分发编译的框架

在本节中,我们将介绍如何通过Cocoapods分发已编译的框架。

我们会:

  1. 创建一个git存储库以将Cocoapods规范文件保存在我们的主目录中
  2. 在我们的主目录中创建一个git存储库,以保存已编译的MyFramework
  3. 创建MyFramework规范并将其推送到在步骤1中创建的Cocoapods规范存储库

首先,我们从创建一个存储Cocoapods规范的存储库开始,然后将该存储库注册到我们的Cocoapods。 运行以下命令:

 光盘〜 
mkdir MySpecs.git
cd MySpecs.git
git init-裸
git clone〜/ MySpecs.git〜/ MySpecs
cd〜/我的规格
触摸README.md
git添加README.md
git commit -m“初始提交”
git push origin -u主
pod repo添加我的规格〜/ MySpecs.git

接下来,让我们创建一个存储库来存储和跟踪MyFramework.framework

 光盘〜 
mkdir MyFrameworkDistribution.git
cd MyFrameworkDistribution.git
git init-裸
git clone〜/ MyFrameworkDistribution.git〜/ MyFrameworkDistribution
cd〜/ MyFrameworkDistribution
触摸README.md
git添加README.md
git commit -m“初始提交”
git push origin -u主

现在我们有一个地方可以存储构建的框架,让我们将MyFramework.framework放到MyFrameworkDistribution目录中。 通过运行open -a Finder ~/MyFrameworkDistribution打开MyFrameworkDistribution目录。 现在将MyFramework.framework拖放到MyFrameworkDistribution目录中。

MyFramework.framework放置在MyFrameworkDistribution存储库中后,我们现在必须将更改提交到存储库。 让我们将此存储库的快照标记为版本0.1.0。 运行以下命令:

  cd〜/ MyFrameworkDistribution 
git添加MyFramework.framework /
git commit -m“添加了MyFramework.framework”
git tag -a 0.1.0 -m“版本0.1.0”
git push origin master
git push origin-标签

最后要做的是为Cocoapods创建规范,说明如何安装MyFramework.framework并通过我们的Cocoapods规范存储库共享该规范。 我们在步骤1中为此目的创建了一个存储库。让我们通过运行以下命令来创建规范文件:

 猫>〜/ MyFramework / MyFramework.podspec <<-EOF 
  Pod :: Spec.new do | s | 
s.name =“ MyFramework”
s.version =“ 0.1.0”
s.summary =“ MyFramework项目的简短描述。”
s.description = <<-DESC
MyFramework项目的扩展描述。
数据中心
s.homepage =“ http://your.homepage/此处”
s.license = {:type =>'版权',:text => <<-许可证
版权2018
许可授予...
执照
}
s.author = {“ $(git config user.name)” =>“ $(git config user.email)”}
s.source = {:git =>“ $ HOME / MyFrameworkDistribution.git”,:tag =>“#{s.version}”}
s.public_header_files =“ MyFramework.framework / Headers / *。h”
s.source_files =“ MyFramework.framework / Headers / *。h”
s.vendored_frameworks =“ MyFramework.framework”
s.platform =:ios
s.swift_version =“ 4.2”
s.ios.deployment_target = '12 .0'
结束
 紧急行动 

最后,分享我们的规范,让我们运行:

  pod repo push my-specs〜/ MyFramework / MyFramework.podspec 

现在,我们已经准备就绪,可以通过Cocoapods使用编译的MyFramework。

消耗编译的框架

在本节中,我们将学习如何使用MyFramework.framework来使用MyFramework.framework。 首先,我们需要一个应用程序来使用它。 让我们获取MyApp项目并将其放置在主目录中。 运行以下命令:

 光盘〜 
curl -o MyApp.zip -L https://www.dropbox.com/s/jfdrj58lgrhjc4t/MyApp.zip -s
解压-q MyApp.zip

接下来,让我们使用MyFramework.framework使用MyApp MyFramework.framework使用MyFramework.framework。 要使用MyFramework我们需要告诉Cocoapods MyApp需要MyFramework以及在哪里可以找到MyFramework的规范。 Podfile ,我们创建了一个Podfile其中包含所有这些详细信息以及有关项目结构的其他信息。 运行以下命令来创建Podfile

 猫>〜/ MyApp / Podfile <<-EOF 
 以“ MyApp”为目标 
use_frameworks!
pod'MyFramework','0.1.0',:source =>“ $ HOME / MySpecs.git”
结束
 紧急行动 

最后,运行以下命令告诉Cocoapods获取MyFramework并将其安装到MyApp

  cd〜/ MyApp 
吊舱安装

这就是通过Cocoapods分发和使用已编译框架的全部内容! 让我们打开MyApp.xcworkspace ,然后在模拟器中构建并运行MyApp

但是,如果我们从设备列表中构建MyApp for Generic iOS设备 ,则会对其进行编译。

我们的编译框架不适用于iOS模拟器。 为什么? 如果您回忆起通过Xcode编译Swift框架 我们从设备列表中选择了通用iOS设备。 这意味着我们的框架仅针对设备而没有针对模拟器。 另一方面,如果我们选择iOS模拟器,那么我们只会为模拟器构建。 如果我们决定仅分发与设备兼容的框架,那么我们框架的集成商将无法使用我们的框架来测试其应用。

有没有一种方法可以使MyFramework以适用于设备和模拟器的方式构建? 🤔是的! 在下一节中,我们将介绍操作方法。

构建和分发通用iOS框架

到目前为止,我们已经能够通过Xcode进行构建,并能够通过Cocoapods分发和使用已编译的iOS框架。 但是,在使用通过Xcode构建的iOS编译框架时,我们发现了一个问题。 我们无法建立一个能够通过Xcode与模拟器和设备一起使用的框架。

在本节中,我们将研究构建可与设备和模拟器一起使用的框架。 我们将这个框架称为通用框架。 为此,我们将通过终端并使用xcodebuild工具来构建我们的框架。 xcodebuild与Xcode一起安装。

在本文中,我们不会过多地研究如何使用xcodebuild 。 需要强调的重要一点是,我们能够使用xcodebuild通过终端通过Xcode用户界面实现我们所做的事情。 现在,我们将添加一个脚本,该脚本将:

  • 为模拟器构建MyFramework
  • 为设备构建MyFramework
  • 将前两个框架​​合并为一个框架

运行以下命令以添加将构建通用MyFramework的脚本:

 猫>〜/ MyFramework / build-universal-framework.sh <<-EOF 
#创建我们放置构建框架的文件夹
mkdir构建
  #建立模拟器框架 
xcodebuild干净的版本\
-project MyFramework.xcodeproj \
-方案MyFramework \
配置发布
-sdk iphonesimulator \
-derivedDataPath派生的数据
  #创建文件夹以存储已编译的模拟器框架 
mkdir构建/模拟器
#将模拟器的编译框架复制到我们的构建文件夹中
cp -r named_data / Build / Products / Release-iphonesimulator / MyFramework.framework构建/模拟器
  #build设备框架 
xcodebuild干净的版本\
-project MyFramework.xcodeproj \
-方案MyFramework \
配置发布
-sdk iphoneos \
-derivedDataPath派生的数据
  #创建文件夹以存储已编译的模拟器框架 
mkdir构建/设备
#将模拟器的编译框架复制到我们的构建文件夹中
cp -r named_data / Build / Products / Release-iphoneos / MyFramework.framework build / devices
#创建文件夹以存储已编译的通用框架
mkdir构建/通用
  ######################创建通用框架####################### ##### 
  #将设备框架复制到通用文件夹 
cp -r build / devices / MyFramework.framework build / universal /
  #创建与模拟器和设备兼容的二进制框架,并在通用框架中替换二进制 
lipo -create \
构建/模拟器/MyFramework.framework/MyFramework \
构建/设备/ MyFramework.framework / MyFramework \
-输出build / universal / MyFramework.framework / MyFramework
  #将模拟器Swift公共接口复制到通用框架 
cp build / simulator / MyFramework.framework / Modules / MyFramework.swiftmodule / * build / universal / MyFramework.framework / Modules / MyFramework.swiftmodule
紧急行动

运行以下命令以执行脚本:

 cd ~/MyFramework && sh build-universal-framework.sh 

该脚本将在名为build的目录中输出生成的框架,该目录带有名为simulatordevicesuniversal子目录。 在每一个中,您都将找到MyFramework.framework ,它们分别与模拟器,设备和两者兼容。

让我们通过Cocoapods分享我们的通用框架。

将通用框架复制到MyFrameworkDistribution存储库中。 之后,将新框架提交到我们的存储库。 然后,将这个版本的框架标记为0.1.1。 运行以下命令:

  cp -r〜/ MyFramework / build / universal / MyFramework.framework〜/ MyFrameworkDistribution / 
cd〜/ MyFrameworkDistribution
git添加MyFramework.framework
git commit -m“已将框架从仅兼容的设备更改为通用”
git push origin master
git tag -a 0.1.1 -m“版本0.1.1”
git push origin-标签

接下来,让我们使用新版本(0.1.1)更新MyFramework规范。 运行以下命令:

  rm〜/ MyFramework / MyFramework.podspec && cat>〜/ MyFramework / MyFramework.podspec <<-EOF 
  Pod :: Spec.new do | s | 
s.name =“ MyFramework”
s.version =“ 0.1.1”
s.summary =“ MyFramework项目的简短描述。”
s.description = <<-DESC
MyFramework项目的扩展描述。
数据中心
s.homepage =“ http://your.homepage/此处”
s.license = {:type =>'版权',:text => <<-许可证
版权2018
许可授予...
执照
}
s.author = {“ $(git config user.name)” =>“ $(git config user.email)”}
s.source = {:git =>“ $ HOME / MyFrameworkDistribution.git”,:tag =>“#{s.version}”}
s.source_files =“ MyFramework.framework / Headers / *。h”
s.public_header_files =“ MyFramework.framework / Headers / *。h”
s.vendored_frameworks =“ MyFramework.framework”
s.platform =:ios
s.swift_version =“ 4.2”
s.ios.deployment_target = '12 .0'
结束
 紧急行动 

最后一步是将MyFramework新规范添加到我们的规范存储库中。 运行以下命令:

  pod repo push my-specs〜/ MyFramework / MyFramework.podspec 

准备使用我们新版本的框架了。 更新MyApp项目中的Podfile以使用我们最新版本的MyFramework 。 运行以下命令:

  rm〜/ MyApp / Podfile && cat>〜/ MyApp / Podfile <<-EOF 
 以“ MyApp”为目标 
use_frameworks!
pod'MyFramework','0.1.1',:source =>“ $ HOME / MySpecs.git”
结束
 紧急行动 

通过运行MyFramework cd ~/MyApp && pod install安装新版本的MyFramework 。 通过运行open -a Xcode MyApp.xcworkspace 。 在模拟器中然后在设备中运行MyApp

now我们现在已经成功地使用Cocoapods部署了通用框架。

最后的笔记

直到最近,上传到App Store的connect(或iTunes Connect)都拒绝了模拟器的任何编译代码。 看来情况已不再如此。 我无法通过使用带有针对模拟器的已编译代码的框架上载应用程序来重现该错误。

本文中未涵盖的限制是,某些集成商如果使用其他Xcode版本,则可能无法使用您的已编译框架。 我可以写一篇完整的博客文章。 也许我会。 现在,如果您愿意,可以在此reddit讨论中了解更多有关它的信息。

分发已编译的框架并非易事。 而且也不容易维护。 因此,请确保您有充分的理由这样做。

摘要

在这篇文章中,我们了解到:

  • 什么是已编译框架,为什么要使用它们
  • 如何构建与设备和模拟器兼容的已编译框架(通用)
  • 如何通过Cocoapods分发已编译的框架

这是有关构建和分发Swift框架的一系列博客文章的最后一部分。 在我的第一篇文章中,我展示了如何使用iOS框架重用Swift代码。 然后,我写了一篇有关如何使用Cocoapods分发Swift框架的文章,其中与集成商共享了我们的Swift代码。 最后,我介绍了如何通过Cocoapods共享Swift框架而不共享我们的Swift代码。

直到下一次 …

我喜欢Swift而不是iOS支持的其他语言。 但是在某些情况下,我无法在iOS中使用Swift。 一种情况就是我们要使用C ++库。

在Onfido,我们使用OpenCV处理来自iOS设备相机的图像,以确保我们捕获最可读,质量最高的文档捕获。 OpenCV用C ++编写。

在下一篇博客文章中,我将向您展示如何处理iPhone上相机的图像。 我们将使用OpenCV处理图像,然后将结果显示给用户。 我们将学习如何在iOS平台上使用其他语言来实现这一目标。 在接下来的博客文章中,我将向您展示如何重用消耗OpenCV的Swift框架。

在Twitter或Medium上关注我,敬请关注!