第0.1節 HTML5和桌面軟件開發的碰撞
當我們談論桌面軟件開發技術的時候,你會想到什么?如果不對技術本身進行更為深入的探討,在我的世界里,有這么多技術概念可以被羅列出來(請原諒我本質上是一個Windows程序員的事實)。
操作系統 API。操作系統發展到今日,幾乎桌面應用的所有功能,都是基於系統API構建的。調用API和語言及技術無關,哪怕是使用匯編。例如(代碼來源於網絡,本地重新編譯):
;我的第一個win32匯編程序
;一個經典的hello world !程序
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;頭文件的定義
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
include kernel32.inc
includelib user32.lib
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;數據段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
szCaption db '我的第一個win32程序',0
szText db 'hello world !',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;代碼段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
start:
invoke MessageBox,NULL,offset szText,offset szCaption,MB_OK
invoke ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
代碼清單0-1 匯編MessageBox
在代碼清單0-1中,通過匯編調用MessageBox Api來呈現一個簡單窗口程序。
代碼清單0-1的運行結果如下:
圖0-1 代碼清單0-1運行結果
同樣的,我們使用c/c++來調用這樣一個win32 API,代碼可能是如下這樣的:
#include "windows.h"
int main()
{
MessageBox(NULL, (LPCWSTR)L"Hello world!",
(LPCWSTR)L"我的第一個win32應用程序", MB_OK);
return 0;
}
代碼清單0-2 c/c++版MessageBox
代碼清單0-2運行結果如下圖:
圖0-2 代碼清單0-2運行結果
在系統API之上,經過抽象與封裝在各個操作系統上,形成了各自的所謂的庫和框架。比如windows的MFC和Delphi等,Linux的Gnome、GTK+、KDE等,Max OS X平台的Cocoa開發庫。對於系統API的強依賴性,直接導致的問題是桌面應用的可移植性,開發人員不得不針對不同平台的操作系統(即使同一平台也不一定能良好兼容)編寫不同的代碼。另外即使你已經編寫了不同的代碼來適配不同的操作系統和平台,仍然沒有辦法保證桌面應用的UI和交互是一致的,這一點上有的開發者認為一致反而是障礙,因為不同平台下的用戶的桌面應用的使用習慣是不一樣的。但是UI呢?我覺得保證UI一致是極其有必要的。
筆者接觸到的最早的跨平台桌面UI庫是Qt。
Qt 是一個跨平台的 C++ 圖形用戶界面庫,由挪威 TrollTech 公司出品,目前包括Qt,基於 Framebuffer 的 Qt Embedded,快速開發工具 Qt Designer,國際化工具 Qt Linguist 等部分 Qt 支持所有 Unix 系統,當然也包括 Linux,還支持 WinNT/Win2k,Win95/98 平台。
圖0-3 Qt
上文中提到的Linux的KDE就是Qt的傑作。Qt做出了兩方面的努力,都很成功,一個是軟件UI,Qt在UI方面展現了獨特的效果,這種效果脫離了所依賴的操作系統的桌面風格,提現了桌面軟件在交互體驗方面的需求;另一個方面是跨平台性,它同時支持windows和Linux,在跨平台的同時保證了自身UI和交互效果的獨立性。
值的一提的是,對於桌面軟件的UI和用戶體驗,Linux和Os X從一開始就做得很好,相反windows一直在快速開發上做文章,這一點一直到.NET 的Winform都沒有什么大的改變。我們不能說在windows上做不出炫酷的或者交互良好的桌面軟件,畢竟強大的系統API能讓我們無所不能,但是這是開發者的追求,不是這個技術體系的給我們的引導,結果是大多數windows桌面軟件都是灰色的,幾乎沒什么好的交互效果(這可能有點偏激)。
現在我們簡單總結下,桌面軟件開發有兩方面的問題成為制約:
1) 跨平台性
2) 低成本的UI和交互自定義
對於跨平台性,上面我們提到應用程序的底層是系統API,系統API具有天然的系統隔離性,對於開發人員處理這種兼容問題難度往往要大於實現應用程序本身。即使是Qt這樣的UI庫,也根本解決不了問題,UI庫可以移植,單應用程序本身不能移植。隨着python和Java這樣的具有獨立運行時的框架出現之后,跨平台的問題似乎看到了曙光。在操作系統API和應用之間加了一個隔離層,解放了開發者。微軟的.NET也模仿了Java,但是只是實現了在windows 各個不同的系統之間的可移植性(微軟現在也加入了開源大軍,.NET也可以支持在Linux,OS X上運行了)。雖然運行時本身還具有系統的強依賴性,但是大多數開發者而言我們可以忽略這些,關注框架提供的基礎類庫而不是系統API。
跨平台性似乎暫時得到了好的解決方案(雖然並不完美,但是從生產力的角度確實得到了空前的提高,我們暫且認為問題得到了解決),那么UI和交互呢?順着剛才的路線去想,在可跨平台的語言基礎上,構建強大的UI庫是不是就解決了這個問題呢?確實有人在這樣做,但是卻沒有真正的成功者。問題出在哪里了呢?
在語言和框架發展的過程中,尤其是互聯網的發展,專家們抽象和發展了應用程序的基礎功能,比如文件訪問、網絡請求、壓縮解壓縮、加密解密等等,這些內容都被集成到了可跨平台的基礎類庫中,UI和交互一直做為附屬品,在這些語言和框架中沒有得到足夠的重視。但是是人們不重視UI和交互嗎?答案是否定的,隨着互聯網的發展,UI和交互越發的得到重視,而且空前發展,UI和交互有了單獨的語言來處理和定義——HTML和CSS。可是遺憾的是這兩門語言並沒有運用到桌面應用里來,在編程領域出現了前端和后端的划分,出現了C/S和B/S的划分,出現了專門的前端程序員和后端程序員,卻沒有桌面程序員。這是歷史的發展,我們無可厚非,而且要快樂的接受。HTML和CSS是全新的語言,和c/c++、Java/C#、Python都有本質的區別,首先它面向UI和交互,可以近乎精准的還原設計;其次它們是聲明性語言,不是命令性語言。聲明性語言為設計而生,你只需告訴它我要個黑色背景就可以了,這是語言層級的支持,而不像命令式語言想的是如何實現一個黑色背景。除了HTML和CSS之外,和它們綁定到一起的還有Javascript,一門很長一段時間只能運行在瀏覽器中同DOM進行交互的語言。
現在我們再回頭看桌面軟件開發,在UI和交互方面沒有辦法和網頁端應用相比,這是從誕生開始就注定的宿命。在網頁端應用飛速發展這些年里,尤其是HTML5出現之后,人們仿佛覺得桌面應用已經日落西山了,早晚有一天會消亡。雖然桌面應用的開發者數量在減少,構建在純桌面環境的的應用也越來越少,但是桌面環境並沒有要消失的跡象,即使是瀏覽器本身也仍然是一個桌面應用,它也只能完成桌面應用的一小部分功能,只要你要使用桌面,就會有桌面應用的需求。
桌面應用開發技術也沒有止步,並和瀏覽器技術一步步融合。
融入互聯網,融入web是人類生活的需求,同時也是桌面軟件開發技術的需求,在軟件內部嵌入和控制網頁成為最初的訴求。於是瀏覽器的功能被精簡,成為組件被引入桌面軟件中,微軟憑借自家瀏覽器技術的強項在.NET 中引入了WebBrowser控件,這一舉措方便了開發者,同時因為WebBrowser控件強依賴系統安裝的瀏覽器,微軟的瀏覽器又和系統依賴過強,導致控件在不同的客戶系統上的展現行為也會有差別。當然離跨平台又遠了一步。
圖0-4 WebBrower控件示例
同時我們也應該看到控件的方式雖然精簡了瀏覽器功能,但是也擴展了Web應用的能力,控件是可以和調用者進行通信的,也就意味着控件是可以通過“后端代碼”訪問本地資源的。但是在這一方面並沒有長足的發展。同時Google開源了Chromium項目,基於C++的CEF項目,將Chromium進行改造使之成為一個控件,相對於微軟的WebBrowser控件,這一舉措意義很大。Chromium是開源的,可以更好的和調用代碼進行交互,甚至可以擴展javascript接口,使之可以調用操作系統資源。
隨着web應用的發展,瀏覽器由於本身的定位和安全特性的限制,很多需要和客戶端交互的功能無法完成,於是出現了瀏覽器擴展的概念,但是擴展也不是無限制的。這方面微軟對瀏覽器的擴展最為粗暴,它直接支持Activex控件,幾乎可以無限制訪問本地資源,但是同時也打破了瀏覽器安全特性,這也是一直到現在很多銀行的網銀只支持IE瀏覽器的原因。其他瀏覽器也在這一方面做出了妥協,瀏覽器的Js或者本地擴展功能都被支持起來,不過僅僅是妥協而已,因為瀏覽器的使命不是開發桌面應用。
在這期間,微軟做了很大的嘗試,首先是基於.NET框架的WPF,微軟推出了XAML語言,全新的聲明性語言,想讓開發者像寫HTML一樣編寫軟件的界面和交互,這不正是廣大開發者的心聲嗎?可以說WPF是很成功的產品,使用WPF我們已經可以能夠開發出炫酷的桌面軟件了。但是從跨平台性角度講,受.NET本身的制約,另外並沒有斬掉開發者和設計師之間的鴻溝。它仍然是傳統桌面軟件的延伸,面向的是仍然是后端開發人員,前端開發、交互設計師、UI設計師並沒有被引入進來。
圖0-5 WPF
微軟在這個方向上並沒有止步,隨着windows8操作系統的推出,Windows Runtime浮出水面。微軟運行使用HTML5和Javascript開發WinRT的應用,看起來非常美好的一件事情,但是在微軟手里卻多出了很多遺憾。雖然我們可以使用HTML5和Javascript開發應用,甚至在移動端,但是這些應用只能運行於Windows Runtime環境,連Windows8的傳統桌面環境都不可以,更不要談什么跨平台了。原因是微軟直接擴展了Javascript類庫,映射到Windows Runtime的底層API上。
圖0-6 Windows Runtime
這期間很多人也在嘗試直接把B/S開發模型轉移到桌面開發中,簡單理解就是在本地啟動一個WebServer 負責訪問本地文件系統,UI端通過擴展將請求發送到Server再回調回來。這種方式看起來簡單,實則實現起來很復雜,涉及到通信機制的改造。豆瓣曾經發布OneRing項目,使用類似的機制,后端使用Python來處理業務。
不論在兩個方向上如何融合,前與后的本質區別並沒有被打破。因為通過修改瀏覽器代碼去一點點擴展Javascript使之成為超級瀏覽器,也不是不可取,只不過這期間的工程量還是很大的,騰訊的Webtop項目就是基於這個想法進行的,不過已經夭折了。本質上還是由於HTML的發展制約,瀏覽器廠商不去讓瀏覽器足夠強大,第三方很難做到。所幸HTML5和Node.js出現了,並被認可和發展壯大起來。
關於Html5的新特性,這里我不展開論述,讀者自行搜索,總之一句話,Html5帶來了翻天覆地的變化,使web應用在功能上可以更像桌面應用了。而Node.js的誕生,直接打破了Javascript只能寄宿於瀏覽器端的限制,直接走到了大后方,在Node運行時上,Javascript可以和其他后端語言一樣訪問本地資源,“為所欲為”(目前Node Js的基礎類庫還沒有辦法和其他后端語言相比,但是語言的功能本質發生了變化,在一個方向上了)。
圖0-7 Html5新特性
圖0-8 Node js
這里要再次提到Google開源,它開源了瀏覽器引擎及Javascript引擎V8,開源使得很多有夢想的程序員可以插上翅膀。於是乎這樣的想法——打破瀏覽器的安全沙箱,讓瀏覽器支持Node Js,前后端通吃——也就正常了。
因為Node Js使用的也是V8引擎,所以改造瀏覽器去兼容Node Js,同時再根據桌面窗口的特性去擴展些API出來,從技術上講小團隊也是可以實現的。前端開發者也很容易加入到桌面軟件開發的大潮中。同樣一款應用,web端和桌面端可以共享一套設計和交互,甚至是同樣的HTML和CSS以及負責交互的Javascript代碼。基於Node Js去實現后端業務邏輯,可以和前端代碼無縫整合,這是目前理想狀態下的桌面軟件開發環境。我們可以寫類似這樣的代碼:
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script>
var process = require('./addon')
console.log(process.getProcessList());
</script>
</body>
</html>
代碼清單0-3 在html頁面中調用nodejs
在瀏覽器中直接集成Node Js,是我們目前看起來技術實現上難度不高,同時可以為桌面軟件開發帶來新希望的方式。下面我們來看看開源界都做了什么。
hex。官方網站http://hex.youdao.com/。heX 提供了一種全新的構建桌面應用的方式,可以使用 web 技術快速構建跨平台的桌面應用。heX 基於 CEF 並且融合了 Chromium 與 Node.js,所以我們可以在 web 頁面中使用各種 Node.js 原生模塊及第三方擴展,同時在這些模塊及擴展中還可以訪問到 HTML 中的 DOM 元素。此外,heX 甚至可以以一種 web 容器的方式嵌入到桌面應用的工程中。
項目目前處於停滯狀態。
圖0-9 hex
appjs。官方網站http://appjs.com/。實現了Html+nodejs開發桌面軟件的功能,項目目前處於停滯狀態。
nw.js。官方網站http://nwjs.io/。引用作者話說“通過Node.js和WebKit技術的融合,開發者可以用HTML5技術編寫UI,同時又能利用Node.js平台上眾多library訪問本地OS的能力,最終達到用Web技術就可以編寫桌面應用的目的。實現上是基於Chromium項目的Content Layer構建(Chromium Browser也同樣基於Content Layer);實現上的特點是把Node.js的消息循環(libuv)和Chromium Renderer進程的消息循環合並到一起,因為這樣才能從DOM(HTML)中直接調用Node.js提供的函數;把Node.js使用的V8引擎和Chromium的V8引擎合並,使得Node.js的Javascript和DOM里面的Javascript可以互相訪問;另外因為是支持本地應用,所以安全模型和Web程序有很大不同:nw.js程序可以做web應用不允許做的很多事情,除了通過node.js訪問本地OS以外,還可以進行跨域訪問等操作。”
圖0-10 nw.js
nw.js目前是該方向上受關注度最高的項目,而且一直在持續更新。
electron.js。官方網站http://electron.atom.io/。electron.js 和nw.js有着千絲萬縷的關系,其前身是github大名鼎鼎的atom shell。是目前最活躍的使用web技術開發桌面軟件的開源項目。包括github的atom和微軟的Visual Studio Code都基於electron.js開發。
圖0-11 electron.js
目前為止,我覺得值得和大家介紹的項目就這么多(當然可能有更好的),這些項目為桌面軟件開發打開了新天地,讓web開發技術和桌面軟件開發技術完美的融合在一起。大家可以到相關的網站去了解項目的詳細信息。從此桌面軟件開發有了新的技術體系,html5+node.js。當然探索還沒有止步,比如edge.js(https://github.com/tjanczuk/edge),打通 了node js 和.NET運行時,可以實現互調,那么我們也是可以node js 為橋梁把復雜的業務邏輯封裝到.NET中。微軟的開源項目.NET Core,也讓很多人產生了新的想法,是否可以將.NET Core 運行時直接打包到瀏覽器中,將.NET 類庫直接生成Javascript 接口供網頁中的js調用呢?
圖0-12 .NET Core 5
在將近兩年的HTML5桌面軟件開發過程中,雖然整體過程是愉快的,但是不可避免的遇到很多問題甚至是無法克服只能繞過的“坑”。兩年里我主要使用的框架是nw.js(那時還叫node-webkit),也在博客上零星的寫了一些nw.js入門的教程,雖然不成體系,文章數量也不多,但是仍然是國內最全的教程了。nw.js 也在不斷的迭代更新,於是我產生了重新動手,寫一本完整的書來記錄兩年來的開發經驗,這里面重要的不是nw.js如何使用,重要的是使用Html5和node.js開發桌面應用我們應該怎么做,會遇到什么問題,如何去解決。
在下一節,會給大家闡述下nw.js的基本實現原理。
nw.js,electron交流群 313717550