问题的提出:
随着项目的愈来愈大,可能会出现好几个团队共同维护一个项目的状况,好比:项目组A负责当中的A块,项目组B负责当中的B块.....这几块彼此之间既独立,也相互联系.对于这样的状况,可以採用约定的方式,比方,你仅仅改动你那块,不要改动公共的.假设要改动公共的,那么必须要通知一下其余组,你们共同决定怎么改动,这样的方式有一个很是大的问题,很是有可能不经意间就改了别的团队的代码.还有维护的愈来愈复杂等.
诸如此类的问题,很是天然的咱们会考虑每个团队创建一个静态库
IOS的静态库有两种,.a和.framework, 动态库.framework居多. 静态库建议也生成.framework模式的,优势是.framework包括了相关的.h文件等..a文件还要本身加入相关的.h文件
静态库:连接时,静态库会被完整地拷贝到可运行文件里。被屡次使用就有多份冗余拷贝.好比咱们在咱们的程序中使用了百度地图的.a文件,另一个应用也使用了百度地图.a.这样整个系统中,会出现两个 百度地图.a文件
动态库:连接时不复制,程序执行时由系统动态载入到内存,供程序调用,系统仅仅载入一次,多个程序共用。节省内存.系统提供的库基本上都属于此类,好比UIKit等,A应用和B应用中都用到了UIKit,系统仅仅载入了一份在内存中.IOS中对于第三方的动态库,很是遗憾,眼下还不支持的.
一:framework的制做
从xcode6開始,已经提供了制做.framework的选项了
如下咱们用系统自带的来新建.framework.而后再加入一个依赖库 AFNetworking
1) xcode的菜单条 File -> New Project 创建一个名为 YohunlUtilsLib 的Cocoa Touch Framework的project. 将Target 改成 7.0(由于现在大多数应用都还要支持7.0sdk,故此处咱们改动为支持7.0)
这时候,编译一下,你可能会遇到警告
(null): Embedded dylibs/frameworks only run on iOS 8 or later
别着急,这个是由于 从IOS8開始,创建的framework能够是动态的(并不是全然意义上的动态,这里的动态,事实上仍是要嵌入到咱们的应用中,而不能够从网上下载,而后用dlopen动态载入的).
咱们要改动 Mach-O Type.从默认的Dynamic Library 改成 Static Library,再编译,警告消失
那么选择 Dynamic Library 仍是 Static Library 有什么影响呢? 我已经实际的检验过了.(我採用了一个包括了 第三方库 AFnetworking的測试project)
Static Library 支持IOS8.0 sdk下面的,从眼下来看,大多数project都还要支持7.0 sdk,因此咱们最常用的就是Static Library
当咱们使用 Static Library时候,生成的framework直接如同加入普通文件的形式加入进来就可以了.它会本身主动在
只是当咱们执行的时候,会提示:
当生成后,加入到演示样例project中,
好吧,这样的模式的加入,看来有些问题呀,还要本身加入依赖库,这些依赖库都是系统的,依据提示本身加入就可以了
再执行,OK
当咱们使用 Dynamic Library模式(
仅仅有IOS8.0及以上才支持)的时候.如同普通文件同样加入到演示样例project中去的话,执行,会出现提示:
dyld: Library not loaded: @rpath/NetTestLib.framework/NetTestLib
Referenced from: /Users/yohunl/Library/Developer/CoreSimulator/Devices/B1DBCA26-C113-4C74-BB81-297D4AF1E0C8/data/Containers/Bundle/Application/C1B4F6D5-96FD-4245-8E6D-4F1C569EEF6F/TestFramework.app/TestFramework
Reason: image not found
解决的方式
在project的配置 Embedded Binaries如下加入.而不是在 Linked Frameworks and Libraries下加入.这样的方式,不需要加入 AFNetworking所需要的系统库,这一点不知道是什么缘由!!!假设有知道缘由的,请也告知我一下啊
再执行,OK
2) 命令行,进入文件夹下 pod init 创建一个podfile文件,因为咱们制做的.framework需要用到AFNetworking网络库 PS:你也可以用随意的方式创建这个podfile文件
打开它,因为我採用 pod init命令创建的,打开后你会发现它已经有内容了
改动其内容为
platform :ios, '7.0'
inhibit_all_warnings!
target 'YohunlUtilsLib' do
pod 'AFNetworking'
end
target 'YohunlUtilsLibTests' do
end
再运行 pod install 创建依赖
打开project,加入一个文件 YONetwork.h,在当中加入方法
@interface
YONetwork :
NSObject
/**
*
获取
github
上用户的
repo
*
*
@param
user
username
*
@param
success
成功的回调
*
@param
failure
失败的回调
*/
- (
void
)getGithubReposForUser:(
NSString
*)user withSuccess:(
void
(^)(
id
responseObject))success failure:(
void
(^)(
NSError
*error))failure;
/**
*
測试
getGithubReposForUser:withSuccess:failure
的
*/
- (
void
)test;
@end
#import
"YONetwork.h"
#import
"AFNetworking.h"
@implementation
YONetwork
- (
void
)getGithubReposForUser:(
NSString
*)user withSuccess:(
void
(^)(
id
responseObject))success failure:(
void
(^)(
NSError
*error))failure
{
AFHTTPRequestOperationManager
*manager = [
AFHTTPRequestOperationManager
manager
];
[manager
GET
:[
NSString
stringWithFormat
:
@"https://api.github.com/users/%@/repos"
, user]
parameters
:
nil
success
:^(
AFHTTPRequestOperation
*operation,
id
responseObject) {
success(responseObject);
}
failure
:^(
AFHTTPRequestOperation
*operation,
NSError
*error) {
failure(error);
}];
}
- (
void
) test {
[
self
getGithubReposForUser
:
@"yohunl"
withSuccess
:^(
id
responseObject) {
NSLog
(
@"getGithubReposForUser response = %@"
,responseObject);
}
failure
:^(
NSError
*error) {
NSLog
(
@"getGithubReposForUser error = %@"
,error);
}];
}
@end
编译执行 (command + B),生成对应的.framework文件
菜单 - organizer
可以看到文件夹结构例如如下:
当中的 YohunlUtilsLib.framework 就是咱们要的 :
注意,YohunlUtilsLib.framework中并无包括AFNetworking库的内容,这一点咱们可以用例如如下的命令来验证.
命令进入 Debug-iphoneos
$ lipo -info YohunlUtilsLib.framework/YohunlUtilsLib
输出
Architectures in the fat file: YohunlUtilsLib.framework/YohunlUtilsLib are: armv7 arm64
说明咱们生成的真机framework:
YohunlUtilsLib.framework 包括了两种架构
armv7 arm64
分离出每一种架构
$ mkdir armV7 当前文件夹创建文件夹,用于存放分离后的架构,和分离出的.o文件
$ lipo YohunlUtilsLib.framework/YohunlUtilsLib -thin armv7 -output ./armv7/YohunlUtilsLib_armv7 分离出armv7架构到目录armV7下
$ cd armV7 进入目录
$ ar -x YohunlUtilsLib_armv7 分离出armv7架构的所有的.o文件
分离后,如图:
可以看到,最后的.framework中,并无包括咱们pod加入的 AFNetworking.
因此 当咱们把咱们生成的YohunlUtilsLib.framework给别人使用过的时候,别人本身要在项目中加入 AFNetworking,不然会提示找不到的错误.
3) 咱们使用命令来合并咱们生成的真机和模拟器的framework
创建一个新的target
target创建后
加入例如如下的合并模拟器和真机的脚本
# Constants
SF_TARGET_NAME=${PROJECT_NAME}
#
本身定义的用来存放最后合并的
framework
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
#IPHONE_DEVICE_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos
WORKSPACE_NAME=${PROJECT_NAME}.xcworkspace
YO_SCHEME=${PROJECT_NAME}
#clean build
是先清除原来的
build
xcodebuild -workspace ${WORKSPACE_NAME} -scheme ${YO_SCHEME} -sdk iphonesimulator -configuration
"${CONFIGURATION}"
clean build
xcodebuild -workspace ${WORKSPACE_NAME} -scheme ${YO_SCHEME} -sdk iphoneos -configuration
"${CONFIGURATION}"
clean build
# build project
#xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/arm64" SYMROOT="${SYMROOT}" ARCHS='arm64' VALID_ARCHS='arm64' $ACTION
#xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/armv7" SYMROOT="${SYMROOT}" ARCHS='armv7 armv7s' VALID_ARCHS='armv7 armv7s' $ACTION
# Copy the framework structure to the universal folder (clean it first)
#
因为
framework
的合并
,lipo
仅仅是合并了最后的
二进制可运行文件
,
因此其余的需要咱们本身复制过来
#
先移除原来的
rm -rf
"${UNIVERSAL_OUTPUTFOLDER}"
mkdir -p
"${UNIVERSAL_OUTPUTFOLDER}"
cp -R
"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework"
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework"
#
合并模拟器和真机的架构
lipo -create
"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}"
"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
-output
"${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
open
"${UNIVERSAL_OUTPUTFOLDER}"
对于以上的脚本,当中用到了很是多的 xcode提早定义的变量,这些变量怎么来的呢?你可以在命令行下, 输入
xcodebuild -workspace YohunlUtilsLib.xcworkspace -scheme YohunlUtilsLib -sdk iphonesimulator -configuration Debug -showBuildSettings > xcodebuild_showBuildSettings.txt
来将所有的xcode提早定义变量都导入到文本
xcodebuild_showBuildSettings.txt 中,而后你就可以选用你需要的啦
固然了,咱们通常都应该合并release模式的,而不是debug模式的framework,这个可以在
ccmmand+B 编译
假设不出错的话,应该会弹出
到此处,咱们的framework创建好了,如下可以创建一个測试project来測试一下,可否够了
4)创建一个single View Application的測试上述framework的project TestFrameworkDemo
将上一步生成的 Release-universal/YohunlUtilsLib.framework 增长到project TestFrameworkDemo
再写一个測试用例:
执行,这时候,你会收到错误提示
还记得前面说过吧,咱们打包的framework并不包括
此时,咱们有两种方式解决问题:
1. 将咱们生成 YohunlUtilsLib.framework 过程当中生成的libAFNetworking.a 拷贝过来,加入到project中(固然了,你要本身合并 libAFNetworking的真机和模拟器的.a文件) [这样的方式的优势是可以保证咱们的YohunlUtilsLib.framework使用到的libAFNetworking和咱们同样的版本号,保证了兼容性,,但同一时候也添加了集成的复杂性,咱们要申明咱们的framework用到了哪些第三方和第三方的版本号信息]
2.在TestFrameworkDemo project中,添加 podFile文件,在当中添加 依赖 pod 'AFNetworking'
又一次pod install一下 [推荐这样的方式,因为,咱们用到的第三方都可以使用pod管理,方便],如下就以这样的方法来讲明
执行,OK!!!
二:使用 pod 的命令 pod lib create 来建立 使用pod的framework
命令例如如下 pod lib create YohunlUtilsPod
注意:各个版本号的cocoapods生成的演示样例project结构什么的,会有点不同,比方最新的带有demo的生成的libproject就自己就是target的名字,但是以前版本号target的名字是 名字_example
pod lib create project名 使会让你确认4个问题,由此来创建project,4个问题都是很是easy的,你可以自行选择
注意到了没?这里咱们的 YohunlUtilsPod 文件夹下,并无podfile文件,那么咱们创建的库要怎么依赖第三方的啊.这里就是
YohunlUtilsPod.podspec 文件出场了,在这个文件里,可以制定咱们生成的framework依赖于什么.有关于spec文件,是重要文件,原则上,仅仅要咱们把这个文件交给别人,别人就可以加入咱们的lib到project里了
编辑
YohunlUtilsPod.podspec 文件(此文件其实是 ruby格式的,假设你用ruby相关的编辑器打开,就能高亮显示了),改动内容为
end
验证podspec文件是否正确是使用命令 在podspec所在文件夹下运行
pod lib lint
假设提示错误的话,它会给出具体的提示,你照着改动就行了,备注:我已经将源代码上传到了github上(你也可以上传你的私有gitserver,通常公司都应该有本身的gitserver)
更改完后,在project中再增长
YONetwork.h和.
YONetwork.m
再执行 pod install
假设提示
SZ-lingdaiping:Example yohunl$ pod install
Updating local specs repositories
Analyzing dependencies
Fetching podspec for `YohunlUtilsPod` from `../`
[!] Unable to satisfy the following requirements:
- `YohunlUtilsPod (from `../`)` required by `Podfile`
- `YohunlUtilsPod (from `../`)` required by `Podfile`
- `YohunlUtilsPod (= 0.1.0)` required by `Podfile.lock`
那么删掉 Podfile.lock文件,因为咱们更改了podspec文件中的库的版本了
看到没,是在 Development Pods目录下,因为并无上传到官方去,因此,在此处是 私有的,因此在Development Pods目录下 .
接下来,如同第一个同样,加入一个新的target,加入 run script脚本 ,执行它,获得
创建一个測试project
注意上面图里面的文字,此处因为咱们的frameworkproject採用dynamic 模式的(上文有论述!!!) 因此需要在Embedded Binaries下加入对应的库.至于为何还要加入 AFNetworking.framework,上面也有论述,是因为咱们打包的.framework并无包括AFNetworking.framework,假设不加上,执行起来,仍是要报错的哦
好了,第一部分讲完了
那么咱们怎么使用 像咱们使用其余开源库那样的,仅仅要在demoproject里加入一句
pod ‘
YohunlUtilsPod' 而后pod install一下就可以加入呢?(固然了,这样的方式,咱们一般是直接源代码模式的framework加入demoproject)
这就是第二部分要讲的.
參考文档: