從Xcode中的動態庫中剝離不需要的架構
自從發佈iOS 8以來,開發人員已經能夠利用動態庫的優勢進行iOS開發。
對於一般開發,爲所有需要的體系結構提供一個動態庫是一件很棒的事,這樣您就可以在所有設備和iOS Simulator上運行而無需進行任何更改。
在我的項目及其各種擴展中,我使用了Reactive Cocoa,並將它作爲預編譯的動態庫包含在我的項目中,其中包含Simulator 和設備的i386和x86_64slice 。armv7arm64
但是,這種方法有一個缺點-因爲它們是在運行時鏈接的,所以當動態庫單獨編譯到最終運行的應用程序時,就無法確定實際需要哪種架構。因此,Xcode只會在編譯時將整個內容複製到您的應用程序包中。除了浪費磁盤空間之外,從理論上講,這沒有真正的缺點。但是實際上,iTunes Connect不喜歡我們添加未使用的二進制切片:
提交AppStore 提示Unsupported Architectures. Your executable contains unsupported architectures ‘[X86_64, i386]’.
解決
那麼,我們如何解決這個問題?
-
我們可以改用靜態庫。但是,在我的項目中有多個目標和擴展,用相同庫的副本膨脹我的所有可執行文件似乎很愚蠢。
-
我們可以每次從源代碼編譯該庫,從而生成一個新的動態庫,其中僅包含每個構建所需的架構。有兩件事讓我感到困擾-首先,一直都在重新編譯所有不變的代碼似乎很浪費,第二是我喜歡保持依賴關係爲靜態,並且每次都進行新的構建意味着我沒有必須再運行穩定的代碼,尤其是如果我開始在Xcode Beta中四處亂搞的時候。如果更改編譯器導致庫中出現奇怪的錯誤怎麼辦?這是非常罕見的事情,但是確實發生了,而且我不知道該庫的代碼庫足以調試它。
-
如果我們沒有開始的源頭,那麼,我們有點不走運。
-
我們可以在構建時弄清楚如何處理它,然後再也不必考慮它。聽起來更像!
腳本解決
今天,我整理了一些構建時腳本來處理此問題,因此我不必再在意它了。
在我的項目文件夾中:
$ lipo -info Vendor/RAC/ReactiveCocoa.framework/ReactiveCocoa
→ Architectures in the fat file: ReactiveCocoa are:
i386 x86_64 armv7 arm64
按下“ build”後:
$ lipo -info Cascable.app/Frameworks/ReactiveCocoa.framework/ReactiveCocoa
→ Architectures in the fat file: ReactiveCocoa are:
armv7 arm64
事不宜遲,這裏是腳本。在構建步驟中添加一個“運行腳本”步驟,將其放置在嵌入框架的步驟之後,將其設置爲“使用”,/bin/sh然後輸入以下腳本:
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
EXTRACTED_ARCHS=()
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done
echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"
echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
done
該腳本將瀏覽您構建的應用程序的Frameworks文件夾,並確保每個框架中僅存在要構建的體系結構。
好多了!現在,我可以在項目中添加大量動態庫,其中包含我將需要的所有體系結構,並且構建過程將處理在任何給定時刻適合哪些體系結構。
參考
https://stackoverflow.com/questions/30547283/submit-to-app-store-issues-unsupported-architecture-x86
http://ikennd.ac/blog/2015/02/stripping-unwanted-architectures-from-dynamic-libraries-in-xcode/