iOS项目嵌入Unity的View(Swift )
一、将Unity导出的文件导入到xcode工程中
1、获取unity导出的unity项目后,在项目XXXX.xcworkspace加入unity项目,如图:
二、编译unity项目,产出UnityFramework
2.1、选中unity的Data,设置右侧的Target Membership,选中Unity-iPhone和UnityFramework
2.2、设置unity项目的buildID 、Version 和build 与主工程一致
2.3、选中unity项目,进行编译,编译成功即可
三、把UnityFramework,加入到主工程中,编译使用
3.1、把UnityFramework,加入到主工程中如图
3.2、在桥接文件中引入
#import <Foundation/Foundation.h>
#include <UnityFramework/UnityFramework.h>
3.3、AppDelegate里引入unity,但并不使用,因为我只是在某个页面会跳转到有unityView的页面,这里看需求处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | import UIKit import UnityFramework @ main class AppDelegate : UIResponder , UIApplicationDelegate , UnityFrameworkListener { @objc var unityFramework : UnityFramework ? var appLaunchOpts : [ UIApplication . LaunchOptionsKey : Any ]? var window : UIWindow ? func application ( _ application : UIApplication , didFinishLaunchingWithOptions launchOptions : [ UIApplication . LaunchOptionsKey : Any ]?) - > Bool { appLaunchOpts = launchOptions // 2 self . window = UIWindow ( frame : UIScreen . main . bounds ) self . window ?. backgroundColor = UIColor . white // // 3 let nav = UINavigationController ( rootViewController : FirstFirstViewController ()) if let nativeWindow = self . window { nativeWindow . rootViewController = nav ; nativeWindow . makeKeyAndVisible () } return true } func initUnityFramework (){ unityFramework = getUnityFramework () if let unityframework = self . unityFramework { unityframework . setDataBundleId ( "com.unity3d.framework" ) unityframework . register ( self ) unityframework . runEmbedded ( withArgc : CommandLine . argc , argv : CommandLine . unsafeArgv , appLaunchOpts : appLaunchOpts ) } } private func getUnityFramework () - > UnityFramework ? { let bundlePath : String = Bundle . main . bundlePath + "/Frameworks/UnityFramework.framework" let bundle = Bundle ( path : bundlePath ) if bundle ?. isLoaded == false { bundle ?. load () } let ufw = bundle ?. principalClass ?. getInstance () if ufw ?. appController () == nil { let machineHeader = UnsafeMutablePointer < MachHeader > . allocate ( capacity : 1 ) machineHeader . pointee = _mh_execute_header ufw !. setExecuteHeader ( machineHeader ) } return ufw } func unityIsInitialized ( ) - > Bool { return ( self . unityFramework != nil & & self . unityFramework ?. appController () != nil ) } // 卸载unity private func unloadUnityInternal () { if let unityFramework = self . unityFramework { unityFramework . unregisterFrameworkListener ( self ) } self . unityFramework = nil } // 监听 func unityDidUnload ( _ notification : Notification !) { unloadUnityInternal () } func unityDidQuit ( _ notification : Notification !) { unloadUnityInternal () } } |
3.4、在跳转有Unity的页面前初始化Unity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | import UIKit class FirstViewController : UIViewController { override func viewDidLoad () { super . viewDidLoad () // Do any additional setup after loading the view. self . view . backgroundColor = . green let pushBtn = UIButton . init ( frame : CGRect ( x : 0 , y : 350 , width : 200 , height : 40 )) pushBtn . addTarget ( self , action : # selector ( pushBtnCLick ), for : . touchUpInside ) pushBtn . setTitle ( "去有Unity的VC" , for : . normal ) pushBtn . backgroundColor = . red self . view . addSubview ( pushBtn ) } // 去有Unity的VC @objc func pushBtnCLick (){ // 去有Unity的VC前unity初始化 guard let appDelegate = UIApplication . shared . delegate as ? AppDelegate else { return } // 这里初始化unity, unity这时候会产生是一个新的window,并覆盖掉默认的window appDelegate . initUnityFramework () // 所以这里要将应用的默认window切换回原来的 window,将unity的window隐藏掉 appDelegate . window ?. makeKeyAndVisible () // 去有Unity的VC let vc = NextViewController () self . navigationController ?. pushViewController ( vc , animated : true ) } } |
3.5、显示unity画面,把appDelegate.unityFramework?.appController()?.rootView加到想加的view上,调用给的API即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // 显示unity view @objc func xianShiBtnCLick (){ // 显示 guard let appDelegate = UIApplication . shared . delegate as ? AppDelegate else { return } self . delegate = appDelegate // guard let unityRootView = appDelegate . unityFramework ?. appController ()?. rootView else { return } unityRootView . frame = CGRect ( x : 0 , y : 0 , width : UIScreen . main . bounds . size . width , height : UIScreen . main . bounds . size . height ) self . view . addSubview ( unityRootView ) self . view . sendSubviewToBack ( unityRootView ) } |
四、unity的交互与退出
4.1、unity的交互,unity开发会暴露出一些方法,在对应的业务场景调用即可
4.2、unity的退出,这里还是使用appDelegate来执行相关操作,但是并不是真的quit卸载退出,只是unloadApplication
1 2 3 4 5 6 7 8 9 10 11 | @objc func destoryBtnClick () { DispatchQueue . main . asyncAfter ( deadline : . now () + 0 ) { guard let appDelegate = UIApplication . shared . delegate as ? AppDelegate else { return } appDelegate . unityFramework ?. unloadApplication () appDelegate . unityFramework ?. appController ()?. rootView . removeFromSuperview () appDelegate . unityFramework ?. appController (). rootViewController . removeFromParent () self . navigationController ?. popViewController ( animated : true ) } } |
五、UnityFramework类说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | UnityFramework类 +(UnityFramework*)getInstance :单例类方法,可将实例返回到 UnityFramework。 -(UnityAppController*)appController :返回 UIApplicationDelegate 的 UnityAppController 子类。这是原生端的根 Unity 类,可以访问应用程序的视图相关对象,例如 UIView、UIViewControllers、CADisplayLink 或 DisplayConnection。 -( void )setDataBundleId:( const char *)bundleId:设置捆绑包,Unity 运行时应在其中查找 Data 文件夹。应在调用 runUIApplicationMainWithArgc 或 runEmbeddedWithArgc 之前调用此方法。 -( void )runUIApplicationMainWithArgc:( int )argc argv:( char *[])argv:从没有其他视图的主要方法中运行 Unity 的默认方式。 -( void )runEmbeddedWithArgc:( int )argc argv:( char *[])argv appLaunchOpts:( NSDictionary *)appLaunchOpts:存在其他视图时,如果需要运行 Unity,需要调用此方法。 -( void )unloadApplication :调用此方法可卸载 Unity,并在卸载完成后接收对 UnityFrameworkListener 的回调。Unity 将释放占用的大部分内存,但不会全部释放。 -( void )registerFrameworkListener:( id )obj :注册监听器对象,用于接收 UnityFramework 生命周期相关事件的回调。 -( void )unregisterFrameworkListener:( id )obj:取消注册监听器对象。 -( void )showUnityWindow:在显示非 Unity 视图时调用此方法,也会显示已经在运行的 Unity 视图。 -( void )pause:( bool )pause:暂停 Unity -( void )setExecuteHeader:( const MachHeader*)header:必须在运行 Unity 之前调用此命令,CrashReporter 才能正常工作。 -( void )sendMessageToGOWithName:( const char *)goName functionName:( const char *)name message:( const char *)msg:此方法是 UnitySendMessage 的代理。它通过名称查找游戏对象,并使用单字符串消息参数来调用 functionName。 ( void )quitApplication:( int )exitCode:调用此方法可完全卸载 Unity,并在 Unity 退出后接收对 UnityFrameworkListener 的回调。Unity 将释放所有内存。 注意:进行此调用后,将无法在同一进程中再次运行 Unity。可在 AppController 上设置 quitHandler 以覆盖默认进程终止 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库