背景阐明
公司要求在其他项目组中供给一个进口, 能够进入拜访到咱们这个项目的界面, 所以咱们决定采用framework的形式, 将咱们的项目打包成一个framework给其他项目组, 然后供给相应的接口调用。但是另一个项目组由于历史原因, 他们的项目没办法用cocoaPod的办法依靠第三方, 所以咱们这边也只能经过第三方源码的办法集成到咱们的framework中。至于如何经过cocoaPod制造依靠第三方库的framework, 后续会再详细阐明。
制造前的常识整理
什么是framework
framework其实便是一个库, 能够供给给别人运用, 但是躲藏内部的详细实现。体系的.framework是动态库,咱们自己树立的.framework是静态库。
静态库和动态库
静态库 连接时完整地仿制至可履行文件中,被多次运用就有多份冗余仿制。 存在形式有.a 和 .framework
动态库 连接时不仿制,程序运转时由体系动态加载到内存,供程序调用,体系只加载一次,多个程序共用,节省内存。存在形式有.framework, .dylib, .tbd
.a与.framework的区别
1 .a是一个纯二进制文件,.framework中除了有二进制文件之外还有资源文件
2 .a文件不能直接运用,至少要有.h文件合作,.framework文件能够直接运用
3 .a + .h + sourceFile = .framework
接下来便是详细创立流程
1 创立Demo项目
快捷键command + shift + n, 挑选App类型, 这个Demo项目是用来运转和测验framework, 由于framework不是一个项目, 无法直接运转
2 创立framework
TARGETS -> +
3 配置framework
Deployment Info 最低的体系要求
建议当然低一些好,(示例 ios9)
Build Active Architecture Only 仅构建活动架构
设置为NO, 即不是只编译当时架构, 假如为Yes, 则只会修改当时挑选的架构, 比如挑选iPhone 13模拟器编译, 则编译后的framework只能用于iPhone 13模拟器
Excluded Architecture 扫除架构
即移除重复的架构, 由于真机和模拟器编译后,framework中arm64架构重复,会导致兼并失利,所以移除模拟器中的arm64架构
iOS指令集常识
armv6
iPhone iPhone2 iPhone3G 第一代和第二代iPod Touch
armv7
iPhone4 iPhone4S
armv7s
iPhone5 iPhone5C
arm64
iPhone5S iPhone6 iPhone6+
指令是向下兼容的,如iPhone5s CPU支撑arm64, 但它一起兼容armv7s,仅仅假如程序运用armv7s指令进行编译,或许无法充分发挥它的64位特性。
Architecture
是指该程序编译时的目标设备(便是ARM指令集,如armv7, armv7s…),编译期会为不同的指令集(设备)生成专有的安装包。不同设备上会履行该设备对应的指令集,如iPhone5s会优履行arm64(假如有)
Dead Code Stripping 死代码剥离
即编译选项优化,是对程序编译出的可履行二进制文件中没有被实际运用的代码进行Strip操作, 给framework包瘦身, 但是关于framework来说, 应该设置为NO, 防止代码、调试符号等被剥离。
Mach-O Type 类型
设置类型为静态库
Build Configutation 编译配置
设置为release
Build Libraries for Distribution 为分发构建库
设置为Yes, 使编译出来的framework向下兼容, 即用高版别Xcode自带的Swift高版别编译出来的framework, 放到低版别Xcode低Swift版别中, 也能运转。否则Swift编译器不会生成必要的”.swiftinterface文件,这是将来编译器能够加载旧库的要害。否则在不同Swift版其他Xcode运转, 会报错 Module compiled with Swift 5.6 cannot be imported by the Swift 5.5.1 compiler
4 开发代码
swift不像OC能够露出接口,在swift中要想给其他工程调用接口,记住在类,办法或属性前加public或许open。
swift权限控制符阐明
open
权限最大,能够被外界模块拜访,承继重写
public
能够被外界工程拜访
internal
默许文件创立时的权限,能够在本工程的拜访
private
只能够在创立的文件内拜访
项目原因, 只能经过源码办法引进第三方结构, 以SnapKit为例, 将SnapKit的源码拖进项目里
一起创立一个测验文件GPKitController.swift, targets挑选GPKit, 代码如下
//
// GPKitController.swift
// GPKit
//
// Created by Darren on 2022/3/25.
//
import UIKit
/**
GPKit控制器
*/
public class GPKitController: UIViewController {
public override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
navigationItem.title = "GPKit"
let label = UILabel()
label.text = "我是GPKit里边的控制器"
label.textColor = .red
view.addSubview(label)
label.snp.makeConstraints { make in
make.center.equalToSuperview()
}
}
}
5 增加编译兼并脚本
framework的编译分为模拟器编译和真机编译, 而咱们供给给别人运用的framework, 一般都是得模拟器和真机都能运转的, 所以必须将两个版其他framework兼并成一个通用的framework
targets -> +
没有运用cocoaPod的兼并脚本代码
#!/bin/sh
# SDK姓名, 改成自己的SDK姓名即可
SDK_NAME=GPKit
# framework终究输出的途径的文件夹
UNIVERSAL_OUTPUTFOLDER="${SRCROOT}/Products/"
# 作业区间, 由于没有用到cocoaPod, 所以是${PROJECT_NAME}.xcodeproj
# 假如用到cocoaPod, 便是${PROJECT_NAME}.xcworkspace
WORKSPACE_NAME=${PROJECT_NAME}.xcodeproj
# 创立输出途径文件夹
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# 移除上次编译生成的framework
rm -rf "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework"
# 编译真机版framework
xcodebuild -target "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# 编译模拟器版framework
xcodebuild -target "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# 仿制编译生成的真机版framework到终究输出的途径
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${SDK_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}"
# 将模拟器结构的swift模块仿制到终究输出的途径
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/Modules/${SDK_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/Modules/${SDK_NAME}.swiftmodule"
fi
# 兼并模拟器和真机framework, 生成通用framework
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/${SDK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/${SDK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${SDK_NAME}.framework/${SDK_NAME}"
# 删去编译之后生成的无关的配置文件
dir_path="${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
# 打开兼并后的文件夹
open "${UNIVERSAL_OUTPUTFOLDER}"
运用cocoaPod的兼并脚本代码
即有经过cocoaPod创立生成.xcworkspace文件, 则脚本代码如下
#!/bin/sh
# SDK姓名, 改成自己的SDK姓名即可
SDK_NAME=GPKit
# framework终究输出的途径的文件夹
UNIVERSAL_OUTPUTFOLDER="${SRCROOT}/Products/"
WORKSPACE_NAME=${PROJECT_NAME}.xcworkspace
# 创立输出途径文件夹
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# 移除上次编译生成的framework
rm -rf "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework"
# 编译真机版framework
xcodebuild -workspace "${WORKSPACE_NAME}" -scheme "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphoneos ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# 编译模拟器版framework
xcodebuild -workspace "${WORKSPACE_NAME}" -scheme "${SDK_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# 仿制编译生成的真机版framework到终究输出的途径
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${SDK_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}"
# 将模拟器结构的swift模块仿制到终究输出的途径
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/Modules/${SDK_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/Modules/${SDK_NAME}.swiftmodule"
fi
# 兼并模拟器和真机framework, 生成通用framework
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/${SDK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SDK_NAME}.framework/${SDK_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${SDK_NAME}.framework/${SDK_NAME}"
# 删去编译之后生成的无关的配置文件
dir_path="${UNIVERSAL_OUTPUTFOLDER}/${SDK_NAME}.framework/"
for file in ls $dir_path
do
if [[ ${file} =~ ".xcconfig" ]]
then
rm -f "${dir_path}/${file}"
fi
done
# 打开兼并后的文件夹
open "${UNIVERSAL_OUTPUTFOLDER}"
6 生成framework
履行脚本, 只需要选中GPKitAggregate, 然后履行run就行
终究生成的目录如下
7 测验framework
随便新建一个项目, 然后将生成的framework拖进去, 创立一个跳转进口
然后分别用模拟器和真机运转, 假如都能成功运转且跳转, 则framework制造成功
8 第三方重复运用问题
测验新树立一个新的framework叫GPKit1, 里边也引用到SnapKit的源码, 然后将GPK和GPKit1都一起导入到测验项目中, 分别跳转进对应的页面, 此刻是能够运转成功和成功跳转, 并不会出现冲突