項目背景:
公司的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");