項目背景:
公司的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時會有對每個標簽的描述信息,根據描述信息可以得知<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 resolved 6 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 -- 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 }
測試運行后發現在CefSharp使用,不起作用。因為我們訪問頁面一開始是通過file:///url的方式進行本地訪問的。有經驗的朋友會發現,瀏覽器很多(比如調動攝像頭)的操作只支持安全源訪問,並且有的瀏覽器會提示是否允許啟動攝像頭。
為了能使用攝像頭所以需要啟動web 服務,以http或者localhost的方式進行訪問。因為,通過HttpListener搭建了個Web 服務,然后測CefSharp3的頁面依舊不可以調用攝像頭,經過通過其他瀏覽器調用顯示沒有問題。
這下又一頭霧水,經過查閱資料,滾滾洪水中找到了那一顆螺絲釘,又位使用過CefSharp的一位 博主的博客 的說明中提到了 CefSharp要進行參數配置的如下:
在CefCommandLineArgs添加了enable-media-stream參數,意思是啟用媒體流
//主要是配置開啟Media的命令參數,此配置可以允許攝像頭打開攝像 settings.CefCommandLineArgs.Add("enable-media-stream", "1");
憶往昔歲月,已然猶記此些。
結后語:
第一次認真編寫博客,排版等還有待完善。希望各位博友多鼓勵,多指教。