如何在CocoaPods中集成同架构(arm64)iOS与iOS模拟器静态库?
问题
我们有一个通过spec.vendored_libraries引用静态库的podspec,该静态库已构建两个arm64架构版本:
- iOS设备版本(路径:
iosArm64/lib/a.a) - iOS模拟器版本(路径:
iosSimulatorArm64/lib/a.a)
现有podspec代码如下:
Pod::Spec.new do |spec| spec.platform = :ios spec.name = 'pod_lib' spec.version = '1.0.0' spec.homepage = 'pod_lib' spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } spec.authors = 'Authors' spec.license = '' spec.summary = 'pod_lib' spec.ios.deployment_target = '13.5' spec.source_files = 'headers/**/*.h' spec.public_header_files = 'headers/**/*.h' spec.vendored_libraries = 'iosArm64/lib/a.a' spec.header_mappings_dir = 'headers' spec.static_framework = true spec.libraries = 'c++' spec.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20', 'CLANG_CXX_LIBRARY' => 'libc++', 'ARCHS' => 'arm64', } end
我们尝试在podspec中同时指定两个库:
spec.vendored_libraries = 'iosArm64/lib/a.a', 'iosSimulatorArm64/lib/a.a'
但由于两个库文件名相同,且CocoaPods暂不支持该场景,此写法无法生效。另外尝试用lipo合并通用二进制:
lipo -create -output libuniversal.a ./iosArm64/lib/a.a ./iosSimulatorArm64/lib/a.a
但因为两者都是arm64架构,lipo无法完成合并。
请问能否通过一个CocoaPod同时兼容这两个平台的库?或者有其他可行的解决方案?
解决方案
方案1:通过Podfile的pre_install钩子动态替换库路径
在项目的Podfile中添加钩子,根据当前构建的目标平台,替换podspec中的vendored_libraries路径:
pre_install do |installer| installer.pod_targets.each do |target| next unless target.name == 'pod_lib' if installer.podfile.target_definitions.values.first.platform.name == :ios && installer.podfile.target_definitions.values.first.platform.simulator? target.specification.attributes['vendored_libraries'] = ['iosSimulatorArm64/lib/a.a'] else target.specification.attributes['vendored_libraries'] = ['iosArm64/lib/a.a'] end end end
这种方式需要使用该pod的项目配合修改Podfile,适合内部私有库场景。
方案2:拆分Subspec区分平台
在podspec中定义两个subspec,分别对应设备和模拟器版本,用户可以根据需要选择:
Pod::Spec.new do |spec| spec.platform = :ios spec.name = 'pod_lib' spec.version = '1.0.0' spec.homepage = 'pod_lib' spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } spec.authors = 'Authors' spec.license = '' spec.summary = 'pod_lib' spec.ios.deployment_target = '13.5' spec.source_files = 'headers/**/*.h' spec.public_header_files = 'headers/**/*.h' spec.header_mappings_dir = 'headers' spec.static_framework = true spec.libraries = 'c++' spec.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20', 'CLANG_CXX_LIBRARY' => 'libc++', 'ARCHS' => 'arm64', } spec.subspec 'Device' do |device| device.vendored_libraries = 'iosArm64/lib/a.a' end spec.subspec 'Simulator' do |sim| sim.vendored_libraries = 'iosSimulatorArm64/lib/a.a' end end
用户在Podfile中可以根据平台选择依赖:
# 设备环境 pod 'pod_lib/Device', '1.0.0' # 模拟器环境 pod 'pod_lib/Simulator', '1.0.0'
方案3:修改静态库文件名并通过XCConfig条件指定
将两个库重命名为不同的文件名(比如a_ios.a和a_sim.a),然后在podspec的pod_target_xcconfig中通过SDK条件配置,让不同平台自动链接对应库:
Pod::Spec.new do |spec| spec.platform = :ios spec.name = 'pod_lib' spec.version = '1.0.0' # 其他基础配置... spec.vendored_libraries = 'iosArm64/lib/a_ios.a', 'iosSimulatorArm64/lib/a_sim.a' spec.pod_target_xcconfig = { 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++20', 'CLANG_CXX_LIBRARY' => 'libc++', 'ARCHS' => 'arm64', 'OTHER_LDFLAGS[sdk=iphoneos*]' => '-l"a_ios"', 'OTHER_LDFLAGS[sdk=iphonesimulator*]' => '-l"a_sim"', 'LIBRARY_SEARCH_PATHS[sdk=iphoneos*]' => '$(PODS_ROOT)/pod_lib/iosArm64/lib', 'LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]' => '$(PODS_ROOT)/pod_lib/iosSimulatorArm64/lib' } end
方案4:使用构建脚本动态替换库文件
在podspec中添加脚本阶段,在编译时根据当前平台复制对应的库到统一目录,再进行链接:
Pod::Spec.new do |spec| # 其他基础配置... spec.vendored_libraries = 'lib/a.a' spec.script_phases = [ { :name => 'Select Correct Static Library', :script => <<-SCRIPT mkdir -p "${PODS_TARGET_SRCROOT}/lib" if [ "${SDK_NAME}" = "iphonesimulator" ]; then cp "${PODS_TARGET_SRCROOT}/iosSimulatorArm64/lib/a.a" "${PODS_TARGET_SRCROOT}/lib/a.a" else cp "${PODS_TARGET_SRCROOT}/iosArm64/lib/a.a" "${PODS_TARGET_SRCROOT}/lib/a.a" fi SCRIPT } ] end
脚本会在每次构建时自动替换为对应平台的库文件,无需用户额外操作。
内容的提问来源于stack exchange,提问作者Felix
相关产品推荐
相关产品推荐

