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 update
void 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 update
void 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 update
void 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的形式改写,建立一个图片管理模块去专门加载图片,我们下期再见