You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将多个内部Swift模块打包为单个第三方Framework?

解决iOS多模块合并为单个Framework交付的问题

这个场景我太熟了——动态Framework的依赖链在第三方真机环境里直接断了,改静态又踩了链接错误和体积暴涨的坑,对吧?别慌,咱们一步步来搞定:

一、先把所有内部模块转成静态库(正确姿势)

之前改静态出问题,大概率是依赖没理顺或者打包方式不对。按下面的步骤来:

  • 修改每个模块的Mach-O类型:打开Common、Product1、Product2这些模块的Target设置,在Build Settings里找到Mach-O Type,改成Static Library。注意:Xcode里的静态Framework其实是静态库的包装,选这个选项后,咱们后续可以把它打包成标准Framework格式。
  • 理顺模块依赖:
    • Product1依赖Common?那就在Product1的Build Phases里,Target Dependencies加Common(保证编译顺序正确),Link Binary With Libraries里也加上Common的静态库/Framework。
    • 你的ProductFramework3rdParty要把所有内部模块都拉进来,同样在Link Binary With Libraries里加Common、Product1、Product2,Target Dependencies也同步加上。
  • 解决链接错误:
    链接报错无非两种:重复符号或者缺失符号。重复符号的话,检查是不是有公共文件被多个模块引用了,赶紧移到Common里统一管理;缺失符号的话,确保所有依赖的系统库(比如Foundation)都加上,要是用了Swift,记得开启Always Embed Swift Standard Libraries。

二、用Aggregate Target打包成单个静态Framework

手动合并太麻烦,用Xcode的Aggregate Target写个脚本自动化搞定:

  1. 新建Aggregate Target:点击项目文件 → Add Target → 选Other下面的Aggregate,命名成PackageFramework就行。
  2. 添加打包脚本:打开这个Aggregate的Build Phases,点+加个New Run Script Phase,把下面的脚本粘进去(记得替换成你的实际模块名):
    # 输出目录,可自定义
    OUTPUT_DIR="${SRCROOT}/FrameworkOutput"
    mkdir -p "${OUTPUT_DIR}"
    
    # 你的内部模块列表
    MODULES=("Common" "Product1" "Product2" "ProductFramework3rdParty")
    
    # 先合并每个模块的模拟器和真机版本
    for MODULE in "${MODULES[@]}"; do
        SIMULATOR_LIB="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${MODULE}.framework/${MODULE}"
        DEVICE_LIB="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${MODULE}.framework/${MODULE}"
        lipo -create "${SIMULATOR_LIB}" "${DEVICE_LIB}" -output "${OUTPUT_DIR}/${MODULE}"
    done
    
    # 构建最终的Framework结构
    FINAL_FRAMEWORK="${OUTPUT_DIR}/ProductFramework3rdParty.framework"
    mkdir -p "${FINAL_FRAMEWORK}/Versions/A/Headers"
    mkdir -p "${FINAL_FRAMEWORK}/Versions/A/Resources"
    
    # 把所有静态库合并成一个
    lipo -create "${OUTPUT_DIR}/Common" "${OUTPUT_DIR}/Product1" "${OUTPUT_DIR}/Product2" "${OUTPUT_DIR}/ProductFramework3rdParty" -output "${FINAL_FRAMEWORK}/Versions/A/ProductFramework3rdParty"
    
    # 复制公开头文件——把所有需要给第三方用的头文件都复制过来
    cp -R "${SRCROOT}/ProductFramework3rdParty/Headers/"* "${FINAL_FRAMEWORK}/Versions/A/Headers/"
    # 如果Common、Product1里有第三方需要的头文件,也得复制
    cp -R "${SRCROOT}/Common/Headers/"* "${FINAL_FRAMEWORK}/Versions/A/Headers/"
    cp -R "${SRCROOT}/Product1/Headers/"* "${FINAL_FRAMEWORK}/Versions/A/Headers/"
    
    # 创建Framework需要的符号链接
    ln -s A "${FINAL_FRAMEWORK}/Versions/Current"
    ln -s Versions/Current/Headers "${FINAL_FRAMEWORK}/Headers"
    ln -s Versions/Current/ProductFramework3rdParty "${FINAL_FRAMEWORK}/ProductFramework3rdParty"
    ln -s Versions/Current/Resources "${FINAL_FRAMEWORK}/Resources"
    
    # 复制资源文件(如果你的框架有图片、xib这些资源的话)
    cp -R "${SRCROOT}/ProductFramework3rdParty/Resources/"* "${FINAL_FRAMEWORK}/Versions/A/Resources/"
    
  3. 执行打包:选择PackageFramework这个Target,先编译模拟器版本,再编译真机版本,或者直接用xcodebuild命令行一次性编译。之后去你设置的FrameworkOutput目录里找合并好的单个Framework就行。

三、把体积降下来

100MB确实太夸张了,咱们来剪一剪:

  • 裁剪架构:如果不需要支持老设备,在Build Settings的Architectures里只保留arm64(真机)和x86_64(模拟器),打包后也可以用lipo -remove命令删掉不需要的架构。
  • 开启代码裁剪:Build Settings里把Dead Code Stripping设为YES,Strip Debug Symbols During Copy设为YES,Strip Style选Non-Global Symbols,让Xcode自动删掉没用的代码。
  • 开启Bitcode:如果第三方支持Bitcode,把Enable Bitcode设为YES,这样苹果分发的时候还会再优化体积,打包出来的Framework也会小很多。

四、验证交付的Framework

把生成的Framework拖到第三方示例App里:

  • 在App的Build Phases的Link Binary With Libraries里添加这个Framework。
  • 静态Framework不需要Embed,所以在Embed Frameworks里别加它,只需要Link就行。
  • 跑真机测试,应该就不会再出现dyld的错误了。

内容的提问来源于stack exchange,提问作者Miro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:25:10