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

浙公网安备 33010602011771号