1、前言
在unity中与后台对接,用await在web端暂时还不支持,所以,协程成为比较好的通用方式,以下适用除post访问外的所有对接
2、对接后台
2.1、安装插件
首先我们需要用到Newtonsoft.dll,如果没有这个.dll的请跟着我一起装上,我们先创建一个脚本WebRequest.cs,然后双击脚本打开VS2022
在上面一排工具栏中,点击“工具”选项
选择NuGet包管理器-管理解决方案的NuGet程序包,这时会弹出一个窗口
点击”浏览“
排在第一的就是我们需要用的插件,插件轻量好用
点击这个后,右侧小窗弹出窗口,像我这样勾选,然后安装
安装完成后,我们回到脚本页面,右键打开所在的文件夹
我们返回工程目录,在Packages这个文件夹下有一个Newtonsoft文件夹,这个就是我们的插件
点进文件夹后有许多net版本,个人比较推荐netstandard2.0
将netstandard2.0下的Newtonsoft.Json.dll拖入我们的工程里,下面开始我们的正文
2.2、代码
回到正题,我们创建好WebRequest.cs后,结构是这样
using Newtonsoft.Json.Linq;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;public class WebRequest : MonoBehaviour
{public string address;// Start is called before the first frame updatevoid Start(){}/// <summary>/// 获取返回对象,如果不存在返回为null/// </summary>/// <typeparam name="T"></typeparam>/// <param name="path">路径</param>/// <param name="callback"></param>/// <returns></returns>public IEnumerator RequestURLWithArray(string path, System.Action<JObject> callback){string paths = address + path;Debug.LogError("当前链接+++" + paths);//jishi();using (var request = UnityWebRequest.Get(paths)){// 发送HTTP请求并等待响应yield return request.SendWebRequest();// 检查是否有错误发生if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError){Debug.LogError(request.error + "链接:" + paths);yield break;}if (!string.IsNullOrEmpty(request.downloadHandler.text)){callback(JObject.Parse(request.downloadHandler.text));}}}
}
由于是教学,我没有现有的后台接口,就用本地json代替,后台对接也只是换一下链接就能继续用
以上代码写完,我们在工程目录Assets下创建StreamingAssets文件夹,在StreamingAssets文件夹中创建“测试.json”,测试.json的数据结构如下:
{
"name":"11111",
"id":123456789,
"password":"123456789"
}
兄弟们一定一定要注意,json必须是utf8格式保存的,不然容易出现读取失败或者乱码等bug
一个非常简单的json,主要是测试用,打算搭一个登录界面来测试所以数据不多,如果兄弟们有大量数据的,也可以用这套东西,博主亲测,几十个接口+几百条数据,完美对接,延时基本上在几百ms,可以接受的
然后我们在WebRequest的Start里写获取,改写一下WebRequest
using Newtonsoft.Json.Linq;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;public class WebRequest : MonoBehaviour
{public string address;// Start is called before the first frame updatevoid Start(){StartCoroutine(RequestURLWithArray(Application.streamingAssetsPath + "/测试.json", (a) =>{Debug.Log($"name:{a["name"]} id: {a["id"]} password: {a["password"]}");}));}/// <summary>/// 获取返回对象,如果不存在返回为null/// </summary>/// <typeparam name="T"></typeparam>/// <param name="path">路径</param>/// <param name="callback"></param>/// <returns></returns>public IEnumerator RequestURLWithArray(string path, System.Action<JObject> callback){string paths = path;Debug.LogError("当前链接== " + paths);//jishi();using (var request = UnityWebRequest.Get(paths)){// 发送HTTP请求并等待响应yield return request.SendWebRequest();// 检查是否有错误发生if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError){Debug.LogError(request.error + "链接:" + paths);yield break;}if (!string.IsNullOrEmpty(request.downloadHandler.text)){callback(JObject.Parse(request.downloadHandler.text));}}}
}
到这里就要注意,敲黑板划重点
我在这里写的输出,是转成JObject对象后以键对值的形式直接取得
Debug.Log($"name:{a["name"]} id: {a["id"]} password: {a["password"]}");
这里的键全部要和json中的变量对的上,才能获取到,当然,除了JObject外还有数组形式,那是另一种结构,我们等下再说
写完后保存,回到unity中,创建空对象 WebRequest将脚本挂在上面,开始运行
这时控制台就会输出我们想要的数据:
以上就是基础用法,不太建议这样用,如果是只有一个json或接口,可以像上述这样写,但是如果不止一个,而且数据多,我们就要换种形式读取
2.3、进阶用法
接下来是进阶用法,我们先创建一个抽象类,这个类继承MonoBehaviour,并且要有一个封装好的JObject参数,一个虚方法init,用来处理收到的数据:
1、新建抽象类Dataabstract.cs
using Newtonsoft.Json.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public abstract class Dataabstract : MonoBehaviour
{public string path;protected JObject data;public JObject Data{get { return data; }set { if (value != null){data = value;init();}else{Debug.LogError("获取失败,请检查链接地址");}}}protected virtual void init(){}
}
2、修改WebRequest.cs
using Newtonsoft.Json.Linq;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;public class WebRequest : MonoBehaviour
{public string address = Application.streamingAssetsPath;public Dataabstract[] Dataabstracts;// Start is called before the first frame updatevoid Start(){init();}void init(){for (int i = 0; i < Dataabstracts.Length; i++){StartCoroutine(RequestURLWithArray(address+"/"+Dataabstracts[i].path, (a) =>{Dataabstracts[i].Data = a;}));}}/// <summary>/// 获取返回对象,如果不存在返回为null/// </summary>/// <typeparam name="T"></typeparam>/// <param name="path">路径</param>/// <param name="callback"></param>/// <returns></returns>public IEnumerator RequestURLWithArray(string path, System.Action<JObject> callback){string paths = path;Debug.LogError("当前链接== " + paths);//jishi();using (var request = UnityWebRequest.Get(paths)){// 发送HTTP请求并等待响应yield return request.SendWebRequest();// 检查是否有错误发生if (request.result == UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError){Debug.LogError(request.error + "链接:" + paths);yield break;}if (!string.IsNullOrEmpty(request.downloadHandler.text)){callback(JObject.Parse(request.downloadHandler.text));}}}
}
3、新建测试类Test1,Test1继承抽象类Dataabstract重写init方法
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Test1 : Dataabstract
{protected override void init(){Debug.Log($"name:{data["name"]} id: {data["id"]} password: {data["password"]}");}
}
回到unity中,新建空物体Test1,挂上Test1脚本,在面板上的path写上我们的json名字,请注意,一定要把 后缀带上,后缀带上,后缀带上
然后我们把Test1拖入WebRequest的Dataabstracts数组中
然后运行就可以看到我们拿到了数据
这样主要是应对大量不同的json或接口要读的, 这是这种格式的多样,下面我们来看另一种格式的json
2.4、另一种带数组的json读取
我们在StreamingAssets下再创建一种json,名字叫测试1.json,数据如下
{"data": [{"name": "123","id": 1,"password": "爱上放大"},{"name": "456","id": 2,"password": "各色地方"},{"name": "789","id": 3,"password": "奥尔格和"}]
}
新建Test2脚本
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityEngine.UI;public class Test2 : Dataabstract
{public int index;[SerializeField] Text[] text;protected override void init(){JArray jArray = (JArray)data["data"];for (int i = 0; i < text.Length; i++){text[i].text = jArray[index][text[i].name].ToString();}}
}
接下来我们回到unity,按我这样的结构创建好东西
把Test2挂到GameObject上,然后各GameObject的index分开,我这里的json有三组数据,所以我这里填的是0-2,这个作为索引去json中的data数组中找数据而已,将每个GameObject下的三个Text拖进Test2中的Text数组中
然后把三个挂了Test2的GameObject拖进WebRequest中的数组中
直接运行就能看到结果
可以看到,我们成功取到了数据,而且几乎没有延时,基本上是运行就有
2.5、总结
在面对如下简单的json时,我们用JObject去拿数据
{"name": "11111","id": 123456789,"password": "123456789"
}
在面对如下稍微复杂的json时,我们用JArray取数据
{"data": [{"name": "123","id": 1,"password": "爱上放大"},{"name": "456","id": 2,"password": "各色地方"},{"name": "789","id": 3,"password": "奥尔格和"}]
}
而我们建的抽象类,只是用了一个简易版的观察者模式,去构建我们的通信模块,方便维护,降低耦合
3、加载图片
public void show(string url,Action<Sprite> ac)
{StartCoroutine(LoadImageFromUrl(url,ac));
}
IEnumerator LoadImageFromUrl(string url, Action<Sprite> ac)
{using (var request = UnityWebRequestTexture.GetTexture(url)){yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success){Debug.Log(request.error);}else{Texture2D texture = DownloadHandlerTexture.GetContent(request);Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));ac(sprite);}}
}
我们可以建一个脚本来测试这段代码,新建Test3
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;public class Test3 : MonoBehaviour
{[SerializeField] Image im;private void Start(){show("https://img1.baidu.com/it/u=4049022245,514596079&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1701622800&t=c88ca2191a6df508642839cff923ed20", (a) =>{im.sprite = a;});}public void show(string url,Action<Sprite> ac){StartCoroutine(LoadImageFromUrl(url,ac));}IEnumerator LoadImageFromUrl(string url, Action<Sprite> ac){using (var request = UnityWebRequestTexture.GetTexture(url)){yield return request.SendWebRequest();if (request.result != UnityWebRequest.Result.Success){Debug.Log(request.error);}else{Texture2D texture = DownloadHandlerTexture.GetContent(request);Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));ac(sprite);}}}
}
回到unity,新建一个Image,把Test3挂上去,运行
可以看到图片已经加载出来了,非常好用,当然这个图片如果多的话可以参考上面读json的形式改写,建立一个图片管理模块去专门加载图片,我们下期再见