项目背景:
公司的XX产品需要升级和以后支持多平台的使用。因为之前项目是由WPF实现的。目前以后想作为Html5来展示页面。
因为涉及到整体更改遇到的问题较多以及其他原因,所以只是内部内容区域先替换为Html5页面,所以需要嵌入Browser控件。
Browser控件的选型:
1.Winform中的WebBrowser
2.WPF中的WebBrowser
3.WebKit.Net
4.CefSharp
5.awesominum
6.OpenWebKitSharp
7. geckofx
经过初步查阅,WebKit.Net、OpenWebKitSharp 和geckofx 都是基于Winform的。CefSharp 在GitHub有源码,并且具备Winform和WPF的版本。awesominum可以允许把网页嵌入到 3D 画面或游戏中,支持unity3D。
经过尝试.Net中的Winform版本的WebBrowser,背景无法直接设置透明, 需要通过Windows Api进行处理(仅查阅,未实际进行处理和验证)。
首先把Winform的WebBrowser放到项目中进行了实验和处理,发现两个致命问题:一个是背景不透明,因为整个背景具有渐变和过渡效果。第二个是,页面切换具有滑动过渡效果。
Winform版的WebBrowser会悬浮最上层,不会渐变隐藏消失。 基于以上两点,针对Winform和基于Winform的其他暂时不在考虑。
(调研其他基于Winform的第三方控件没有具体查看是否内部已经处理这些问题,喜欢深入研究的同学或使用过的同学也可以告诉我啊)
目前 调研CefSharp和Awesominum。
CefSharp的源码Demo进行测试,目前是符合需求。Awesominum初步查看也符合需求。
特定需求:在某个Html5页面中 需要调用摄像头进行录像拍摄。
现象:在CefSharp的初步显示具备摄像头打开的页面时,无法打开摄像头。开始查找问题,最后发现 要给CefSharp的CommandLineArgs添加一些命令才可以显示处理,并且要启动WebServer服务。(后面会详细讲解此问题)
而在Awesominum中未找到可以添加命令行参数的方法,所以姑且放弃。最好还是先选用CefSharp。
目前,引用CefSharp,我是通过Nuget进行获取安装的。
关于Nuget的使用,大家可以自行搜索使用。Nuget还可以自己搭建公司专属的插件服务器和客户端调用。
其中需要注意的是:
1.使用正确的Package source资源地址进行搜索下载。
如下图,在搜搜CefSharp的时候,要使用nuget.org地址或All下载资源,这样才能搜索到CefSharp,Microsoft Visual Studio Offline Packages 则是针对微软的一些插件和应用包。
2.插件的安装和卸载都要要用Nuget进行处理
在使用过程中,有时候会遇到解决方案打开,然后操作生成项目时,提示正在恢复还原Nuget包,然后,然后,就一直然后了... 那叫个等的花都谢了。强制关闭,下次还是会有滴。还是放弃抵抗吧。
如果Nuget的包恢复和还原出来错活着不需要了,还是通过Nuget进行卸载,以免有残留。真是不使用不知道,一使用全乱套,啊哈哈~~~~
纯属个人体会,个中滋味,各自体会。
----------------以下为使用CefSharp过程中,个人遇到的一些问题和注意事项------------------------
一:引用CefSharp的编译需要指定目标平台X86或X64
在我们解决方案中,一般默认都是AnyCup的,所以在生成时会提示错误。
因为CefSharp的使用需要明确目标平台的。所以生成时,要指定是x86还是x64,因为我们项目需要 要改为X86. 有的会问,我已经修改目标平台为x86了,如下图 位置:1、2处。而编译还是生成不成功呢?这是为什么呢?为什么呢?
请不要在项目的属性上进行设置。要在整个解决方案的配置上进行设置 引用CefSharp的项目的Platform 平台。仔细看你会发现 解决方案的的项目的平台如下图 位置3处和 项目属性中是不一致的呢。所以切记。
二:CefSharp中的生成目录的问题
在我们项目中,CefSharp的项目是作为插件的方式嵌入主框架中的,所以生成目录到了根目录下的Plugins目录下。运行后,你会发现一直提示无法找到CefSharp.core.dll等相关的dll文件。 哈哈,找不到,找不到就对了。
CefSharp是到根目录下(默认是指Bin)的环境中寻找dll的,所以无法进行找到。暂时也未从源码案例中找到进行设置目录的方式(若其他忍知晓可以告知我哦)。
不过这样也不要紧,不就是在程序的运行环境中找不到吗?我们自己添加上不就行了。代码如下:
var pluginsPath = Path.Combine(Environment.CurrentDirectory, "Plugins"); var path = Environment.GetEnvironmentVariable("PATH") + ";" + pluginsPath; Environment.SetEnvironmentVariable("PATH", path, EnvironmentVariableTarget.Process);
在程序运行启动时,把对应的环境变量路径添加上Plugins的路径。运行起来,你会发现可以了。
三:关于CefSharp生成时产生的各种文件是否项目都必须用到的问题
比如,生成的文件中有扩展名为.pak的文件,pak文件是一种特殊的文件压缩格式。 比较常应用于游戏。 关于此类文件,在使用CefSharp也需要具备此类文件。
网上搜索:将locales及其下所有都设置为输出,里面有个en-US.pak文件,如没有,则应用程序会启动显示错误退出。再将devtools_resources.pak 设置为输出,否则调用devtools时将报错不能打开。(常见问题官网解释)通过在CefSharp的源码中搜索也确实使用到了pak文件,所以此类文件也不可缺少。四:关于CefSharp显示页面一直闪烁的问题。
具体查找过程就不详述,只能一把鼻涕一把泪的说 那也是一个煎熬的过程,不能说问题有多大,只能说很小的问题,没有找对方向。现在就把问题告诉大家。
经过和从GitHub下载的CefSharp3的源码进行对比,最终发现,我们未进行配置app.manifest文件的配置,大神们也许很多app.manifest文件的用途,而对于我这种不踩一两次坑,不长教训的,以前都会轻轻掠过这种东西。
app.manifest的文件可以通过添加文件来自动生成。也可以从源码中拷贝过来。然后在项目的属性=》应用(Application)中进行Resources=》Manifest配置上。下面描述app.manifest的描述的功能。
其中主要 代码片段入下:
12 24 25 29 303 6 7 8 239 10 11 12 13 14 15 16 17 18 19 20 21 22 31 32 34true 33
自动添加app.manifest时会有对每个标签的描述信息,根据描述信息可以得知<dpiAware>true</dpiAware>其实是设置适应高高dpi对程序的影响。目前很多电脑都是高dpi的。
应该是 不同操作系统下,渲染机制是有区别的,所以为了更好的适应高dpi和不同系统的影响,所以最好不同的系统可以按照自己专属的环境进行处理,而supportedOs标签的设置解决了这类问题。
五:关于Windows8.1系统运行程序 页面依旧闪烁的原因。
在配置好app.manifest之后,以为可以源码的解决了页面闪烁的问题。而后,被告知Windows8.1的系统却依旧闪烁。这下又懵逼了~~懵逼~~了~~~!!!
后来又仔细阅读关于CefSharp中的代码和各种配置,在源码CefSharp3的命令行参数CefCommandLineArgs的配置中惊奇的发现了下面一段代码:
1 var osVersion = Environment.OSVersion;2 //Disable GPU for Windows 7 3 if (osVersion.Version.Major == 6 && osVersion.Version.Minor == 1)4 {5 // Disable GPU in WPF and Offscreen examples until #1634 has been resolved6 settings.CefCommandLineArgs.Add("disable-gpu", "1");7 }
其中,Major和Minor分别指代系统的主版本(大版本)、次版本(小版本)版本号。其中指定了Windows7系统会禁用 GPU。,突发奇想,是否windows8.1也是因为这个问题?然后开始验证。
所以,经查阅,各系统的对应版本如下:
系统的主版本、次版本
1 Windows 10 -- 10.0* 2 Windows Server 2016 Technical Preview -- 10.0* 3 Windows 8.1 -- 6.3* 4 Windows Server 2012 R2 -- 6.3* 5 Windows 8 -- 6.2 6 Windows Server 2012 --6.2 7 Windows 7 -- 6.1 8 Windows Server 2008 R2 -- 6.1 9 Windows Server 2008 -- 610 Windows Vista -- 611 Windows Server 2003 R2 -- 5.212 Windows Server 2003 -- 5.213 Windows XP 64-Bit Edition -- 5.214 Windows XP -- 5.115 Windows 2000 -- 5
如上图得知,若判断是否为Windows8.1系统,判断osVersion.Version.Major == 6 && osVersion.Version.Minor == 3 即可,
但是不知源码中 为何要判断windows7的禁用GPU,在windows7下取消禁用GPU的测试,发现页面并未闪烁。
但是为了安全起见,并且身边没有window8和其他的系统,所以决定,应用CefSharp的时候,配置CefCommandLineArgs进行了只判断osVersion.Version.Major == 6的处理,即windows8.1、windows8、windows7等都禁用了GPU。
暂且不知,这以后是否会成为历史遗留问题~~~~~嘻嘻~~。
六:关于 调试状态运行程序不报错,但是页面却一直未显示的问题
直接运行exe程序,提示找不到 CefSharp.BrowserSubprocess.exe和CefSharp.Core.dll等missing的问题。
在操作cefsharp项目并拷贝文件到输出目录过程中,会未对CefSharp.BrowserSubprocess.exe进行处理,导致CefSharp对应的运行环境下未有CefSharp.BrowserSubprocess.exe文件。
而CefSharp的浏览器是需要依赖此文件的,所以,才会出现页面显示不出画面的问题。CefSharp.BrowserSubprocess.exe文件是安装Nuget时自动下载下来的,但是在项目应用过程中,并不会拷贝生成到特定的输出目录下,
所以,想把此文件进行保存下载,上次到源码管理中,生成的时候也自动复制到输出目录,以避免丢失此文件而报错的情况。
处理方式:
在项目中添加了Files文件,并把CefSharp.BrowserSubprocess.exe 放入其中,设置属性为Content和Copy Always
设置项目生成成功后的脚本,拷贝到运行环境目录 即可。
七:关于使用CefSharp起用摄像头的问题
为什么要针对这个问题拿出来说一说你呢?可能会有人问:调用摄像头不是js操作的问题吗?跟CefSharp有什么关系。 请往下看eb( ̄▽ ̄)d
因项目要显示的网页中 有一个需要打开摄像头拍照的功能,js的代码如下:
1 var mediaStream = null, track = null; 2 var video; 3 var n = 0; 4 navigator.getMedia = (navigator.getUserMedia || 5 navigator.webkitGetUserMedia || navigator.mozGetUserMedia || 6 navigator.msGetUserMedia); 7 if (navigator.getMedia) { 8 navigator.getMedia( 9 {10 video: true11 },12 // successCallback13 function (stream) {14 var s = window.URL.createObjectURL(stream);15 video = document.getElementById('video');16 video.src = window.URL.createObjectURL(stream);17 mediaStream = stream;18 track = stream.getTracks()[0];19 $scope.photoBtnDiable = false; $scope.$apply();20 },21 // errorCallback22 function (err) {23 $scope.errorPhoto();24 console.log("The following error occured:" + err);25 });26 } else {27 $scope.errorPhoto();28 }29 //拍照30 $scope.snap = function () {31 var canvas1 = document.getElementById('canvas1');32 var canvas2 = document.getElementById('canvas2');33 34 var ctx1 = canvas1.getContext('2d');35 var ctx2 = canvas2.getContext('2d');36 37 ctx1.drawImage(video, 0, 0, canvas1.width, canvas1.height);38 n++;39 if (n % 2 == 0) {40 ctx2.drawImage(video, 0, 0, canvas2.width, canvas2.height);41 } else {42 ctx1.drawImage(video, 0, 0, canvas1.width, canvas1.height);43 }44 //$uibModalInstance.close(canvas.toDataURL("image/png"));45 };46 //关闭摄像头47 $scope.closeCamera = function () {48 if (mediaStream != null) {49 if (mediaStream.stop) {50 mediaStream.stop();51 }52 $scope.videosrc = "";53 }54 if (track != null) {55 if (track.stop) {56 track.stop();57 }58 }59 }
测试运行后发现在CefSharp使用,不起作用。因为我们访问页面一开始是通过file:///url的方式进行本地访问的。有经验的朋友会发现,浏览器很多(比如调动摄像头)的操作只支持安全源访问,并且有的浏览器会提示是否允许启动摄像头。
为了能使用摄像头所以需要启动web 服务,以http或者localhost的方式进行访问。因为,通过HttpListener搭建了个Web 服务,然后测CefSharp3的页面依旧不可以调用摄像头,经过通过其他浏览器调用显示没有问题。
这下又一头雾水,经过查阅资料,滚滚洪水中找到了那一颗螺丝钉,又位使用过CefSharp的一位 的说明中提到了 CefSharp要进行参数配置的如下:
在CefCommandLineArgs添加了enable-media-stream参数,意思是启用媒体流
//主要是配置开启Media的命令参数,此配置可以允许摄像头打开摄像 settings.CefCommandLineArgs.Add("enable-media-stream", "1");
忆往昔岁月,已然犹记此些。
结后语:
第一次认真编写博客,排版等还有待完善。希望各位博友多鼓励,多指教。
我近期设立了一个小目标:(比如 先赚他一个亿,哈哈) 多发博文和博友互动,整理思路,弥补不足,多学习开源,参与开源。忘自己以后会越来越牛~~~~~~~