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工程)

這就是第二部分要講的.

參考文檔:

相關文章
相關標籤/搜索