基本思路:
Xcode 工程創(chuàng)建工作空間档痪,一個(gè)工作空間包含 iOS原生工程,一個(gè)為3D工程邢滑。通過UnityFramework.framework 進(jìn)行橋接通信腐螟。 unity工程注冊(cè)代理,原生實(shí)現(xiàn)交互方法困后、
unity 調(diào)取iOS 代理模式交互數(shù)據(jù)乐纸。
iOS調(diào)取unity 通過UnityFramework 提供的發(fā)送消息方法。
正文:
Unity 2019.3.a2及更高版本摇予,以及Xcode 9.4及更高版本汽绢。
下載Unity 2019.3.a2: https://unity3d.com/alpha/2019.3
1.生成iOS工程
首先在Unity編輯器打開UnityProject項(xiàng)目,選擇Menu -> Window -> Package Manager侧戴,因?yàn)?.0.8版本不兼容使用Unity作為庫宁昭,所以要移除Ads資源包,或更新Ads資源包到v 3.*版本酗宋。
選擇Menu -> Edit -> Player Settings -> Player -> iOS設(shè)置標(biāo)簽頁 -> Identification Section积仗,設(shè)置有效的Bundle Identification和Signing Team ID,以避免后續(xù)步驟出現(xiàn)Xcode簽名問題蜕猫。
打開Menu -> File -> Builds Settings寂曹,在此選擇并切換平臺(tái)為iOS。將UnityProject項(xiàng)目構(gòu)建到iosBuild文件夾丹锹。
2.創(chuàng)建Xcode工作空間
設(shè)置Xcode工作空間
Xcode工作空間允許同時(shí)處理多個(gè)項(xiàng)目稀颁,并結(jié)合它們的結(jié)果芬失。
我們?cè)赬code打開NativeiOSApp.xcodeproj楣黍。選擇File -> New -> Workspace,創(chuàng)建工作空間棱烂,把它保存在UaaLExample/both.xcworkspace租漂。
關(guān)閉NativeiOSApp.xcodeproj項(xiàng)目,此后的步驟會(huì)在剛創(chuàng)建的工作空間項(xiàng)目完成颊糜。
選擇File -> Add Files to “both”哩治,把NativeiOSApp.xcodeproj和第2步生成的Unity-iPhone.xcodeproj添加到相同等級(jí)的工作空間。
3.將iOS工程 加入工作空間
將unity導(dǎo)出工程加入工作空間
如果使用pod 將pods 工程加入工作空間
file -> addFile to ""
3個(gè)工作空間平級(jí)
-
添加UnityFramework.framework
5.設(shè)置Data文件夾為 UnityFramework.framework 部分
6.公開橋接文件
工程配置完畢衬鱼。以下是代碼配置
-
AppDelegate.mm 修改為 MM
將 main.m 與AppDelegate 寫入同一個(gè)文件#include <UnityFramework/UnityFramework.h> #include <UnityFramework/NativeCallProxy.h> #include <mach/mach.h> UnityFramework* UnityFrameworkLoad() { NSString* bundlePath = nil; bundlePath = [[NSBundle mainBundle] bundlePath]; bundlePath = [bundlePath stringByAppendingString: @"/Frameworks/UnityFramework.framework"]; NSBundle* bundle = [NSBundle bundleWithPath: bundlePath]; if ([bundle isLoaded] == false) [bundle load]; UnityFramework* ufw = [bundle.principalClass getInstance]; if (![ufw appController]) { // unity is not initialized [ufw setExecuteHeader: &_mh_execute_header]; } return ufw; } void showAlert(NSString* title, NSString* msg) { UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {}]; [alert addAction:defaultAction]; // auto delegate = [[UIApplication sharedApplication] delegate]; UIViewController *vc = [UIApplication sharedApplication].delegate.window.rootViewController; [vc presentViewController:alert animated:YES completion:nil]; } int gArgc = 0; char** gArgv = nullptr; NSDictionary* appLaunchOpts; @interface AppDelegate : UIResponder<UIApplicationDelegate, UnityFrameworkListener, NativeCallsProtocol> @property (strong, nonatomic) UIWindow *window; @property UnityFramework* ufw; @property (assign, nonatomic) BOOL isStartUnity ; - (void)initUnity; - (void)ShowMainView; - (void)didFinishLaunching:(NSNotification*)notification; - (void)didBecomeActive:(NSNotification*)notification; - (void)willResignActive:(NSNotification*)notification; - (void)didEnterBackground:(NSNotification*)notification; - (void)willEnterForeground:(NSNotification*)notification; - (void)willTerminate:(NSNotification*)notification; - (void)unityDidUnloaded:(NSNotification*)notification; @end @implementation AppDelegate - (bool)unityIsInitialized { return [self ufw] && [[self ufw] appController]; } #pragma mark - 打開3D - (void)showUnityView { if(![self unityIsInitialized]) { showAlert(@"Unity is not initialized", @"Initialize Unity first"); } else { [[self ufw] showUnityWindow]; } } #pragma mark - 打開原生 - (void)showNativeView { [self.window makeKeyAndVisible]; } #pragma mark - 發(fā)消息 - (void)sendMsgToUnity:(NSString *)strClass method:(NSString *)strMethod value:(NSString *)strValue { // [[self ufw] sendMessageToGOWithName: "Cube" functionName: "ChangeColor" message: "yellow"]; [[self ufw] sendMessageToGOWithName:strClass.UTF8String functionName:strMethod.UTF8String message:strValue.UTF8String]; } - (void)showHostMainWindow { [self showHostMainWindow:@""]; } - (void)showHostMainWindow:(NSString*)color { // if([color isEqualToString:@"blue"]) self.viewController.unpauseBtn.backgroundColor = UIColor.blueColor; // else if([color isEqualToString:@"red"]) self.viewController.unpauseBtn.backgroundColor = UIColor.redColor; // else if([color isEqualToString:@"yellow"]) self.viewController.unpauseBtn.backgroundColor = UIColor.yellowColor; // [UIApplication sharedApplication].keyWindow.rootViewController = ; // [self.window makeKeyAndVisible]; [self showNativeView]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. [self initUnity]; if (@available(iOS 10.0, *)) { // [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) { // NSInteger appMemoryBytes = qs_getAppMemoryBytes(); // NSLog(@"使用了 %f MB 內(nèi)存", appMemoryBytes / 1024.0f/ 1024.0f); // }]; } else { // Fallback on earlier versions } return YES; } //獲取當(dāng)前App的內(nèi)存使用值 uint64_t qs_getAppMemoryBytes() { task_vm_info_data_t vmInfo; mach_msg_type_number_t count = TASK_VM_INFO_COUNT; kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count); if (result != KERN_SUCCESS) return 0; return vmInfo.phys_footprint; } #pragma mark - 初始化UnityManage #pragma mark - 初始化3D - (void)initUnity { if([self unityIsInitialized]) { showAlert(@"Unity already initialized", @"Unload Unity first"); return; } [self setUfw: UnityFrameworkLoad()]; [[self ufw] setDataBundleId: "com.unity3d.framework"]; [[self ufw] registerFrameworkListener:self]; [NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self]; [[self ufw] runEmbeddedWithArgc: gArgc argv: gArgv appLaunchOpts: appLaunchOpts]; [NSTimer scheduledTimerWithTimeInterval:5 repeats:NO block:^(NSTimer * _Nonnull timer) { [self showUnityView]; }]; } - (void)unloadUnity { if(![self unityIsInitialized]) { showAlert(@"Unity is not initialized", @"Initialize Unity first"); } else { // [UnityFrameworkLoad() unloadApplicaion: true]; } } #pragma mark - 釋放回調(diào) - (void)unityDidUnload:(NSNotification*)notification { NSLog(@"unityDidUnloaded called"); [[self ufw] unregisterFrameworkListener: self]; [self setUfw: nil]; } - (void)applicationWillResignActive:(UIApplication *)application { [[[self ufw] appController] applicationWillResignActive: application]; } - (void)applicationDidEnterBackground:(UIApplication *)application { [[[self ufw] appController] applicationDidEnterBackground: application]; } - (void)applicationWillEnterForeground:(UIApplication *)application { [[[self ufw] appController] applicationWillEnterForeground: application]; } - (void)applicationDidBecomeActive:(UIApplication *)application { [[[self ufw] appController] applicationDidBecomeActive: application]; } - (void)applicationWillTerminate:(UIApplication *)application { [[[self ufw] appController] applicationWillTerminate: application]; } @end int main(int argc, char * argv[]) { NSString * appDelegateClassName; gArgc = argc; gArgv = argv; @autoreleasepool { if (false) { // run UnityFramework as main app id ufw = UnityFrameworkLoad(); // Set UnityFramework target for Unity-iPhone/Data folder to make Data part of a UnityFramework.framework and call to setDataBundleId // ODR is not supported in this case, ( if you need embedded and ODR you need to copy data ) [ufw setDataBundleId: "com.unity3d.framework"]; [ufw runUIApplicationMainWithArgc: argc argv: argv]; } else { // run host app first and then unity later UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String: "AppDelegate"]); } } return UIApplicationMain(argc, argv, nil, appDelegateClassName); }
采坑經(jīng)驗(yàn):
1.Data文件夾一定要 包含到 UnityFramework.framework 不然報(bào)錯(cuò)
2.NativeCallProxy.h 包含到 UnityFramework.framework 并且公開
- 報(bào)錯(cuò) # [MapFileParser.sh: Permission denied]
此報(bào)錯(cuò)因文件權(quán)限問題導(dǎo)致
執(zhí)行指令
chmod +x /Users/......./MapFileParser.sh (MapFileParser.sh所在的目錄)
4.unity啟動(dòng)成功 直接跳入3D頁面
找到 unity工程中的幾處跳轉(zhuǎn) 全部注釋
關(guān)鍵字 [window makeKeyAndVisible];
5.僵尸斷點(diǎn)會(huì)導(dǎo)致untiy工程內(nèi)存持續(xù)增加业筏。不要勾選
demo 地址
鏈接: https://pan.baidu.com/s/1JFWjbrh2x-qAsCzMwLywLA
提取碼: 9a71