unity 整合到原生iOS项目(swift 2.3)

作者: 童冀 | 来源:发表于2016-11-17 14:27 被阅读2271次

    老司机走开

    网上有很多unity集成到Objective-C的教程, 出门左拐,度娘谷歌都有,这里就不重复介绍了

    公司项目需求

    现有项目swift 2.3 + unity
    虐死人啊

    网上教程有篇老外的

    1. 你项目不用cocoapods
    2. 你看得懂作者思路

    just go ->
    How to use Unity 3D within an iOS app

    使用cocoapods,直接越坑

    废话不多说,下面步骤:

    1. unity导出工程

    没啥难度,配置好就行, 注意 : 设备方向最好是Auto Rotation, 再由iOS端控制方向,会减少不少bug
    Auto Rotation

    2. 添加Unity.xcconfig 文件到项目路径

    文件地址, blitzagency提供

    Unity.xcconfig

    按图步骤,设置project的配置,Debug和Release改成Unity就行

    添加UnityBridge.h, UnityUtils.h, UnityUtils.mm 到项目

    //更改整个extern "C" int custom_unity_init 里面代码为:
    extern "C" int custom_unity_init(int argc, char* argv[])
    {
        @autoreleasepool
        {
            UnityInitTrampoline();
            UnityParseCommandLine(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"]);
        }
        
        return 0;
    }
    

    3. 将unity导出文件添加到项目中

    第一步的导出工程只需要Classes,Data,Libraries,这三个
    新建文件夹ios_ui_animation, 拷贝进去


    新建文件夹

    4. 更改工程配置

    配置如图

    更改 UNITY_RUNTIME_VERSION 为你unity工程版本号,我的是 5.3.1f1

    5. 添加run script 到 build phase

    添加:

    rm -rf "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data";
    cp -Rf "$UNITY_IOS_EXPORT_PATH/Data" "$TARGET_BUILD_DIR/$PRODUCT_NAME.app/Data";

    添加步骤

    6. 清理unity文件

    把unity导出项目Classes,Data,Libraries文件拷贝到ios_ui_animation


    拷贝

    Classes, Libraries 设置 Create groups


    设置
    Data 设置 Create folder
    设置
    目录结构

    7. 删除引用

    先删除引用libraries里面的libil2cpp文件夹,然后再删除Classes里面的Native文件夹里面的所有.h文件

    都是删除引用 删除

    8. 变更unity里方法,引用等

    找到main.mm

    注释这个import
    //#import "UnitySubAppDelegate.h"
    //方法替换一下
    int main(int argc, char* argv[])
    {
        @autoreleasepool
        {
            UnityInitTrampoline();
            UnityParseCommandLine(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([UnitySubAppDelegate class]));
        }
    
        return 0;
    }
    //替换为
    int main_unity_default(int argc, char* argv[])
    {
        @autoreleasepool
        {
            UnityInitTrampoline();
            UnityParseCommandLine(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([UnitySubAppDelegate class]));
            UIApplicationMain(argc, argv, nil, [NSString stringWithUTF8String:AppControllerClassName]);
        }
        
        return 0;
    }
    
    //找到UnityAppController.h
    //最上面添加
    @class UnityViewControllerBase;
    
    //注释此方法
    //inline UnityAppController*    GetAppController()
    //{
    //  return (UnityAppController*)[UIApplication sharedApplication].delegate;
    //}
    
    //替换为此方法
    NS_INLINE UnityAppController* GetAppController()
    {
        NSObject<UIApplicationDelegate>* delegate = [UIApplication sharedApplication].delegate;
        UnityAppController* currentUnityController = (UnityAppController *)[delegate valueForKey:@"currentUnityController"];
        return currentUnityController;
    }
    

    9. 自己swift项目

    //打开AppDelegate.swift
    
    //注释@UIApplicationMain, 让swift从main.swift启动
    //@UIApplicationMain
    
    //项目添加如下代码
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
        var currentUnityController: UnityAppController!
    
    
        func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            currentUnityController = UnityAppController()
            currentUnityController.application(application, didFinishLaunchingWithOptions: launchOptions)
            return true
        }
    
        func applicationWillResignActive(application: UIApplication) {
            currentUnityController.applicationWillResignActive(application)
        }
    
        func applicationDidEnterBackground(application: UIApplication) {
            currentUnityController.applicationDidEnterBackground(application)
        }
    
        func applicationWillEnterForeground(application: UIApplication) {
            currentUnityController.applicationWillEnterForeground(application)
        }
    
        func applicationDidBecomeActive(application: UIApplication) {
            currentUnityController.applicationDidBecomeActive(application)
        }
    
        func applicationWillTerminate(application: UIApplication) {
            currentUnityController.applicationWillTerminate(application)
        }
    }
    
    //添加一个新的main.swift文件到工程里
    //添加如下代码
    import Foundation
    import UIKit
    // overriding @UIApplicationMain
    custom_unity_init(Process.argc, Process.unsafeArgv)
    UIApplicationMain(Process.argc, Process.unsafeArgv, NSStringFromClass(UIApplication), NSStringFromClass(AppDelegate))
    

    10. pod install 之后

    //添加代码到Unity.xcconfig 里面
    #include "Pods/Target Support Files/Pods-你的项目名/Pods-你的项目名.debug.xcconfig"
    #include "Pods/Target Support Files/Pods-你的项目名/Pods-你的项目名.release.xcconfig"
    

    Project -> Build Settings -> User-Defined
    查看PODS_ROOT等相关路径是否正确


    设置

    添加依赖库


    添加依赖库

    11. 加载unity view

    func loadUnity(sender: UIButton) {
            let unityview = UnityGetGLView()
            unityview.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview(unityview)
            let views = ["view": unityview]
            let w = NSLayoutConstraint.constraintsWithVisualFormat("|[view]|", options: [], metrics: nil, views: views)
            let h = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: [], metrics: nil, views: views)
            
            view.addConstraints(w + h)
        }
    

    跑起来试一下
    集成只支持unity+swift2.3!!!!
    集成只支持unity+swift2.3!!!!
    集成只支持unity+swift2.3!!!!
    有任何问题,发评论我

    相关文章

      网友评论

      • 起个名字好难O0:我最后报错 cp: /Data: No such file or directory
        Command PhaseScriptExecution failed with a nonzero exit code. 最后一句编译时 /bin/sh -c /Users/vp/Library/Developer/Xcode/DerivedData/ 是shell那出问题了吗
      • 0607e57cd4bd:你好,如果项目使用cocopod之后,直接添加
        #include "Pods/Target Support Files/Pods-你的项目名/Pods-你的项目名.debug.xcconfig"
        #include "Pods/Target Support Files/Pods-你的项目名/Pods-你的项目名.release.xcconfig"
        这段配置,cocoapod的header搜索路径也会被覆盖掉导致无法找到头文件,请问一下怎么处理呢,不可能每次pod更新都手动同步到unity.xcconfig吧
      • paintingStyle:你好 有问题请教下
        iOS端内部嵌入了两款AR的游戏,进入不同的场景使用 UnitySendMessage("Controller", "OpenSence",data);传递不同的参数,但是只有第一次启动他才能进入其中一个,当进入第二个发送新的消息时还是会显示第一个的游戏画面,iOS端Unity是无法关闭的,后来测试加入 UnityLoadApplication();
        Profiler_InitProfiler();
        切换偶尔是正常的,但有时候会显示错乱

        麻烦看下
        (void)showUnityWindow {

        if (_didResignActive) {

        UnityPause(false);
        }
        _didResignActive = NO;

        UnityLoadApplication();
        Profiler_InitProfiler();

        self.window.hidden =YES;
        self.unityWindow.hidden = NO;
        [self.unityWindow makeKeyWindow];
        }

        (void)hideUnityWindow {

        UnityPause(true);
        _didResignActive = YES;
        Profiler_UninitProfiler();

        self.unityWindow.hidden = YES;
        self.window.hidden = NO;
        [self.window makeKeyWindow];
        }

        发送消息代码:

        (void)wjBtnDidClicked {

        [kAppDelegate showUnityWindow];

        [self toUnityPageWithValue:@"wj"];
        }

        (void)scenesBtnDidClicked {

        [kAppDelegate showUnityWindow];

        [self toUnityPageWithValue:@"scenes"];
        }

        #pragma mark - 跳转到对应的Unity页面

        (void)toUnityPageWithValue:(NSString *)value {

        // TODO: 新增代码
        //报错SendMessage: object Controller does not have receiver for function openSence! 说明UnitySendMessage传递的对象不具备相应的方法

        const char *data = [value UTF8String];

        /**
        你那边需要打开场景的话 需要 传值给 OpenSence这个函数 通过ios给unity对象传值的方式 值有两个 "wj" 和 ”scenes“

        "Controller" "openSence" "wj 或者 scenes"
        */

        UnitySendMessage("Controller", "OpenSence",data);
        }
      • paintingStyle:你好,请教下
        iOS端内部嵌入了两款AR的游戏,进入不同的场景使用 UnitySendMessage("Controller", "OpenSence",data);传递不同的参数,但是只有第一次启动他才能进入其中一个,当进入第二个发送新的消息时还是会显示第一个的游戏画面,iOS端Unity是无法关闭的,后来测试加入 UnityLoadApplication();
        Profiler_InitProfiler();
        切换偶尔是正常的,但有时候会显示错乱,麻烦看下
        (void)showUnityWindow {

        if (_didResignActive) {

        UnityPause(false);
        }
        _didResignActive = NO;

        UnityLoadApplication();
        Profiler_InitProfiler();

        self.window.hidden =YES;
        self.unityWindow.hidden = NO;
        [self.unityWindow makeKeyWindow];
        }

        (void)hideUnityWindow {

        UnityPause(true);
        _didResignActive = YES;
        Profiler_UninitProfiler();

        self.unityWindow.hidden = YES;
        self.window.hidden = NO;
        [self.window makeKeyWindow];
        }

        发送消息代码:

        (void)wjBtnDidClicked {

        [kAppDelegate showUnityWindow];

        [self toUnityPageWithValue:@"wj"];
        }

        (void)scenesBtnDidClicked {

        [kAppDelegate showUnityWindow];

        [self toUnityPageWithValue:@"scenes"];
        }

        #pragma mark - 跳转到对应的Unity页面

        (void)toUnityPageWithValue:(NSString *)value {

        // TODO: 新增代码
        //报错SendMessage: object Controller does not have receiver for function openSence! 说明UnitySendMessage传递的对象不具备相应的方法

        const char *data = [value UTF8String];

        /**
        你那边需要打开场景的话 需要 传值给 OpenSence这个函数 通过ios给unity对象传值的方式 值有两个 "wj" 和 ”scenes“

        "Controller" "openSence" "wj 或者 scenes"
        */

        UnitySendMessage("Controller", "OpenSence",data);
        }
        童冀:显示错误,具体是啥错误
      • c27e8de08bfe:你好,我最近刚开始学Unity3D+iOS的开发,我首先在Unity3D里建立一个很简单的模型,然后按照你的方法以及这个教程 http://www.jianshu.com/p/e8217896d6ff, 一步步往xcode导入建好的Unity3D工程,但最后遇见了这样的错误,


        /Users/xxxxxxx/Documents/xxxxx/myUnity3DiOSDemoV01/Unity/Classes/Unity/UnityReplayKit_Scripting.mm:146:54: Use of undeclared identifier 'nullptr'

        我也自己也在网上搜了很久,始终不得其解,望大神赐教呀, 万分感谢
        :pray:
        童冀:@JingWang_48ec :+1: 棒棒的
        c27e8de08bfe:忘了说的我的工作环境了,xCode8.1 + Swift3.0 + Unity3D5.5.1f

        多谢,另外一个朋友帮我找到问题所在了,因为有些C++的编译器不支持 nullpt r这个东西,所以就会报错,所以需要到这个两个地方去更改编译器的设置, 首先在Project Navigator里选中工程文件夹,然后

        Project -> Building Setting 选中 All,然后在搜索框里搜Compiler,更改下面两处的设置

        Apple LLVM 8.0-Language -> C language dialect -> GNU99[-std=gnu99]
        Apple LLVM 8.0-Language C++ -> C++ language dialect -> GNU++11[-std=gnu++11]

        类似的在Target -> Building Setting 选中 All,然后在搜索框里搜Compiler,更改下面两处的设置

        Apple LLVM 8.0-Language -> C language dialect -> GNU99[-std=gnu99]
        Apple LLVM 8.0-Language C++ -> C++ language dialect -> GNU++11[-std=gnu++11]

        Undeclared type ‘nullptr’ 的编译错误就应该可以解决了
        童冀:我的项目里没有这个文件,应该是引擎自己生成的,这个需要到unity论坛看看了
      • 8eea1ad5e92b:感谢分享!新手请教AppDelegate中一直报错:Use of undeclared type 'UnityAppController' 要如何解决?
        童冀:@8eea1ad5e92b 改成AppController
      • FeelAlive_付饶:非常nice,解决了我们公司的遇到的难题,感谢博主!
        希望再接再厉,攻克swift3.0!
      • db5b7ed46863:首先谢谢你的文章啊,其次,有个问题,也是在swift3.0,unity界面无法显示出来是怎么回事?
        编译运行都ok,unity导出之后xcode prj又可以运行显示,集成在swift中无法显示。

        我把工程传到https://git.oschina.net/nickluck/unity-swift-test.git 这个上面了,麻烦帮忙看下,谢谢~!

        如果不方便,可以发一份你的demo工程给我测试下吗?
        童冀:@nickluck 那你得调UnityPause(false); 如果从场景启动,得发送unity消息了,UnitySendMessage("LoadGVRScene", "StartGVRScene", ""); //我的调的这个
        db5b7ed46863:@童冀 view debug 我已经查看了,unity view是加载出来了,但是无法显示unity内容。
        童冀:@nickluck 1. 我们项目2.3,还未升级到swift3,出现的各种异常我没法解决
        2. 显示不出来有各种原因,你用view debug先看看,
        3. 公司项目,非私人的,不能公开
      • wqf_525:1.Classes/UnityAppController.h:26:2: Unknown type name 'UnityViewControllerBase'
        2.Failed to import bridging header 'UnityBridge.h',怎么尝试都一样!xcode8.1
        删除再添加也是一样
        wqf_525:@wqf_525 UIApplicationMain(
        CommandLine.argc,
        UnsafeMutableRawPointer(CommandLine.unsafeArgv)
        .bindMemory(
        to: UnsafeMutablePointer<Int8>.self,
        capacity: Int(CommandLine.argc)),
        nil,
        NSStringFromClass(AppDelegate.self)
        )

        这样改了之后才能用
        wqf_525:@童冀 swift 3.0 ,你这个main.swift,完全没法儿用,他把Process 改成了CommandLine
        童冀:@wqf_525 1.你没仔细看,UnityAppController.h 文件里面需要添加 @class UnityViewControllerBase; 这一句
        2. UnityBridge.h 其实是给项目里没创建-Bridging-Header.h文件用的,你要么把UnityBridge.h添加为工程的bridge,要么把里面代码拷贝到你之前的-Bridging-Header.h里面去,同时改Unity.xcconfig 里面SWIFT_OBJC_BRIDGING_HEADER = (你当前用的)-Bridging-Header.h;
        就行啦

      本文标题:unity 整合到原生iOS项目(swift 2.3)

      本文链接:https://www.haomeiwen.com/subject/zhztpttx.html