pod標準化改造

背景

當前pod 開發(fā)需要手動維護framework工程的文件的引用。

1. 在主工程使用development pod開發(fā)時,非常容易遺漏個別添加新增文件或文件改名的引用,維護成本高。

2. 多人并行開發(fā)時,引用的維護還可能產(chǎn)生沖突,進一步增加維護成本。

3. 部分文件,不通過直接調(diào)用,例如runtime的Swizzling method,如果遺漏可能導(dǎo)致功能錯誤。

4. 實際pod工程中,會產(chǎn)生重復(fù)文件,沒有被引用的文件,成了垃圾文件,混在其中,可能出現(xiàn)改了沒效果的疑難問題。

方案

使用pod命令,創(chuàng)建標準化的pod工程,代替Xcode創(chuàng)建的framework工程。

pod lib create MyPod

pod lib create MyPod
pod目錄
Pod標準工程無法build sdk,使用腳本改造。(以下以LMGeofence為例)

open_sdk.sh

#!/bin/bash
set -e

#SDK_TYPE宏,實現(xiàn)在編譯時,不同SDK使用不同的邏輯 
SDK_TYPE=${1:-0}

GITIGNORE_FILE=".gitignore"

# 如果 .gitignore 不存在,則創(chuàng)建
if [ ! -f "$GITIGNORE_FILE" ]; then
  echo "??  .gitignore not found, creating..."
  touch "$GITIGNORE_FILE"
fi

# Example/build和Example/Pods兩個文件夾不必管理(兩個目錄都體積都比較大)
IGNORE_ENTRIES=("Example/build" "Example/Pods")

# 循環(huán)檢查并添加
for ENTRY in "${IGNORE_ENTRIES[@]}"; do
  if ! grep -qxF "$ENTRY" "$GITIGNORE_FILE"; then
    echo "$ENTRY" >> "$GITIGNORE_FILE"
    echo "? Added: $ENTRY"
  else
    echo "??  Already exists: $ENTRY"
  fi
done

echo "?? .gitignore updated successfully."

if ! command -v pod &>/dev/null; then
  echo "? 未檢測到 CocoaPods,請先執(zhí)行:sudo gem install cocoapods"
  exit 1
fi

# pod file 需要把所有pod庫設(shè)置為static,不使用static的話,如果被依賴的庫中有static的話,會無法運行
# 如果項目中有一個庫必須是靜態(tài)庫時, 那么其整個依賴鏈路上的所有庫都必須以靜態(tài)庫被引入
PLUGIN="cocoapods-pod-linkage"
if pod plugins | grep -q "$PLUGIN"; then
  # echo "? 已安裝 $PLUGIN,檢查是否有更新..."
  echo "? 已安裝 $PLUGIN"
  # gem update "$PLUGIN"
else
  echo "?? 未安裝 $PLUGIN,正在安裝..."
  gem install "$PLUGIN"
fi

echo "? $PLUGIN 已準備就緒"


cd Example

insert_or_update_constant() {
  local FILE="$1"
  local VAR_NAME="$2"
  local NEW_VALUE="$3"
  local SECOND_LINE="$4"

  if [ ! -f "$FILE" ]; then
    echo "? File not found: $FILE"
    return 1
  fi

  echo "?? Editing file: $FILE"

  # 第一行變量存在則更新
  if grep -q "^${VAR_NAME}" "$FILE"; then
    sed -i '' "s|^${VAR_NAME} *=.*|${VAR_NAME} = ${NEW_VALUE}|" "$FILE"
    echo "?? Updated ${VAR_NAME} = ${NEW_VALUE}"
  else
    # 插入到文件頂部
    sed -i '' "1s|^|${VAR_NAME} = ${NEW_VALUE}\n|" "$FILE"
    echo "? Inserted ${VAR_NAME} = ${NEW_VALUE} at top"
  fi

  # 第二行插入邏輯(可選)
  if [ -n "$SECOND_LINE" ] && ! grep -q "^${SECOND_LINE}$" "$FILE"; then
    sed -i '' "2i\\
${SECOND_LINE}
" "$FILE"
    echo "? Inserted second line: ${SECOND_LINE}"
  fi
}

# Pod file插入sdk_type變量及注釋
insert_or_update_constant "Podfile" "sdk_type" "${SDK_TYPE}" "#sdk_type參數(shù), Aqara SDK: 0, 第三方SDK: 1, 其他: 待定"

cd ..

PODSPEC_FILE=$(ls *.podspec 2>/dev/null | head -n 1)

if [ -z "$PODSPEC_FILE" ]; then
  echo "? No .podspec file found in current directory."
  exit 1
fi

echo "? Found podspec: $PODSPEC_FILE"

# podspec插入sdk_type變量及注釋
insert_or_update_constant "$PODSPEC_FILE" "sdk_type" "${SDK_TYPE}" "#sdk_type參數(shù), Aqara SDK: 0, 第三方SDK: 1, 其他: 待定"

cd Example

# 1. 源碼安裝 Pods
all_source=1 pod install

cd ..

# 選擇對應(yīng)的scheme
PROJECT_PATH="_Pods.xcodeproj"
USER_NAME=$(id -un)
SCHEME_DIR="${PROJECT_PATH}/xcuserdata/${USER_NAME}.xcuserdatad/xcschemes"
SCHEME_NAME="LMGeofence"
SCHEME_FILE="${SCHEME_DIR}/${SCHEME_NAME}.xcscheme"
USER_NAME=$(id -un)
PLIST_PATH="${PROJECT_PATH}/xcuserdata/${USER_NAME}.xcuserdatad/xcschemes/xcschememanagement.plist"

# 確保文件存在
if [ ! -f "$PLIST_PATH" ]; then
  echo "?? xcschememanagement.plist not found, creating..."
  mkdir -p "$(dirname "$PLIST_PATH")"
  cat > "$PLIST_PATH" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>SchemeUserState</key>
  <dict/>
</dict>
</plist>
EOF
fi

# 確保該 scheme 被設(shè)置為 isShown = true(不使用共享)
/usr/libexec/PlistBuddy -c "Set :SchemeUserState:${SCHEME_NAME}.xcscheme:isShown true" "$PLIST_PATH" 2>/dev/null \
|| /usr/libexec/PlistBuddy -c "Add :SchemeUserState:${SCHEME_NAME}.xcscheme:isShown bool true" "$PLIST_PATH"

echo "? 已勾選用戶私有 scheme: ${SCHEME_NAME}"

#修改scheme的配置為Release
echo "??  修改 scheme 配置為 Release..."

echo "?? Scheme file path: $SCHEME_FILE"

open _Pods.xcodeproj

# 用 xmlstarlet(如果可用)優(yōu)雅修改,否則用 sed 簡單替換
if command -v xmlstarlet >/dev/null 2>&1; then
  echo "?? xmlstarlet"
  xmlstarlet ed -L \
    -u '//LaunchAction/@buildConfiguration' -v 'Release' \
    "$SCHEME_FILE"
else
  # fallback:用 sed 直接替換 Debug → Release
  echo "?? perl"
  perl -i -pe '
  BEGIN{$/="\n";}
  if(/<LaunchAction/ .. />/){ s/buildConfiguration = "[^"]*"/buildConfiguration = "Release"/; }
' "$SCHEME_FILE"
fi

echo "? 已將 ${SCHEME_NAME}.xcscheme 的 Build Configuration 改為 Release"
sdk_type = 0
#sdk_type參數(shù), Aqara SDK: 0, 第三方SDK: 1, 其他: 待定

use_modular_headers!
use_frameworks!:linkage => :static  #設(shè)置為靜態(tài)framework

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/volcengine/volcengine-specs.git'

platform :ios, '13.0'

target 'LMGeofence_Example' do
  #此處也可以根據(jù)情況設(shè)置Path,使用本地庫
  pod 'LMBaseEncryption',:git =>'https://git.aqara.com/aqara-app/sdk/ios/lmbaseencryption.git',:tag=>'1.0.0'
  pod 'RealReachability', :git => 'http://git.aqara.com/aqara-app/sdk/ios/Charts.git', :branch => 'RealReachability'
  #pod 'LMFramework',:git =>'http://git.aqara.com/aqara-app/sdk/ios/lmframework.git',:tag=>'5.2.1'
    pod 'LMFramework', :path=>'../../LMFramework'
  pod 'CocoaLumberjack'
  pod 'YYModel'
  #pod 'LMCommonUI',:git =>'http://git.aqara.com/aqara-app/sdk/commonui/commonui_ios.git',:branch=>'dev_automation'
  pod 'LMCommonUI', :path=>'../../LMCommonUI'
  pod 'Masonry'
  pod 'JZLocationConverter', :git => 'https://github.com/MrLittleWhite/JZLocationConverter.git'
  pod 'LMModulesCenter',:git => 'https://git.aqara.com/aqara-app/sdk/ios/lmmodulescenter.git',:tag => '1.0.1'
  #pod 'LMSwiftCore', :git => 'https://git.aqara.com/aqara-app/sdk/ios/lmswiftcore.git',:tag => '1.0.8'
  pod 'LMSwiftCore', :path=>'../../lmswiftcore'
  #pod 'LMCommonUISwift',:git => 'https://git.aqara.com/aqara-app/sdk/commonui/commonuiswift/lmcommonuiswift.git',:tag => '1.0.9'
  pod 'LMCommonUISwift', :path=>'../../lmcommonuiswift'


  
  pod 'LMGeofence', :path => '../'

  target 'LMGeofence_Tests' do
    inherit! :search_paths
    
    
    
  end
end

post_install do |installer|
  
  target_name = "LMGeofence"
  
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      #設(shè)置所有target的最低配置,否則編譯可能報不一致錯誤
      config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
    end
  end
  #添加輸出sdk包腳本到build phrase中
  installer.pods_project.targets.each do |target|
    if target.name == target_name
      
      # 修改Build Libraries for Distribution的Release下為YES
      target.build_configurations.each do |config|
        next unless config.name == 'Release'

        config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
      end

      # 先清掉舊的同名腳本,避免重復(fù)
      target.shell_script_build_phases
            .select { |phase| phase.name == "#{target_name} SDK Build Script" }
            .each { |phase| target.build_phases.delete(phase) }

      # 添加新的 Run Script Phase
      phase = target.new_shell_script_build_phase("#{target_name} SDK Build Script")
      phase.shell_script = <<-SCRIPT

#******Script begin*******
# Type a script or drag a script file from your workspace to insert its path.
TARGET_NAME='LMGeofence'
SDK_DIR=$(dirname "$(dirname "$SRCROOT")")
if [ "${ACTION}" = "build" ]
then
INSTALL_DIR=${SRCROOT}/Products/${TARGET_NAME}.framework

DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework

SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework

# 如果真機包或模擬包不存在,則退出合并
if [ ! -d "${DEVICE_DIR}" ] || [ ! -d "${SIMULATOR_DIR}" ]
then

FMK_NAME=${TARGET_NAME}
rm -rf ${SDK_DIR}/SourceSDK
mkdir -p ${SDK_DIR}/SourceSDK
INSTALL_DIR1=${SDK_DIR}/SourceSDK/${FMK_NAME}.framework
DEVICE_DIR1=${BUILD_DIR}/Release-iphoneos/${FMK_NAME}/${FMK_NAME}.framework
echo ${INSTALL_DIR1}
echo ${DEVICE_DIR1}
cp -R "${DEVICE_DIR1}/" "${INSTALL_DIR1}/"
exit 0
fi

# 如果合并包已經(jīng)存在,則替換
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

mkdir -p "${INSTALL_DIR}"

cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"

# 使用lipo命令將其合并成一個通用framework
# 最后將生成的通用framework放置在工程根目錄下新建的Products目錄下
lipo -create "${DEVICE_DIR}/${TARGET_NAME}" "${SIMULATOR_DIR}/${TARGET_NAME}" -output "${INSTALL_DIR}/${TARGET_NAME}"

#合并完成后打開目錄
open "${SRCROOT}/Products"

fi

FMK_NAME=${TARGET_NAME}
rm -rf ${SDK_DIR}/SourceSDK
mkdir -p ${SDK_DIR}/SourceSDK
INSTALL_DIR=${SDK_DIR}/SourceSDK/${FMK_NAME}.framework
DEVICE_DIR=${BUILD_DIR}/Release-iphoneos/${FMK_NAME}/${FMK_NAME}.framework

cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
#******Script end*******

      SCRIPT
    end
  end
end
改造后工程

若習(xí)慣使用命令行,可直接調(diào)用open_sdk.sh,打開SDK工程,點擊運行,即可輸出SDK包。
也可直接雙擊OpenSDK程序,可自動打開終端執(zhí)行命令。若期間工程有編譯問題,修復(fù)后可直接在該終端點擊上顯示上次執(zhí)行的命令,再執(zhí)行即可。

源碼和SDK切換優(yōu)化

podspec

  if ENV['all_source'] || ENV['geofence_source']
    s.source_files  = 'LMGeofence/**/*.{c,cpp,h,m,swift}'
  else
    s.vendored_frameworks = "SourceSDK/*.framework"
  end

宿主工程Podfile

  if ENV['geofence_source']
    pod 'LMGeofence', :path => '../LMGeofence'
  elsif
    pod 'LMGeofence',:git => 'https://git.aqara.com/aqara-app/sdk/ios/lmgeofence.git',:commit => '6c6a695537c788e73cf6672de42bce27965fbeb6'
  end

單獨源碼調(diào)試LMGeofence的pod源碼,命令如下:
local=1 chart_source=1 pod install --verbose

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容