前面介绍了chromium中WebUI机制的几个主要的组件,这篇文章,用一个功能来看看WebUI是怎么使用的。
本实例的背景:显示一个自定义的设置界面,包括对历史记录、书签、cookies等一系列用户数据的操作,现在我使用其中的一个功能来介绍一下大致的实现。
首先,我们要创建几个类:
HistoryUI:继承自WebUI中的controller;在这个类中,我们还创建了一个WebUIDataSourceImpl类的实例,主要用来提供数据;
webui对象,这个对象是在加载本地页面时由webcontents创建好的;
HistoryService,这个类是一个执行类,主要作用是来维护一个线程,用来执行我们指定的操作,这个类是我自己定义的,使用时可以自己指定其他的类;
HistoryBackend,这个类也是自己定义的,其中定义了我们在这个本地页面中要执行的操作。
现在我们来看这个过程:
在HistoryUI中:
HistoryUI::HistoryUI(){
...
web_ui->RegisterMessageCallback("deleteHistoryItemByDate", base::Bind(&HistoryUI::HandleDeleteHistoryItemByDate, base::Unretained(this)));
...
}
void HistoryUI::HandleDeleteHistoryItemByDate(const base::ListValue* arg) {
base::string16 key, id, date;
args->GetString(0, &key);
args->GetString(1, &id);
args->GetString(2, &date);
HistoryService* hs = HistoryService::GetInstance();
hs->DeleteItemByDate(date,
base::Bind(&HistoryUI::CallJavaScriptFunctionWith2Args, base::Unretained(this),
base::StringValue(key), base::StringValue(id)));
}
上面的两个函数:
第一在构造函数中,发挥了WebUI类的功能,"deleteHistoryItemByDate"就是页面调到js代码,由js代码传递过来的参数的第一个值。
如上一篇文章提到的,js产生调用之后,通过V8引擎将参数传递到render进程,然后render进程通过IPC消息将这个参数传递到browser进程,这个IPC消息就是被此处的webui对象所处理,解析出其携带的参数,然后调用已经注册的回调函数。
第二个函数,这个函数就是注册到webui中的js直接调用回调函数,但我们此时看到在这个函数中,我们又一次绑定了一个回调函数:CallJavaScriptFunctionWith2Args,这个函数的实质就是调用了webui中的方法来调用js代码,附带了两个参数。以上这两点就体现出了webui的作用,就是将js调用c++以及c++执行js联系起来。
继续来看代码:
在HistoryBackend中:
void HistoryBackend::DeleteItemByDate(const base::string16& date, base::Callback<void()> callback) {
if (HistoryDataBase::GetInstance()->DeleteItemByDate(base::UTF16ToUTF8(date))) {
...
}
callback.Run();
}
以上这个HistoryBackend中定义的具体的实现方法,也就是js调用下来之后,实现具体功能的函数。我现在分析的功能就是按时间来删除条目。在具体的操作正确结束之后,执行了第二个参数callback,这个就是在HistoryUI中注册的调用js代码的方法,用来执行在功能完成后,向js发出响应。
继续看代码:
void HistoryService::DeleteItemByDate(const base::string16& date, base::Callback<voiid()> callback) {
service_backend_->scheduleTask(base::Bind(&HistoryBackend::DeleteItemByDate, history_backend, date, callback));
}
从以上的代码中可以看到一个schedultTask的函数,它的目的就是维持一个线程,把Bind的函数一个个放进线程里面去执行。此处,callback就是来自于在HistoryUI中注册的CallJavaScriptFunctionWith2Arg()。而次数又继续绑定了函数,那就是HistoryBackend的DeleteItemByDate函数,最终运行就是HistoryBackend::DeleteItemByDate.
在以上的代码中,后两个类都是自己实现的,在具体做的时候,需要根据具体的情况来定义自己的函数。
关于以上类以及函数的调用关系需要捋一捋,Callback顾名思义,就是一个回调函数,此处理解为闭包貌似好一点,因为在callback中包含了函数地址以及函数参数,其实就相当于是打包了一个函数要运行的一个环境。
在WebUI过程中,还有一个部分,那就是资源文件的编译、使用,放在下一篇文章再详细介绍chromium里面对本地资源的处理方法。