背景阐明

公司要求在其他项目组中供给一个进口, 能够进入拜访到咱们这个项目的界面, 所以咱们决定采用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不是一个项目, 无法直接运转

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解

2 创立framework

TARGETS -> +

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解

3 配置framework

Deployment Info 最低的体系要求

建议当然低一些好,(示例 ios9)

Swift+第三方库的framework制作流程详解

Build Active Architecture Only 仅构建活动架构

设置为NO, 即不是只编译当时架构, 假如为Yes, 则只会修改当时挑选的架构, 比如挑选iPhone 13模拟器编译, 则编译后的framework只能用于iPhone 13模拟器

Swift+第三方库的framework制作流程详解

Excluded Architecture 扫除架构

即移除重复的架构, 由于真机和模拟器编译后,framework中arm64架构重复,会导致兼并失利,所以移除模拟器中的arm64架构

Swift+第三方库的framework制作流程详解

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, 防止代码、调试符号等被剥离。

Swift+第三方库的framework制作流程详解

Mach-O Type 类型

设置类型为静态库

Swift+第三方库的framework制作流程详解

Build Configutation 编译配置

设置为release

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解

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

Swift+第三方库的framework制作流程详解

4 开发代码

swift不像OC能够露出接口,在swift中要想给其他工程调用接口,记住在类,办法或属性前加public或许open。

swift权限控制符阐明

open

权限最大,能够被外界模块拜访,承继重写
public

能够被外界工程拜访
internal

默许文件创立时的权限,能够在本工程的拜访
private

只能够在创立的文件内拜访

项目原因, 只能经过源码办法引进第三方结构, 以SnapKit为例, 将SnapKit的源码拖进项目里

Swift+第三方库的framework制作流程详解

一起创立一个测验文件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 -> +

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解

没有运用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就行

Swift+第三方库的framework制作流程详解

终究生成的目录如下

Swift+第三方库的framework制作流程详解

7 测验framework

随便新建一个项目, 然后将生成的framework拖进去, 创立一个跳转进口

Swift+第三方库的framework制作流程详解

然后分别用模拟器和真机运转, 假如都能成功运转且跳转, 则framework制造成功

Swift+第三方库的framework制作流程详解

8 第三方重复运用问题

测验新树立一个新的framework叫GPKit1, 里边也引用到SnapKit的源码, 然后将GPK和GPKit1都一起导入到测验项目中, 分别跳转进对应的页面, 此刻是能够运转成功和成功跳转, 并不会出现冲突

Swift+第三方库的framework制作流程详解

Swift+第三方库的framework制作流程详解