Cocoapods

转发收藏超详细,原文地址:http://www.cocoachina.com/ios/20150906/13323.htmlhtml

问题的提出:ios

随着项目的愈来愈大,可能会出现好几个团队共同维护一个项目的状况,例如:项目组A负责其中的A块,项目组B负责其中的B块.....这几块彼此之间既独立,也相互联系.对于这种状况,能够采用约定的方式,好比,你只修改你那块,不要修改公共的.若是要修改公共的,那么必需要通知一下其它组,你们共同决定怎么修改,这种方式有一个很大的问题,颇有可能不经意间就改了别的团队的代码.还有维护的愈来愈复杂等.git

诸如此类的问题,很天然的咱们会考虑每一个团队创建一个静态库github

iOS的静态库有两种,.a和.framework,  动态库.framework居多.   静态库建议也生成.framework模式的,好处是.framework包含了相关的.h文件等..a文件还要本身添加相关的.h文件shell

静态库:连接时,静态库会被完整地复制到可执行文件中,被屡次使用就有多份冗余拷贝.例如咱们在咱们的程序中使用了百度地图的.a文件,另一个应用也使用了百度地图.a.这样整个系统中,会出现两个 百度地图.a文件api

动态库:连接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存.系统提供的库基本上都属于此类,例如UIKit等,A应用和B应用中都用到了UIKit,系统只加载了一份在内存中.IOS中对于第三方的动态库,很遗憾,目前还不支持的.xcode

一:framework的制做ruby

从xcode6开始,已经提供了制做.framework的选项了服务器

blob.png

下面咱们用系统自带的来新建.framework.而后再添加一个依赖库 AFNetworking网络

1) xcode的菜单栏  File -> New Project  创建一个名为  YohunlUtilsLib 的Cocoa Touch Framework的工程. 将Target 改成 7.0(因为如今大多数应用都还要支持7.0sdk,故此处咱们修改成支持7.0)

这时候,编译一下,你可能会遇到警告

blob.png

1
( null ): Embedded dylibs/frameworks only run on iOS 8 or later

别着急,这个是因为 从IOS8开始,创建的framework能够是动态的(并非彻底意义上的动态,这里的动态,其实仍是要嵌入到咱们的应用中,而不可以从网上下载,而后用dlopen动态加载的).

咱们要修改 Mach-O Type.从默认的Dynamic Library 改成 Static Library,再编译,警告消失

blob.png

那么选择 Dynamic Library 仍是   Static Library 有什么影响呢? 我已经实际的检验过了.(我采用了一个包含了 第三方库 AFnetworking的测试工程)

Static Library 支持IOS8.0 sdk如下的,从目前来看,大多数工程都还要支持7.0 sdk,因此咱们最经常使用的就是Static Library

当咱们使用   Static Library时候,生成的framework直接如同添加普通文件的形式添加进来就能够了.它会自动在

blob.png

不过当咱们运行的时候,会提示:

当生成后,添加到示例工程中,

blob.png

好吧,这种模式的添加,看来有些问题呀,还要本身添加依赖库,这些依赖库都是系统的,根据提示本身添加就能够了

再运行,OK

当咱们使用 Dynamic Library模式(只有iOS8.0及以上才支持)的时候.如同普通文件同样添加到示例工程中去的话,运行,会出现提示:

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

blob.png

解决的方式

在工程的配置  Embedded Binaries下面添加.而不是在 Linked Frameworks and Libraries下添加.这种方式,不须要添加 AFNetworking所须要的系统库,这一点不知道是什么缘由!!!若是有知道缘由的,请也告知我一下啊

blob.png

再运行,OK

2)  命令行,进入目录下  pod init 创建一个podfile文件,由于咱们制做的.framework须要用到AFNetworking网络库 PS:你也能够用任意的方式创建这个podfile文件

打开它,由于我采用 pod init命令创建的,打开后你会发现它已经有内容了

blob.png

修改其内容为

1
2
3
4
5
6
7
platform :ios,  '7.0'
inhibit_all_warnings!
target  'YohunlUtilsLib'  do
pod  'AFNetworking'
end
target  'YohunlUtilsLibTests'  do
end

再执行 pod install 创建依赖

打开工程,添加一个文件  YONetwork.h,在其中添加方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@interfaceYONetwork :NSObject
/**
*  获取github上用户的repo
*
*  @paramuser   用户名
*  @paramsuccess成功的回调
*  @paramfailure失败的回调
*/
- (void)getGithubReposForUser:(NSString*)user withSuccess:(void(^)(idresponseObject))success failure:(void(^)(NSError*error))failure;
/**
*  测试 getGithubReposForUser:withSuccess:failure的
*/
- (void)test;
@end
#import"YONetwork.h"
#import "AFNetworking.h"
@implementationYONetwork
- (void)getGithubReposForUser:(NSString*)user withSuccess:(void(^)(idresponseObject))success failure:(void(^)(NSError*error))failure
{
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManagermanager];
[manager GET:[NSStringstringWithFormat:@ "https://api.github.com/users/%@/repos" , user] parameters:nilsuccess:^(AFHTTPRequestOperation*operation,id responseObject) {
success(responseObject);
} failure:^(AFHTTPRequestOperation*operation,NSError*error) {
failure(error);
}];
}
- (void) test {
[selfgetGithubReposForUser:@ "yohunl" withSuccess:^(idresponseObject) {
NSLog(@ "getGithubReposForUser response = %@" ,responseObject);
} failure:^(NSError*error) {
NSLog(@ "getGithubReposForUser error = %@" ,error);
}];
}
@end

blob.png

编译运行 (command + B),生成相应的.framework文件

菜单 -  organizer

blob.png

能够看到目录结构以下:

blob.png

其中的 YohunlUtilsLib.framework 就是咱们要的: 注意,YohunlUtilsLib.framework中并无包含AFNetworking库的内容,这一点咱们能够用以下的命令来验证.

命令进入 Debug-iphoneos

1
$ lipo -info YohunlUtilsLib.framework/YohunlUtilsLib

输出

1
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文件

分离后,如图:

blob.png

能够看到,最后的.framework中,并无包含咱们pod添加的 AFNetworking.因此 当咱们把咱们生成的YohunlUtilsLib.framework给别人使用过的时候,别人本身要在项目中添加 AFNetworking,不然会提示找不到的错误.

验证的方式能够参见 http://jiapumin.iteye.com/blog/2119102  主要是利用命令

3) 咱们使用命令来合并咱们生成的真机和模拟器的framework

创建一个新的target

blob.png

target创建后

blob.png

添加以下的合并模拟器和真机的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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}"

blob.png

对于以上的脚本,其中用到了不少的 xcode预约义的变量,这些变量怎么来的呢?你能够在命令行下, 输入

xcodebuild -workspace YohunlUtilsLib.xcworkspace -scheme YohunlUtilsLib -sdk iphonesimulator -configuration Debug -showBuildSettings > xcodebuild_showBuildSettings.txt

来将全部的xcode预约义变量都导入到文本xcodebuild_showBuildSettings.txt 中,而后你就能够选用你须要的啦

固然了,咱们通常都应该合并release模式的,而不是debug模式的framework,这个能够在

blob.png

blob.png

ccmmand+B 编译

若是不出错的话,应该会弹出

blob.png

到此处,咱们的framework创建好了,下面能够创建一个测试工程来测试一下,是否能够了

4)创建一个single View Application的测试上述framework的工程 TestFrameworkDemo

将上一步生成的 Release-universal/YohunlUtilsLib.framework 加入到工程 TestFrameworkDemo

再写一个测试用例:

blob.png

运行,这时候,你会收到错误提示

blob.png

还记得前面说过吧,咱们打包的framework并不包含

此时,咱们有两种方式解决这个问题:

1. 将咱们生成 YohunlUtilsLib.framework 过程当中生成的libAFNetworking.a 拷贝过来,添加到工程中(固然了,你要本身合并 libAFNetworking的真机和模拟器的.a文件) [这种方式的好处是能够保证咱们的YohunlUtilsLib.framework使用到的libAFNetworking和咱们同样的版本,保证了兼容性,,但同时也增长了集成的复杂性,咱们要申明咱们的framework用到了哪些第三方和第三方的版本信息]

2.在TestFrameworkDemo 工程中,增长 podFile文件,在其中加入 依赖  pod 'AFNetworking'

从新pod install一下 [推荐这种方式,由于,咱们用到的第三方均可以使用pod管理,方便],下面就以这种方法来讲明

blob.png

运行,OK!!!

源码在  https://github.com/yohunl/TestFrameworkDemo.git

framework在  https://github.com/yohunl/YohunlUtilsLib.git

二:使用 pod 的命令  pod lib create 来建立 使用pod的framework

采用cocoapods自带的命令,比较方便的http://guides.cocoapods.org/making/using-pod-lib-create   例如  pod lib create BZLib.能够自带demo的

命令以下   pod lib create YohunlUtilsPod

注意:各个版本的cocoapods生成的示例工程结构什么的,会有点不同,好比最新的带有demo的生成的lib工程就自己就是target的名字,可是以前版本target的名字是 名字_example

pod lib create 工程名  使会让你确认4个问题,由此来创建工程,4个问题都是很简单的,你能够自行选择

blob.png

blob.png

注意到了没?这里咱们的 YohunlUtilsPod 目录下,并无podfile文件,那么咱们创建的库要怎么依赖第三方的啊.这里就是 YohunlUtilsPod.podspec 文件出场了,在这个文件中,能够制定咱们生成的framework依赖于什么.有关于spec文件,是关键文件,原则上,只要咱们把这个文件交给别人,别人就能够添加咱们的lib到工程里了

blob.png

编辑YohunlUtilsPod.podspec 文件(此文件其实是 ruby格式的,若是你用ruby相关的编辑器打开,就能高亮显示了),修改内容为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Pod::Spec. new  do  |s|
s.name             =  "YohunlUtilsPod"
s.version          =  "1.0.0"
s.summary          =  "测试pod生成framework的YohunlUtilsPod."
s.description      =  "测试用的,咱们用来测试使用pod lib create 生成的framework工程"
s.homepage         =  "https://github.com/yohunl/YohunlUtilsPod"
# s.screenshots     = "www.example.com/screenshots_1", "www.example.com/screenshots_2"
s.license          =  'MIT'
s.author           = {  "yohunl"  =>  "yohunl@163.com"  }
s.source           = { :git =>  "https://github.com/yohunl/YohunlUtilsPod.git" , :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/'
s.platform     = :ios,  '7.0'
s.requires_arc =  true
s.source_files =  'Pod/Classes/**/*'
s.resource_bundles = {
'YohunlUtilsPod'  => [ 'Pod/Assets/*.png' ]
}
# s.public_header_files = 'Pod/Classes/**/*.h'
# s.frameworks = 'UIKit', 'MapKit'
s.dependency  'AFNetworking'
end

验证podspec文件是否正确是使用命令  在podspec所在目录下执行  pod lib lint

blob.png

若是提示错误的话,它会给出详细的提示,你照着修改就行了,备注:我已经将源码上传到了github上(你也能够上传你的私有git服务器,通常公司都应该有本身的git服务器)

更改完后,在工程中再加入  YONetwork.h和.YONetwork.m

blob.png

再运行 pod install

若是提示

1
2
3
4
5
6
7
8
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脚本 ,运行它,获得

blob.png

创建一个测试工程

blob.png

注意上面图里面的文字,此处由于咱们的framework工程采用dynamic 模式的(上文有论述!!!)  因此须要在Embedded Binaries下添加相应的库.至于为何还要添加 AFNetworking.framework,上面也有论述,是由于咱们打包的.framework并无包含AFNetworking.framework,若是不加上,运行起来,仍是要报错的哦

好了,第一部分讲完了

那么咱们怎么使用 像咱们使用其它开源库那样的,只要在demo工程里添加一句

pod ‘YohunlUtilsPod' 而后pod install一下就能够添加呢?(固然了,这种方式,咱们通常是直接源码模式的framework加入demo工程)

这就是第二部分要讲的.

参考文档:

相关文章
相关标签/搜索