項目背景:
公司的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的描述的功能。
其中主要 代碼片段入下:
- 1 <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
- 2 <application>
- 3 <!-- A list of the Windows versions that this application has been tested on and is
- 4 is designed to work with. Uncomment the appropriate elements and Windows will
- 5 automatically selected the most compatible environment. -->
- 6
- 7 <!-- Windows Vista -->
- 8 <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
- 9
- 10 <!-- Windows 7 -->
- 11 <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
- 12
- 13 <!-- Windows 8 -->
- 14 <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
- 15
- 16 <!-- Windows 8.1 -->
- 17 <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
- 18
- 19 <!-- Windows 10 -->
- 20 <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
- 21
- 22 </application>
- 23 </compatibility>
- 24
- 25 <!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
- 26 DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
- 27 to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
- 28 also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
- 29
- 30 <application xmlns="urn:schemas-microsoft-com:asm.v3">
- 31 <windowsSettings>
- 32 <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
- 33 </windowsSettings>
- 34 </application>
app.manifest的主要代碼片段
自動添加app.manifest時會有對每個標簽的描述信息,根據描述信息可以得知true其實是設置適應高高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 resolved
- 6 settings.CefCommandLineArgs.Add("disable-gpu", "1");
- 7 }
CefSharp禁用GPU的命令行參數
其中,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 -- 6
- 10 Windows Vista -- 6
- 11 Windows Server 2003 R2 -- 5.2
- 12 Windows Server 2003 -- 5.2
- 13 Windows XP 64-Bit Edition -- 5.2
- 14 Windows XP -- 5.1
- 15 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: true
- 11 },
- 12 // successCallback
- 13 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 // errorCallback
- 22 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 }
JS調用攝像頭拍照代碼
測試運行后發現在CefSharp使用,不起作用。因為我們訪問頁面一開始是通過file:///url的方式進行本地訪問的。有經驗的朋友會發現,瀏覽器很多(比如調動攝像頭)的操作只支持安全源訪問,並且有的瀏覽器會提示是否允許啟動攝像頭。
為了能使用攝像頭所以需要啟動web 服務,以http或者localhost的方式進行訪問。因為,通過HttpListener搭建了個Web 服務,然后測CefSharp3的頁面依舊不可以調用攝像頭,經過通過其他瀏覽器調用顯示沒有問題。
這下又一頭霧水,經過查閱資料,滾滾洪水中找到了那一顆螺絲釘,又位使用過CefSharp的一位 博主的博客 的說明中提到了 CefSharp要進行參數配置的如下:
在CefCommandLineArgs添加了enable-media-stream參數,意思是啟用媒體流
- //主要是配置開啟Media的命令參數,此配置可以允許攝像頭打開攝像
- settings.CefCommandLineArgs.Add("enable-media-stream", "1");