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 以覆盖默认进程终止

 

posted @   甘林梦  阅读(2566)  评论(6编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示