桌面应用开发的新秀——webview

如果让你以最快的方式开发一个桌面应用,你会怎么做?
用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下的效果。

桌面应用开发的新秀——webview

怎么玩?以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下也能执行成功。其他平台的我没测,换个命令编译后应该也是没问题的。

上一篇:C++模板参数替换的理解


下一篇:ElasticSearch5.x几个为什么