天天看點

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

有沒有寫SDK或者要将一些常用的工具類做成Framework的經曆? 你或許自己寫腳本完成了這項工作,相信也有很多的人使用 iOS-Universal-Framework ,随着Xcode 6的釋出,相信小夥伴們已經都知道了,Xcode 6支援做Framework了. 同時iOS-Universal-Framework開發者也宣布不在繼續維持此項目的開發,建議開發者使用Xcode 6制作,目前網上也有很多制作iOS Framework的資料,但大多都不夠詳細,接下來本文會詳情介紹一下在Xcode 6下制作iOS Framework.

關于靜态庫和動态庫的概念,網上資料很多,這裡不做叙述,隻講解制作過程。

建立iOS動态庫

建立工程并選擇預設Target為Cocoa Touch Framework, 如圖:

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

做編碼工作,在這裡我簡單的寫了一個Utils的類,并寫了一個log方法

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

設定開放的頭檔案:Framework中有些類可能是一些私有的輔助工具,不需要使用者看到,在這裡隻需要把開放出去的類放到Public下, 如圖

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

這樣生成的Framework的Headers目錄下也隻能看到Public的頭檔案

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

編碼完成之後,直接Run就能成功生成Framework檔案了,選擇 xCode->Window->Organizer->Projects->Your Project, 打開工程的Derived Data目錄,這樣就能找到生成的Framework檔案了,如圖

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)
Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

建立測試工程,使用生成的Framework

将Framework檔案導入到測試工程,調用Framework中的代碼

MyUtils *utils = [MyUtils new]; 
[utils log:@"didFinishLaunchingWithOptions"];
           

運作報錯(Reason: Image Not Found)

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

為什麼會這樣的?因為我們做的是動态庫,在使用的時候需要額外加一個步驟,要把Framework同時添加到‘Embedded Binaries’中

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

注意: 在XCode 6之前是沒有這個選項的(我沒發現),是以理論上XCode 5及之前的版本無法使用Xcode 6下生成的Framework動态庫。

到這裡,假定你整個過程都是使用的模拟器做的,那看上去會很順利。這時候嘗試将測試工程部署到真機上,問題來了

ld: warning: ignoring file /work/ios/MyFrameworkTest/MyFrameworkTest/MyFramework.framework/MyFramework, file was built for x86_64 which is not the architecture being linked (armv7): /work/ios/MyFrameworkTest/MyFrameworkTest/MyFramework.framework/MyFramework

Undefined symbols for architecture armv7:

  "_OBJC_CLASS_$_MyUtils", referenced from:

      objc-class-ref in AppDelegate.o

ld: symbol(s) not found for architecture armv7

clang: error: linker command failed with exit code 1 (use -v to see invocation)

為什麼會這樣?錯誤提示已經很明顯了,因為我們制作動态庫的時候,選的裝置是模拟器,如果選真機的話,那生成的庫也隻能在真機上使用,那我們該怎樣制作一個通用的動态庫呢? 簡單的方法是分别生成模拟器和真機上運作的庫,然後在合并,這個方法,在每次生成動态庫的時候,過程都會很繁瑣,下面我們用一個腳本來自動完成它。

制作通用動态庫

建立Aggregate Target

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

添加script到建立的Target

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)
# Sets the target folders and the final framework product.
# 如果工程名稱和Framework的Target名稱不一樣的話,要自定義FMKNAME
# 例如: FMK_NAME = "MyFramework"
FMK_NAME=${PROJECT_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# -configuration ${CONFIGURATION}
# Clean and Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"
open "${INSTALL_DIR}"
           

選中建立的Target,Run, 如果沒有異常的話,會自動彈出生成的Framework檔案

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

這樣生成的動态庫就能同時支援模拟器和真機了。

Xcode 6下制作通用靜态庫

上面我們也提到了,這樣生成的動态庫恐怕很難在Xcode 5上使用,那我們為什麼非要用動态庫呢,一般情況下不是用靜态庫就好了嗎? So Easy!隻需要修改一個參數即可生成靜态庫了。

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

使用靜态庫的話,就可以把Framework從‘Embedded Binaries’中删除了. 親測在Xcode 5下可用。把新生成的庫導入到測試工程,試試在模拟器和真機上運作,一切OK.

不巧,如果你用的真機是iPhone5 C, 那悲劇又要發成了,生成的Framework竟然不支援armv7s,不知是Xcode 6的bug,還是因為蘋果認為使用armv7s的裝置太少,可以不支援了.Xcode 建立工程,預設的Architectures竟然不包含armv7s.

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

想要生成的庫支援armv7s,把armv7s添加到Architectures中,重新生成Framework即可

Xcode 6制作動态及靜态通用Framework(解決不支援 armv7s arm64 armv7)

判斷一個Framework支援哪些架構

我們該怎麼驗證生成的Framework支援哪些平台呢,總不能一個個測試吧?當然不用.下面的指令是加上armv7s前後生成的framework的對比

Yearsdembp:Products Years$ lipo -info ./MyFramework.framework/MyFramework 
Architectures in the fat file: ./MyFramework.framework/MyFramework are: i386 x86_64 armv7 arm64 
Yearsdembp:Products Years$ lipo -info ./MyFramework.framework/MyFramework 
Architectures in the fat file: ./MyFramework.framework/MyFramework are: armv7 armv7s i386 x86_64 arm64