天天看點

iOS腳本自動編譯靜态包/靜态庫

在iOS開發中,有時候為了項目子產品間的互相獨立性,降低子產品間的耦合,通常将底層相對穩定的子產品抽取出來,形成SDK,以靜态包或者靜态庫的形式引入項目。這中間免不了編譯打包靜态包/庫,通常的做法是模拟器和真機分别編譯,然後再将兩個靜态包或者庫

lipo

合并成一個。這樣的工作做多了,難免覺得麻煩,想省事兒,整一腳本變得自然而然了。

喜歡我的可以關注收藏我的個人部落格:

RobberJJ

1. 建立一個靜态包/庫工程(已有請跳過這一步)

建立如下圖:

iOS腳本自動編譯靜态包/靜态庫

Build Lib

在Trargets下面,點選左下角的“+”,選擇添加一個新的Target, 然後選擇“Aggregate”選項,建立一個集合類target,如下圖所示:

iOS腳本自動編譯靜态包/靜态庫

Build Target

2. 給集合類添加依賴

在Targets下面選中我們建立的集合類,然後Build Phases --> Target Dependencies 下面添加我們需要編譯的靜态庫,如下圖所示:

iOS腳本自動編譯靜态包/靜态庫

添加依賴

3. 添加腳本

在Targets下面選中我們建立的集合類,然後在Build Phases下,點選左上角的“+”,選擇"New Run Script Phase"選項,如下圖:

iOS腳本自動編譯靜态包/靜态庫

添加運作腳本

然後設定我們運作的腳本的所在位置,如下圖所示:

iOS腳本自動編譯靜态包/靜态庫

設定腳本位置

注意:

../scripts/build-framework.sh 表示腳本的位置在目前工程的上一個目錄下地scripts檔案夾下. 當然"../"也可以用"${SRCROOT}/../"來代替.
腳本位置可根據實際情況自行設定。

4. 選擇我們建立的集合類的target,編譯

在編譯時,你可能會遇到下面的錯誤:

Permission denied.
           

這是因為shell腳本,還沒有添加可執行的權限。

解決辦法:在終端上, cd 進入到腳本所在的檔案夾; 然後使用 chmod +x ./yourShellName.sh 指令, 成功之後,就可以正常的運作Xcode工程了。

5. 指定target

一般來說我們編譯的target名稱,跟我們的project工程的名稱是一樣的,但是,如果我們修改了我們的target名稱,需要在我們制定腳本的位置後面跟上我們需要編譯的target名稱,既:腳本位置+空格+target名稱。如下圖:

iOS腳本自動編譯靜态包/靜态庫

指定target

6. shell腳本源碼

編譯library的腳本

#!/bin/sh

#要build的target名
target_Name=${PROJECT_NAME}
if [[ $1 ]]
then
target_Name=$1
fi

UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}_Products"

# 建立輸出目錄,并删除之前的檔案
rm -rf "${UNIVERSAL_OUTPUT_FOLDER}"
mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}"

# 分别編譯真機和模拟器版本
xcodebuild -target "${target_Name}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${target_Name}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

#複制頭檔案到目标檔案夾
HEADER_FOLDER="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/include/${target_Name}"
if [[ -d "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/usr/local/include" ]]
then
    HEADER_FOLDER="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/usr/local/include"
fi
cp -R "${HEADER_FOLDER}" "${UNIVERSAL_OUTPUT_FOLDER}"

#合成模拟器和真機.a包
lipo -create "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${target_Name}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${target_Name}.a" -output "${UNIVERSAL_OUTPUT_FOLDER}/lib${target_Name}.a"

# 判斷build檔案夾是否存在,存在則删除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi

#打開目标檔案夾
open "${UNIVERSAL_OUTPUT_FOLDER}"

           

編譯framework的shell腳本

#!/bin/sh
#要build的target名
TARGET_NAME=${PROJECT_NAME}
if [[ $1 ]]
then
TARGET_NAME=$1
fi
UNIVERSAL_OUTPUT_FOLDER="${SRCROOT}/${PROJECT_NAME}_Products/"

#建立輸出目錄,并删除之前的framework檔案
mkdir -p "${UNIVERSAL_OUTPUT_FOLDER}"
rm -rf "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework"

#分别編譯模拟器和真機的Framework
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${TARGET_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

#拷貝framework到univer目錄
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework" "${UNIVERSAL_OUTPUT_FOLDER}"

#合并framework,輸出最終的framework到build目錄
lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/${TARGET_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/${TARGET_NAME}"

#删除編譯之後生成的無關的配置檔案
dir_path="${UNIVERSAL_OUTPUT_FOLDER}/${TARGET_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done

#判斷build檔案夾是否存在,存在則删除
if [ -d "${SRCROOT}/build" ]
then
rm -rf "${SRCROOT}/build"
fi

rm -rf "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator" "${BUILD_DIR}/${CONFIGURATION}-iphoneos"

#打開合并後的檔案夾
open "${UNIVERSAL_OUTPUT_FOLDER}"