「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
公司工程项目基于cocoapods
完成了的组件化
,为了能够提升编译速度,我们进行了组件二进制化
,工程代码是swift
代码。在这里总结下swift 和 OC 混编
下的组件二进制化,这里主要介绍两种二进制组件:framework
和xcframework
。
制作framework
模版工程
我们通过 Cocoapods
的模板,创建一个有Example
的工程。在终端输入pod lib create Animal
,语言选择 swift
,并打开workspace
工程。
在 podspec
文件中增加 Alamofire
依赖,指定为静态framework
,并将Build Settings
中的Build Libraries for distribution
设置为true
在 Animal/Classes
目录下新建OC
文件Monkey.h/m
@implementation Monkey
-(void)run {
NSLog(@"猴子跑起来了.....");
}
@end
新建 Animal.swift
,并引入Alamofire
和Monkey类
import Foundation
import Alamofire
open class Animal: NSObject {
public func beginRun() {
let a = SessionManager()
print("Alamofire ------- \(a)")
print("开始跑步")
}
public func monkeyRun(){
let monkey = Monkey()
monkey.run()
}
}
这样,我们就可以在主工程里面引入使用了
override func viewDidLoad() {
super.viewDidLoad()
let animal = Animal()
animal.beginRun()
animal.monkeyRun()
}
Shell脚本制作
接下来,我们将使用脚本借助Pods.xcodeproj
的工程配置,一步完成framework的制作,核心步骤如下:
- 1,编译
真机
设备的framework
。
xcodebuild -${WORK_TYPE} "${SRCROOT}/Pods.xcodeproj" -scheme $SCHEME_NAME -configuration ${CONFIGURATION} -sdk iphoneos
- 2,编译
模拟器
设备的framework
。
xcodebuild -${WORK_TYPE} "${SRCROOT}/Pods.xcodeproj" -scheme $SCHEME_NAME -configuration ${CONFIGURATION} -sdk iphonesimulator -arch x86_64
- 3,合并为通用
framwork
。
lipo -create "${DEVICE_DIR}/${TARGETNAME}" "${SIMULATOR_DIR}/${TARGETNAME}" -output "${INSTALL_DIR}/${TARGETNAME}"
- 4,拷贝
模拟器设备
和真机设备
下的swiftmodule
文件,放到通用framwork
的swiftmodule
目录下
cp -r ${SIMULATOR_SWIFTMODULE_DIR}/* "${INSTALL_DIR}/Modules/${TARGETNAME}.swiftmodule"
cp -R "${INSTALL_DIR}" "${FINAL_FRAMEWORK_PATH}"
把buildFramework.sh
放至Example
目录下,运行脚本sh buildFramework.sh
即可。
这样我们就完成了通用framwork
的制作,并把所有架构下的swiftmodule
文件和swiftInterface
文件存放到了总的文件夹里面。
build
脚本如下:
// buildFramework.sh
TARGETNAME='Animal'
WORK_TYPE="project" # 有效值 project / workspace (cocoapods项目)
SCHEME_NAME="Animal"
SCRIPT_PATH=$(cd `dirname $0`; pwd)
SRCROOT=${SCRIPT_PATH}/Pods
WORK_PATH=${SRCROOT}/${TARGETNAME}
rm -rf ${SCRIPT_PATH}/build
BUILD_ROOT=${SCRIPT_PATH}/build
CONFIGURATION="Release"
mkdir ${SCRIPT_PATH}/build
echo "🚀 开始创建${TARGETNAME}.framework"
INSTALL_DIR=${SRCROOT}/Products/${TARGETNAME}.framework
DEVICE_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphoneos/${TARGETNAME}/${TARGETNAME}.framework
DEVICE_SWIFTMODULE_DIR=${DEVICE_DIR}/"Modules"/${TARGETNAME}".swiftmodule"
SIMULATOR_DIR=${BUILD_ROOT}/${CONFIGURATION}-iphonesimulator/${TARGETNAME}/${TARGETNAME}.framework
SIMULATOR_SWIFTMODULE_DIR=${SIMULATOR_DIR}/"Modules"/${TARGETNAME}".swiftmodule"
echo "🚀 开始编译真机设备"
xcodebuild -${WORK_TYPE} "${SRCROOT}/Pods.xcodeproj" -scheme $SCHEME_NAME -configuration ${CONFIGURATION} -sdk iphoneos
if [ "$?" != 0 ]
then
echo "❎❎ 真机设备编译失败..."
exit 0
fi
xcodebuild -${WORK_TYPE} "${SRCROOT}/Pods.xcodeproj" -scheme $SCHEME_NAME -configuration ${CONFIGURATION} -sdk iphonesimulator -arch x86_64
if [ "$?" != 0 ]
then
echo "❎❎ 模拟器设备编译失败..."
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
lipo -create "${DEVICE_DIR}/${TARGETNAME}" "${SIMULATOR_DIR}/${TARGETNAME}" -output "${INSTALL_DIR}/${TARGETNAME}"
# 拷贝 simulator 的swiftmodule
cp -r ${SIMULATOR_SWIFTMODULE_DIR}/* "${INSTALL_DIR}/Modules/${TARGETNAME}.swiftmodule"
if [ "$?" != 0 ]
then
echo "❎❎ 拷贝失败..."
exit 0
fi
# 拷贝 真机 的swiftmodule
cp -r ${DEVICE_SWIFTMODULE_DIR}/* "${INSTALL_DIR}/Modules/${TARGETNAME}.swiftmodule"
FINAL_FRAMEWORK_PATH=${SRCROOT}/../../
cp -R "${INSTALL_DIR}" "${FINAL_FRAMEWORK_PATH}"
echo "🚀 ✌️ ✌️ ✌️ ${TARGETNAME}.framework 制作成功"
echo "${TARGETNAME}.framework 路径:${FINAL_FRAMEWORK_PATH}"
二进制和源码切换
在完成二进制框架
制作之后,我们通过podspec
文件的subspec
,来实现组件二进制依赖
和源码切换
,
在podspec
文件中,添加如下
此时完整的podspec
文件如下
Pod::Spec.new do |s|
s.name = 'Animal'
s.version = '0.1.0'
s.summary = 'A short description of Animal.'
s.description = <<-DESC
Animal
DESC
s.homepage = 'https://github.com/1260197127@qq.com/Animal'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { '1260197127@qq.com' => '1260197127@qq.com' }
s.source = { :git => 'https://github.com/1260197127@qq.com/Animal.git', :tag => s.version.to_s }
s.ios.deployment_target = '9.0'
s.dependency 'Alamofire'
s.static_framework = true
s.pod_target_xcconfig = { 'BUILD_LIBRARY_FOR_DISTRIBUTION' => true }
s.subspec 'Framework' do |sf|
sf.vendored_framework = "Animal.framework"
end
s.subspec 'Source' do |sc|
sc.source_files = 'Animal/Classes/**/*'
end
s.default_subspecs = 'Framework'
end
默认是使用 Framwork
,如果想要切换源码
和二进制
,可以在Podfile
文件里面,进行切换
use_frameworks!
platform :ios, '9.0'
target 'Animal_Example' do
# pod 'Animal', :path => '../', :subspecs => ["Framework"] # 使用Framework
# pod 'Animal/Framework', :path => '../' # 使用Framework
# pod 'Animal/Source', :path => '../' # 使用源码
pod 'Animal' , :path => '../' # 默认使用 framework
target 'Animal_Tests' do
inherit! :search_paths
end
end
我们查看 Animal
工程,此时引用的是 Animal.framework
。
至此,我们使用framwork
来实现组件二进制和源码切换就完成了,相比于framework
,在Xcode 11
之后,有一个更好的二进制框架xcframework
,苹果官方也是推荐使用xcframework
的。
xcframework
xcframework
有几个好处
1,可以用单个.xcframework文件提供多个平台的分发二进制文件。
2,可以按照平台划分,可以包含相同架构的不同平台文件。
制作 xcframework
同样借助cocoapods
工程,我们使用shell
脚本,一步完成xcframwrok
的制作。
核心步骤有两步,
- 1,在
Release
环境下,对不同平台分别进行archive
(开启Build Libraries for distribution
)。
xcodebuild archive -project "${SRCROOT}/Pods.xcodeproj" -scheme $SCHEME_NAME -configuration ${CONFIGURATION} -destination 'generic/platform=iOS' -archivePath "../archives/$SCHEME_NAME.framework-iphoneos.xcarchive" SKIP_INSTALL=NO
xcodebuild archive -project "${SRCROOT}/Pods.xcodeproj" -scheme $SCHEME_NAME -configuration ${CONFIGURATION} -destination 'generic/platform=iOS Simulator' -archivePath "../archives/${SCHEME_NAME}.framework-iphonesimulator.xcarchive" SKIP_INSTALL=NO
- 2,使用
xcodebuild -create-xcframework
创建xcframwork
。
xcodebuild -create-xcframework \
-archive "../archives/${SCHEME_NAME}.framework-iphonesimulator.xcarchive" \
-framework "${SCHEME_NAME}.framework" \
-archive "../archives/${SCHEME_NAME}.framework-iphoneos.xcarchive" \
-framework "${SCHEME_NAME}.framework" \
-output "../${SCHEME_NAME}.xcframework"
运行脚本sh buildXCFramework.sh
,我们就可以得到xcframework
文件。
使用xcframework
使用方式和framework
是一致的,将vendored_framework
指向Animal.xcframework
即可。
常见问题
1 ,⚠️:x86_64-apple-ios-simulator.swiftsourceinfo' is either malformed or generated by a different Swift version. Note that it uses an unstable format and may leak internal project details, it should not be distributed alongside modules
如果我们使用.framework
的形式,在swift
版本更新时,会报这个警告,使用xcframework
可以解决这个问题。
2,❌:Module compiled with Swift 5.1.xx cannot be imported by the Swift 5.4.xxx compiler:
当swift
进行大版本升级时,如果没有开启 Build Libraries for distribution
,则会报这个错误,所以,在制作二进制时,将其设置为YES
即可。
总结
我们分别探讨了使用framework
和xcframework
两种方式,来制作swift二进制组件
,然后通过subspec
的形式,实现组件二进制
和源码
的切换。
本文涉及到的代码
和Shell
脚本,已上传至Animal,脚本文件在 Example
目录下,有需要的可以自行下载。
如果觉得有收获请按如下方式给个
爱心三连
:👍:点个赞鼓励一下
。🌟:收藏文章,方便回看哦!
。💬:评论交流,互相进步!
。