Github 代码地址:github.com/SuiShanpu/i…
一、创建静态库
1、选择 Create New Project(我的是 Xcode 16)
2、选择类型为 Framework
3、设置名称,语言(选哪种语言似乎没有差别)
4、生成的项目基本结构如下图:
5、设置最低适配 iOS 版本(根据项目需求设置)
6、设置为静态库(必须设置)
Mach-O Type:只有系统是动态库,外部的都是静态库。
Build Libraries for Distribution 为分发构建库
把
Build Libraries for Distribution设置为YES。这是根据前边的记录,打包 XCFramework 所用到的设置。设置为Yes, 使编译出来的framework向下兼容, 即用高版本Xcode自带的Swift高版本编译出来的framework, 放到低版本Xcode低Swift版本中, 也能运行。
Define Module:这个默认就是 YES;如果使用 swift 语言则必须设置为 YES。
二、代码及相关配置
以下几种场景,根据自身情况任选其中一种即可。(前面是 framewoek 包的语言;后面是要用的项目的语言)
1、OC 包给 OC、Swift 项目均可用
编写代码
- 添加文件 OcDemo.h
// OcDemo.h
#import <UIKit/UIKit.h>
@interface OcDemo : NSObject
- (NSString *)get:(NSString *)code;
@end
- 添加文件 OcDemo.m
// OcDemo.m
#import "OcDemo.h"
@interface OcDemo()
@end
@implementation OcDemo
- (instancetype)init {
self = [super init];
return self;
}
- (NSString *)get:(NSString *)code {
return [NSString stringWithFormat:@"我是 OcDemo: %@", code];
}
@end
- 添加新文件到头文件 FrameworkDemo.h
** 第一,先添加 h 文件到 Xcode 的头文件配置中:
** 第二,再在代码中引入 h 文件:
// FrameworkDemo.h
#import <FrameworkDemo/OcDemo.h>
2、Swift 包给 Swift 项目用
编写代码
- 添加文件 SwiftDemo.swift
// SwiftDemo.swift
// 都需要设置为 public 类型
public class SwiftDemo {
public init() {}
public func get(code: String) -> String? {
return "我是 SwiftDemo: " + code;
}
}
- 源文件 FrameworkDemo.h 不能动 (必须存在,且在头文件配置中)
3、Swift 包给 OC 项目用
编写代码
- 添加文件 SwiftDemo.swift
// SwiftDemo.swift
import Foundation
// Swift 中需继承 NSObject 才能被 OC 识别
public class SwiftDemo: NSObject {
// Swift方法需添加 @objc 修饰符才能被 OC 识别
@objc
public func get(code: String) -> String? {
return "我是 SwiftDemo: " + code;
}
}
设置相关配置
Generated Header Name 默认为:包名称-Swift.h。
将 Install Generated Header 配置为 YES。
此时会在编译后的 “FrameworkDemo/DerivedData/universal/FrameworkDemo.xcframework/ios-arm64/FrameworkDemo.framework/Modules/” 文件夹下生成 “module.modulemap”,内容如下:
// module.modulemap
// 这个名称必须与项目名称一致
framework module FrameworkDemo {
// 这个名称文件必须存在(空的即可),必须与XCode 中配置项 Generated Header Name 一致
umbrella header "FrameworkDemo.h"
export *
module * { export * }
}
// 下面这个,只有 Install Generated Header 配置为 YES 时,才会生成。
// 当 swift 包应用在 oc 项目中时,必须有这个才可以
module FrameworkDemo.Swift {
header "FrameworkDemo-Swift.h"
requires objc
}
三、使用外部脚本进行编译
1、根目录下添加脚本文件
2、添加脚本内容
#!/bin/bash
# 停止脚本遇到任何错误时
set -e
# 获取脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 项目配置(有3处修改为自己工程名称)
WORKSPACE_PATH="$SCRIPT_DIR/FrameworkDemo.xcodeproj/project.xcworkspace"
SCHEME="FrameworkDemo"
CONFIGURATION="Release"
DERIVED_DATA_DIR="$SCRIPT_DIR/DerivedData"
FRAMEWORK_NAME="FrameworkDemo"
# 创建输出目录
mkdir -p ${DERIVED_DATA_DIR}/universal
# 编译真机架构
xcodebuild -configuration $CONFIGURATION -derivedDataPath ${DERIVED_DATA_DIR}/iOS -workspace $WORKSPACE_PATH -scheme $SCHEME -sdk iphoneos clean build
# 编译模拟器架构
xcodebuild -configuration $CONFIGURATION -derivedDataPath ${DERIVED_DATA_DIR}/simulator -workspace $WORKSPACE_PATH -scheme $SCHEME -sdk iphonesimulator clean build
# 创建XCFramework
xcodebuild -create-xcframework \
-framework ${DERIVED_DATA_DIR}/iOS/Build/Products/Release-iphoneos/${FRAMEWORK_NAME}.framework \
-framework ${DERIVED_DATA_DIR}/simulator/Build/Products/Release-iphonesimulator/${FRAMEWORK_NAME}.framework \
-output ${DERIVED_DATA_DIR}/universal/${FRAMEWORK_NAME}.xcframework
# 删除无关的配置文件
rm -rf "${DERIVED_DATA_DIR}/iOS"
rm -rf "${DERIVED_DATA_DIR}/simulator"
echo "Universal XCFramework is created at: ${DERIVED_DATA_DIR}/universal/${FRAMEWORK_NAME}.xcframework"
echo "-------------编译完成---------------------------"
3、运行脚本 (我是用 VSCode 运行的)
% sh build.sh
xcframework 包可以将多种平台(iPhone、iPad、Mac、Simulator或arm64、i386、x86_64)的库文件打包在一起;同时供真机(arm64架构的)和模拟器(x86_64 和 arm64 架构的)使用。
四、在 iOS 工程中使用
1、在 Xcode 中打开 iOS 工程
2、使用 framework 包
将 xcframework 文件夹(FrameworkDemo/DerivedData/universal/FrameworkDemo.xcframework)整个拖入 即可。
3、代码中使用
在 OC 中用
#import <FrameworkDemo/FrameworkDemo.h>
# OC 用在 OC 中
NSString *demoStr = [[[OcDemo alloc] init] get:@"rondle"];
# Swift 用在 OC 中(注意方法名称变了)
NSString *demoStr = [[[SwiftDemo alloc] init] getWithCode:@"rondle"];
在 Swift 中用
import FrameworkDemo
// Swift 用在 Swift 中
let demoStr = SwiftDemo().get(code: "rondle");
// OC 用在 Swift 中
let demoStr = OcDemo().get("rondle");
------------------ 结束 -----------------
附:在一个纯 OC 项目中使用 swift 的 framework 包时报错
如果报错: “Undefined symbol: swift_FORCE_LOAD$_swiftCompatibility51”
此时,需要在项目工程新建至少一个 swift 文件(空的也可以),然后选择创建桥接头文件。
就会生成如下文件和配置项