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