• 在原生APP中集成Unity容器


    随着技术的发展,越来越多的APP期望拥有3D,AR的能力。要达到这个目标可以选择使用原生开发,也可以使用Unity成熟的3D开发技术链,通过嵌入的方式将Unity容器嵌入到APP中。这里介绍的是通过嵌入Unity容器的方式来实现APP的3D,AR能力的。
     
    Unity集成到iOS应用的本质是将Unity中所有用到的资源,模型,代码打包成一个framework动态库,然后嵌入到APP的内部。APP启动后加载Unity页面时,会加载这个framework动态库和里面的所有资源。然后在APP中展示这个Unity页面。
     
    Unity集成到iOS应用的官方提供的方案是以Workspace的方式集成,具体步骤如下:
    1.Unity项目通过Unity Editer 导出一个iOS项目,这个iOS项目里包含了整个Unity项目的所有代码和资源,可以直接运行在iOS系统上。
    2.用Xcode创建一个原生的iOS项目
    3.用Xcode创建一个Workspace, 然后通过add file 的形式将这2个项目添加到一个Workspace下面。
    4.修改Unity-iPhone项目打包设置,使其打包出适合嵌入的UnityFramework动态库,
    5.修改NativeiOSApp项目配置,添加UnityFramework动态库。

     

    对Workspace下面的2个项目进行配置
    Unity-iPhone创建
    在生成UnityFramework动态库前,需要将Unity项目导出一个iOS项目,导出的过程如下:
    1.点击File->Building Settings进入到选择导出页面

    2.选择要导出的平台,这里选择iOS,然后点击右下角的"Switch Plateform"按钮,然后点击上面的“Add Open Scenes”添加场景

    3.点击“Build”,导出iOS项目

     

    Unity-iPhone设置
    关闭以Workspace方式打开的Xcode,单独打开Unity-iPhone项目
    1.在Unity-iPhone项目中,设置Data 这个Group的 Target Memebership, 将里面的UnitFramework项打勾,表示这个Data在生成Framework静态库时也要作为其中的一员,放置进去。
    2.将NativeCallProxy.h头文件从Framework的 protect组移动到public组,将头文件开放出来。路径为: Unity-iPhone / Libraries / Plugins / iOS / NativeCallProxy.h
    3.手机连接电脑,运行,生成静态库。

     

    NativeiOSApp原生项目设置
    以Workspace方式打开项目
    1.在NativeiOSApp Target - General - Frameworks, Libraries, and Embedded Content 通过点击+ 将UnityFramework设置嵌入到项目中
    2.在NativeiOSApp Target - Build Phases - Link Binary With Libraries中,点击-,将UnityFramework移除,表示禁止在项目链接时将UnityFramework链接到可执行文件中,它只作为内嵌在APP中的静态库在运行时加载使用。
    3.手机连接电脑,运行,看到Demo运行的效果。
     
     
    Unity与原生通信
    Unity调用原生
    1.首先在原生中实现代理协议NativeCallProxy中的方法(注册由谁来处理unity的调用)和添加暴露给unity的方法。
    NativeCallProxy.h文件中方法的声明
    1
    2
    3
    4
    5
    6
    __attribute__ ((visibility("default")))
    @interface FrameworkLibAPI : NSObject
    // call it any time after UnityFrameworkLoad to set object implementing NativeCallsProtocol methods
    +(void) registerAPIforNativeCalls:(id) aApi;
     
    @end
    NativeCallProxy.cpp文件中方法的实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @implementation FrameworkLibAPI
     
    id api = NULL;
    +(void) registerAPIforNativeCalls:(id) aApi
    {
        api = aApi;
    }
     
    @end
    给Unity暴露的原生调用方法
    1
    2
    3
    extern "C" {
        void showHostMainWindow(const char* color) { return [api showHostMainWindow:[NSString stringWithUTF8String:color]]; }
    }
    2.然后在原生的Unity启动时,注册这个处理的对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    - (void)initUnity
    {
        [self setUfw: UnityFrameworkLoad()];
        // Set UnityFramework target for Unity-iPhone/Data folder to make Data part of a UnityFramework.framework and uncomment call to setDataBundleId
        // ODR is not supported in this case, ( if you need embedded and ODR you need to copy data )
        [[self ufw] setDataBundleId: "com.unity3d.framework"];
        [[self ufw] registerFrameworkListener: self];
        [NSClassFromString(@"FrameworkLibAPI") registerAPIforNativeCalls:self];
     }
    3.在Unity中,调用iOS的原生方法
    Cube.cs脚本中声明在APP中存在方法showHostMainWindow
    1
    2
    3
    4
    5
    6
    #if UNITY_IOS || UNITY_TVOS
    public class NativeAPI {
        [DllImport("__Internal")]
        public static extern void showHostMainWindow(string lastStringColor);
    }
    #endif
    Cube.cs脚本中添加Unity 2d按钮点击事件,调用iOS原生方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    void OnGUI()
    {
        GUIStyle style = new GUIStyle("button");
        style.fontSize = 45;
        if (GUI.Button(new Rect(10, 300, 600, 100), "Show Main With Color", style)) showHostMainWindow();
    }
     
     
    void showHostMainWindow()
    {
    #if UNITY_ANDROID
        try
        {
            AndroidJavaClass jc = new AndroidJavaClass("com.unity.mynativeapp.SharedClass");
            jc.CallStatic("showMainActivity", lastStringColor);
        } catch(Exception e)
        {
            appendToText("Exception during showHostMainWindow");
            appendToText(e.Message);
        }
    #elif UNITY_IOS || UNITY_TVOS
        NativeAPI.showHostMainWindow(lastStringColor);
    #endif
    }

     

    原生调用Unity
    点击原生发送消息按钮,发消息给Unity。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    self.btnSendMsg = [UIButton buttonWithType: UIButtonTypeSystem];
    [self.btnSendMsg setTitle: @"Send Msg" forState: UIControlStateNormal];
    [self.btnSendMsg addTarget: self action: @selector(sendMsgToUnity) forControlEvents: UIControlEventPrimaryActionTriggered];
     
     
    - (void)sendMsgToUnity
    {
        [[self ufw] sendMessageToGOWithName: "Cube" functionName: "ChangeColor" message: "yellow"];
    }
     
    /*
    goName: 场景中的游戏物体GameObject
    name: 这个游戏物体挂载的脚本中的一个方法
    msg: 参数
    */
    - (void)sendMessageToGOWithName:(const char*)goName functionName:(const char*)name message:(const char*)msg
    {
        UnitySendMessage(goName, name, msg);
    }
     
    void  UnitySendMessage(const char* obj, const char* method, const char* msg);
    Cube.cs脚本中的方法实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    string lastStringColor = "";
    void ChangeColor(string newColor)
    {
        appendToText( "Changing Color to " + newColor );
     
        lastStringColor = newColor;
     
        if (newColor == "red") GetComponent().material.color = Color.red;
        else if (newColor == "blue") GetComponent().material.color = Color.blue;
        else if (newColor == "yellow") GetComponent().material.color = Color.yellow;
        else GetComponent().material.color = Color.black;
    }
     
    Unity热更新
    在Unity项目中使用纯C#构建的渐渐不能适应移动端的需求,移动端通常通过添加热更新插件来实现热更新功能。这个过程起关键作用的是Lua和起对应的解释器。
    lua是解释型语言,并不需要事先编译成块,而是运行时动态解释执行的。
    这样LUA就和普通的游戏资源如图片,文本没有区别,因此可以在运行时直接从WEB服务器上下载到持久化目录并被其它LUA文件调用。
    Lua热更新解决方案是通过一个Lua热更新插件(如ulua、slua、tolua、xlua等)来提供一个Lua的运行环境以及和C#进行交互。
    所以lua热更新的流程可以简单理解为:将逻辑代码使用脚本实现,再将脚本转化为文本资源,最后以更新资源的形式来更新程序,以此来实现热更新。
    注意:
    在iOS应用内的Unity容器中,Untiy的C#资源和Lua资源都是在Unity容器内部进行加载的。如果Unity采用的Lua热更新,则需要原生侧在Lua脚本和资源下载完成后通知Unity进行加载展示。


    Demo地址
    NativeiOSApp项目地址:https://github.com/zhfei/uaal-example
    将 Unity 集成到原生 iOS 应用程序中官方文档:https://docs.unity3d.com/cn/2020.2/Manual/UnityasaLibrary-iOS.html
     
     
     
     
     
  • 相关阅读:
    6.DApp-用Web3实现前端与智能合约的交互
    ESP8266/esp32接入阿里云物联网平台点灯控制类案例
    [题]Trie字符串统计 #字典树
    C语言:求最大数不用数组
    数据不平衡GPT调研
    如何使用VSCode将iPad Pro转化为功能强大的开发工具?
    2023-10-28 思考-精力管理-分析
    Bug记录:【com.fasterxml.jackson.databind.exc.InvalidDefinitionException】
    SpringBoot2运维实用篇(二)—— 配置高级
    典型行业大数据应用和安全风险和解决方案
  • 原文地址:https://www.cnblogs.com/zhou--fei/p/17622488.html