• Unity 关于低版本是否可以引用高版本构建内容的可行性验证



    🎈 简介

    本篇内容以Unity的一个相对较低的版本(2017.4.40)和一个相对较高的版本(2020.3.33),来验证在低版本中是否可以使用高版本中构建的内容,包括如下内容:

    • 在Unity2017.4.40(使用C#6)中是否可以引入Unity2020.3.33(使用C#8)构建的dll并正常使用;
    • 在Unity2017.4.40中是否可以加载在Unity2020.3.33中构建的AssetsBundle资源;

    🎈 低版本是否可以引用高版本构建的dll

    在Unity2020.3.33中,我们开启一个携程,使用UnityWebRequest发起网络请求来获取百度知道网页(www.baidu.com)上的内容,代码示例如下:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    namespace SKFramework.Test
    {
        public class TEST : MonoBehaviour
        {
            private void Start()
            {
                StartCoroutine(TestCoroutine());
            }
    
            private IEnumerator TestCoroutine()
            {
                string url = "www.baidu.com";
                using (UnityWebRequest request = UnityWebRequest.Get(url))
                {
                    yield return request.SendWebRequest();
                    Debug.Log(request.downloadHandler.text);
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    运行结果如下:
    Console Log
    其中using语句在C# 8.0中有了新的写法(C# 8.0中的新增功能 - C#指南),如下图所示:

    using 声明
    我们在示例代码使用新的using声明

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    namespace SKFramework.Test
    {
        public class TEST : MonoBehaviour
        {
            private void Start()
            {
                StartCoroutine(TestCoroutine());
            }
    
            private IEnumerator TestCoroutine()
            {
                string url = "www.baidu.com";
                using UnityWebRequest request = UnityWebRequest.Get(url);
                yield return request.SendWebRequest();
                Debug.Log(request.downloadHandler.text);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    yield return request.SendWebRequest发起网络请求后,一般会先判断请求是否成功,在以往的API中会通过如下方式判断:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    namespace SKFramework.Test
    {
        public class TEST : MonoBehaviour
        {
            private void Start()
            {
                StartCoroutine(TestCoroutine());
            }
    
            private IEnumerator TestCoroutine()
            {
                string url = "www.baidu.com";
                using UnityWebRequest request = UnityWebRequest.Get(url);
                yield return request.SendWebRequest();
                if (request.isNetworkError || request.isHttpError)
                {
                    Debug.Log(request.downloadHandler.text);
                }
                else
                {
                    Debug.LogError(string.Format("发起网络请求失败:{0}", request.error));
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    但是当我们查看其定义可以发现它已经弃用(Obsolete)了:

    //
    // 摘要:
    //     Returns true after this UnityWebRequest encounters a system error. (Read Only)
    [Obsolete("UnityWebRequest.isNetworkError is deprecated. Use (UnityWebRequest.result == UnityWebRequest.Result.ConnectionError) instead.", false)]
    public bool isNetworkError => result == Result.ConnectionError;
    
    //
    // 摘要:
    //     Returns true after this UnityWebRequest receives an HTTP response code indicating
    //     an error. (Read Only)
    [Obsolete("UnityWebRequest.isHttpError is deprecated. Use (UnityWebRequest.result == UnityWebRequest.Result.ProtocolError) instead.", false)]
    public bool isHttpError => result == Result.ProtocolError;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    因为在新版本使用新增属性result来判断请求是否成功:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    namespace SKFramework.Test
    {
        public class TEST : MonoBehaviour
        {
            private void Start()
            {
                StartCoroutine(TestCoroutine());
            }
    
            private IEnumerator TestCoroutine()
            {
                string url = "www.baidu.com";
                using UnityWebRequest request = UnityWebRequest.Get(url);
                yield return request.SendWebRequest();
                if (request.result == UnityWebRequest.Result.Success)
                {
                    Debug.Log(request.downloadHandler.text);
                }
                else
                {
                    Debug.LogError(string.Format("发起网络请求失败:{0}", request.error));
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    下面我们将其封装为一个接口并构建dll导入到Unity2017.4.40中去使用,接口代码如下:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    namespace SKFramework.Test
    {
        public class TEST
        {
            public void Execute(MonoBehaviour executer)
            {
                executer.StartCoroutine(TestCoroutine());
            }
    
            private IEnumerator TestCoroutine()
            {
                string url = "www.baidu.com";
                using UnityWebRequest request = UnityWebRequest.Get(url);
                yield return request.SendWebRequest();
                if (request.result == UnityWebRequest.Result.Success)
                {
                    Debug.Log(request.downloadHandler.text);
                }
                else
                {
                    Debug.LogError(string.Format("发起网络请求失败:{0}", request.error));
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    📍 如何构建dll动态库

    打开Visual Studio创建新项目,模板选择如图所示:

    创建新项目
    C# 8.0对应框架.Net Framework 4.8(C#版本 与 .NET Framework 对应关系及各版本语法差异)

    配置新项目
    创建后将我们的示例代码拷入其中,发现UnityEngine的部分报错,因为我们还没有引用UnityEngine.dll

    封装接口
    UnityEngine.dll所在文件夹目录如下,需要到Unity Editor的安装目录下去找:

    UnityEngine.dll
    添加引用:

    添加引用
    引用添加完成,再次右键项目,点击生成,然后将生成的dll动态库导入到Unity2017.4.40创建的项目中。

    生成dll动态库

    📍 如何将Unity使用的C#语言版本改为6.0

    参考文章:配置Unity2017和VS2015使用C# 6.0

    • Player Sttings中将Scripting Runtime Version修改为Experimental(.Net 4.6 Equivalent)
      Player Settings

    • Visual Studio中打开工具 - 选项 - 适用于Unity的工具 - 杂项,将访问项目属性修改为true;
      访问项目属性

    • 重启再打开属性设置目标框架为.Net Framework 4.6.1,编写测试脚本:

    using UnityEngine;
    using SKFramework.Test;
    
    public class Example : MonoBehaviour 
    {
        private void Start()
        {
            new TEST().Execute(this);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    运行结果:

    运行结果

    🎈 低版本是否可以加载高版本构建的AssetsBundle

    • 在Unity2020.3.33中创建一个Prefab预制体:

    Prefab

    • 新建Assets Bundle

    Assets Bundle

    • 构建Assets Bundle,使用工具代码如下:
    #if UNITY_EDITOR
    using System.IO;
    using UnityEditor;
    using UnityEngine;
    
    namespace SK.Framework.Tools
    {
    public class SimpleAssetsBundle : EditorWindow
    {
        [MenuItem("SKFramework/Tools/Simple AssetsBundle")]
        public static void Open()
        {
            var window          = GetWindow<SimpleAssetsBundle>();
            window.titleContent = new GUIContent("Simple AssetsBundle");
            window.minSize      = new Vector2(300f, 100f);
            window.maxSize      = new Vector2(1080f, 100f);
            window.Show();
        }
    
        //打包路径
        private string path;
        //打包选项
        private BuildAssetBundleOptions options;
        //目标平台
        private BuildTarget target;
    
        private const float labelWidth = 80f;
    
        private void OnEnable()
        {
            path = EditorPrefs.HasKey(EditorPrefsKeys.path) ? EditorPrefs.GetString(EditorPrefsKeys.path) : Application.streamingAssetsPath;
            options = EditorPrefs.HasKey(EditorPrefsKeys.options) ? (BuildAssetBundleOptions)EditorPrefs.GetInt(EditorPrefsKeys.options) : BuildAssetBundleOptions.None;
            target = EditorPrefs.HasKey(EditorPrefsKeys.target) ? (BuildTarget)EditorPrefs.GetInt(EditorPrefsKeys.target) : BuildTarget.StandaloneWindows;
        }
    
        private void OnGUI()
        {
            //路径
            GUILayout.BeginHorizontal();
            GUILayout.Label("Path", GUILayout.Width(labelWidth));
            string newPath = EditorGUILayout.TextField(path);
            if (newPath != path)
            {
                path = newPath;
                EditorPrefs.SetString(EditorPrefsKeys.path, path);
            }
            //浏览 选择路径
            if (GUILayout.Button("Browse", GUILayout.Width(60f)))
            {
                newPath = EditorUtility.OpenFolderPanel("AssetsBundle构建路径", Application.dataPath, string.Empty);
                if (!string.IsNullOrEmpty(newPath) && newPath != path)
                {
                    path = newPath;
                    EditorPrefs.SetString(EditorPrefsKeys.path, path);
                }
            }
            GUILayout.EndHorizontal();
    
            //选项
            GUILayout.BeginHorizontal();
            GUILayout.Label("Options", GUILayout.Width(labelWidth));
            var newOptions = (BuildAssetBundleOptions)EditorGUILayout.EnumPopup(options);
            if (newOptions != options)
            {
                options = newOptions;
                EditorPrefs.SetInt(EditorPrefsKeys.options, (int)options);
            }
            GUILayout.EndHorizontal();
    
            //平台
            GUILayout.BeginHorizontal();
            GUILayout.Label("Target", GUILayout.Width(labelWidth));
            var newTarget = (BuildTarget)EditorGUILayout.EnumPopup(target);
            if (newTarget != target)
            {
                target = newTarget;
                EditorPrefs.SetInt(EditorPrefsKeys.target, (int)target);
            }
            GUILayout.EndHorizontal();
    
            GUILayout.FlexibleSpace();
    
            //构建按钮
            if (GUILayout.Button("Build"))
            {
                //检查路径是否有效
                if (!Directory.Exists(path))
                {
                    Debug.LogError(string.Format("无效路径 {0}", path));
                    return;
                }
                //提醒
                if (EditorUtility.DisplayDialog("提醒", "构建AssetsBundle将花费一定时间,是否确定开始?", "确定", "取消"))
                {
                    //开始构建
                    BuildPipeline.BuildAssetBundles(path, options, target);
                }
            }
        }
    
        private class EditorPrefsKeys
        {
            public static string path    = "SIMPLEASSETSBUNDLE_PATH";
            public static string options = "SIMPLEASSETSBUNDLE_OPTIONS";
            public static string target  = "SIMPLEASSETSBUNDLE_TARGET";
        }
    }
    }
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 将构建出的ab包导入到Unity2017.4.40项目中的Streaming Assets文件夹中:
      Streaming Assets

    编写测试脚本:

    using UnityEngine;
    using SKFramework.Test;
    using System.Collections;
    using UnityEngine.Networking;
    
    public class Example : MonoBehaviour 
    {
        private void Start()
        {
            //new TEST().Execute(this);
            StartCoroutine(ExampleCoroutine());
        }
    
        private IEnumerator ExampleCoroutine()
        {
            string url = Application.streamingAssetsPath + "/player";
    
            WWW www = new WWW(url);
            yield return www;
            if (www.error == null)
            {
                var ab = www.assetBundle;
                Debug.Log(ab == null);
            }
            else
            {
                Debug.LogError(www.error);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    运行结果:

    Console Log

    🎈 结论

    以上述的结果来看,在相对较低的版本中,无论是引入相对较高的版本生成的dll,还是加载相对较高版本构建的ab包,都会出现些许问题,是否有相应解决方案尚需确定。

  • 相关阅读:
    rmq创建主题
    【UE5 Cesium】18-Cesium for Unreal 建立飞行跟踪器(3)
    安装keras、tensorflow
    Python 3.12.0 Release 版本
    231 基于matlab的北斗信号数据解析
    Faiss原理和使用总结
    在react项目中让webpack使用mock数据
    想学设计模式、想搞架构设计,先学学 UML 系统建模吧
    es查询初学
    【ARM AMBA5 CHI 入门 12.2 -- CHI 协议层详细介绍 】
  • 原文地址:https://blog.csdn.net/qq_42139931/article/details/126692167