/**
*
* Copyright (C) 2020 Wei Keting<weikting@gmail.com>. All rights reserved.
* @Time : 2021-04-04 12:18
* @Last Modified: 2022-12-10 17:27
* @File : webviewgtk.c
* @Description :
*
* 依赖下载:
* sudo apt install libwebkit2gtk-4.1-doc libwebkit2gtk-4.1-dev libgtk-3-dev
* gcc webviewgtk.c -o webviewgtk -D_GNU_SOURCE -g3 -Wall `pkg-config --cflags --libs webkit2gtk-4.1`
*
*/
#include <gtk/gtk.h>
#include <glib.h>
#include <webkit2/webkit2.h>
#include <sys/types.h>
#include <unistd.h>
static void
web_view_javascript_finished(GObject *object,
GAsyncResult *result,
gpointer user_data) {
GError *error = NULL;
JSCValue *js_result = webkit_web_view_evaluate_javascript_finish(WEBKIT_WEB_VIEW(object),
result, &error);
if (!js_result) {
g_warning("Error running javascript: %s", error->message);
g_error_free(error);
return;
}
if (jsc_value_is_string(js_result)) {
gchar *str_value = jsc_value_to_string(js_result);
JSCException *exception = jsc_context_get_exception(jsc_value_get_context(js_result));
if (exception)
g_warning("Error running javascript: %s", jsc_exception_get_message(exception));
else
g_print("Script result: %s\n", str_value);
g_free(str_value);
} else {
g_warning("Error running javascript: unexpected return value");
}
}
static gboolean
on_webview_load_failed(WebKitWebView *webview,
WebKitLoadEvent load_event,
gchar *failing_uri,
GError *error,
gpointer user_data) {
g_printerr("%s: %s\n", failing_uri, error->message);
return FALSE;
}
static void
handle_script_message(WebKitUserContentManager *self,
WebKitJavascriptResult *js_result,
gpointer user_data) {
JSCValue *value = webkit_javascript_result_get_js_value(js_result);
gchar *str_value = jsc_value_to_string(value);
JSCException *exception = jsc_context_get_exception(jsc_value_get_context(value));
if (exception)
g_warning("Error running javascript: %s", jsc_exception_get_message(exception));
else
g_printerr("Script result: %s\n", str_value);
g_printerr("%s: %s\n", __func__, str_value);
g_free(str_value);
}
static gboolean
handle_script_message_with_reply(WebKitUserContentManager *self,
JSCValue *value,
WebKitScriptMessageReply *reply,
gpointer user_data) {
gchar *str_value = jsc_value_to_string(value);
JSCContext *context = jsc_value_get_context(value);
/* It is possible to handle the reply asynchronously,
* by simply calling g_object_ref() on the reply and returning TRUE.
* webkit_script_message_reply_ref(reply);
*
* async code here
*
* webkit_script_message_reply_unref(reply);
*/
JSCValue *js_value = jsc_value_new_string(context, str_value);
webkit_script_message_reply_return_value(reply, js_value);
g_printerr("%s: %s\n", __func__, str_value);
g_free(str_value);
return TRUE; // TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
}
static void
on_button_clicked(GtkButton *button,
WebKitWebView *webview) {
static gint t = 0;
gchar buf[128] = {0};
g_snprintf(buf, sizeof(buf) - 1, "change_span_id('_n%d')", t);
t += 1;
// 在webview当前的html页面中直接运行js代码
webkit_web_view_evaluate_javascript(webview, buf, -1, NULL, NULL, NULL,
web_view_javascript_finished, NULL);
}
static void
webkit_web_extension_initialize(WebKitWebContext *context,
gpointer user_data) {
g_printerr("%s: %d\n", __FUNCTION__, getpid());
// 设置web extendsion扩张.so文件的搜索目录
webkit_web_context_set_web_extensions_directory(context, ".");
}
/**
** 创建window,添加webkit控件
**
**/
static void
on_activate(GtkApplication *app) {
g_assert(GTK_IS_APPLICATION(app));
GtkWindow *window = gtk_application_get_active_window(app);
if (window == NULL)
window = g_object_new(GTK_TYPE_WINDOW,
"application", app,
"default-width", 600,
"default-height", 300,
NULL);
// 注册处理web extensions的初始化函数
g_signal_connect(webkit_web_context_get_default(), "initialize-web-extensions",
G_CALLBACK(webkit_web_extension_initialize), NULL);
GtkWidget *webview = webkit_web_view_new();
g_signal_connect(webview, "load-failed", G_CALLBACK(on_webview_load_failed), NULL);
// 加载网页
GFile *file = g_file_new_for_path("webview.html");
gchar *uri = g_file_get_uri(file);
webkit_web_view_load_uri(WEBKIT_WEB_VIEW(webview), uri);
g_free(uri);
g_object_unref(file);
// 注册 window.webkit.messageHandlers.msgToNative.postMessage(value) 的回调函数
WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager(
WEBKIT_WEB_VIEW(webview));
g_signal_connect(manager, "script-message-received::msgToNative",
G_CALLBACK(handle_script_message), NULL);
webkit_user_content_manager_register_script_message_handler(manager, "msgToNative");
// 注册 window.webkit.messageHandlers.msgToNativeReply.postMessage(value) 的回调函数
// 函数调用有返回值
g_signal_connect(manager, "script-message-with-reply-received::msgToNativeReply",
G_CALLBACK(handle_script_message_with_reply), NULL);
webkit_user_content_manager_register_script_message_handler_with_reply(manager,
"msgToNativeReply",
NULL);
/* Enable the developer extras */
WebKitSettings *setting = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webview));
g_object_set(G_OBJECT(settings), "enable-developer-extras", TRUE, NULL);
GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
GtkWidget *button = gtk_button_new_with_label("change span");
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(webview), TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));
gtk_widget_show_all(GTK_WIDGET(vbox));
gtk_window_present(window);
g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), webview);
}
int main(int argc,
char *argv[]) {
g_autoptr(GtkApplication)
app = gtk_application_new("com.weiketing.webkit_webview", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(on_activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}