- 沙盒:浏览器的安全机制,浏览器内的进程不能直接访问本地计算机中的硬盘等硬件或数据。必须通过js作为中间层实现。
- 需求:通过一个按钮,点击后选择文件传到webgl进程中。
- 前置说明:需要有webgl模版等基础配备,已经可以发布webgl程序。
- 借鉴:http://t.csdnimg.cn/p7de5
一、在__Internal.jslib中添加如下代码块
javascript
mergeInto(LibraryManager.library,
{
LoadFile:function (gameobjectName,fitter) {
var gameobjectNameStr=Pointer_stringify(gameobjectName);
var fitterStr=Pointer_stringify(fitter);
console.log("GetSelectFileURL");
console.log("需要被发送的物体名称转化:");
console.log(gameobjectNameStr);
console.log("需要筛选文件类型转化:");
console.log(fitterStr);
var fileInput = document.getElementById("load");//通过id获取创建好的input元素
if(!fileInput){
var fileInput = document.createElement('input');//创建input元素
console.log("创建input元素");
fileInput.setAttribute('id', "load");//给创建的input设置id
fileInput.setAttribute('type', 'file');
fileInput.setAttribute('style','display:none;');
fileInput.setAttribute('style','visibility:hidden;');
fileInput.setAttribute('multiple', '');
fileInput.disabled=true;//使input元素不可点击,否则会导致页面上所有位置都可唤起文件对话框
document.body.appendChild(fileInput);
}
fileInput.accept=fitterStr;
fileInput.disabled=false;//设置input可点击,否则无法通过click()打开文件对话框
fileInput.click()//打开文件对话框
fileInput.onclick = function (event) {
this.value = null;
};
fileInput.onchange = function (event) {
//如果需要在unity中获取文件内容,在onchange中获取后通过SendMessage()传回给unity
var files = event.target.files;
var res={
Path:URL.createObjectURL(files[0]),
FileName:files[0].name
};
gameInstance.SendMessage(gameobjectNameStr, 'FileDialogResult', JSON.stringify(res));
}
document.onmouseup = function() {
fileInput.click();
document.onmouseup = null;
}
fileInput.disabled=true;//结束时再次设置input不可点击,保证点击其他位置无法打开文件对话框
//确保只有点击按钮2时才能打开文件对话框
},
});
代码说明
该js脚本中,LoadFile函数名,接收一个游戏物体名称和过滤文件格式字符串。
游戏物体名称用于在该js函数中发送广播,叫该游戏物体执行指定挂在在该物体mono脚本上的指定方法。
注意:所有C#传给js的字符串都需要用Pointer_stringify过一遍,才能转化成js识别的字符串。
主要逻辑为:js动态创建一个元素,设置交互属性,定义选择文件事件函数,在函数内部用:
javascript
gameInstance.SendMessage(gameobjectNameStr, 'FileDialogResult', JSON.stringify(res));
其中,gameInstance是unity运行实例,有的叫unityInstance或者别的东西,具体看自己js模版中定义的变量。gameobjectNameStr:转化过后的游戏物体名称;FileDialogResult:游戏物体上的需要被执行的函数;JSON.stringify(res):该函数接收的一个参数,这里我封装为一个json对象可以传递多个参数,传过去后解析为一个文件信息类。
二、调用
在ui按钮中挂载脚本,这里文件格式以表格为例:
cs
public class JSFileInfo
{
public string Path { get; set; }
public string FileName { get; set; }
}
cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.Networking;
public class LoadExlBtn : MonoBehaviour
{
public string fileFullPath;
[DllImport("__Internal")]
private static extern void LoadFile(string gameobjectName,string fitter);
public void Add_File()
{
if (Application.platform == RuntimePlatform.WebGLPlayer)
{
LoadFile(gameObject.name,".xls,.xlsx");//web端调用方法
}
}
public void FileDialogResult(string JsFileInfoStr)
{
Debug.Log(JsFileInfoStr);
JSFileInfo jsFileInfo = JsonConvert.DeserializeObject<JSFileInfo>(JsFileInfoStr);
Debug.Log(jsFileInfo.Path);
Debug.Log(jsFileInfo.FileName);
StartCoroutine(LoadData(jsFileInfo,null));
}
IEnumerator LoadData(JSFileInfo jsFileInfo,Action<FileStream> action)
{
UnityWebRequest request = UnityWebRequest.Get(jsFileInfo.Path);
//创建文件夹
string dirPath = Path.Combine(Application.persistentDataPath, "Exls");
Debug.Log("将被存至目录:"+dirPath);
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
string fullPath = Path.Combine(dirPath, jsFileInfo.FileName);
request.downloadHandler = new DownloadHandlerFile(fullPath);//路径+文件名
Debug.Log("复制到沙盒ing");
yield return request.SendWebRequest();
if (request.result==UnityWebRequest.Result.Success)
{
Debug.Log("复制到沙盒完成");
fileFullPath = fullPath;
FileStream fs = new FileStream(fullPath, FileMode.Open);
Debug.Log(fs.Length);//byte
Debug.Log(fs.Name);//路径+名
if (action!=null)
{
action(fs);
}
fs.Close();
FileInfo f = new FileInfo(fullPath);
Debug.Log(f.Name);
}else
{
Debug.Log(request.error);
}
}
}
主要逻辑:
-
编辑器中添加按钮监听Add_File()
-
调用外部js中的LoadFile,传入本按钮名称、文件过滤格式。
-
在js中创建点击元素,模拟点击,获取文件对于浏览器沙盒来说的url(是blob:xxx的形式),广播消息给这个按钮的FileDialogResult。
-
在FileDialogResult中开协程用UnityWebRequest将文件存到浏览器沙盒中的persistentDataPath。
-
(如果是图片文字等简单的东西可以不用存为实体文件,直接用api)
csIEnumerator LoadTexture2D(string url, Action<Texture2D> taskCompletedCallBack) { UnityWebRequest request = UnityWebRequestTexture.GetTexture(url); yield return request.SendWebRequest(); if (request.isHttpError || request.isNetworkError) { } else { var texture = DownloadHandlerTexture.GetContent(request); taskCompletedCallBack(texture); } }
-
在yield return request.SendWebRequest()后打开文件流处理文件逻辑。