一个静态库框架模板: iOS Universal Framework Mk 7

项目地址: https://github.com/kstenerud/iOS-Universal-Framework

 

这是一个Xcode 4使用的项目模板,而不是一个新的开源框架。

 

这是项目主页,介绍得很清楚,我把它抓过来翻译了一下。

 

我们为什么需要框架(Framework)?

要想用一种开发者友好的方式共享库是很麻烦的。你不仅仅需要包含库本身,还要加入所有的头文件,资源等等。

苹果解决这个问题的方式是框架(framework)。基本上,这是含有固定结构并包含了引用该库时所必需的所有东西的文件夹。不幸的是,iOS禁止所有的动态库。同时,苹果也从Xcode中移除了创建静态iOS框架的功能。

Xcode仍然可以支持创建框架的功能,重启这个功能,我们需要对Xcode做一些小小的改动。

把代码封装在静态框架是被app store所允许的。尽管形式不同,本质上它仍然是一种静态库。

框架(Framework)的类别

大部分框架都是动态链接库的形式。因为只有苹果才能在iOS设备上安装动态库,所以我们无法创建这种类型的框架。

静态链接库和动态库一样,只不过它是在编译时链接二进制代码,因此使用静态库不会有动态库那样的问题(即除了苹果谁也不能在iOS上使用动态库)。

“伪”框架是通过破解Xcode的目标Bundle(使用某些脚本)来实现的。它在表面上以及使用时跟静态框架并无区别。“伪”框架项目的功能几乎和真实的框架项目没有区别(不是全部)。

“嵌入”框架是静态框架的一个包装,以便Xcode能获取框架内的资源(图片、plist、nib等)。

本次发布包括了创建静态框架和“伪”框架的模板,以及二者的“嵌入”框架。

用哪一种模板?

本次发布有两个模板,每个模板都有“强”“弱”两个类别。你可以选择最适合一种(或者两种都安装上)。

最大的不同是Xcode不能创建“真”框架,除非你安装静态框架文件xcspec在Xcode中。这真是一个遗憾(这个文件是给项目使用的,而不是框架要用的)。

简单第

简单说,你可以这样决定用哪一种模板:

  • 如果你不想修改Xcode,那么请使用“伪”框架版本
  • 如果你只是想共享二进制(不是项目),两种都可以
  • 如果你想把框架共享给不想修改Xcode的开发者,使用“伪”框架版本
  • 如果你想把框架共享给修改过Xcode的开发者,使用“真”框架版本
  • 如果你想把框架项目作为另一个项目的依赖(通过workspace或者子项目的方式),请使用“真”框架(或者“伪”框架,使用-framework——见后)
  • 如果你想在你的框架项目中加入其他静态库/框架,并把它们也链接到最终结果以便不需要单独添加到用户项目中,使用“伪”框架

“伪”框架

“伪”框架是破解的“reloacatable object file”(可重定位格式的目标文件, 保存着代码和数据,适合于和其他的目标文件连接到一起,用来创建一个可执行目标文件或者是一个可共享目标文件),它可以让Xcode编译出类似框架的东西——其实也是一个bundle。

“伪框架”模板把整个过程分为几个步骤,用某些脚本去产生一个真正的静态框架(基于静态库而不是reloacatable object file)。而且,框架项目还是把它定义为wrapper.cfbundle类型,一种Xcode中的“二等公民”。

因此它跟“真”静态框架一样可以正常工作,但当存在依赖关系时就有麻烦了。

依赖问题

如果不使用依赖,只是创建普通的项目是没有任何问题的。但是如果使用了项目依赖(比如在workspace中),Xcode就悲剧了。当你点击“Link Binary With Libraries”下方的’+’按钮时,“伪框架”无法显示在列表中。你可以从你的“伪”框架项目的Products下面将它手动拖入,但当你编辑你的主项目时,会出现警告:

warning: skipping file '/somewhere/MyFramework.framework' (unexpectedfile type 'wrapper.cfbundle' in Frameworks & Libraries build phase)

并伴随“伪”框架中的链接错误。

幸运的是,有个办法来解决它。你可以在”Other Linker Flags”中用”-framwork”开关手动告诉linker去使用你的框架进行链接:

-framework MyFramework

警告仍然存在,但起码能正确链接了。

添加其他的库/框架

如果你加入其他静态(不是动态)库/框架到你的“伪”框架项目中,它们将“链接”进你最终的二进制框架文件中。在“真”框架项目中,它们是纯引用,而不是链接。

你可以在项目中仅仅包含头文件而不是静态库/框架本身的方式避免这种情况(以便编译通过)。

“真”框架

“真”框架各个方面都符合“真”的标准。它是真正的静态框架,正如使用苹果在从Xcode中去除的那个功能所创建的一样。

为了能创建真正的静态框架项目,你必需在Xcode中安装一个xcspec文件。

如果你发布一个“真”框架项目(而不是编译),希望去编译这个框架的人必需也安装xcspec文件(使用本次发布的安装脚本),以便Xcode能理解目标类型。

注意:如果你正在发布完全编译的框架,而不是框架项目,最终用户并不需要安装任何东西。

我已经提交一个报告给苹果,希望他们在Xcode中更新这个文件,但那需要一点时间.OpenRadarlink here

加其他静态库/框架

如果你加入其他静态(不是动态)库/框架到你的“真”框架项目,它们只会被引用,而不会象“伪”框架一样被链接到最终的二进制文件中。

从早期版本升级

如果你是从Mk6或者更早的版本升级,同时使用“真”静态框架,并且使用Xcode4.2.1以前的版本,请运行uninstall_legacy.sh以卸载早期用于Xcode的所有修正。然后再运行install.sh,重启Xcode。如果你使用Xcode4.3以后,只需要运行install.sh并重启Xcode。

安装

分别运行Real Framework目录或Fake Framework目录下的install.sh脚本进行安装(或者两个你都运行)。

重启Xcode,你将在新项目向导的Framework&Library下看到StaticiOS Framework(或者Fake Static iOS Framework)。

卸载请运行unistall.sh脚本并重启Xcode。

创建一个iOS框架项目

  1. 创建新项目。
  2. 项目类型选择Framework&Library下的Static iOS Framework(或者Fake Static iOS Framework)。
  3. 选择“包含单元测试”(可选的)。
  4. 在target中加入类、资源等。
  5. 凡是其他项目要使用的头文件,必需声明为public。进入target的Build Phases页,展开Copy Headers项,把需要public的头文件从Project或Private部分拖拽到Public部分。

编译你的 iOS 框架

  1. 选择指定target的scheme
  2. 修改scheme的Run配置(可选)。Run配置默认使用Debug,但在准备部署的时候你可能想使用Release。
  3. 编译框架(无论目标为iOS device和Simulator都会编译出相同的二进制,因此选谁都无所谓了)。
  4. 从Products下选中你的framework,“show in Finder”。

在build目录下有两个文件夹:(yourframework).framework and (your framework).embeddedframework.

如果你的框架只有代码,没有资源(比如图片、脚本、xib、coredata的momd文件等),你可以把(yourframework).framework 分发给你的用户就行了。如果还包含有资源,你必需分发(your framework).embeddedframework给你的用户。

为什么需要embedded framework?因为Xcode不会查找静态框架中的资源,如果你分发(your framework).framework, 则框架中的所有资源都不会显示,也不可用。

一个embedded framework只是一个framework之外的附加的包,包括了这个框架的所有资源的符号链接。这样做的目的是让Xcode能够找到这些资源。

使用iOS 框架

iOS框架和常规的Mac OS动态框架差不多,只是它是静态链接的而已。

在你的项目中使用一个框架,只需把它拖仅你的项目中。在包含头文件时,记住使用尖括号而不是双引号括住框架名称。例如,对于框架MyFramework:

#import

使用问题

Headers Not Found

如果Xcode找不到框架的头文件,你可能是忘记将它们声明为public了。参考“创建一个iOS框架项目”第5步。

No Such Product Type

如果你没有安装iOS Universal Framework在Xcode,并企图编译一个universal框架项目(对于“真”框架,不是“假”框架),这会导致下列错误:

target specifies product type 'com.apple.product-type.framework.static',but there's no such product type for the 'iphonesimulator' platform

为了编译“真”iOS静态框架,Xcode需要做一些改动,因此为了编译“真”静态框架项目,请在所有的开发环境中安装它(对于使用框架的用户不需要,只有要编译框架才需要)。

The selected run destination is not valid for this action

有时,Xcode出错并加载了错误的active设置。首先,请尝试重启Xcode。如果错误继续存在,Xcode产生了一个坏的项目(因为Xcode4的一个bug,任何类型的项目都会出现这个问题)。如果是这样,你需要创建一个新项目重来一遍。

链接警告

第一次编译框架target时,Xcdoe会在链接阶段报告找不到文件夹:

ld: warning: directory not found for option'-L/Users/myself/Library/Developer/Xcode/DerivedData/MyFramework-ccahfoccjqiognaqraesrxdyqcne/Build/Products/Debug-iphoneos'

此时,可以clean并重新编译target,警告会消除。

Core Data momd not found

对于框架项目和应用程序项目,Xcode会以不同的方式编译momd(托管对象模型文件)。Xcode会简单地在根目录创建.mom文件,而不会创建一个.momd目录(目录中包含VersionInfo.plist和.mom文件)。

这意味着,当从一个embedded framework的model中实例化NSManagedObjectModel时,你必需使用.mom扩展名作为model的URL,而不是采用.momd扩展名。

NSURL *modelURL = [[NSBundle mainBundle]URLForResource:@"MyModel" withExtension:@"mom"];

Unknown class MyClass in Interface Builder file.

由于静态框架采用静态链接,linker会剔除所有它认为无用的代码。不幸的是,linker不会检查xib文件,因此如果类是在xib中引用,而没有在O-C代码中引用,linker将从最终的可执行文件中删除类。这是linker的问题,不是框架的问题(当你编译一个静态库时也会发生这个问题)。苹果内置框架不会发生这个问题,因为他们是运行时动态加载的,存在于iOS设备固件中的动态库是不可能被删除的。

有两个解决的办法:

  1. 让框架的最终用户关闭linker的优化选项,通过在他们的项目的Other Linker Flags中添加-ObjC和-all_load。
  2. 在框架的另一个类中加一个该类的代码引用。例如,假设你有个MyTextField类,被linker剔除了。假设你还有一个MyViewController,它在xib中使用了MyTextField,MyViewController并没有被剔除。你应该这样做:

在MyTextField中:

+ (void)forceLinkerLoad_ {}

在MyViewController中:

+(void) initialize {     [MyTextField forceLinkerLoad_]; }

他们仍然需要添加-ObjC到linker设置,但不需要强制all_load了。

第2种方法需要你多做一点工作,但却让最终用户避免在使用你的框架时关闭linker优化(关闭linker优化会导致object文件膨胀)。

unexpected file type 'wrapper.cfbundle' in Frameworks &Libraries build phase

这个问题发生在把“假”框架项目作为workspace的依赖,或者把它当作子项目时(“真”框架项目没有这个问题)。尽管这种框架项目产生了正确的静态框架,但Xcode只能从项目文件中看出这是一个bundle,因此它在检查依赖性时发出一个警告,并在linker阶段跳过它。

你可以手动添加一个命令让linker在链接阶段能正确链接。在依赖你的静态框架的项目的OtherLinker Flags中加入:

-framework MyFramework

警告仍然存在, 但不会导致链接失败。

Libraries being linked or not being linked into the finalframework

很不幸, “真”框架和“假”框架模板在处理引入的静态库/框架的工作方式不同的。

“真”框架模板采用正常的静态库生成步骤,不会链接其他静态库/框架到最终生产物中。

“假”框架模板采用“欺骗”Xcode的手段,让它认为是在编译一个可重定位格式的目标文件,在链接阶段就如同编译一个可执行文件,把所有的静态代码文件链接到最终生成物中(尽管不会检查是否确实目标代码)。为了实现象“真”框架一样的效果,你可以只包含库/框架的头文件到你的项目中,而不需要包含库/框架本身。

Unrecognized selector in (some class with a category method)

如果你的静态库或静态框架包含了一个模块(只在类别代码中声明,没有类实现),linker会搞不清楚,并把代码从二进制文件中剔除。因为在最终生成的文件中没有这个方法,所以当调用这个类别中定义的方法时,会报一个“unrecognizedselector”异常。

要解决这个,在包含这个类别的模块代码中加一个“假的”类。linker发现存在完整的O-C类,会将类别代码链接到模块。

我写了一个头文件 LoadableCategory.h,以减轻这个工作量:

#import "SomeConcreteClass+MyAdditions.h"

#import "LoadableCategory.h"  MAKE_CATEGORIES_LOADABLE(SomeConcreteClass_MyAdditions);   @implementation SomeConcreteClass(MyAdditions)

  ... 

@end

在使用这个框架时,仍然还需要在Build Setting的Other Linker Flags中加入-ObjC。

执行任何代码前单元测试崩溃

 

 

 

 

http://blog.csdn.net/jason20ming/article/details/7487139

今天看了一天关于Static Library以及Static Frame的相关资料,先记下来,以免忘了。

跟大多数操作系统相同,Mac OS X及iOS上均支持静态链接库和动态链接库(这样说可能有点不恰当,但是都是这个意思附近的了)

在Xcode 4.3中如果是新建一个Mac OS X的项目,可以看见“Framework & Library”内有各种各样的Library及Framework的模板,当然,这些都可以是静态链接或者动态链接的。

但是如果新建的是iOS的项目,在“Framework  & Library”内的模板就少得可怜,就只有一个“Cocoa Touch Static Library”,顾名思义就是一个静态链接库模板。

静态链接库用起来的颇为麻烦,libxml2就是一个例子,首先要加入linker内让linker找到符号,然后还需要配置Header让compiler可以找到这些符号的定义。基于这种不人性化操作,苹果在自己的平台上推出了一种新的引用方式,那就是Framework。

Framework其实就是将Header及Library打包在一起方便使用,在苹果的官方文档,Framework还可以嵌套打包,其称为Umbrella Framework,不过其不建议普通用户这样做而已。我们平常使用的QuartzCore、UIKit、CoreFoundation等均打包为Framework。

可惜的是,因为没有模板,所以不能简单地创建一个Framework,但是一个开源的模板项目可以帮到我们:iOS-Universal-Framework。

这个模板分开两块:Fake Static Framework 和 Real Static Framework,安装及使用方法在github上的项目有详细教程(其实很简单,运行一个脚本就OK)。

看到名字开始会很疑惑,这东西还能有Fake和Real的?

原来,苹果出于某种原因的考虑,在Xcode上禁用了iOS项目引入非官方Framework的功能,所以这里的Framework分成了两种。

Fake的是通过一个bundle模拟Framework,这个不需要对Xcode进行任何改动,只需要添加一个项目模板即可,但是使用这个模板并且开启ARC时候会出现问题,这个后面会说道。

Real的生成出来的product就是一个真真正正的Framework,但是由于Xcode不支持在iOS上使用自定义Framework,所以需要向Xcode内加入两个xcspec文件以启用支持。

将两个模板都安装完成后,可以看见iOS中的“Framework & Library”多出了两个Framework的模板。看看名字,里面均有一个“Static”,这表示生成的Framework都是静态的,因为苹果是禁止开发者向iOS内添加动态库的,这样就可以保证所有应用的依赖均来源于苹果内部,降低开发难度也可以保证应用不会因为缺少依赖库而Crash。所以,无论Static Framework或者Static Library,最终所有的符号均会被内联到程序中,跟直接在项目内编写代码是一样的。

既然生成的二进制都是一样的,为什么还要提取一个库出来呢?虽然iOS上二进制是不可共享的,但是代码是可以共享的,可以将经常使用的组件提出成一个公共库,再供给程序使用,这样可以有效减低程序内的代码量。(说离题了。。。)

下面说说 Static Library、Fake Static Framework、Real Static Framework 使用需要注意的事项以及其优劣,特别是在Deployment Target 在 iOS 5.0以下时候容易出现的问题。

 

Static Library:

简单的静态链接库,其使用Libtool生成静态链接库文件,不会因为开启iOS 4.0以下版本的ARC而强制将libarclite链接至静态链接库;但是,其使用较为麻烦,不方便发布。

Static Library在生成的静态库时候会加上一个参数-arch_only armv7(使用模拟器时是:-arch_only i386),即使这个库只可用于模拟器或者真实设备,现在貌似暂时没有办法设置其同时支持armv7和i386。

 

Fake Static Framework:

这个不是一个真正的Framework,实际类型是Core Foundation Bundle,所以叫做Fake Framework。

因为其生成的目标是CFBundle,所以Xcode使用Ld命令生成目标静态库,这样在工程内的Link Binary with Libraries不能有系统的Framework和Library,一旦引入系统的库,Ld命令会将引入库的所有符号内联到当前工程中,当其它工程引用这个静态库的时候就会出现Duplicate symbol define的错误!

基于这个原因,在Deployment Target低于5.0而且开启ARC的时候可能会出现Duplicate symbol define: objc_retainObject()的错误,出现这个错误的原因如下:

1. Fake Static Framework使用Ld命令生成库,而不是使用Libtool生成库,当Framework工程的Deployment Target低于5.0而且开启ARC的时候编译器会向程序写入内存管理方面的代码,而Ld命令会将libarclite库内对应的函数(如objc_retainObject())的定义加入到当前的静态库中。

2. 在引用Framework的工程中,如果Deployment Target低于5.0而且开启ARC,同1道理,Ld命令会向项目内引入libarclite库并将定义加入当前项目,但是由于在引入的Framework中已经包含有相关符号,所以会出现Duplicate symbol define。

解决方案如下:在Fake Static Framework生成的时候将Deployment Target改为5.0或更高,在编写代码的时候将其改回对应版本(因为5.0以下的不支持weak关键字,改回低版本有利于IDE的提示);或者将引用Framework的工程的Deployment Target改为5.0或更高,但是这样则会失去对低版本的支持。

 

Real Static Framework:

这个是一个真正的Framework,其生成的文件实际类型就是Framework。其内部包含的静态库是由Libtool生成的,所以不存在ARC的问题,而且可以在Link Binary with Libraries中加入系统的Framework,其只会在生成的库中加入对应Framework或Library的引用,而不会将定义也加入其中。

但是,由于苹果的限制,Xcode不支持Real Static Framework直接引用,需要加入两个xcspec文件才可以使用,但是使用这个方式的Framework会将不会存在上述两个静态库的n问题,是现时来说最方便的库。

 

如果你在Xcode4.3中创建静态框架(或库)target时,勾选了“withunit tests”,当你试图运行单元测试时,它会崩溃:

Thread 1: EXC_BAD_ACCESS (code=2, address=0x0) 0 0x00000000 --- 15 dyldbootstrap:start(...)

这是lldb中的一个bug。你可以用GDB来运行单元测试。编辑scheme,选择Test,在Info标签中将调试器Debugger从LLDB改为GDB。

 

 

 

 

 

http://spin.atomicobject.com/2011/12/13/building-a-universal-framework-for-ios/

Apple has invested quite a bit of time into making it easy to compile for a number of different architectures in XCode. For instance, compiling a library into its armv6, armv7, and i386variants is just a matter of specifying the supported architecture types. However, there isn’t a built-in mechanism to take the binaries built for the various architectures and merge them into a universal iOS framework.

Before we go through the steps of building a universal iOS framework we should first reviewwhat a framework is and why they are useful.

 

What is a ‘framework’ and why are they useful?

Apple defines a framework as:

… a hierarchical directory that encapsulates shared resources, such as a dynamic shared library, nib files, image files, localized strings, header files, and reference documentation in a single package.

So instead of having header files and binaries in disperate locations a framework brings everything together into one package (a directory with a known structure). Packaging a library as a framework simplifies things for developers because it not only provides a binary to link against but it includes all of the necessary header files to reference as well.

What is a ‘universal’ framework?

A universal framework can be defined as a framework that contains a binary which has been built for a number of architectures (armv6, armv7, i386) and can be statically1 linked against. This is particularly useful in iOS development because an application can be built for the simulator (i386) and the device (armv6, armv7).

1 Statically linking a library resolves symbols at compile time and embeds the library into the application. It is not possible, currently, to create a dynamic framework for iOS.

Building a ‘universal’ framework

Firstly, there is a project called iOS Universal Framework that simplifies the process of building a universal framework by providing an XCode template. However, I think it is still a meaningful exercise to understand how a universal framework is built using XCode.

Lets get started:

Create a new project

  1. File -> New -> New Project (Command-Shift-N)
  2. Select Frameworks & Libraries under iOS
  3. Select “Cocoa Touch Static Library” and click “Next”
  4. Provide a name for the library

一个静态库框架模板: iOS Universal Framework Mk 7_第1张图片

Configure architectures

By default the static library is configured to only build for armv7 so we need to add armv6 and i386 to ensure that the static library is built for older devices (iPhone 3G/Original, early generation iPod Touch) and the simulator.

 

一个静态库框架模板: iOS Universal Framework Mk 7_第2张图片

 

Create aggregate target

An aggregate target aggregates other targets together. In effect, it wraps a number of script executables and copy file tasks in a specified order.

  1. File -> New Target
  2. Select “Other” under iOS
  3. Select “Aggregate”
  4. Give it a name (MyLibrary-iOS for example)

一个静态库框架模板: iOS Universal Framework Mk 7_第3张图片

 

Build static libraries

Under the “Build Phases” section of the aggregate target we are going to add a build phase that compiles a static library for i386 and ARM. In the next step we’ll merge the binaries into a fat binary.

  1. Select MyLibrary-iOS target
  2. Select “Build Phases”
  3. Click “Add Build Phase”
  4. Select “Add Run Script”
  5. Name it “Build Static Libs”

一个静态库框架模板: iOS Universal Framework Mk 7_第4张图片

 

 

xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator -target ${PROJECT_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator

xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos -target ${PROJECT_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos

This Gist brought to you by GitHub.

 

Build universal binary

We are going to add another “Run Script” phase that builds the framework itself. The script is going to:

Create a directory structure that mimics the same directory structure seen in Apple’s dynamic frameworks:

 

SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a" &&
DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" &&
UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal" &&
UNIVERSAL_LIBRARY_PATH="${UNIVERSAL_LIBRARY_DIR}/${PRODUCT_NAME}" &&
FRAMEWORK="${UNIVERSAL_LIBRARY_DIR}/${PRODUCT_NAME}.framework" &&

 

# Create framework directory structure.
rm -rf "${FRAMEWORK}" &&
mkdir -p "${UNIVERSAL_LIBRARY_DIR}" &&
mkdir -p "${FRAMEWORK}/Versions/A/Headers" &&
mkdir -p "${FRAMEWORK}/Versions/A/Resources" &&

This Gist brought to you by GitHub.

 

Merge the static libraries built for the various architectures into a fat binary using a tool calledlipo:

 

# Generate universal binary for the device and simulator.
lipo "${SIMULATOR_LIBRARY_PATH}" "${DEVICE_LIBRARY_PATH}" -create -output "${UNIVERSAL_LIBRARY_PATH}" &&

This Gist brought to you by GitHub.

 

Move the appropriate files into place:

 

# Move files to appropriate locations in framework paths.
cp "${UNIVERSAL_LIBRARY_PATH}" "${FRAMEWORK}/Versions/A" &&
ln -s "A" "${FRAMEWORK}/Versions/Current" &&
ln -s "Versions/Current/Headers" "${FRAMEWORK}/Headers" &&
ln -s "Versions/Current/Resources" "${FRAMEWORK}/Resources" &&
ln -s "Versions/Current/${PRODUCT_NAME}" "${FRAMEWORK}/${PRODUCT_NAME}"

This Gist brought to you by GitHub.

 

一个静态库框架模板: iOS Universal Framework Mk 7_第5张图片

The full script can be found here.

Copy header files into place

  1. Select “Add Build Phase”
  2. Click “Add Copy Files”
  3. Set “Destination” to “Absolute Path”
  4. Set subpath to ${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal/${PRODUCT_NAME}.framework/Versions/A/Headers/
  5. Add header files that should be public to the list

一个静态库框架模板: iOS Universal Framework Mk 7_第6张图片

 

Configure aggregate target build against the ‘Release’ configuration

  1. Product -> Edit Scheme
  2. Choose aggregate target (MyLibrary-iOS)
  3. Select “Run”
  4. Choose “Release” under Build Configuration

一个静态库框架模板: iOS Universal Framework Mk 7_第7张图片

 

Build and verify framework

  1. Select aggregate target
  2. Build it (Command-B)

Verify that the binary was built for the correct architectures using lipo:

 

lipo -info build/Release-iphoneuniversal/MyLibrary-iOS.framework/MyLibrary-iOS
 
Architectures in the fat file: build/Release-iphoneuniversal/MyLibrary-iOS.framework/MyLibrary-iOS are: i386 armv6 armv7
 
 
This Gist brought to you by  GitHub.
 
Ensure that the header files are copied into place (XCode is known to mess this up on occasion):
 
 
 
tree build/Release-iphoneuniversal/MyLibrary-iOS.framework/
build/Release-iphoneuniversal/MyLibrary-iOS.framework/
├── Headers -> Versions/Current/Headers
├── MyLibrary-iOS -> Versions/Current/MyLibrary-iOS
├── Resources -> Versions/Current/Resources
└── Versions
    ├── A
    │   ├── Headers
    │   │   └── MyLibrary.h
    │   ├── MyLibrary-iOS
    │   └── Resources
    └── Current -> A
 
7 directories, 3 files
 
This Gist brought to you by  GitHub.
 

Conclusion

Creating a universal framework certainly requires a fair amount of upfront work. However, it is a great mechanism to distribute your library to the masses without making them work to use it. There is not any configuration (header paths) or tweaking (warnings, ARC vs non-ARC files) required on the part of the user. Which means less work for you having to respond to issues and complaints.

Update 02/07/2012: I’ve updated the scripts to ensure that they work when XCode is configured to choose the build directory (derived). The “Build static libs” script is the one that must be updated.

你可能感兴趣的:(移动开发,xcode,测试)