如果是按照上面这样写,恭喜你,打包出来的东西肯定报错,反序列化得到的全都是 null。
而且网上搜索的话,很难搜到原因,貌似遇到这个问题的人并不多?没办法,求着后端小哥哥帮忙改接口,把接口全都写成 key-value 的形式就可以用了。
为什么会出现这个问题?在原本都已经放弃的时候,无意中发现了这个插件
JSON.NET FOR UNITY
,在这个插件的介绍里找到了答案
While many in the Unity Community have succeeded in getting JSON .NET to work for their games, it has never worked properly with iOS or IL2CPP. The iOS errors are due to incompatibilities with AOT (Ahead of Time Compilation) that is used by Mono/IL2CPP in iOS.
大致的意思就是,
JSON.NET
在 iSO 平台上因为 ATO 的问题不能直接用,我想 WebGL 应该也是类似的问题吧,看着这个插件的支持平台上,写了 WebGL,抱着试一试的想法尝试了一下,还真的可以,行得通,这个坑算是解决了,反序列化 Json 不能直接用
JSON.NET
库,要用 Unity 商店里的那个插件。
在 Unity 里,非桌面平台,尽量少用 nuget 仓库里的东西,如果要用,也要先确保 Unity 不同平台的支持情况,尽量用 Unity 商店里的插件,因为 Unity 商店里的插件一般都会注明平台支持情况
更新 推荐使用
Utf8Json
更快,但相比
Json.Net
缺少 JArray 和 JObject 等特性,推荐使用
Newtonsoft.Json-for-Unity
,版本更新,功能更多。
相比其他问题,这个问题已经不能叫问题了,只要稍微有点 Web 开发经要就能解决,因为所有请求都是从 js 里发出的,所以很容易遇到跨域问题,只要加上对应的返回头就可以了
Access-Control-Allow-Origin
。
Unity 打包 WebGL 平台文件时,要尤其注意跨域问题,一定要提前和后端讲明
相比之下,AB 包就没什么坑了,中规中矩,常规用法就可以了,建议按场景打包,虽然会有重复资源,但是操作简单啊,如果自己手动分包的话,麻烦的要死。
唯一要注意的一点就是 IL2CPP 编译时代码剥离的问题,这一点随便一百度,都会有很多教程告诉你怎么做。
我们使用了网络音频,所以要注意网络音频的格式,打包出来的网页网络音频要用 wav 格式的,而在客户端可以使用 ogg 格式。
private IEnumerator PlayWebAudio(string url, float d)
#if UNITY_EDITOR || !UNITY_WEBGL
using (var www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.OGGVORBIS))
#elif UNITY_WEBGL
using (var www = UnityWebRequestMultimedia.GetAudioClip(url, AudioType.WAV))
#endif
yield return www.SendWebRequest();
yield return new WaitForSeconds(d);
if (www.isNetworkError || www.isHttpError)
Debug.Log(www.error);
var clip = DownloadHandlerAudioClip.GetContent(www);
PlayAudioClip(clip);
}
Unity 在使用网络资源的时候,要注意音频格式,不同平台的支持情况不一样,不确定的时候就用 wav 格式吧
这个看了半天也没搞懂真正的用法,只能写个简单点的函数
先说明一下,能百度到的东西,很多都是过时的,而且大家都是你抄我,他抄你,抄来抄去,没啥意思。我找了一圈,就发现一篇是比较实用的,而且写得也挺易懂的
链接
最好的工具是 Unity 的官方文档,这个文档写的真不错,很多方法都有很详细的示例
文档
因为以前在 UE4 上也研究过这个东西,所以对 Emscripten 也有一定的了解。看一下文档就大致该知道怎么做了。
首先是在
Plugins目录下
创建一个
.jslib
文件,名字叫什么都无所谓,然后在里面写一些函数,尽量简单一点,越简单越好,函数的形式可以参考官方文档,要注意,官方文档给的这几个示例函数都是比较具有代表性的,基本上你能用到的东西,都已经告诉你该怎么处理了,传参,返回值,资源处理,该有的都有了。
mergeInto(LibraryManager.library, {
Hello: function () {
window.alert("Hello, world!");
HelloString: function (str) {
window.alert(Pointer_stringify(str));
PrintFloatArray: function (array, size) {
for(var i = 0; i < size; i++)
console.log(HEAPF32[(array >> 2) + i]);
AddNumbers: function (x, y) {
return x + y;
StringReturnValueFunction: function () {
var returnStr = "bla";
var bufferSize = lengthBytesUTF8(returnStr) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(returnStr, buffer, bufferSize);
return buffer;
BindWebGLTexture: function (texture) {
GLctx.bindTexture(GLctx.TEXTURE_2D, GL.textures[texture]);
});
在需要调用的时候,这样写
using UnityEngine;
using System.Runtime.InteropServices;
public class NewBehaviourScript : MonoBehaviour {
[DllImport("__Internal")]
private static extern void Hello();
[DllImport("__Internal")]
private static extern void HelloString(string str);
[DllImport("__Internal")]
private static extern void PrintFloatArray(float[] array, int size);
[DllImport("__Internal")]
private static extern int AddNumbers(int x, int y);
[DllImport("__Internal")]
private static extern string StringReturnValueFunction();
[DllImport("__Internal")]
private static extern void BindWebGLTexture(int texture);
void Start() {
Hello();
HelloString("This is a string.");
float[] myArray = new float[10];
PrintFloatArray(myArray, myArray.Length);
int result = AddNumbers(5, 7);
Debug.Log(result);
Debug.Log(StringReturnValueFunction());
var texture = new Texture2D(0, 0, TextureFormat.ARGB32, false);
BindWebGLTexture(texture.GetNativeTextureID());
}
这个示例,能看懂的人肯定是一看就懂,看不懂的估计还要再补一下基础知识,仿照这个示例,咱们自己来写一个
jslib:
mergeInto(LibraryManager.library, {
GetUrlParam: function (str) {
var paraName = Pointer_stringify(str);
var result = GetUrlParamFun(paraName);
var bufferSize = lengthBytesUTF8(result) + 1;
var buffer = _malloc(bufferSize);
stringToUTF8(result, buffer, bufferSize);
return buffer;
});
简单分析一下,有个方法叫
GetUrlParam
,带有一个参数,已经确定需要传字符串进来,所以需要使用
Pointer_stringify()
方法,注意传参是将内容写入内存,使用指针去指的所以要用
Pointer_stringify
,再下面,调用一个叫
GetUrlParamFun
的函数,获取返回值,再后面就是将结果返回给 Unity,也是将结果写入内存,然后用指针去指。(我指针理解的不够透彻,上面这段话难免会有一些问题)
需要在网页中插入一段 js:
function GetUrlParamFun(paraName) {
var url = document.location.toString();
var arrObj = url.split("?");
if (arrObj.length > 1) {
var arrPara = arrObj[1].split("&");
var arr;
arr = arrPara[i].split("=");
if (arr != null && arr[0] == paraName) {
return decodeURIComponent(arr[1]);
return "";
else {
return "";
}
上面这一段代码是用来获取页面 url 中的参数的
C#脚本中写
using UnityEngine;
#if !UNITY_EDITOR && UNITY_WEBGL
using System.Runtime.InteropServices;
#endif
public class XXXX : MonoBehaviour
#if !UNITY_EDITOR && UNITY_WEBGL
[DllImport("__Internal")] private static extern string GetUrlParam(string str);
#endif
private void Start()
#if !UNITY_EDITOR && UNITY_WEBGL
string from = GetUrlParam("from");
Debug.Log(from);
#endif
}