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 框架,安全、规范地对外提供接口,同时保留内部实现的私密性。

相关推荐
Antonio9157 小时前
【Swift】UIKit:UISegmentedControl、UISlider、UIStepper、UITableView和UICollectionView
开发语言·ios·swift
1***81538 小时前
Swift在服务端开发的可能性探索
开发语言·ios·swift
S***H2838 小时前
Swift在系统级应用中的开发
开发语言·ios·swift
HarderCoder12 小时前
SwiftUI 状态管理极简之道:从“最小状态”到“状态树”
swift
Antonio91512 小时前
【Swift】 UIKit:UIGestureRecognizer和UIView Animation
开发语言·ios·swift
蒙小萌19931 天前
Swift UIKit MVVM + RxSwift Development Rules
开发语言·prompt·swift·rxswift
Antonio9151 天前
【Swift】Swift基础语法:函数、闭包、枚举、结构体、类与属性
开发语言·swift
Antonio9151 天前
【Swift】 Swift 基础语法:变量、类型、分支与循环
开发语言·swift
songgeb1 天前
[WWDC 21]Detect and diagnose memory issues 笔记
性能优化·swift
金融小师妹2 天前
基于机器学习与深度强化学习:非农数据触发AI多因子模型预警!12月降息预期骤降的货币政策预测
大数据·人工智能·深度学习·1024程序员节