背景
当前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