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的页面,这里看需求处理

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

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即可

 // 显示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

    @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类说明

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章