unity2019版本融合iOS

基本思路:

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作為庫(kù),所以要移除Ads資源包,或更新Ads資源包到v 3.*版本。

選擇Menu -> Edit -> Player Settings -> Player -> iOS設(shè)置標(biāo)簽頁(yè) -> 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í)的工作空間。

image.png

3.將iOS工程 加入工作空間
將unity導(dǎo)出工程加入工作空間
如果使用pod 將pods 工程加入工作空間
file -> addFile to ""


image.png

3個(gè)工作空間平級(jí)

  1. 添加UnityFramework.framework


    image.png

5.設(shè)置Data文件夾為 UnityFramework.framework 部分


image.png

6.公開橋接文件

image.png

工程配置完畢。以下是代碼配置

  1. 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 并且公開

  1. 報(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頁(yè)面
    找到 unity工程中的幾處跳轉(zhuǎn) 全部注釋
    關(guān)鍵字 [window makeKeyAndVisible];
    image.png

    5.僵尸斷點(diǎn)會(huì)導(dǎo)致untiy工程內(nèi)存持續(xù)增加。不要勾選
    image.png

demo 地址
鏈接: https://pan.baidu.com/s/1JFWjbrh2x-qAsCzMwLywLA
提取碼: 9a71

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 概述 在多數(shù)移動(dòng)應(yīng)用中任何時(shí)候都只能有一個(gè)應(yīng)用程序處于活躍狀態(tài),如果其他應(yīng)用此刻發(fā)生了一些用戶感興趣的那么通過通知...
    莫離_焱閱讀 6,708評(píng)論 1 8
  • iphone開發(fā)筆記 退回輸入鍵盤 - (BOOL) textFieldShouldReturn:(id)text...
    愛易寒曲易散閱讀 682評(píng)論 0 1
  • //設(shè)置尺寸為屏幕尺寸的時(shí)候self.window = [[UIWindow alloc] initWithFra...
    LuckTime閱讀 955評(píng)論 0 0
  • 2019年的520,別人在朋友圈里曬男朋友,而我曬我的消消樂。 我用行動(dòng)證明我是快樂的單身狗。 520這一天讓我想...
    念憶往昔閱讀 833評(píng)論 0 1
  • 今天我們語(yǔ)文學(xué)了小青蛙,生字,數(shù)學(xué)學(xué)了鐘表,還有圍棋
    郭宇妍閱讀 193評(píng)論 0 0

友情鏈接更多精彩內(nèi)容