- 0.1:一、前言
- 0.2:二、功能介绍
- 0.3:三、系统要求
- 0.4:四、问题解决
一、前言
最近有个项目需要实现一个PC客户端,客户端主要功能是加载前端网页,通过客户端按钮实现网页的切换。使客户端内容和网页内容看起来是一个整体。我这里使用的开发工具是Unity2021.3,加载网页用的插件是3D WebView for Windows and macOS (Web Browser),版本4.2。地址:https://assetstore.unity.com/packages/tools/gui/3d-webview-for-windows-and-macos-web-browser-154144 。客户端运行环境是Windows系统,最开始的时候也考虑过使用WPF进行开发,但是我很长时间没有用WPF了,就选择了使用Unity开发了。
二、功能介绍
摘自插件在asset store页面上的概述。
1.加载网页
插件可以从URL或者本地的html文件中加载网页。webview.WebView.LoadUrl(url);
2.观看视频
插件默认可以看YouTube的视频,但是其他类型的网页视频基本看不了(除了ogg、webM等)。因为很多格式是需要H.264 License,所以插件默认不支持观看。但是插件提供了试用方法,打包后也是有效的。
3.方便使用
插件提供了几种预制体,可以拖拽到场景中快速上手使用。
4.屏幕键盘
插件提供了屏幕键盘,方便在触摸屏上使用。
5.由Chromium支持
6.可以与前端js交互
7.监听浏览器事件
例如TitleChanged、UrlChanged 以及 PageLoadFailed
8.查看PDF
9.支持世界坐标系和画布
10.包括额外的 Chromium 专用 API
11.支持透明页面
三、系统要求
• Windows 8+ (x64, x86) 以及 D3D11 显卡
• macOS 10.10+ (x64) 以及 Metal 显卡
• Unity 5.6+(由于 Unity 的一个程序漏洞,Windows 不支持 2017.3 - 2018.1 版本)
四、问题解决
官网上有很多实用的文章和教程,能够解决遇到的大部分问题。官方文档https://support.vuplex.com/search 其他零碎问题:输入法、中文输入、开启上传文件、开启下载文件、文件保存位置、光标状态、页面内拖拽或拖拽滑动页面、cookie的增删改查。
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using UnityEngine; using Vuplex.WebView; using Vuplex.WebView.Demos; using Debug = UnityEngine.Debug; /// <summary> /// 解决webview输入问题 没有这个脚本,不能正常输入 /// (解决中文输入是在CanvasWebViewPrefab.cs Input.imeCompositionMode = IMECompositionMode.On;) /// 解决在Windows平台上传文件,打开选择文件对话框 /// </summary> public class WebViewKeyBoardInput : MonoBehaviour { private CanvasWebViewPrefab canvasWebView; HardwareKeyboardListener _hardwareKeyboardListener; public System.Action<ProgressChangedEventArgs> OnLoadProgressChanged; async void Start() { canvasWebView = transform.GetComponent<CanvasWebViewPrefab>(); #region 输入框输入功能 _setUpHardwareKeyboard(canvasWebView); #endregion await canvasWebView.WaitUntilInitialized(); #region 开启上传功能 var standaloneWebView = canvasWebView.WebView as StandaloneWebView; standaloneWebView.SetNativeFileDialogEnabled(true); #endregion #region 开启下载功能 var webViewWithDownloads = canvasWebView.WebView as IWithDownloads; if (webViewWithDownloads == null) { Debug.Log("This 3D WebView plugin doesn't yet support IWithDownloads: " + canvasWebView.WebView.PluginType); return; } webViewWithDownloads.SetDownloadsEnabled(true); webViewWithDownloads.DownloadProgressChanged += (sender, eventArgs) => { Debug.Log($@"DownloadProgressChanged: Type: {eventArgs.Type}, Url: {eventArgs.Url}, Progress: {eventArgs.Progress}, Id: {eventArgs.Id}, FilePath: {eventArgs.FilePath}, ContentType: {eventArgs.ContentType}" ); if (eventArgs.Type == ProgressChangeType.Finished) { Debug.Log("Download finished"); // 默认下载路径是 Application.temporaryCachePath(Appdata/Local/Temp/公司名/应用名) string[] filePath = eventArgs.FilePath.Split('\\'); string fileName = filePath[filePath.Length - 1]; //如果原来路径上存在该文件 则需要删除后在进行移动 if(File.Exists(Application.dataPath + "/../Download/" + fileName)) { File.Delete(Application.dataPath + "/../Download/" + fileName); } //移动到指定的固定位置 File.Move(eventArgs.FilePath, Application.dataPath + "/../Download/" + fileName); //打开下载文件的目录 Application.OpenURL($"File://{Application.dataPath}/../Download/"); //只能打开绝对路径 //string newPath = Application.dataPath + "/../Download/" + fileName; //WindowsTools.ExplorerFile(newPath); } }; #endregion #region file选择 新版3dwebview4.2支持自定义文件对话框(也有bug,多次选择没有效果) //var webViewWithFileSelection = canvasWebView.WebView as IWithFileSelection; //if (webViewWithFileSelection != null) //{ // webViewWithFileSelection.FileSelectionRequested += (sender, eventArgs) => // { // // Note: Here's where the application could use a system API or third party // // asset to show a file selection UI and then pass the selected file(s) to // // the Continue() callback. // var filePaths = new string[] { OpenWindowDialog() }; // eventArgs.Continue(filePaths); // }; //} #endregion #region 页面加载失败回调 canvasWebView.WebView.PageLoadFailed += WebView_PageLoadFailed; #endregion #region 加载进度 新版插件才支持 canvasWebView.WebView.LoadProgressChanged += (sender, args) => { if(OnLoadProgressChanged!=null) { OnLoadProgressChanged.Invoke(args); } }; #endregion #region 光标状态 新版插件才支持 #endregion } /// <summary> /// 页面加载失败回调 失败后显示提示,同时让浏览器加载空页面防止出现404界面 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void WebView_PageLoadFailed(object sender, System.EventArgs e) { WindowsTools.MessageBox(System.IntPtr.Zero, "数据加载失败,请检查是否可以连接到服务器!", "错误", 0); canvasWebView.WebView.LoadUrl("about:blank"); } void _setUpHardwareKeyboard(CanvasWebViewPrefab webView) { _hardwareKeyboardListener = HardwareKeyboardListener.Instantiate(); _hardwareKeyboardListener.KeyDownReceived += (sender, eventArgs) => { var webViewWithKeyDown = webView.WebView as IWithKeyDownAndUp; if (webViewWithKeyDown != null) { webViewWithKeyDown.KeyDown(eventArgs.Value, eventArgs.Modifiers); } else { webView.WebView.SendKey(eventArgs.Value); } }; _hardwareKeyboardListener.KeyUpReceived += (sender, eventArgs) => { var webViewWithKeyUp = webView.WebView as IWithKeyDownAndUp; webViewWithKeyUp?.KeyUp(eventArgs.Value, eventArgs.Modifiers); }; } float timer = 0; private void Update() { //让弹窗保持在最前端 因为不知道什么时候才有弹窗,所以循环查找 timer += Time.deltaTime; if(timer >= 0.5f) { SetFileDialogFor(); timer = 0; } } private void SetFileDialogFor() { IntPtr hWnd =WindowsTools.FindWindow(null,"Open Files"); if (hWnd == IntPtr.Zero) hWnd = WindowsTools.FindWindow(null, "Open File"); if(hWnd != IntPtr.Zero) WindowsTools.SetForegroundWindow(hWnd); } }
cookie操作
//保存cookie private async void SetWebCookie(string cookieValue) { if (Web.CookieManager == null) { Debug.Log("Web.CookieManager isn't supported on this platform."); return; } string[] urlSplit = loginUrl.Split(':'); var success = await Web.CookieManager.SetCookie(new Cookie { Domain = urlSplit[1].Replace("//", ""), Path = "/", Name = "Admin-Token", Value = cookieValue, //到期时间7天 ExpirationDate = (int)DateTimeOffset.Now.ToUnixTimeSeconds() + 60 * 60 * 24* 7, HttpOnly = false, Secure = false }); Debug.Log($"保存cookie {success}!"); } //获取cookie private async void GetCookie() { if (Web.CookieManager == null) { Debug.Log("Web.CookieManager isn't supported on this platform."); return; } var cookies = await Web.CookieManager.GetCookies("http://192.168.32.227"); if (cookies.Length > 0) { Debug.Log("Cookie: " + cookies[0]); } else { Debug.Log("Cookie not found."); } }
我想知道,使用3D webview的时候能否达到这样的需求。
我有一个可以全屏幕拖动的悬浮框层级在webview之上,点击这个悬浮框可以弹出对话框提示用户是否确认关闭webview。
需求是这个悬浮框不会影响webview的渲染以及点击事件,对话框层级同样是在webview上面,在对话框出现时无法穿透点击webview。
期待您的回复
应该是能实现的,当你使用CanvasWebViewPrefab作为渲染网页的载体,它就相当于UGUI中的挂Image的物体。
你好 我用这个插件单独运行时没问题,但是放进项目中就会卡,延迟也很大,请问应怎么解决呢
提供的信息太少了,没办法判断是插件的原因,还是你项目中其它功能的原因。