美文网首页iOS-swiftiOS开发记录Unity技术分享
最新iOS 整合Unity(xCode9.1 Swift4.0

最新iOS 整合Unity(xCode9.1 Swift4.0

作者: 与之书 | 来源:发表于2017-10-10 15:15 被阅读1442次

    0

    1. xCode9.0才支持swift4.0,但是9.0有一个bug,拖入的第三方库不会自动编译,详见XCode9 拖入文件 不自动添加 compile sources 所以使用9.1beta版本
      2.beta版每次添加framework要选两次才有用,暂时没有解决方法,官方也没有版本更新
      3.准备好一个xCode9.1和一个正常导出的Unity工程

    Unity 工程导出时区分模拟器和真机,只能在对应设备运行,如果使用了AR,只能在真机上运行。
    先单独运行下unity项目,模拟器版本会报UnityMetalSupport.h中有重复定义,直接注释报错代码即可,真机运行不报这个错误,然后能正常运行即可进行整合工作

    1、新建工程

    > 1.1 xCode9新建工程都是面向iOS11的,如果要兼容低版本系统,比如8.0,需要手动选择。
    并且在LaunchScreen和main storyboard设置中去掉“Use Safe Area Layout Guides”(safe area 只支持9.0以后)
    
    02safeArea.png

    > 1.2 将Unity目录和工程目录放在同一文件夹内


    01目录结构.png

    > 1.3 右键——>创建Group without floder
    (xCode9创建group新增了同时建立文件夹的选项,这里选择不建立文件夹)
    命名为Unity(任意命名)

    2、拖入Unity相关文件 放在新建的Unity Group下

    classes和libraries  不copy 创建group
    data    不copy 创建reference
    raw 下的Vuforia和qcar也要放在根目录 同样选择reference
    拖入交接文件和配置文件(也可以手动创建) 
    最终目录见第四点添加配置图   
    

    3、 桥接文件和配置文件

    3.1 配置文件MyUnity.xcconfig
    //
    //  Created by 空橙记 on 2017/9/30.
    
    GCC_THUMB_SUPPORT = NO
    GCC_USE_INDIRECT_FUNCTION_CALLS = NO
    // 版本号要改成对应
    UNITY_RUNTIME_VERSION = 5.3.4f1
    UNITY_SCRIPTING_BACKEND = il2cpp
    
    CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
    CLANG_WARN_OBJC_ROOT_CLASS = YES
    
    CLANG_CXX_LANGUAGE_STANDARD = c++0x
    CLANG_CXX_LIBRARY = libc++
    GCC_ENABLE_CPP_EXCEPTIONS = YES
    GCC_C_LANGUAGE_STANDARD = c99
    OTHER_CFLAGS = -DINIT_SCRIPTING_BACKEND=1
    GCC_DYNAMIC_NO_PIC = NO
    OTHER_LDFLAGS = -weak_framework CoreMotion -weak-lSystem
    ENABLE_BITCODE = NO
    
    // 要手动添加framework  头文件路径  库文件路径
    //GCC_PREFIX_HEADER = $(UNITY_IOS_EXPORT_PATH)/Classes/Prefix.pch;
    
    //改成自己对应的路径 导出的Unity路径
    UNITY_IOS_EXPORT_PATH = /Users/xhvr/SWIFT/UnityMonis
    

    a.事实上所有的setting都可以在这里设置,比如framework,也可以手动添加到OTHER_LDFLAGS中,头文件、库文件路径类似,但不是很推荐这么做
    b.之前将所有framework都写在OTHER_LDFLAGS中,报了个错,Stack Overflow上说,又时候顺序也会造成link问题
    c.另一个原因是不直观,例如再要引入地图、分享或者其他功能时,不知道哪些已经添加过,哪些没有添加
    d.而像头文件路径、库文件路径,不同的Unity项目导出时文件夹有所不同,有些有plugins文件夹有些没有,手动加会直观些
    f.如果觉得麻烦,自己的一些内容又是固定的,可以在Build Setting中设置好,直接command+c复制,command+v粘贴在config文件中,自己保存起来重复使用。

    如果之前已经对某些配置做了修改,再配置config文件的话,并不会覆盖,所以比如使用百度地图, other linker flags 添加了-ObjC,那么config文件里配置不生效,需要删除-ObjC,此时配置会生效,再在最后加上-ObjC
    如果出现RegisterAllClasses() in RegisterMonoModules.o 的报错,看看other c flags是不是添加了 -DINIT_SCRIPTING_BACKEND=1

    3.2 UnityBridge.h 文件
    #ifndef UnityBridge_h
    #define UnityBridge_h
    
    #import <UIKit/UIKit.h>
    #import "UnityUtils.h"
    #import "UnityAppController.h"
    #import "UnityInterface.h"
    #endif /* UnityBridge_h */
    
    3.3 UnityUtils.h 文件 (添加了一个初始化方法)
    #ifndef UnityUtils_h
    #define UnityUtils_h
    void unity_init(int argc, char* argv[]);
    #endif /* UnityUtils_h */
    
    3.4 UnityUtils.mm 文件
    #include "RegisterMonoModules.h"
    #include "RegisterFeatures.h"
    #include <csignal>
    #import <UIKit/UIKit.h>
    
    static const int constsection = 0;
    void UnityInitTrampoline();
    
    extern "C" void unity_init(int argc, char* argv[])
    {
        @autoreleasepool
        {
            UnityInitTrampoline();
    // Unity版本不同,有些可能要选UnityInitRuntime的方法
    //        UnityInitRuntime(argc, argv);
            UnityParseCommandLine(argc, argv);
            
            RegisterMonoModules();
            NSLog(@"-> registered mono modules %p\n", &constsection);
            RegisterFeatures();
            std::signal(SIGPIPE, SIG_IGN);
        }
    }
    

    以上有报错不用管,先放着
    设置Objective-C Bridging Header 为UnityBridge.h文件

    06桥接bridge.png

    4、修改配置

    info处添加MyUnity.xcconfig

    03添加配置.png
    设置Unity文件夹路径
    04Unity文件夹路径.png
    设置prefix文件路径
    07prefix.png
    添加头文件路径和库文件路径
    08头文件.png
    09库文件.png

    添加framework

    10framework.png

    路径都是可以直接拖的
    framework的bug上面说过,就是要选两次

    5、创建main.swift

    内容如下

    import Foundation
    import UIKit
    // 这个方法名要和UnityUtils中的相同
    unity_init(CommandLine.argc, CommandLine.unsafeArgv)
    UIApplicationMain(
        CommandLine.argc,
        UnsafeMutableRawPointer(CommandLine.unsafeArgv)
            .bindMemory(
                to: UnsafeMutablePointer<Int8>.self,
                capacity: Int(CommandLine.argc)),
        nil,
        NSStringFromClass(AppDelegate.self)
    )
    

    注释Appdelegate.swift中的 @UIApplicationMain

    6、其他文件修改

    1. 找到Unity中的main.mm文件,注释main方法
    1. 在UnityAppController.h中替换inline方法
    //替换为此方法
    NS_INLINE UnityAppController* GetAppController()
    {
        NSObject<UIApplicationDelegate>* delegate = [UIApplication sharedApplication].delegate;
        // 这里的@字符串 要和Appdelegate.swift中的变量名一致
        UnityAppController* currentUnityController = (UnityAppController *)[delegate valueForKey:@"unityController"];
        return currentUnityController;
    }
    
    1. 修改AppDelegate
    //@UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        var unityController: UnityAppController?
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            unityController = UnityAppController()
            unityController?.application(application, didFinishLaunchingWithOptions: launchOptions)
            return true
        }
        
        func applicationWillResignActive(_ application: UIApplication) {
            unityController?.applicationWillResignActive(application)
        }
        
        func applicationDidEnterBackground(_ application: UIApplication) {
            unityController?.applicationDidEnterBackground(application)
        }
        
        func applicationWillEnterForeground(_ application: UIApplication) {
            unityController?.applicationWillEnterForeground(application)
        }
        
        func applicationDidBecomeActive(_ application: UIApplication) {
            unityController?.applicationDidBecomeActive(application)
        }
        
        func applicationWillTerminate(_ application: UIApplication) {
            unityController?.applicationWillTerminate(application)
        }
    }
    

    7.使用

    创建一个新的ViewController 或者在ViewController中也可以
    使用AR需要添加相机权限
    在viewDidLoad()中直接添加
    self.view.addSubView(UnityGetGLView())
    如果不要全屏,可以手动设置frame
    

    8.bug

    在buildSetting中设置swift版本如果是3.2,能正常运行没有任何问题,如果设置4.0会报
    valueForUndefinedKey的错误。解决很简单,在appdelegate中加上@objc 即可
    
        @objc var unityController: UnityAppController?
    

    如果Unity版本比较低,可能会遇到xxx was compiled with optimization - stepping may behave oddly; variables may not be available的问题,请在building setting-> Other C Flags 中添加:-DRUNTIME_IL2CPP=1,前面加的也要保留。然后把Optimization Level ,debug的部分都改成none。
    参考: https://stackoverflow.com/questions/45078851/optimization-stepping-may-behave-oddly-ios-unity

    参考:童冀的2.3融合教程
    swift3.0融合Unity
    的一部分内容,不过还是得说一下,原文中很多步骤是不需要的,例如添加脚本、例如main.mm中main方法的替换(直接注释即可,参见下面matt_eaton博客内容)。而有些方法已经不适用,例如main.swift中的UIApplicationMain方法,原文中的会报错。
    blitzagency的教程以及一些文件
    matt_eaton 的一篇博客
    swift4.0 整合Unity报错问题

    内容不算很难,但是xCode9的坑有点多,尤其不能自动编译第三方库,测试了好久。然后9.1的framework添加两次。。。以及safe area设置等等,在整合前花了太多时间处理IDE的问题。

    参照阅读之前写的xCode8.3 + OC +Unity教程
    对照一下,可以理解得更清楚一些。

    如果文章有所帮助,欢迎打赏😄


    😄.png

    相关文章

      网友评论

      • 起个名字好难O0:UnityUtils这三个文件是哪来的? 自己创建的吗
        与之书:@起个名字好难O0 这个太久没有接触了 当时只是临时做的一个ios项目 正常来说这个方法应该是没问题的 如果是找不到方法 把上面的步骤每一步再对一下 或者看看swift的版本,如果报了其他错,暂时想不到什么信息
        起个名字好难O0:@与之书 UnitUtils.h里面的方法是void unity_init(int argc, char* argv[]); 然后自己新建的main.swift里面不管是用custom_unity_init(CommandLine.argc, CommandLine.unsafeArgv) 还是unity_init(CommandLine.argc, CommandLine.unsafeArgv) 都会报错
        与之书:@起个名字好难O0 是的
      • 79292ce48ab6:请问楼主有遇到过真机运行崩溃的问题么?我按照你的教程接进去了,然后在运行的时候崩在UnityAppController.mm文件中的UnityInitApplicationNoGraphics这个方法处。
        79292ce48ab6:@与之书 我已经解决了,谢谢你的回复。
        与之书:@Ht黄涛先生 很久没接触了……看看日志具体报什么错吧
      • ebfedff14320:您好
        在製作畢業專題的專案上
        我按照您的步驟全部做完後
        在“3.4 UnityUtils.mm 文件”這個步驟中,
        添加的這行
        UnityParseCommandLine(argc, argv);
        會報錯(Use of undeclared identifier 'UnityParseCommandLine'),
        後面也按照指示
        設置了Objective-C Bridging Header
        還是一樣。

        如果我把這行註解掉
        會出現錯誤
        clang: error: no such file or directory: 'CoreMotion'
        不知道怎麼解決..

        //我的 Unity 專案沒有用到 AR
        //但是有類似一樣要開相機的功能
        //另外 mac 上的 Unity 版本是 〃2017.2.0f3 〃這個好像差異滿大的@@?
        //版本號也有在 MyUnity.xcconfig 中有改掉

        希望您能在繁忙之中抽空幫忙解答謝謝><
        与之书:@虎_e459 也可能是头文件没有正确引用的问题 可以全局搜一下这个方法看下在Unity的哪个文件中,确认下是否导入正确。 头文件和库文件的导入上文也有说 也可以对照oc语言的整合看下是否有遗漏
        与之书:手头没有设备可以测试(项目使用以前公司的mac mini做的)。找不到UnityParseCommandLine这份方法的问题我没有碰到过,后面配置好之后,报错就消失了。main.mm中的main方法有注释掉么? Unity版本差别挺大的,不过看起来2017应该也不会是太旧的版本。据说早期的版本应该用UnityInitRuntime(argc, argv);(就是文中注释掉的方法),如果不行的话,看看链接blitzagency的教程,看看有没有帮助。
        ebfedff14320:另外
        在 ViewController.swift(原始的)添加的這行
        self.view.addSubView(UnityGetGLView())
        也會報錯(Value of type 'UIView' has no member 'addSubView')
        後來去查了一下addSubView改成addSubview就好了(?
        不過剛剛上面的問題還是沒解決orz
      • YDomo:你好,我是个人版unity 导入xcode项目时候,只是导出一个空的文件夹,请问是什么问题
        与之书:嗯? Unity导出是空的? 如果是Unity的部分,我可能解答不了,直接是别人给的。

      本文标题:最新iOS 整合Unity(xCode9.1 Swift4.0

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