Universal(Fat) Framework for Swift Projects

最近在給朋友做一個項目,要求將涉及到的算法內容整理成一個單獨的framework,這樣可以隱藏算法細節,方便交付。這個需求可以很容易地通過Cocoa Touch Framework實現。不過在交付的時候存在一個頭疼的問題:默認情況下,Xcode在編譯Cocoa Touch Framework時只會編譯出支持模擬器或者真機的Framework,而無法編譯出同時支持模擬器和真機的Framework,即Universal(Fat) Framework。這一需求還需要進一步地利用一些系統腳本來實現。

這裏假設你已經有了一個能夠正常工作,編譯的包含Cocoa Touch Framework的工程。我這裏實現時使用的是Xcode10.2。

事實上我在調研中發現了很多不同的實現編譯Universal Framework的教程,但是他們並不總是有用,我這裏只遴選了我自己測試通過沒有問題的思路。這一思路通過Archive過程來打包輸出framework

首先從Xcode左上角選擇Cocoa Touch Framework的默認scheme,然後點擊Edit Scheme

在Archive的post-action中添加一個運行腳本(New Run Script Action)

腳本內容如下:

exec > /tmp/${PROJECT_NAME}_archive.log 2>&1

UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal

if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: Detected, stopping"
else
export ALREADYINVOKED="true"

# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"

echo "Building for iPhoneSimulator"
xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 6' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build

# Step 1. Copy the framework structure (from iphoneos build) to the universal folder
echo "Copying to output folder"
# 這行是在我參考的腳本的基礎上添加進去的。腳本在運行過程中有一個問題:在試圖將
# archive過程中生成的device framework拷貝進來時,總是拷貝的framework文件夾
# 的內容,而非整個文件夾,所以我們這裏手動創建這個文件夾
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}"
cp -R "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}"

# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/."
echo "SIMULATOR_SWIFT_MODULES_DIR: ${SIMULATOR_SWIFT_MODULES_DIR}"
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule"
fi

# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory
echo "Combining executables"
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${EXECUTABLE_PATH}"

# Step 4. Create universal binaries for embedded frameworks
#for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do
#BINARY_NAME="${SUB_FRAMEWORK%.*}"
#lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}"
#done

# Step 5. Convenience step to copy the framework to the project's directory
echo "Copying to project dir"
yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}"

open "${PROJECT_DIR}"

fi

上述腳本的內容主要來自於export-fat-swift-dynamic-framework,我在這裏根據實際情況進行了更改

此時執行archive操作(Product->Archive)完成後會自動彈出Finder窗口顯示新生成的framework的位置(應當就是位於項目根目錄下)。

原文地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章