Swift项目生成Framework流程以及与OC的区别

一. 引言

Swift 已经成为 iOS 开发的主流语言,在实际项目中,打包成 Framework(二进制框架) 已经是模块化、组件化开发的常见需求。

对于 Objective-C 而言,制作 Framework 几乎是轻车熟路的流程:只需设置好暴露头文件,一切都能顺利调用。

但当我们用 Swift 来生成 Framework 时,对于新手而言往往会遇到各种让人困惑的问题------

比如:

  • 源码似乎被"暴露"出去了?
  • 明明设置了暴露文件却依旧无法访问?
  • public、internal 的边界到底是如何决定的?

在本篇文章中,我们将以一个"播放器"为例,从零开始讲解 Swift 项目生成 Framework 的完整流程,并重点分析它与 Objective-C 在模块暴露机制、访问控制以及编译产物结构上的区别。希望读完之后,你能彻底搞懂 Swift Framework 打包背后的逻辑。

二. 生成步骤

接下来我们就以一个"播放器"为例,演示如何从零开始创建并打包一个 Swift Framework。

在这个示例中,我们将创建一个名为 PlayerFramework 的框架,用来模拟一个简单的播放器逻辑。

其中会包含:

  • 两个公开方法:play() 和 pause() ------ 对外提供播放与暂停功能。
  • 一个私有方法:loadMediaFile()加载资源,仅供框架内部使用。

完成后,我们会将生成的 .framework 文件导入到另一个示例项目中进行测试,确保外部调用正常、私有方法不可访问。

2.1 创建Framework工程

对于创建工程的步骤OC项目和Swift项目到的确是没有什么区别。

新建一个Project,菜单栏选择"iOS" ,向下拉到"Framework & Library"然后选择Framework。

然后输入 "Product Name" 选择 "Team"等等信息,Most important of all ,"Language"要选择Swift,不然就该去看OC教程了。

创建好的工程目录结构如下:

  1. 最上面的 PlayerFramework工程的根目录。

  2. PlayerFramework 文件夹 是源码文件,这个目录才是 真正的代码与配置文件所在位置,一般包括:

  • PlayerFramework.h
  • Swift 源文件(比如稍后你要放的 PlayerHelper.swift)
  • Info.plist(框架的配置文件)

PlayerFramework.h:

这个是 Umbrella Header(总头文件),在 Objective-C 框架中非常重要,用于声明哪些符号对外暴露。

但在 纯 Swift Framework 中,这个文件基本不会起作用,

因为 Swift 的符号暴露完全由关键字 public / internal / private 控制。

  1. PlayerFramework( 图书馆图标)

这是 编译产物文件夹(Build Products),也就是编译完成后生成的真正的 .framework 文件。

每次你在 Xcode 里 Build 后,系统会在这里生成一份新的 Framework。

它一般包含:

  • 一个 "📖 图书图标" 的文件:这是实际的二进制可执行文件(PlayerFramework 本体),内部就是 Swift 编译器输出的 .o 链接产物。
  • 一个 Resources/ 文件夹:存放资源文件(图片、plist、json等),如果你的框架带有资源就会放在这里。

这个文件夹并不是你自己维护的,而是 Xcode 自动生成的 编译产物

2.2 构建PlayeHelper类

接下来,我们来创建一个示例类 ------ PlayerHelper,用来模拟播放器的核心逻辑。在这个例子中,我们会定义两个对外暴露的公共方法:play() 和 pause(),同时在内部实现一个私有的加载方法 loadMediaFile()。

文件位置

该文件应该在"PlayerFramework"文件夹下与 "PlayerFramework.h"同级。

PlayerHelper.swift 示例代码

代码内加了完整的注释,需要注意的是整个类需要使用public修饰,对外暴露的方法也需要使用public修饰。

Swift 复制代码
import Foundation

/// 播放器辅助类
/// 用于提供外部调用的播放与暂停接口。
public class PlayerHelper {
    
    /// 初始化方法
    public init() {}
    
    // MARK: - 对外暴露的接口
    
    /// 开始播放
    /// 调用该方法后会触发内部加载逻辑(示意)
    public func play() {
        print("🎵 Start playing...")
        loadMediaFile()
    }
    
    /// 暂停播放
    /// 暂停当前的播放任务
    public func pause() {
        print("⏸ Pause playback.")
    }
    
    // MARK: - 私有逻辑(不会对外暴露)
    
    /// 加载媒体文件,仅供内部调用
    /// 外部工程无法访问此方法
    private func loadMediaFile() {
        print("🔒 Load media from local file system.")
    }
}

2.3 设置配置信息

接下来我们还需要到"Build Setting"中查看一下配置信息,大多数情况下这些配置都是符合要求的,但是我们在这里还是来介绍一下,以便满足不同的需求。

设置 Defines Module

Build Settings → Packaging → Defines Module

将其设置为YES。

  • 表示当前 Framework 会作为一个独立的 Swift Module 存在。
  • 外部项目才能通过 import PlayerFramework 导入你的框架。
  • 如果关闭,则 Swift 编译器无法识别模块名。
设置 Build Libraries for Distribution

Build Settings → Build Options → Build Libraries for Distribution

将其值设置为:YES。

  • 启用 Module Stability(模块稳定性),可避免因 Swift 版本不同而无法加载。
  • 生成 .swiftinterface 文件,用于暴露框架 API 接口签名(不会泄露实现代码)。
  • 这是 Swift 框架"被安全调用"的关键一步。
确认 Mach-O Type

Build Settings → Linking → Mach-O Type

选择动态库还是静态库。这个根据自己需要来选择,希望简单点的话直接选择静态库" Static Library"。

  • 表示生成的 Framework 是一个可动态加载的库。
  • 这也是我们常说的 "动态 Framework",可以被多个 App 引用而不重复加载。
  • 若选择 Static Library,则会在编译时被打包进 App,这种方式适用于 SDK,不适合模块化分发。

2.4 编译生成Framework

配置信息都检查完成之后,我们直接运行项目或者"command+B" 编译项目,关于生成的是真机使用的还是模拟器:

在Xcode的左上角选择目标设备,可以选择"Any iOS Device (arm64)"来编译适用于真机的版本,或者"Any iOS Simulator Device(arm64,x86_64)"。

也可以参考下面的文章进行合并:

https://blog.csdn.net/weixin_39339407/article/details/142988880?fromshare=blogdetail&sharetype=blogdetail&sharerId=142988880&sharerefer=PC&sharesource=weixin_39339407&sharefrom=from_link

编译成功之后之后,在菜单栏选择"Project" -> "Show build Folder in Finder"

就可以看见我们已经生成的Framework:

我们编译和运行的都是debug包,不能在生产环境使用嗷。

生成release环境的Framework可以选择"Archive",如果有不太明白的可以私信或者留言。

三. Swift生成的Framework内容解析

当我们构建完成后(无论是运行在真机还是模拟器),在 Products 文件夹中会生成一个成品:

3.1 Headers 文件夹

PlayerFramework.framework/Headers/PlayerFramework.h

这个文件就是我们在工程里看到的 Umbrella Header

在 Objective-C 框架中,这个文件非常重要,

因为只有被列入公共头文件(Public Headers)的符号,才能被外部访问。

但在 Swift 框架中情况完全不同:Swift 框架不会依赖 .h 文件

  • 所有对外可见的符号由 public / open 修饰符控制;
  • 即使删除 .h 文件,Swift 框架依然可以被正常导入;
  • .h 文件的存在主要是为了 兼容 Objective-C 调用 Swift 框架 的情况。

所以,如果你纯 Swift 开发,这个文件几乎没用,只是个"占位符"。

3.2 Info.plist

这是 Framework 的元信息文件,包含:

  • 框架的版本号
  • 编译环境信息
  • Bundle Identifier 等

你基本不需要手动修改它。

3.3 Modules 文件夹

这个文件夹是 Swift 框架能被识别为 模块(Module) 的关键。

module.modulemap

这个文件告诉编译器:"这个 Framework 是一个模块,模块名叫 PlayerFramework。"

内容通常如下:

Swift 复制代码
framework module PlayerFramework {
  umbrella header "PlayerFramework.h"
  export *
  module * { export * }
}

这段配置表示:

  • 框架的对外入口是 PlayerFramework.h
  • 模块名为 PlayerFramework
  • 允许 Swift 和 Objective-C 互操作(export *)

即使你没有手动设置,Xcode 会自动生成。

PlayerFramework.swiftmodule

这个文件夹里放的是 Swift 模块描述文件,它包含几种文件类型:

文件 作用
.swiftmodule Swift 编译器读取的模块定义(二进制格式)
.swiftdoc Swift 文档元数据(方法签名、注释等)
.swiftinterface 当你启用 "Build Libraries for Distribution = YES" 后生成的 文本描述文件,用于模块稳定性

3.4 PlayerFramework (二进制文件)

这是整个框架的核心部分。它是编译后的 Mach-O 动态库(.dylib 格式),包含你所有 Swift 源码的编译产物。

四. 使用Framework

接下来我们新建一个普通的Swift项目就叫"TestFrameworkDemo",然后呢将我们刚刚生成的PlayerFramework导入到项目中。

在ViewController可以直接引用该Framework,然后按住"command"使用鼠标点击"PlayerFramework"进入内部会发现,只有我们设置为public的方法可以被看见,并且只有方法方法名,并不会暴露方法内部的实现:

里面所有使用public修饰的方法,在外面都可以直接被调用。

五. Swift 与 Objective-C 的区别

其实OC与Swift构建Framework会有区别的根本原因在于Swift 与 Objective-C 在框架暴露机制上的本质区别

5.1 Objective-C:通过「头文件」决定暴露范围

在 Objective-C 的世界里,所有的符号暴露都是通过 头文件(.h) 来完成的。

如果你希望外部项目能访问某个类或方法,必须:

  • 把对应的 .h 文件添加到
  • Build Phases → Headers → Public 下;
  • 在 Umbrella Header(例如 PlayerFramework.h)中 #import 进来。
objectivec 复制代码
// PlayerManager.h
@interface PlayerManager : NSObject
- (void)play;
@end

若没有将 PlayerManager.h 添加为 Public,

即使你在别的文件中 import 了,也无法被外部工程识别。

所以,在 OC 框架中,"文件是否被暴露"完全取决于你有没有公开头文件。

5.2 Swift:通过「访问控制修饰符」决定暴露范围

Swift 的设计理念是模块化和安全性优先,

因此框架的暴露范围不再依赖外部文件配置,而是完全由 访问控制修饰符 决定:

修饰符 可见范围 说明
private 当前文件内 完全隐藏
fileprivate 当前源文件 类似私有
internal(默认) 当前模块 默认,仅框架内部可见
public 可被其他模块访问 框架对外公开的 API
open 可被访问且可被继承/重写 用于需要被扩展的 API

无需再去设置 "Public Headers",Swift 编译器会根据修饰符自动生成 .swiftinterface 接口文件,供外部模块识别和调用。

5.3 模块层面的区别

对比项 Objective-C Swift
暴露机制 头文件(Public Headers) 访问修饰符(public/open)
入口文件 Umbrella Header (.h) 自动生成 modulemap
接口文件 .h 文件 .swiftinterface 文件
源码泄露风险 可能(若暴露实现文件) 无(只生成签名信息)
模块导入方式 #import <Framework/Header.h> import FrameworkName

六.结语

通过本篇教程,我们完整演示了 Swift 项目生成 Framework 的流程,并重点解析了其与 Objective-C 的区别:

  • Swift 不依赖 Public Headers 来控制暴露范围,而是通过 访问修饰符 决定哪些方法可被外部访问;
  • 编译生成的 .framework 中只包含 二进制和接口签名,源码不会暴露;
  • 对外暴露的 public 方法只是签名,对实现逻辑是不可见的,这让框架更加安全和可维护。

掌握这些原理后,你就可以自信地构建 Swift 框架,安全、规范地对外提供接口,同时保留内部实现的私密性。

相关推荐
纵有疾風起14 小时前
C++—string(1):string类的学习与使用
开发语言·c++·经验分享·学习·开源·1024程序员节
kitsch0x9718 小时前
论文学习_LLM4Decompile: Decompiling Binary Code with Large Language Models
1024程序员节
hazy1k19 小时前
51单片机基础-继电器实验
stm32·单片机·嵌入式硬件·51单片机·1024程序员节
Brianna Home1 天前
大模型如何变身金融风控专家
人工智能·深度学习·机器学习·自然语言处理·stable diffusion·1024程序员节
songgeb1 天前
What Auto Layout Doesn’t Allow
swift
YGGP1 天前
【Swift】LeetCode 240.搜索二维矩阵 II
swift
TDengine (老段)1 天前
TDengine 数据函数 CORR 用户手册
大数据·数据库·物联网·时序数据库·tdengine·1024程序员节
彩云回2 天前
多维尺度分析法(MDS)
人工智能·机器学习·1024程序员节
j_xxx404_2 天前
Linux:权限复盘扩展|粘滞位|软件包管理器|Linux软件生态
linux·1024程序员节