webkit2gtk的自定义协议与内容交互

我们使用GTK+开发的时候,为了方便地显示Web内容,可以把一个webkit 内嵌进去。相应的GTK+的接口实现为webkit2gtk

使用方法

使用方法非常简单,只要使用webkit_web_view_new来生成一个WebKitWebView,之后当成其它的普通的GtkWidget放入Gtk的布局中就行了。

如:

GtkWidget *box = mVbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
GtkWidget *view = webkit_web_view_new_with_context (context);
gtk_box_pack_start(GTK_BOX(box), view, TRUE, TRUE, 0);

之后,就可以使用webkit_web_view_load_uri函数加载网页了。

webkit_web_view_load_uri (WEBKIT_WEB_VIEW (view), "https://www.baidu.com/");

自定义协议思路

但是,一般我们开发过程中,经常需要自定义Web的请求协议,而不是常规地HTTP,以实现我们自定义的任务。比如,要加载的文件在本地,或者在数据库中,等等。

这时候,我们就可以先生成一个WebKitWebContext,之后再生成这个Context之上的WebKitWebView,然后使用WebKitWebContext注册协议。

WebKitWebContext的注册协议函数原型为:

void
webkit_web_context_register_uri_scheme
                               (WebKitWebContext *context,
                                const gchar *scheme,
                                WebKitURISchemeRequestCallback callback,
                                gpointer user_data,
                                GDestroyNotify user_data_destroy_func);

其中,scheme为协议名称,callback为加载这种协议的时候执行的回调函数,user_data为回调时带的上层参数。

而WebKitURISchemeRequestCallback的定义为:

void
(*WebKitURISchemeRequestCallback) (WebKitURISchemeRequest *request,
                                   gpointer user_data);

其中,user_data就是使用webkit_web_context_register_uri_scheme注册的时候的user_data参数。而WebKitURISchemeRequest则是我们需要重点关注以及处理的结构,我们就是要通过它来实现自定义的加载行为。

WebKitURISchemeRequest支持的接口为:

const gchar * 	webkit_uri_scheme_request_get_scheme ()
const gchar * 	webkit_uri_scheme_request_get_uri ()
const gchar * 	webkit_uri_scheme_request_get_path ()
WebKitWebView * 	webkit_uri_scheme_request_get_web_view ()
void 	webkit_uri_scheme_request_finish ()
void 	webkit_uri_scheme_request_finish_error ()

在我们注册的回调函数里面,就可以通过webkit_uri_scheme_request_get_uri或者webkit_uri_scheme_request_get_path来获取页面正要请求的资源,我们为它准备好相应资源以后,再通过webkit_uri_scheme_request_finish来返回给WebKitWebView,或者使用webkit_uri_scheme_request_finish_error通知它失败。

其中,webkit_uri_scheme_request_finish还有webkit_uri_scheme_request_finish_error的原型分别为:

void
webkit_uri_scheme_request_finish (WebKitURISchemeRequest *request,
                                  GInputStream *stream,
                                  gint64 stream_length,
                                  const gchar *mime_type);

void
webkit_uri_scheme_request_finish_error
                               (WebKitURISchemeRequest *request,
                                GError *error);

看到这里,相信我们对于整个逻辑就比较清楚了。

自定义协议举例

比如,我们要增加一种协议叫做helloworld,我们希望WebKitWebView访问本地文件的格式为helloworld:///home/user1/p.html,就可以如下实现:

WebKitWebContext *context = webkit_web_context_new_ephemeral ();  
GtkWidget *view = webkit_web_view_new_with_context (context);
webkit_web_context_register_uri_scheme (  
    context, "helloworld",  
    WebKitURISchemeRequestCallback (webcontext_load_helloword_callback), NULL,  
    NULL);

……

void
webcontext_load_helloworld_callback (WebKitURISchemeRequest *request,
                                        gpointer arg1)
{
  gssize stream_length;
  const gchar *path, *type;

  path = webkit_uri_scheme_request_get_path (request);

  type = "text/html";
  gchar *contents = /* 本地资源读取过程略 */;
  if (contents)
    {
      /* 特别注意:这个实现中,contents 必须是需要free的内存,因为stream被处理完成以后,会在ref为0的时候自动释放,这时候会一起释放contents,释放的函数为g_memory_input_stream_new_from_data的最后一个回调函数,这里设为free。*/
      GInputStream *stream = g_memory_input_stream_new_from_data (
          contents, stream_length, free);
      webkit_uri_scheme_request_finish (request, stream, stream_length, type);
      g_object_unref (stream);
    }
  else
    {
      GError *error
      = g_error_new (G_FILE_ERROR_FAULT, -1, "Not found path:%s page.", path);
      webkit_uri_scheme_request_finish_error (request, error);
      g_error_free (error);
    }
}

页面联动(判断滚动到页尾举例)

WebKitWebView的页面进行滚动,有的是用户滑动的滚动条,也有的是页面里面的Javascript脚本操作,但是这些滚动的状态,如何通知到我们的代码调用这里呢?

这就需要WebKitWebView关联的WebKitUserContentManager。

通过名字也可以看出来,这个结构的目的,就是Web页面内容的管理器。通过这个管理器,我们就可以把页面的状态与我们的代码联系起来。

使用方法为,在WebKitWebView的WebKitUserContentManager里,注册相应的Javascript消息,然后把消息与WebKitUserContentManager的回调函数连接。

之后,在页面里面执行JavaScript代码,使用window.webkit.messageHandlers发送相应的消息到我们的WebKitUserContentManager,就触发了我们的回调函数。

比如,我们要判断Web页面是否到达末尾,就可以这样实现:

首先,在UserContentManager里注册一个消息,然后把这个消息与回调函数连接:

WebKitUserContentManager *man  
    = webkit_web_view_get_user_content_manager (WEBKIT_WEB_VIEW (view));  
webkit_user_content_manager_register_script_message_handler (man, "bottom");    
g_signal_connect (man, "script-message-received::bottom",  
                  G_CALLBACK (webview_arrive_bottom), this);

……

void  
webview_arrive_bottom (WebKitUserContentManager *man,  
                              WebKitJavascriptResult *res, gpointer arg1)  
{  
  printf ("webkit arrived bottom \n");  
}

之后,在WebKitWebView里,判断到达内容末尾的时候,使用Javascript发送"bottom"消息:

const gchar *javascript  
    = "if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) { window.webkit.messageHandlers.bottom.postMessage('reached');}";

webkit_web_view_run_javascript (view, javascript, NULL, NULL, NULL);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值