207

我有一个现有的 iOS 应用程序,并且想要添加我一直在开发的大量代码作为另一个项目,只是为了便于测试。新块基本上处理将图像保存到各种共享服务等。因为共享代码需要大量测试和未来更新,我想知道将代码块合并到我现有应用程序中的最佳方法是什么。

我不知道它应该是静态库、动态库还是框架,老实说,我不确定有什么区别,或者我应该如何去做并在 Xcode 中设置它。

我所知道的是,我需要/想要为共享代码保留一个单独的测试和更新应用程序,并让主应用程序使用它。

4

3 回答 3

248

First, some general definitions (specific to iOS):

Static library - a unit of code linked at compile time, which does not change.

However, iOS static libraries are not allowed to contain images/assets (only code). You can get around this challenge by using a media bundle though.

A better, more formal definition can be found on Wikipedia here.

Dynamic library - a unit of code and/or assets linked at runtime that may change.

However, only Apple is allowed to create dynamic libraries for iOS . You're not allowed to create these, as this will get your app rejected. (See this other SO post for confirmation and reasoning on such).

Software Framework - a compiled set of code that accomplishes a task... hence, you can actually have a static framework or a dynamic framework, which are typically just the compiled versions of the above.

See the Wiki on Software Framework for more details.

Hence on iOS, your only option is basically to use a static library or static framework (the main difference being that a static framework is distributed as a compiled .a file most often, whereas a static library may simply be included as a subproject - you can see all of the code - which is compiled first and its resulting .a file used as a dependency by the project).

Now that we're clear(er) on these terms, setting up a static library and supporting media bundle for iOS isn't too difficult, and there are many tutorials on how to do such. I personally would recommend this one:

https://github.com/jverkoey/iOS-Framework

This is a pretty straight-forward guide and doesn't have the disadvantage of dealing with "fake static libraries"... check it out for more info...

Once you've created your static library, it's as easy as including it as a submodule within Git for use across different projects.

Good Luck.

EDIT

Regarding a subproject within a project, as far as I know, to get this to work/compile correctly, you essentially have to set up a compile chain where the subproject is compiled first, which creates a static framework .a file that is used as a dependency by the project.

Here's another useful tutorial which talks about this:

http://www.cocoanetics.com/2011/12/sub-projects-in-xcode/

EDIT 2

As of iOS 8, Apple now permits developers to create dynamic frameworks! (Note: your app must have a minimum target of iOS 8 to include a dynamic framework... back porting isn't allowed.)

This has been added as a new project template. In Xcode 6.1, this can be found at:

New Project -> iOS -> Framework & Library -> Cocoa Touch Framework
于 2013-03-11T04:41:05.843 回答
73

Mach-O 文件格式(Mach Object - .o)

在 iOS 世界中,每个源文件都被转换为目标文件 - ABI [About] Mach-O 文件[About]将被打包成最终的可执行(应用程序、框架)、文件(库),它的行为由Mach-O type[About ]

Package是一个本身作为文件的目录 - opaque file. 它是为用户体验而创建的,以使对内部结构进行一些更改变得复杂,这可能导致不可预测的程序行为。包用于Document Package或与Bundle. 您可以Show Package Contents在 Finder中使用

Bundle是一个具有特定结构的目录,用于组织二进制文件(可执行代码)和该代码的资源(例如图像、笔尖... Assets.car 文件[关于])。Bundle 包含Info.plist[关于]文件。Bundle 是为开发人员体验而创建的。也可以打包。有几种类型的捆绑包:

  • application bundle-Application target
  • framework bundleversioned bundle作为一个子类型 -Framework Target
  • loadable bundle(aka plug-in bundle) - '... Bundle' (UI Testing Bundle, Unit Testing Bundle) - 可以在运行时加载。.bundleMac OS 的扩展
  • [Mac OS] XPC Service- 跨进程通信是一种进程间通信(IPC)。它可以用作不同进程上的模块(由launchd根进程管理)[关于]
  • 其他(dSYM[关于]捆绑)

Application- .ipa, .app[关于] - packaged application bundle- 可启动程序。

Application extension[关于] - 从 iOS v8 - 扩展应用程序的功能,当用户与其他应用程序交互时可用。App extension作为捆绑包的一部分,Containing app但它在自己的沙箱(处理器,内存...)上运行,尝试使用的应用程序app extension称为Host App. 扩展应用程序的类型:

  • 行动
  • 分享
  • 照片编辑
  • 今天又名小部件
  • ...

共享通用代码和资源。部署目标为 iOS 8+ 时可用。

Tests-packaged loadable bundle用于测试二进制文件。插件架构允许我们将新功能(测试用例)作为单独的模块添加到现有二进制文件中

库和框架

[库与框架]

Martin Fowler 谈 InversionOfControl

库本质上是一组可以调用的函数,现在通常组织成类。每个调用都会做一些工作并将控制权返回给客户端。

框架体现了一些抽象设计,内置了更多行为。为了使用它,您需要通过子类化或插入您自己的类将您的行为插入到框架中的各个位置。然后,框架的代码会在这些点调用您的代码。程序的主要控制是倒置的,从你移到框架上。这种现象就是控制反转(也称为好莱坞原则 - “不要打电话给我们,我们会打电话给你”

iOS 上的库和框架

它们可以帮助您解决:模块化、重用、封装、缩短构建时间

Library是为一个或多个架构编译的 Mach-O 目标文件[检查静态或动态]的集合。

Static library- .a(又名静态存档库,静态链接共享库[doc]) - 当您将其添加到应用程序中时,静态链接器编译期间将合并库中的目标文件并将它们与应用程序目标文件一起打包成一个可执行文件文件。缺点是输出文件大

从 Xcode 9.0 开始,支持 Swift 静态库。

Dynamic library- .dylib(又名动态共享库、共享对象、动态链接库[doc])在加载或运行时与应用程序的可执行文件动态链接,但不会复制到其中。在练习应用程序的包将包含带有文件的 Frameworks 文件夹。所有 iOS 和 macOS系统库都是. 缺点是启动时间很慢,因为所有动态库都应该被复制和链接。.dylibdynamic

[静态与动态链接]

Text-based stub library- .tbd[关于],它dynamic library是位于目标设备上的文本存根。因此,您不应该将动态库打包到您的包中。它具有尺寸效应。

Frameworkaka binary framework-.framework是一个not packaged framework bundle(允许开发人员轻松查看头文件和资源),其中包含已编译的static or dynamic库、头文件和资源。

Static framework包含一个static library与其资源一起打包的。

Dynamic frameworkaka Embedded framework- 来自 iOS v8 - 包含dynamic library和 资源。除此之外,动态框架可以在单个包中包含同一动态库的不同版本 ( versioned bundle)。也Embedded framework用于App Extension

[静态与动态框架]

Umbrella framework 【聚合目标】是一个包含其他框架的框架。它在 iOS 上不受官方支持,这就是为什么不建议开发人员创建它们[Official doc]。实际上,它是一组子框架(或嵌套框架)。当您创建具有依赖项的框架时,消费者(例如应用程序)负责将此依赖项与您的框架一起添加到项目中。作为开发人员,很自然地尝试找到一种方法将这一职责从消费者转移到您的职责。结果,您认为这Umbrella framework是一种拯救,但通常它会导致管理版本以及创建和支持它的复杂性方面出现严重问题。

Fake Framework- 是在 a 下的特定操作的结果,static library以创建具有.framework扩展名的捆绑包,其行为将与dynamic framework. 当 Xcode 不支持创建框架时使用此技术,因为没有框架模板。假框架的实现之一。在 Xcode 6 中,Apple 添加了 iOS 框架支持。

Modular Framework[关于] -@import它是一个框架,其中包含一个.modulemap文件。模块可以包含子模块。主要优点是您可以节省构建时间Modular Framework

Universal Library or Framework(aka Fat) [lipo] [Aggregate target]包含多种架构。例如,您的发布版本应该支持某个拱门,您可以通过Build Active Architecture Only [ONLY_ACTIVE_ARCH]对其进行调节

XCFramework[About]由 Xcode 11 引入,它是一个bundle包含多种架构(arm、x86_64...)和平台(iOS、MacOS...)的产品。它应该替换一个Universal Framework

Dependency[关于]您可以使用第三方代码作为目标的一部分。它允许您重用来自许多来源的代码,例如 - 另一个项目、同一工作区中的项目、另一个目标、库、框架等。

如何构建和使用静态库:

如何构建和使用动态框架[更改为静态]

[Xcode 构建系统]
[Xcode 组件]
[动态链接器]

于 2019-12-06T15:38:28.897 回答
2

您还可以为 CocoaPods ( http://guides.cocoapods.org/making/private-cocoapods.html#1.-create-a-private-spec-repo ) 创建 .podspec 文件,并像使用任何其他 pod 一样使用它唯一的区别是它是您的私有 pod,并且对外界不可见(我不确定如果您的 pod 应该创建 CoreData 模型会发生什么,但据我了解,情况并非如此)。

于 2014-08-06T11:43:51.107 回答