Unity-iPhone、Unity-Framework target 如何选择、@rpath报错

背景:

Unity 2019.3+ 引入了全新的 UnityFramework 架构:

旧架构 (Unity 2019.2 及更早)

复制代码
└── Unity-iPhone.app
    └── Unity-iPhone (包含所有代码的可执行文件)

新架构 (Unity 2019.3+)

复制代码
└── Unity-iPhone.app
    ├── Unity-iPhone (轻量级启动器)
    └── Frameworks/
        └── UnityFramework.framework (核心 Unity 代码存放处)

主要改进点

  1. Unity C# 代码 → 通过 IL2CPP 编译 → 最终生成 UnityFramework.framework
  2. Unity 原生插件 → 统一集成到 UnityFramework target
  3. Unity-iPhone 应用 → 仅作为轻量级启动外壳

iOS应用的限制

  • 应用沙盒限制:每个 iOS 应用都在自己的沙盒中运行,只能访问自己沙盒内的文件
  • 系统路径限制:不能像传统桌面系统那样将动态库安装在系统路径(如 /usr/lib)
  • 代码签名要求:所有可执行代码必须经过苹果的代码签名验证

OS应用沙盒机制要求,所有第三方动态库必须被嵌入到应用包内。如果只链接而未嵌入,应用在设备上启动时,系统在约定的位置找不到这个动态库,就会抛出@rpath相关的错误,也就是链接只在编译时有用,能够减少编译时间

为什么一定要添加到Unity-iPhone中

  • 应用包构建:unity-iPhone 是最终生成 .app 包的主 target
  • 资源包含:只有添加到 unity-iPhone 的资源才会被打包到最终应用中
  • 代码签名:所有嵌入的框架都需要与主应用一起签名

加载方式

复制代码
unity-iPhone (主应用)
├── 应用启动代码
├── Info.plist
├── 资源文件
└── Frameworks/
    ├── UnityFramework.framework (动态库)
    └── YourCustomFramework.framework (你的动态库) ← 必须在这里

链接三方库和嵌入三方库的不同

  • 链接:在Build Phases的 Link Binary With Libraries阶段。这步是告诉编译器:"我这个程序需要这些库"。
  • 嵌入:在Build Phases的 Embed Frameworks阶段。这步是告诉打包系统:"请把这些动态库复制到最终的应用包(.app)里"。

Cocos 与 Unity的 target的不同

Cocos的单一Target结构:Cocos Creator打包后通常生成一个主Target(例如mygame-mobile)。当你使用use_frameworks!让CocoaPods以动态框架形式集成库时,这些框架会被自动添加到这个主Target中。CocoaPods的脚本通常会自动配置好编译时的链接和运行时的嵌入,所以即使有动态库,一般也能正常运行,不容易出现@rpath错误

动态库与静态库的区别

🔄 动态库与静态库的核心区别

代码加载机制差异

特性 静态库 动态库
内存布局 代码嵌入主可执行文件 独立内存段,支持共享
加载时机 应用启动时完整加载 支持按需延迟加载
代码共享 每个进程独享副本 多进程共享同一物理内存
热更新 不支持 理论可行(iOS受限)
耦合度 紧密耦合 松散耦合

内存占用对比

静态库多进程之间引用才会复制多份,单进程多target并不会多份

c 复制代码
// 静态库场景:3进程共用静态库
进程A: [主程序 + 静态库副本A]
进程B: [主程序 + 静态库副本B] 
进程C: [主程序 + 静态库副本C]
总内存 = 3 × (主程序 + 静态库)

// 动态库场景:3进程共用动态库
进程A: [主程序] → 共享动态库
进程B: [主程序] → 共享动态库
进程C: [主程序] → 共享动态库
总内存 = 3 × 主程序 + 1 × 动态库

📱 iOS采用动态库的三大优势

系统框架高效共享,核心系统框架均为动态库:
复制代码
UIKit.framework
Foundation.framework  
CoreGraphics.framework
静态库方案会导致:
  • 重复占用磁盘空间
  • 内存使用效率低下
  • 系统更新复杂化
  • 扩展架构支持
    • 主应用与扩展共享库资源
    • 避免多份静态库副本
    • 显著优化存储和内存
模块化开发支持
swift 复制代码
// 独立模块开发架构
AppModuleA.framework    // Team A
AppModuleB.framework    // Team B
AppModuleC.framework    // Team C

// 优势:
// - 团队独立开发测试
// - 二进制级别集成
// - 版本灵活管理

如何选择

  1. AppDelegate 相关功能 → 归入 Unity-iPhone 目标

  2. URL 与推送通知处理 → 归入 Unity-iPhone 目标

  3. 纯 UI 界面(非游戏相关) → 归入 Unity-iPhone 目标

  4. Unity C# 调用的 DllImport 方法 → 添加至所有目标(addToAllTargets)

  5. UnitySendMessage 相关调用 → 添加至所有目标(addToAllTargets)

  6. 不确定归属的功能 → 建议添加至所有目标(最稳妥方案)

podfile 中的链接标签

传统静态库(无特殊配置)

  • 打包方式:所有代码 → 生成 .a 文件 → 直接链接到主应用
  • 优点:⚡ 性能最优
  • 缺点:❌ 完全不支持 Swift(致命缺陷),
  • 稍微增加包体大小,不是缺陷

动态框架(use_frameworks!)

  • 打包方式: 生成 .framework 动态库
  • 优点:✅ 完整支持 Swift
  • 缺点:🐌 启动时间增加 35-60%(尤其当加载 30+ 个框架时)

静态框架(use_frameworks! :linkage => :static)

  • 打包方式:.framework,强制使用静态库,内签到App内
  • 优点:✅ 支持 Swift ⚡ 接近静态库的性能

动态框架(use_frameworks! :linkage => :dynamic)

use_frameworks! 的生效范围

  • 三方库只能是源码的形式,有cocoapod进行编译
  • 对于podfile中包含了static_framework = true/false的三方库,不生效
  • 对于预编译好的静态库、或者动态库,不生效
  • 优先以三方库的设置为准

@rpath/报错

App加载Unity-iPhone时,在Framework中没找到对应的库。在

如果使用的是use_frameworks! :linkage => :static,说明该库尝试静态链接失败了,需要手动添加到Unity-iPhone这个target即可。

总结

  1. 使用use_frameworks! :linkage => :static标签,获取更快地启动时间、支持swift

  2. 如果使用EDM4U插件,dependency 里面使用addToAllTarget=true,防止动态库未静态链接成功,报@rpath错误

相关推荐
游戏开发爱好者87 小时前
带签名时间戳接口的重放与压力测试实战,用动态值在发送前现算签名
网络协议·计算机网络·网络安全·ios·adb·https·压力测试
玖玥拾19 小时前
Unity3D RPG 入门项目(八)游戏设置面板、帧率控制、快捷技能药品栏、技能解锁系统
游戏·3d·unity·游戏引擎
ellis197020 小时前
u3d插件xLua[十] lua侧判空问题
unity
2501_9160074720 小时前
申请 iOS 推送证书并配置 APNs 群发推送教程
android·ios·小程序·https·uni-app·iphone·webview
weixin_4038101321 小时前
苹果群控带机量实测:一台电脑能稳定控多少台iPhone
自动化·iphone·跨境电商·苹果投屏·多媒体运营·安卓中控
weixin_4038101321 小时前
iOS自动化脚本怎么避免风控?无屏幕镜像截图原理详解
ios·自动化·跨境电商·苹果群控·苹果投屏·多媒体运营
wangruofeng1 天前
3 步把 MacBook 变成 7×24 远程主机,人在外面随时接管桌面
ios·agent·mac
weixin_403810131 天前
iOS免越狱自动化蓝牙HID方案:不装代理也能跑脚本
运维·ios·自动化·跨境电商·ai智能体·ios投屏·苹果投屏
牛哇网络工作室1 天前
UnityHDRP写实数字人全流程基础5—语音输入和语音识别
android·unity·c#·游戏引擎·aigc·语音识别·xcode
GitLqr1 天前
Flutter 3.47 与 Dart 3.13:你必须了解的迁移指南
flutter·ios·dart