- 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的物体。
你好 我用这个插件单独运行时没问题,但是放进项目中就会卡,延迟也很大,请问应怎么解决呢
提供的信息太少了,没办法判断是插件的原因,还是你项目中其它功能的原因。