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 以覆蓋默認進程終止

 

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