- 說明
- 參考網址unity導出工程導入到iOS原生工程中詳細步驟
- 我現(xiàn)在有兩個工程玻佩,一個是從unity中導出的iOS工程,一個是自己創(chuàng)建的unity工程税稼,如下所示:
0.png
- 導入unity模塊
- unity中導出的iOS工程是這樣子的:
1.png
- 將Classes文件夾郎仆、Data文件夾扰肌、Libraries曙旭、MapFileParser晶府、MapFileParser.sh這五個復制到自己的iOS工程中
2.png
- 將Data川陆、QCAR(QCAR文件在Data->Raw里面)文件夾以以下方式添加
3.png
- 將Classes、Libraries以以下方式添加
4.png
- 添加引用庫文件
打開從unity中導出的iOS工程鳞绕,查看其引用的庫文件猾昆,如圖所示
5.png
將上面的庫文件骡苞,添加到自己的工程中
- 關閉bitcode
在build settings中關閉bitcode -
在 other Linker Flags 添加
-weak_framework CoreMotion -weak-lSystem
14.png - 在Other C Flags中添加 -DINIT_SCRIPTING_BACKEND=1,如圖所示
6.png
- 添加pch文件
7.png
如果項目中有多個pch文件烘苹,請將其合并成一個pch文件镣衡,再添加
- 在Header Search Paths 添加頭文件引用
打開從unity導出的工程档悠,查看Header Search Paths中添加的頭文件,如圖所示
8.png
將其添加到自己工程的Header Search Paths中
- 在Library Search Path 中添加庫引用
打開從unity導出的工程惰说,查看ibrary Search Path中添加的頭文件吆视,如圖所示
9.png
將其添加到自己工程的ibrary Search Path中
- 在user-Defined 添加
打開從unity導出的工程啦吧, 在build settings中查看user-Defined拙寡,如圖所示
10.png
并將其添加到自己項目的 user-Defined中
11.png
- 添加Run Script
打開從unity導出的工程般堆, 在build phases中查看Run Script擎宝,如圖所示:
12.png
- 更改main.m文件為main.mm文件浑玛。將Classes中的main.mm中的內容復制顾彰,粘貼到原來工程的main.mm中。然后刪除Classes中的main文件筋搏。
#include "RegisterMonoModules.h"
#include "RegisterFeatures.h"
#import "AppDelegate.h"
#include <mach/mach_time.h>
#include <csignal>
// Hack to work around iOS SDK 4.3 linker problem
// we need at least one __TEXT, __const section entry in main application .o files
// to get this section emitted at right time and so avoid LC_ENCRYPTION_INFO size miscalculation
static const int constsection = 0;
void UnityInitTrampoline();
// WARNING: this MUST be c decl (NSString ctor will be called after +load, so we cant really change its value)
const char* AppControllerClassName = "UnityAppController";
int main(int argc, char* argv[])
{
signed long long startTime = mach_absolute_time();
@autoreleasepool
{
UnitySetStartupTime(startTime);
UnityInitTrampoline();
UnityInitRuntime(argc, argv);
RegisterMonoModules();
NSLog(@"-> registered mono modules %p\n", &constsection);
RegisterFeatures();
// iOS terminates open sockets when an application enters background mode.
// The next write to any of such socket causes SIGPIPE signal being raised,
// even if the request has been done from scripting side. This disables the
// signal and allows Mono to throw a proper C# exception.
std::signal(SIGPIPE, SIG_IGN);
//UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:AppControllerClassName]);
UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
return 0;
}
#if TARGET_IPHONE_SIMULATOR && TARGET_TVOS_SIMULATOR
#include <pthread.h>
extern "C" int pthread_cond_init$UNIX2003(pthread_cond_t *cond, const pthread_condattr_t *attr)
{ return pthread_cond_init(cond, attr); }
extern "C" int pthread_cond_destroy$UNIX2003(pthread_cond_t *cond)
{ return pthread_cond_destroy(cond); }
extern "C" int pthread_cond_wait$UNIX2003(pthread_cond_t *cond, pthread_mutex_t *mutex)
{ return pthread_cond_wait(cond, mutex); }
extern "C" int pthread_cond_timedwait$UNIX2003(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime)
{ return pthread_cond_timedwait(cond, mutex, abstime); }
#endif // TARGET_IPHONE_SIMULATOR && TARGET_TVOS_SIMULATOR
并將main函數(shù)中的 UIApplicationMain方法修改為UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
- 在Classes的UnityAppController.mm中的- (void)applicationDidBecomeActive:(UIApplication*)application方法中奔脐,注釋掉[self performSelector: @selector(startUnity:) withObject: application afterDelay: 0]方法,這樣做的目的峦朗,是為防止unity的內容隨著應用的啟動波势,而啟動;
- (void)applicationDidBecomeActive:(UIApplication*)application
{
::printf("-> applicationDidBecomeActive()\n");
[self removeSnapshotView];
if (_unityAppReady)
{
if (UnityIsPaused() && _wasPausedExternal == false)
{
UnityWillResume();
UnityPause(0);
}
UnitySetPlayerFocus(1);
}
else if (!_startUnityScheduled)
{
_startUnityScheduled = true;
// [self performSelector: @selector(startUnity:) withObject: application afterDelay: 0];
}
_didResignActive = false;
}
- 修改appDelegate.h
#import <UIKit/UIKit.h>
@class UnityAppController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property(strong,nonatomic)UINavigationController *navi;
@property (strong, nonatomic) UIWindow *window;
@property (strong,nonatomic)UnityAppController* unityAppController;
- (void)shouldAttachRenderDelegate;
@end
- 將appDelegate.m修改為appDelegate.mm尺铣,并對其內容進行修改
#import "AppDelegate.h"
#import "ViewController.h"
#import "UnityAppController.h"
@interface AppDelegate ()
@end
extern "C" void VuforiaSetGraphicsDevice(void* device, int deviceType, int eventType);
extern "C" void VuforiaRenderEvent(int marker);
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
BOOL returnBool;
if (_unityAppController == nil) {
_unityAppController = [[UnityAppController alloc] init];
}
[_unityAppController application:application didFinishLaunchingWithOptions:launchOptions];
ViewController *vc = [[UIStoryboard storyboardWithName:@"Main" bundle:nil]instantiateViewControllerWithIdentifier:@"viewVC"];
self.navi = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController=self.navi;
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
[_unityAppController applicationWillResignActive:application];
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
[_unityAppController applicationDidEnterBackground:application];
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
[_unityAppController applicationWillEnterForeground:application];
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[_unityAppController applicationDidBecomeActive:application];
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
[_unityAppController applicationWillTerminate:application];
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
- (void)shouldAttachRenderDelegate
{
UnityRegisterRenderingPlugin(&VuforiaSetGraphicsDevice, &VuforiaRenderEvent);
}
@end
- 在Classes的UnityAppController.h中,更改GetAppController()方法(當然要先引入#import "AppDelegate.h"
inline UnityAppController* GetAppController()
{
AppDelegate *dele = (AppDelegate *)[UIApplication sharedApplication].delegate;
return (UnityAppController *)dele.unityAppController;
}
- 在UnityAppController.mm中重寫- (void)shouldAttachRenderDelegate方法
- (void)shouldAttachRenderDelegate {
AppDelegate *deleg = [UIApplication sharedApplication].delegate;
[deleg shouldAttachRenderDelegate];
}
ok,通過上面的步驟,我們就已經將unity的功能導入自己的項目中兑障,接下來做的,就是點擊按鈕逞怨,啟動unity模塊
Main.storyBoard的ViewController創(chuàng)建一個UIButton,并將Storyboard ID設為“viewVC”
13.png
- 在ViewController.m實現(xiàn)其點擊事件(記得倒入#import "UnityAppController.h"叠赦,#import "AppDelegate.h")
#pragma mark----打開AR-----
- (IBAction)doOpenAR:(id)sender {
static bool flg=NO;
if (flg) {//如果不是第一次啟動革砸,則之間切換window
[GetAppController() restartUnity];
}
else//如果是第一次點擊按鈕,則需要啟動unity
{
[GetAppController() preStartUnity];
[GetAppController() startUnity:[UIApplication sharedApplication]];
[UnityGetMainWindow() makeKeyAndVisible];
flg=YES;
}
}
- 在UnityAppController.h中申明-(void) restartUnity册踩,在UnityAppController.mm中實現(xiàn)
-(void) restartUnity
{
_window.rootViewController=_rootController;
[_window makeKeyAndVisible];
[UnityGetMainWindow() makeKeyAndVisible];
if (_didResignActive) {
UnityPause(false);
_didResignActive=NO;
}
}
- 這樣效拭,我們就能啟動unity的模塊了,但是慕的,關閉或隱藏unity模塊挤渔,也需要我們操作。
- 我們需要在UnityAppController.mm中的- (void)startUnity:(UIApplication*)application方法里嫉父,添加一個按鈕
- (void)startUnity:(UIApplication*)application
{
NSAssert(_unityAppReady == NO, @"[UnityAppController startUnity:] called after Unity has been initialized");
UnityInitApplicationGraphics(UNITY_FORCE_DIRECT_RENDERING);
// we make sure that first level gets correct display list and orientation
[[DisplayManager Instance] updateDisplayListInUnity];
UnityLoadApplication();
Profiler_InitProfiler();
[self showGameUI];
UIButton *button=[UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(doHideenUnity) forControlEvents:UIControlEventTouchUpInside];
button.frame=CGRectMake(0, 0, 50, 50) ;
[button setTitle:@"退出" forState:UIControlStateNormal];
//[button setBackgroundColor:[UIColor purpleColor]];
[_rootView addSubview:button];
[self createDisplayLink];
UnitySetPlayerFocus(1);
}
- 并實現(xiàn)按鈕的點擊事件
-(void)doHideenUnity
{
UnityPause(true);
_didResignActive=YES;
Profiler_UninitProfiler();
AppDelegate *delet=[UIApplication sharedApplication].delegate;
[delet.window makeKeyAndVisible];
}
- ok,完成
可能遇到了問題
- 重復的main.mm稽鞭,記得刪除Classes文件的main.mm
- 如果有多個pch文件引镊,記得進行合并