pod标准化改造

背景

当前pod 开发需要手动维护framework工程的文件的引用。

1. 在主工程使用development pod开发时,非常容易遗漏个别添加新增文件或文件改名的引用,维护成本高。

2. 多人并行开发时,引用的维护还可能产生冲突,进一步增加维护成本。

3. 部分文件,不通过直接调用,例如runtime的Swizzling method,如果遗漏可能导致功能错误。

4. 实际pod工程中,会产生重复文件,没有被引用的文件,成了垃圾文件,混在其中,可能出现改了没效果的疑难问题。

方案

使用pod命令,创建标准化的pod工程,代替Xcode创建的framework工程。

pod lib create MyPod

pod lib create MyPod
pod目录
Pod标准工程无法build sdk,使用脚本改造。(以下以LMGeofence为例)

open_sdk.sh

#!/bin/bash
set -e

#SDK_TYPE宏,实现在编译时,不同SDK使用不同的逻辑 
SDK_TYPE=${1:-0}

GITIGNORE_FILE=".gitignore"

# 如果 .gitignore 不存在,则创建
if [ ! -f "$GITIGNORE_FILE" ]; then
  echo "⚠️  .gitignore not found, creating..."
  touch "$GITIGNORE_FILE"
fi

# Example/build和Example/Pods两个文件夹不必管理(两个目录都体积都比较大)
IGNORE_ENTRIES=("Example/build" "Example/Pods")

# 循环检查并添加
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,请先执行:sudo gem install cocoapods"
  exit 1
fi

# pod file 需要把所有pod库设置为static,不使用static的话,如果被依赖的库中有static的话,会无法运行
# 如果项目中有一个库必须是静态库时, 那么其整个依赖链路上的所有库都必须以静态库被引入
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参数, 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参数, Aqara SDK: 0, 第三方SDK: 1, 其他: 待定"

cd Example

# 1. 源码安装 Pods
all_source=1 pod install

cd ..

# 选择对应的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 被设置为 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(如果可用)优雅修改,否则用 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参数, Aqara SDK: 0, 第三方SDK: 1, 其他: 待定

use_modular_headers!
use_frameworks!:linkage => :static  #设置为静态framework

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

platform :ios, '13.0'

target 'LMGeofence_Example' do
  #此处也可以根据情况设置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|
      #设置所有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

      # 先清掉旧的同名脚本,避免重复
      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

# 如果合并包已经存在,则替换
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
改造后工程

若习惯使用命令行,可直接调用open_sdk.sh,打开SDK工程,点击运行,即可输出SDK包。
也可直接双击OpenSDK程序,可自动打开终端执行命令。若期间工程有编译问题,修复后可直接在该终端点击上显示上次执行的命令,再执行即可。

源码和SDK切换优化

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

单独源码调试LMGeofence的pod源码,命令如下:
local=1 chart_source=1 pod install --verbose

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容