如果让你以最快的方式开发一个桌面应用,你会怎么做?
用html画好界面,然后给它加一个exe的壳子。
我们知道electron就可以做到。
为什么要加exe的壳子呢?直接用浏览器不好吗?
不好。因为不能Alt+Tab来切换应用。而且浏览器的标签页太多了,根本不知道之前打开的应用在哪个标签里。
除了electron,我们还可以使用webview。
electron优点:成熟,有很多写好的api可以用。有很多成功的案例,比如Atom, VS Code等。配合npm和前端相关技术,
开发起来真的非常方便,每次保存后自动刷新页面,debug的时候有Webkit的开发者工具可以直接调试JS。
web应用只需要兼容一个webkit就行了。
在“启动浏览器”这一步,开发者不用操心。直接开发html页面即可。
electron缺点:打包后文件太大,一个很小的程序打包后也要几十兆,因为它把整个webkit打包进去了。
webview优点:
它使用OLE技术,先创建一个窗口,然后把浏览器嵌入到应用程序里。
浏览器的bar被隐藏了,应用程序也没有多余的菜单。生成的exe感觉就像是用原生的win32 API写出来的客户端一样。
打包后文件很小。通常是几百KB左右。如果只是做一款小工具给别人或者自己用,当然是越小越好了。
“启动浏览器”的时候开发者可以自己创建窗口,控制消息循环等。就是很低层,可玩性强,仿佛回到了windows编程的时代。
webview缺点:不太成熟,开发起来不太方便。不能直接调试JS。如果用C/C++的话,编译速度太慢,编译一次至少7秒。编译的时候如果
忘了关掉exe程序,编译还会失败。而且在VS Studio上还不知道怎么编译,只能装一个mingw,用命令行来编译。
还是建议大家用golang来“启动浏览器”,因为golang的编译速度很快,而且语言上没有那么底层。
用C的话连个字符串都没有,还有恶心的字符集编码问题。尤其当涉及到中文字符串的时候,不是专业C/C++的根本玩不转。
而且不同的系统用的浏览器不一样,web应用需要兼容各种浏览器。虽然有react,vue这样的框架可以解决,但是如果没有使用这些框架怎么办?
如果只想做一个小工具,我建议用webview,先来看一下win10下的效果。
怎么玩?以C为例。
1.下载并安装mingw-w64,网速要好,装好了要配置一下环境变量。
2.github上将webview.h下载下来
3.创建demo2.c文件,在demo2.c里包含webview.h头文件
4.创建index.html和index.js文件。
5.编译。gcc demo2.c -DWEBVIEW_WINAPI=1 -lole32 -lcomctl32 -loleaut32 -luuid -mwindows -o webview-example2.exe
第一步不是必需的,如果你可以在VS Studio上编译成功,请忽略第一步和第五步的编译命令。
demo2.c
#define WEBVIEW_IMPLEMENTATION
#include "webview.h"
#include <stdio.h>
#include <unistd.h>
#ifdef WEBVIEW_WINAPI
#define GetCurrentDir _getcwd
#define PATH_SEPARATOR "\\"
#elif defined DWEBVIEW_GTK
#include <unistd.h>
#define GetCurrentDir getcwd
#define PATH_SEPARATOR "/"
#else
// WEBVIEW_COCOA for mac os
#define GetCurrentDir getcwd
#define PATH_SEPARATOR "/"
#endif
void GetCurrentWorkingDir(char *buff) {
GetCurrentDir( buff, MAX_PATH );
}
static void my_cb(struct webview *w, const char *arg) {
webview_set_title(w, "New title2");
// 所有文件都是utf-8格式保存的,但是messagebox还是乱码
// 我不知道怎么优雅的解决,弄了半天,只有这样不乱码
// 命令行里加-finput-charset=UTF-8 -fexec-charset=UTF-8也不行
wchar_t * msg = L"JS成功调用了C方法";
wchar_t * title = L"来自exe的消息";
MessageBoxW(NULL,msg,title,MB_OK);
webview_eval(w, "alert('C方法里也成功调用了JS的alert方法');");
}
#ifdef WIN32
int WINAPI WinMain(HINSTANCE hInt, HINSTANCE hPrevInst, LPSTR lpCmdLine,
int nCmdShow) {
#else
int main() {
#endif
// 获取当前exe所在的路径,因为index.html跟它在一块儿
char buff[MAX_PATH];
GetCurrentWorkingDir(buff);
strcat (buff,PATH_SEPARATOR);
strcat (buff,"index.html");
// 定义窗口基本信息,注意这里注册了一个回调函数my_cb
struct webview webview = {
.title = "abc",
.url = buff,
.width = 800,
.height = 600,
.debug = 1,
.resizable = 1,
.external_invoke_cb = my_cb
};
webview_init(&webview);
int blocking = 0;
webview_set_title(&webview, "New title");
while (webview_loop(&webview, blocking) == 0){}
webview_exit(&webview);
// 还有其他函数留待大家探索,比如debug。
return 0;
}
index.html
<html>
<head>
<script src="index.js"></script>
</head>
<body>
<h1>Hello webview!</h1>
<button onclick="external.invoke('my_cb')">call C function</button>
</body>
</html>
index.js
var userAgent = window.navigator.userAgent
alert(userAgent)
// 这个地方我只想看看,它用的是不是win10的edge浏览器,好像不是。
// 显示的是 Mozilla/5.0(Windows NT6.2;WOW64;Trident/7.0;rv:11.0) like Gecko
这个生成的exe这样286KB。而且在win7下也能执行成功。其他平台的我没测,换个命令编译后应该也是没问题的。