原文: 關于CefSharp的坎坷之路
項目背景:
公司的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時會有對每個标簽的描述資訊,根據描述資訊可以得知<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 }
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");
憶往昔歲月,已然猶記此些。
結後語:
第一次認真編寫部落格,排版等還有待完善。希望各位博友多鼓勵,多指教。
我近期設立了一個小目标:(比如 先賺他一個億,哈哈) 多發博文和博友互動,整理思路,彌補不足,多學習開源,參與開源。忘自己以後會越來越牛~~~~~~~