Guide 開髮指南

快速開發桌面應用

在fibjs 中啟動一個桌面應用是很快的,只需要鍵入以下代碼,即可打開並運行一個WebView 窗口:

1 2 3 4 5
var gui = require("gui"); gui.open("https://fibjs.org", { "type": "native" });

這段代碼會打開一個操作系統內置的WebView 窗口,並進入fibjs.org 的網站。

然而,系統內置的WebView 無論在接口功能還是兼容性,都不能滿足強大的桌面應用開發。因此fibjs 還支持基於cef 的應用開發。

cef 簡介

cef 全稱Chromium Embedded Framework,是一個基於Google Chromium 的開源項目。Google Chromium 項目主要是為Google Chrome 應用開發的,而cef 的目標則是為第三方應用提供可嵌入瀏覽器支持。cef 隔離底層Chromium 和Blink 的複雜代碼,並提供一套產品級穩定的API,發布跟踪具體Chromium 版本的分支,以及二進制包。cef 的大部分特性都提供了豐富的默認實現,讓使用者做盡量少的定制即可滿足需求。cef 的典型應用場景包括:

  • 嵌入一​​個兼容HTML5 的瀏覽器控件到一個已經存在的本地應用。
  • 創建一個輕量化的殼瀏覽器,用以託管主要用Web 技術開發的應用。
  • 有些應用有獨立的繪製框架,使用cef 對Web 內容做離線渲染。
  • 使用cef 做自動化Web 測試。

cef3 是基於Chomuim Content API 多進程構架的下一代cef,擁有下列優勢:

  • 改進的性能和穩定性(JavaScript 和插件在一個獨立的進程內執行)。
  • 支持Retina 顯示器。
  • 支持WebGL 和3D CSS 的GPU 加速。
  • 類似WebRTC 和語音輸入這樣的前衛特性。
  • 通過DevTools 遠程調試協議以及ChromeDriver2 提供更好的自動化UI測試。
  • 更快獲得當前以及未來的Web 特性和標準的能力。

準備運行環境

cef3的二進制包可以在[這個頁面]下載,當前fibjs所對應的版本是v90。其中包含了在特定平台(Windows,Mac OS X以及Linux)編譯特定版本cef3所需的全部文件。不同平台的目錄結構不太,你需要在下載後重新組織資源目錄結構。

Windows 操作系統(Windows)

在Windows平台上文件夾結構大致如下,你通常可以在二進制包內的ReleaseResources目錄下找到全部文件:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Application ├── fibjs.exe ├── chrome_100_percent.pak ├── chrome_200_percent.pak ├── chrome_elf.dll ├── d3dcompiler_47.dll ├── icudtl.dat ├── libEGL.dll ├── libGLESv2.dll ├── libcef.dll ├── locales │ ├── am.pak │ ├── ...... │ └── zh-TW.pak ├── resources.pak ├── snapshot_blob.bin ├── swiftshader │ ├── libEGL.dll │ └── libGLESv2.dll └── v8_context_snapshot.bin

Linux 操作系統(Linux)

在Linux平台上文件夾結構大致如下,你通常可以在二進制包內的ReleaseResources目錄下找到全部文件:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
Application ├── fibjs ├── chrome_100_percent.pak ├── chrome_200_percent.pak ├── icudtl.dat ├── libEGL.so ├── libGLESv2.so ├── libcef.so ├── locales │ ├── am.pak │ ├── ...... │ └── zh-TW.pak ├── resources.pak ├── snapshot_blob.bin ├── swiftshader │ ├── libEGL.so │ └── libGLESv2.so └── v8_context_snapshot.bin

在Linux Server上因為沒有桌面環境支持,只可以以--headless模式運行,當以無窗口模式運行時,需要安裝xorg:

1
apt install xorg

在一些gpu支持不好的Linux Desktop,還需要增加--disable-gpu啟動選項禁用gpu渲染。

Mac X 平台(Mac OS X)

在Mac X平台上文件夾結構大致如下,你通常可以在二進制包內的Release/Chromium Embedded Framework.framework目錄下找到全部文件,如果你下載的是cefclient,那麼你需要打開app的Contents找到相應的文件:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Application ├── fibjs ├── Chromium Embedded Framework ├── Libraries │ ├── libEGL.dylib │ ├── libGLESv2.dylib │ ├── libswiftshader_libEGL.dylib │ ├── libswiftshader_libGLESv2.dylib │ ├── libvk_swiftshader.dylib │ └── vk_swiftshader_icd.json └── Resources ├── Info.plist ├── ...... └── zh_TW.lproj └── locale.pak

你還可以使用gui.config設置cef_path來指定cef的二進制路徑,從而更加靈活地部署運行環境。當未設定cef_path時,cef二進製文件必須與fibjs執行文件部署在同一個目錄下。

1 2 3
gui.config({ "cef_path": cef_path });

準備好運行環境,再運行以下代碼

1 2 3 4 5
var gui = require("gui"); gui.open("https://fibjs.org", { // "type": "native" });

同樣會看到一個加載了fibjs官網的瀏覽器窗口,但是它的引擎已經是最新的Chrome內核了。注意此處需要取消type選項,否則還將打開os內置的webview。

gui 的基礎應用十分簡便,參照gui 文檔即可迅速實現,不再贅述。接下來主要介紹一些特別的應用方式。

前後端服務對接

基於web 的桌面應用通常有兩種擴展方式,一種是WebView 擴展,另一種是在本地實現前後端分離。前一種方式,對WebView 做了侵入式擴展,運行環境與標準的瀏覽器其實已經不再兼容。後一種方式則需要在本地開啟一個http Server,這樣又導致服務接口對外暴露。

fibjs針對桌面應用的擴展,基於cef的協議擴展能力,將WebView和fibjs的Handler融合在一起,使得WebView可以在進程內直接連接到對應的Handler處理器,在完全兼容傳統B/S前後端開發範式的同時,確保了安全性和可移植性。同時前後端代碼,也與標準的B/S前後端開發完全一致,可以在瀏覽器內開發調試,然後直接移植為本地應用。

fibjs配置後端處理器的方式,是通過gui.config完成的。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
gui.config({ "backend": { "cef://test/": cef_files_path, "http://cef_test/": { "/mock/:act": (r, a) => { if (a == 'header') { r.response.write(r.firstHeader('test')); r.response.addHeader("test", "world"); } else if (a == 'post') { r.response.write(`[${r.firstHeader("Content-type")}]`); r.response.write(r.body.readAll()); } }, "/*": cef_files_path } } });

這段代碼定義了兩個後端,一個是cef協議的test domain,指向靜態目錄cef_files_path,另一個是http的cef_test domain,指向一個路由。

在cef 裡,對非標準協議的處理有一些限制,比如不支持向服務器post 數據,因此如果希望兼容性更好的前後端通信,需要定義http 或者https 後端,當然這個後端也並不是通過網絡協議完成通信,而是在進程內部直接對接的。

關於如何開發Handler 後端,可以參閱:hello, world

無窗口模式

在自動化測試或者流程自動化場景中,業務運行過程無需用戶交互,因此可以以無窗口模式在服務器上自動運行。這時就需要headless 模式來運行。

fibjs 支持兩種方式的headless,分別是全局headless 和實例headless。

全局模式下,所有的窗口都將以headless模式運行,無論創建窗口是是如何設定的。全局模式的運行方式,是指定--headless啟動選項。

1
fibjs --headless test.js

在程序啟動時調用gui.config配置也可以達到同樣的目標:

1 2 3
gui.config({ "headless": true });

在Linux Server 下,雖然headless 模式不需要桌面支持,但是cef 基礎模塊仍需要一些基礎組件支持,因此需要安裝xorg:

1
apt install xorg

在一些應用裡,需要同時存在用戶交互和自動化處理,這時可以單獨指定某個窗口使用headless 模式:

1 2 3
var win = gui.open("https://fibjs.org", { "headless": true });

需要注意的是,headless 實例因為沒有用戶交互,不能被用戶主動關閉,因此程序要在不需要的時候自行關閉,否則因為實例的存在,進程將不會自動退出。

DevTools 接口

Chrome DevTools Protocol 允許工具對Chromium,Chrome 和其它基於Blink 的瀏覽器進行測試、檢查、調試以及配置。Chrome DevTools Protocol 被分為多個域(DOM,Debugger,Network 等),每個域定義了相應支持的commands 和相關的events。

fibjs封裝了cdp的訪問接口,可以充分運用cef內置的cdp接口,直接調試WebView內的網頁。WebView用於訪問cdp服務的接口,是WebView.dev。關於cdp的詳細文檔,可以參閱:https://chromedevtools.github.io/devtools-protocol/

以下列舉的是幾個常用的代碼片段,用於展示如何使用dev操控頁面元素。詳細的使用演示,可以參閱test/cef_test.js

查詢DOM

1 2 3 4 5 6 7 8 9 10 11 12 13
function getOuterHTML(win, selector) { var doc = win.dev.DOM.getDocument(); var e = win.dev.DOM.querySelector({ "nodeId": doc.root.nodeId, "selector": selector }); var html = win.dev.DOM.getOuterHTML({ "nodeId": e.nodeId }); return html.outerHTML; }

模擬鼠標操作

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
function click(win, selector) { var doc = win.dev.DOM.getDocument(); var e = win.dev.DOM.querySelector({ "nodeId": doc.root.nodeId, "selector": selector }); var box = win.dev.DOM.getBoxModel({ "nodeId": e.nodeId }); var mi = { "x": box.model.content[0] + 1, "y": box.model.content[1] + 1, "button": 'left', "clickCount": 1 } mi.type = "mousePressed"; win.dev.Input.dispatchMouseEvent(mi); mi.type = "mouseReleased"; win.dev.Input.dispatchMouseEvent(mi); }

模擬鍵盤操作

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
function type(win, text) { for (char of text) { win.dev.Input.dispatchKeyEvent({ "type": "char", "text": char }); } } function press(win, key) { var code = key_code[key]; var ki = { "key": key, "code": key, "windowsVirtualKeyCode": code, "nativeVirtualKeyCode": code }; ki.type = "keyDown"; win.dev.Input.dispatchKeyEvent(ki); ki.type = "keyUp"; win.dev.Input.dispatchKeyEvent(ki); }

頁面截屏

1 2 3 4 5 6 7 8 9 10 11
var ret = win.dev.Page.captureScreenshot({ clip: { "x": 0, "y": 0, "width": 100, "height": 100, "scale": 1 } }); var img = gd.load(encoding.base64.decode(ret.data));

模擬User-Agent

1 2 3 4 5 6 7 8 9
var win = gui.open(); win.on('open', () => { win.dev.Network.setUserAgentOverride({ userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_1 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) Version/10.0 Mobile/14A403 Safari/602.1', }); win.loadUrl('https://fibjs.org'); });

監聽事件

1 2 3 4 5 6 7 8 9
var win = gui.open(); win.on('open', () => { win.dev.Page.enable(); win.dev.Page.on("frameNavigated", ev => { console.log(ev.frame.url); win.close(); }); });

多媒體支持

因為版權問題,cef 的二進制發行版中通常不包含mp4 和mp3 的解碼。但是cef 中包含開源的webm 解碼,對於獨立的桌面應用,建議使用免費授權的webm 編碼處理音頻和視頻。

小結

通過這個小節的介紹,我們可以快速開發自己的桌面應用,將html 渲染成圖片或者PDF,利用cdp 的強大接口建立前端自動化測試和流程自動化引擎。

👉 【服務端模塊熱更新