A tiny cross-platform webview library written in C++ using EdgeHTML / WinRT (Windows), Cocoa + Webkit (MacOS) and WebkitGTK (Linux).
Inspired from zerge's webview, this library was rewritten with several priorities:
- A more "C++"-like API
- Support for Microsoft Edge on Windows
- Replaced Objective-C runtime C code with actual Objective-C code
| Windows | MacOS | Linux | |
|---|---|---|---|
| Version | Windows 10, v1809+ | Tested on MacOS Mojave, Catalina | Tested on Ubuntu 18.04.02 LTS |
| Web Engine | EdgeHTML | Webkit | WebKit |
| GUI | Windows API | Cocoa | GTK |
There is also experimental support for the new Edge (Chromium) for Windows.
// main.cpp
#include "webview.h"
WEBVIEW_MAIN {
// Create a 800 x 600 webview that shows Google
wv::WebView w{800, 600, true, true, Str("Hello world!"), Str("http://google.com")};
if (w.init() == -1) {
return 1;
}
while (w.run() == 0);
return 0;
}Since Windows (WinAPI) uses std::wstrings, all string literals should be wrapped in the macro Str(s).
The following URL schemes are supported:
- HTTP(S):
http://andhttps:// - Local file:
file:///, make sure to point to anhtmlfile- TODO: this doesn't work in Windows
- Inline data:
data:text/html,<html>...</html>- TODO: test on Windows
Check out example programs in the examples/ directory in this repo.
Note: WEBVIEW_MAIN is a macro that resolves to the correct entry point:
#ifdef WEBVIEW_WIN
#define WEBVIEW_MAIN int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
#else
#define WEBVIEW_MAIN int main(int argc, char **argv)
#endifThis is needed since Win32 GUI applications uses WinMain as the entry point rather than the standard main. You can write your own main for more control, but make sure to use WinMain if you need to support Windows.
There are several limitations on Windows stemming from the EdgeHTML webview:
- The webview cannot be run as an administrator.
- The webview cannot navigate to local HTML files (i.e:
file:///...).
If you have CMake installed, the included config should work for all platforms.
First define WEBVIEW_WIN before adding webview.h.
In order to target EdgeHTML (Microsoft Edge), webview uses the new C++/WinRT API. This requires some additional requirements:
tl;dr: Upgrade to latest version of Windows 10, install Visual Studio 2019, install the Windows 10 SDK, and add the C++/WinRT VSIX.
To debug, install the Microsoft Edge DevTools.
- Requires C++17
- Visual Studio 2017, recommended 2019
- C++/WinRT Visual Studio Extension
Also, use std::wstring in place of std::string when using webview APIs (with the exception of wv::WebView::callback).
I don't like Visual Studio!
While not officially supported, Microsoft does use Clang internally for testing purposes. If you want to use Clang, they have some basic instructions on their website.
I've gotten clang-cl to compile with the following steps:
-
Download / clone this repo and navigate to it.
-
Install the Windows 10 SDK. Make sure to install at least version 1809.
- (Optional) Add
cppwinrt.exeto your PATH (located inC:\Program Files (x86)\Windows Kits\10\{version}\bin\x86\cppwinrt.exe).
- (Optional) Add
-
Run
cppwinrt.exe -in sdk. (Optionally, you can add the-verboseflag.)- This should generate a local directory called
winrtcontaining a bunch of headers. These are WinRT projection headers that you can use to consume from C++ code. You will be needing these headers for compilation. - For more on
cppwinrt.exe, check out this blog post by the creator of C++/WinRT.
- This should generate a local directory called
-
Install LLVM 8.0.0. (I've tested it with 8.0.0, but Microsoft says LLVM 6.0.0 should work too.)
- (Optional) Add LLVM to your PATH, specifically
clang-cl.exe.
- (Optional) Add LLVM to your PATH, specifically
-
Compile by running
clang-cl examples\main.cpp /EHsc /I "." -Xclang -std=c++17 -Xclang -Wno-delete-non-virtual-dtor -o webview.exe /link "WindowsApp.lib" "user32.lib" "kernel32.lib".
If your winrt/ directory is located somewhere else, change the /I "." argument above.
You may result in some compiler errors in some of the winrt:: headers. I fixed them by manually editing the headers in the winrt/ subdirectory.
- Requires Windows 10, version 1809 (Build 17763)
The C++/WinRT API is fairly new, and its webview was introduced in v1803 (UniversalAPIContract v6). This also uses WebViewControl.AddInitializeScript introduced in v1809. For more information about API contracts, read this blog post by Microsoft.
Also, displaying localhost in the webview will only work after adding a loopback exception. A simple way to enable this is to run
CheckNetIsolation.exe LoopbackExempt -a -n=Microsoft.Win32WebViewHost_cw5n1h2txyewy
This can then be checked using CheckNetIsolation.exe LoopbackExempt -s. Read more about network loopbacks here.
webview depends on the Cocoa and Webkit frameworks. Also, make sure your compiler supports Objective-C (g++ and clang++ should both work).
To compile,
g++ main.cpp -DWEBVIEW_MAC -ObjC++ -std=c++11 -framework Cocoa -framework Webkit -o webview
First install gtk+-3.0 and webkit2gtk-4.0:
sudo apt-get install libgtk-3-dev libwebkit2gtk-4.0-37 libwebkit2gtk-4.0-dev
Then to compile,
g++ main.cpp -DWEBVIEW_GTK=1 `pkg-config --cflags --libs gtk+-3.0 webkit2gtk-4.0` -o webview
Make sure to define WEBVIEW_GTK.
To communicate from JavaScript to C++, use the method window.external.invoke:
// JavaScript
window.exteral.invoke('hello world!');// C++
void callback(WebView &w, std::string &arg) {
// arg = "hello world!"
}This method can only accept strings, so objects must be serialized in some way:
// JavaScript
window.external.invoke(JSON.stringify({ foo: 'bar' }));Note: On Windows, all strings are std::wstring due to the underlying WinRT API. On Linux, they are std::string. The only exception is WebView::setCallback, which uses std::string even on Windows.
If you need to support Windows, make sure to use the following main declaration:
#ifdef WIN32
int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
#else
int main() {
#endif
// ...
}WebView(int width, int height, bool resizable, bool debug, string title,
string url = DEFAULT_URL)The default url (DEFAULT_URL) will render a blank page with a single root div:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
</head>
<body>
<div id="app"></div>
<script type="text/javascript"></script>
</body>
</html>int init();Initializes the webview window.
0 if successful, otherwise -1.
#include "webview.h"
int main() {
wv::WebView w{800, 600, true, true, "My WebView"};
// Initialize the webview
if (w.init() == -1) {
return 1;
}
// Do stuff with the webview
return 0;
}void setCallback(std::function<void(WebView &, std::string &)> callback);Attaches a function that will run when receiving messages from JavaScript.
- callback: A callback function
#include "webview.h"
void callback(WebView &w, std::string &arg) {
if (arg == "color") {
w.css("body { background-color: red; }");
}
}
// ...
w.setCallback(callback);void setTitle(string title);Sets the title of the webview window.
- title: The new title of the webview
void setFullscreen(bool fs);Sets the webview window to fullscreen or windowed mode.
- fs: True if setting to fullscreen, false if windowed
Sets the background color of the webview. If the webpage has a background color, it will take precedence over this color.
void setBgColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a)- r: Red component of the color (0 to 255)
- g: Green component of the color (0 to 255)
- b: Blue component of the color (0 to 255)
- a: Alpha component of the color (0 to 255)
bool run();Runs one iteration of the main loop. This method is blocking if no events are pending.
True if the webview window will be closed, otherwise false.
#include "webview.h"
int main() {
wv::WebView w{800, 600, true, true, "My WebView"};
if (w.init() == -1) {
return 1;
}
// Keep running until the window will close
while (w.run() == 0);
return 0;
}void navigate(string uri);Navigates the webview to the specified URI.
- uri: URI to the webpage
void preEval(string js);Injects the JavaScript string into the webpage before it loads.
void eval(string js);Executes the JavaScript string in the current webpage.
- js: JavaScript string to execute
#include "webview.h"
void callback(WebView &w, std::string &arg) {
if (arg == "eval") {
w.eval("alert('boo!')");
}
}
int main() {
wv::WebView w{800, 600, true, true, "My WebView"};
if (w.init() == -1) {
return 1;
}
w.setCallback(callback);
while (w.run() == 0);
return 0;
}The alert will display when this is executed in the webpage:
window.external.invoke('eval');void css(string css);Applies the CSS string to the current webpage.
- css: CSS string to apply
This method works similar to WebView::eval.
#include "webview.h"
void callback(WebView &w, std::string &arg) {
if (arg == "style") {
w.css("p { color: red; }");
}
}
int main() {
wv::WebView w{800, 600, true, true, "My WebView"};
if (w.init() == -1) {
return 1;
}
w.setCallback(callback);
while (w.run() == 0);
return 0;
}All p tags will be colored red when this is executed in the webpage:
window.external.invoke('style');void exit();Closes the webview window. This will cause the next invocation of WebView::run to return true.