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错误

相关推荐
平行云9 小时前
World Labs & Paraverse:统一3D世界的创造与访问
3d·unity·ai·ue5·aigc·实时云渲染·云xr
2501_9160088910 小时前
手机抓包app大全:无需root的安卓抓包软件列表
android·ios·智能手机·小程序·uni-app·iphone·webview
jtymyxmz15 小时前
《Unity Shader》7.2.3 实践 在切线空间下计算
unity·游戏引擎
胖虎116 小时前
iOS 如何全局修改项目字体
ios·hook·ios字体·字体适配·ios字体适配
songgeb17 小时前
iOS App进入后台时会发生什么
ios
笑尘pyrotechnic17 小时前
运行,暂停,检查:探索如何使用LLDB进行有效调试
ios·objective-c·lldb
metaRTC19 小时前
webRTC IPC客户端React Native版编程指南
react native·react.js·ios·webrtc·p2p·ipc
在路上看风景19 小时前
1.5 Material
unity
ajassi20001 天前
开源 Objective-C IOS 应用开发(十八)音频的播放
ios·开源·objective-c