cocoapods應用第一部分-xcode建立.framework相關

問題的提出:
隨着項目的愈來愈大,可能會出現好幾個團隊共同維護一個項目的狀況,好比:項目組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,不然會提示找不到的錯誤.  
 驗證的方式可以參見  http://jiapumin.iteye.com/blog/2119102  主要是利用命令   

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
採用cocoapods自帶的命令,比較方便的 http://guides.cocoapods.org/making/using-pod-lib-create   好比  pod lib create BZLib.可以自帶demo的
命令例如如下   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相關的編輯器打開,就能高亮顯示了),改動內容爲
Pod::Spec.new do |s|
  s.name             = "YohunlUtilsPod"
  s.version          = "1.0.0"
  s.summary          = "
測試 pod 生成 framework YohunlUtilsPod."

  s.description      = "
測試用的 , 咱們用來測試使用 pod lib create 生成的 framework project "

  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/<TWITTER_USERNAME>'

  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

假設提示錯誤的話,它會給出具體的提示,你照着改動就行了,備註:我已經將源代碼上傳到了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)

這就是第二部分要講的.



參考文檔:
相關文章
相關標籤/搜索