OpenHarmony_Web子系统介绍
简介架构代码目录接口与服务web组件nwebview提供的接口CEF提供的接口与服务CEF简介CEF结构Browser进程的实现结构Render进程的实现结构其他Cef重要类简介ohos_nweb目录简介ohos_nweb\include下的nwebview层src/ohos_nweb中对web内核封装实现ohos_nweb\src\cef_delegate下对cef接口和nwebview
简介架构代码目录接口与服务web组件nwebview提供的接口CEF提供的接口与服务CEF简介CEF结构Browser进程的实现结构Render进程的实现结构其他Cef重要类简介ohos_nweb目录简介ohos_nweb\include下的nwebview层src/ohos_nweb中对web内核封装实现ohos_nweb\src\cef_delegate下对cef接口和nwebview接口的封装实现流程简要流程启动流程融合渲染流程销毁流程其他参考文献
简介
web(World Wide Web)即全球广域网,也称为万维网,它是一种基于超文本和HTTP的、全球性的、动态交互的、跨平台的分布式图形信息系统,是建立在Internet上的一种网络服务,为浏览者在Internet上查找和浏览信息提供了图形化的、易于访问的直观界面。
基于web的浏览器功能十分强大,可以通过B/S形式实现多种功能,如在线音视频播放,在线购物等,为用户提供了方便快捷的上网方式。
这里的web子系统介绍的是实现上述功能所提供的能力。
架构
----------------------- | web组件 | ----------------------- | nwebview | ----------------------- | CEF | ----------------------- | Chromium | ----------------------- | OpenHarmony基础库 | ---------------------
-
web组件:OpenHarmony的UI组件。
-
nwebview:基于CEF构建的OpenHarmony web组件的Native引擎。
-
CEF:CEF全称Chromium Embedded Framework,是一个基于Google Chromium 的开源项目。
-
Chromium: Chromium是一个由Google主导开发的网页浏览器内核。以BSD许可证等多重自由版权发行并开放源代码。
代码目录
base/web/webview/ ├── ohos_nweb # openharmony适配代码 │ ├── include # 定义了一些常用接口,如前进后退等 │ ├── prebuilts # NWeb.hap,基于third_party_chromium源码仓构建 │ └── src └── test # nwebview测试代码
接口与服务
web组件
-
web组件,就是在webview中用于执行显示、下载、改变页面大小等任务的UI组件。开发者可以在这里根据nwebview为OpenHarmony提供的接口做自定义开发与适配工作。这里的目录在foundation\ace\ace_engine\frameworks\core\components\web,需要指出的是,这是3.1release版本的目录,3.2版本的目录稍有不同,为foundation\arkui\ace_engine\frameworks\core\components\web。
foundation/ace/ace_engine/frameworks/core/components/ ├── web # ace_engine下的web组件 │ ├── resource # 接受nwebview提供的接口,并按功能重写 │ ├── build.gn # 配置编译选项 │ └── 其他文件 #调用包括pipeline中render的各个功能和focus控制焦点的各个功能 -
在/resource/web_client_impl.h中,WebClientImpl继承了NWebHandler,从而使web组件获得了对页面一定的控制,然后通过指针使得WebDelegate可以对NWeb操控,如按需求初始化NWeb并创建窗口,更新浏览器的userAgent,改变webview大小,加载URL等。
///web_client_impl.h class WebDelegate; ... class WebClientImpl : public OHOS::NWeb::NWebHandler{ ... WeakPtr<WebDelegate> webDelegate_; ... }//web_delegate.h //调用WM中创建、销毁窗口等方法 ... class WebDelegate : public WebResource { ... std::shared_ptr<OHOS::NWeb::NWeb> webview_; }//web_delegate.cpp ··· void WebDelegate::UpdateUserAgent(const std::string& userAgent)//更新userAgent { auto context = context_.Upgrade(); if (!context) { return; } context->GetTaskExecutor()->PostTask( [weak = WeakClaim(this), userAgent]() { auto delegate = weak.Upgrade(); if (delegate && delegate->webview_) { std::shared_ptr<OHOS::NWeb::NWebPreference> setting = delegate->webview_->GetPreference(); setting->PutUserAgent(userAgent); } }, TaskExecutor::TaskType::PLATFORM); } ...//web_delegate.cpp ··· void WebDelegate::Resize(const double& width, const double& height)//改变webview大小 { auto context = context_.Upgrade(); if (!context) { return; } context->GetTaskExecutor()->PostTask( [weak = WeakClaim(this), width, height] () { auto delegate = weak.Upgrade(); if (delegate && delegate->webview_ && !delegate->window_) { delegate->webview_->Resize(width, height); } }, TaskExecutor::TaskType::PLATFORM); } ...//web_delegate.cpp ··· void WebDelegate::LoadUrl()//加载URL { auto context = context_.Upgrade(); if (!context) { return; } context->GetTaskExecutor()->PostTask( [weak = WeakClaim(this)] () { auto delegate = weak.Upgrade(); if (delegate && delegate->webview_) { delegate->webview_->Load(delegate->webComponent_->GetSrc()); } }, TaskExecutor::TaskType::PLATFORM); } ...//web_delegate.cpp ··· sptr<OHOS::Rosen::Window> WebDelegate::CreateWindow()//创建webview的窗口 { auto context = context_.Upgrade(); if (!context) { return nullptr; } float scale = context->GetViewScale(); constexpr int DEFAULT_HEIGHT = 1600; int DEFAULT_HEIGHT_WITHOUT_SYSTEM_BAR = (int)(scale * context->GetRootHeight()); int DEFAULT_STATUS_BAR_HEIGHT = (DEFAULT_HEIGHT - DEFAULT_HEIGHT_WITHOUT_SYSTEM_BAR) / 2; constexpr int DEFAULT_LEFT = 0; int DEFAULT_TOP = DEFAULT_STATUS_BAR_HEIGHT; int DEFAULT_WIDTH = (int)(scale * context->GetRootWidth()); sptr<Rosen::WindowOption> option = new Rosen::WindowOption(); option->SetWindowRect({ DEFAULT_LEFT, DEFAULT_TOP, DEFAULT_WIDTH, DEFAULT_HEIGHT_WITHOUT_SYSTEM_BAR }); option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_LAUNCHING); option->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FLOATING); auto window = Rosen::Window::Create("ohos_web_window", option); return window; } ... -
其他部分,是使用pipeline中render来渲染页面,使用focus来控制页面焦点。
//render_web.h//渲染相关 ··· class RenderWeb : public RenderNode { DECLARE_ACE_TYPE(RenderWeb, RenderNode); public: static RefPtr<RenderNode> Create(); RenderWeb(); ~RenderWeb() override = default; void Update(const RefPtr<Component>& component) override; void PerformLayout() override; void OnAttachContext() override; } ···//rosen_render_web.h//渲染相关 ··· class RosenRenderWeb final : public RenderWeb { DECLARE_ACE_TYPE(RosenRenderWeb, RenderWeb); public: void DumpTree(int32_t depth) override; #ifdef OHOS_STANDARD_SYSTEM void Update(const RefPtr<Component>& component) override; void OnAttachContext() override; void Paint(RenderContext& context, const Offset& offset) override; void SyncGeometryProperties() override; std::shared_ptr<RSNode> CreateRSNode() const override; #endif } ···//web_element.h//调节焦点 ··· class WebElement : public RenderElement, public FocusNode { DECLARE_ACE_TYPE(WebElement, RenderElement, FocusNode); public: void SetNewComponent(const RefPtr<Component>& newComponent) override; void Update() override; void OnFocus() override; } ···
ace这部分主要是为JS UI框架提供动画解析、DOM(Document Object Model)树构建、布局计算、渲染命令构建与绘制、事件管理等能力。
关于JS UI框架的介绍 https://gitee.com/openharmony/arkui_ace_engine 或在md文档中查看foundation\ace\ace_engine\README_zh.md
nwebview提供的接口
nwebview中定义了为OpenHarmony的web组件提供基础功能支持的众多接口,同时是对下一层CEF框架的进一步封装,使得OpenHarmony可以按需定制自己的web功能,让开发者在使用web子系统开发浏览器时不需要关注繁杂的CEF和chromium,更加方便并专注于开发工作。需要指出的是,web子系统仍存在一些问题,nwebview的功能仍然正在逐步完善。
-
nweb_access_request.h 提供连接请求处理的接口,定义定位音视频捕获等服务的状态码,并定义如下接口: virtual std::string Origin() = 0;获取试图访问资源的网页的来源; virtual int ResourceAcessId() = 0;获取网页试图访问的资源ID; virtual void Agree(int resourceId) = 0;同意访问给定资源的源; virtual void Refuse() = 0;拒绝请求;
-
nweb_adapter_common.h 定义页面的宽高和surface缓冲;
-
nweb_adapter_helper.h 创建一个NWebAdapterHelper的单例,提供bool类型初始化函数,并定义根据参数是surface还是window去创建一个nwebview;
-
nweb_console_log.h 定义控制台输出日志函数,并定义日志类型;
-
nweb_context_menu_params.h 定义Nweb菜单上下文参数,包括ContextMenuTypeFlags,ContextMenuMediaType,ContextMenuEditStateFlags三种类型参数,并定义了一些获取与判断参数性质的接口;定义了Nweb快速菜单上下文参数,包括QuickMenuEditStateFlags,MenuEventFlags,MenuCommandId三种类型参数,并定义了一些获取参数性质的接口;定义了Nweb菜单上下文和Nweb快速菜单上下文的回调;
-
nweb_controller_handler.h 定义了Nweb的handler控制器,主要接口包括通过handler的Id去设置与获取对应的handler;
-
nweb_cookie_manager.h 管理web页面的cookie,如设置和获取当前页面是否允许发送与接收cookie,设置和获取当前页面是否允许设置第三方Cookie,设置和获取当前页面是否可以发送和接受文件方案URL的Cookie等;
-
nweb_data_base.h 主要用于管理http认证凭证,包括保存用户名和密码,并管理当前页面的相应权限;
-
nweb_data_resubmission_callback.h 定义Nweb数据是重新发送回调,包括重新发送与取消发送两个接口;
-
nweb_download_callback.h 定义了在web页面下载文件时回调,通知主机应用程序应下载文件的接口;
-
nweb_export.h 设置web页面的是否可视属性;
-
nweb_file_selector_params.h 定义FileSelectorMode参数类型,定义了一些在文件选择器选择文件时一些操作的接口;
-
nweb_find_callback.h 定义了通知主机应用程序回调;
-
nweb_geolocation_callback_interface.h 定义了在从usrs报告地理位置权限状态时回调的接口;
-
nweb_handler.h 定义了图片颜色类型(RGBA/BGRA)和图片的alpha类型(不透明/前乘/后乘,与图片透明度有关),定义了一系列与sdk有关的接口,如加载url,显示message,定义了与JS和其他属性与开关有关的接口;
-
nweb_hit_testresult.h 定义了一系列供点击测试的参数,如UNKNOWN_TYPE,ANCHOR_TYPE,PHONE_TYPE,定义了设置与获取Type和extra的接口;
-
nweb_helper.h 定义装载和卸载so的函数,定义以create_info为参数的创建web页面的函数,实现了nweb_adapter_helper.h中的CreateNweb函数;
-
nweb_input_event_consumer.h 定义以keyEvent,pointerEvent和axisEvent为参数的OnInputEvent接口并实现,并根据参数类型决定不同的动作;
-
nweb_javascript_result_callback.h 定义获取js执行结果的接口;
-
nweb_js_dialog_result.h 定义js对话的确认回应和取消回应接口;
-
nweb_js_http_auth_result.h 定义js对话的确认回应和取消回应接口,定义了处理来自用户的IsHttpAuthInfoSaved响应的接口;
-
nweb_js_ssl_error_result.h 定义了网页遇到SSL错误时用户选择的响应接口;
-
nweb_js_ssl_select_cert_result.h 定义了确认使用指定的私钥和客户端证书链,取消此证书请求,暂时忽略此证书请求的接口;
-
nweb_log.h 定义日志消息等级(debug,info,warn等);
-
nweb_preference.h 定义同步设置NWeb首选项和Web首选项的接口,如页面宽高,页面字体等;
-
nweb_save_cookie_callback.h 定义了保存cookie后回调的函数;
-
nweb_store_web_archive_callback.h 定义了保存web存档后回调的函数;
-
nweb_surface_adapter.h 定义获取页面大小,获取渲染接口,请求缓冲,复制页面框架和刷新缓冲的函数;
-
nweb_touch_handle_state.h 定义了触摸类型参数TouchHandleType,定义了对页面获取属性和判断的接口;
-
nweb_url_resource_error.h 定义了获取遇到URL源错误时的错误信息描述和错误码接口;
-
nweb_url_resource_request.h 定义了访问URL源请求时的一些接口;
-
nweb_url_resource_response.h 定义了访问URL源回应的一些接口;
-
nweb_web_storage.h 定义了保存和删除web源的接口,定义了设置web源的函数;
-
nweb_window_adapter.h 定义注册事件回调,请求同步当前窗口,获取页面大小,获取渲染接口,同步回调函数(surface->FlushBuffer);
-
nweb_value_callback.h 定义接收值的接口,这个值的类型为模板;
-
nweb_value.h 定义设置与获取数据类型的函数;
-
nweb.h 对外框架,提供了一系列生命周期接口和控制web页面的接口,如加载给定的URL,执行缩放操作等(不包括渲染和窗口部分)。
CEF提供的接口与服务
CEF简介
CEF全称Chromium Embedded Framework,是一个基于Google Chromium 的开源项目。Google Chromium项目主要是为Google Chrome应用开发的,而CEF的目标则是为第三方应用提供可嵌入浏览器支持。CEF作用是在客户端嵌入网页界面。
CEF结构
一个浏览器有很多个CefBrowser窗口,这些窗口都是在Browser进程中创建的。CEF是多进程架构的,CEF进程主要有一个Browser(浏览器)进程和多个render(渲染)进程。Browser被定义为主进程,负责窗口管理,网络请求,网页管理 、网络交互。browser从服务器请求到了响应,将html文本发送给render 进程,render进程加载html,进行渲染,展示网页的内容;除此之外,render进程还负责Js Binding和对Dom节点的访问。

Browser进程的实现结构
Browserapp要继承CefApp和CefBrowserProcessHandler类,来实现browserapp的定义。同时要新建clienthandler类实现图中的回调函数接口类,用来处理拦截响应请求、管理生命周期、下载、显示加载、右键菜单等。在main函数中初始化、启动消息循环。调用CefBrowserHost的静态方法创建browser窗口对象,在render进程的Frame中加载渲染内容。

Render进程的实现结构
Render要继承CefApp和CefRenderProcessHandler类,在main函数中初始化。通过CefSettings.browser_subprocess_path配置render可执行程序路径。browser进程就会去启动这个进程去渲染网页。

其他Cef重要类简介
-
CefBrowser是浏览器窗口类,相当于浏览器的外壳框架窗口,包含向前、向后、加载、获取内部frame的等方法。调用CefBrowserHost的静态方法创建一个CefBrowser对象,表示一个网页窗口。
-
CefBrowserHost是CefBrowser的一个主对象,CefBrowser中有方法virtual CefRefPtr<CefBrowserHost> GetHost() = 0;返回CefBrowser的主CefBrowserHost对象。然而CefBrowser对象又是通过CefBrowserHost类的静态方法来创建的。CefBrowserHost类包含一些CefBrowser操作方法,相当于是控制类,可以控制CefBrowser的创建、获取、关闭;获取打开CefBrowser窗口的窗口句柄、请求上下文(RequestContext);下载、查找、鼠标、键盘触发事件、焦点控制、拖拽事件等。
-
CefFrame是网页界面类,每个CefBrowser窗口包含一个主CefFrame对象和若干个子Frame对象。主CefFrame相当于网页的主界面,子CefFrame相当于主页面的子页面。CefFrame包含获取网页上的文字、HTML源码字符串、网页名字标题、加载的url、所属的CefBrowser指针、V8Context等。还可以用LoadURL或LoadRequest加载页面。
-
CefApp是应用程序类,网页嵌入程序都要实现这样一个应用程序类。提供了一些简单的接口:命令行参数修改,主题修改,获取进程句柄等。还有很多的子类,例如SimpleApp、ClientApp等,clientapp又有很多子类ClientAppBrowser、ClientApprender、ClientAppOther,表示不同的应用类型。
-
CEF创建对象形式如CefRefPtr<SimpleApp> app(new SimpleApp);或者CefRefPtr<SimpleApp> app = new SimpleApp();创建的指针引用计数由CefRefPtr管理,CefRefPtr通过调用AddRef()和Release()方法自动管理引用计数。
-
CefClient提供了获取各种handler的接口,例如上下文菜单handler、对话框handler、显示状态handler,下载事件handler、拖动事件handler、查找事件handler、键盘handler、生命周期事件handler、加载页面事件handler、离屏render进程handler、请求事件handler等。但是只是返回事件的handle。每个handler的具体的回调函数不在CefClient类中,需要继承各个handler类,才可以实现回调。CefClient类只有一个回调函数OnProcessMessageReceived用来处理进程间的通讯消息。
-
CefContextMenuHandler是网页上的右键菜单事件回调函数类,提供OnBeforeContextMenu回调函数,在右键菜单弹出之前修改或者禁用右键菜单。右键菜单按钮响应回调RunContextMenu、右键菜单命令回调OnContextMenuCommand菜单禁用回调函数OnContextMenuDismissed等。可以拦截右键菜单响应,进行自定义的处理。
-
CefDisplayHandler提供了一些页面显示回调函数,例如网址发送变化OnAddressChange,网页标题OnTitleChange发生变化,网页图标发生变化OnFaviconURLChange,全屏变化OnFullscreenModeChange,显示提示消息OnTooltip,状态栏消息显示OnStatusMessage,控制台消息回调OnConsoleMessage,设置了自动调整大小回调OnAutoResize,加载进程变化回调OnLoadingProgressChange。
-
CefDownloadHandler网页上下载文件类,提供开始从网页下载文件回调函数OnBeforeDownload,下载文件进度更新回调函数OnDownloadUpdated。
-
CefDragHandler处理鼠标拖动事件,提供鼠标拖动进入网页回调函数OnDragEnter,网页中可以拖动放入的区域发生变化回调函数OnDraggableRegionsChanged。
-
CefKeyboardHandler处理键盘响应事件,提供键盘按键响应回调函数。拦截键盘消息。
-
efLifeSpanHandler是生命周期处理类,新打开一个网页或者关闭一个网页时,会触发回调函数。OnBeforePopup这个只能在创建一个新的弹出式网页时,才会触发,如果是在一个网页中打开一个子网页,回调函数是拦截不到消息的。OnAfterCreated网页创建完成后的回调函数。browser销毁之前会触发回调函数OnBeforeClose。还有一个关闭回调函数DoClose有点复杂,当调用CefBrowserHost::CloseBrowser()函数关闭browser,或者browser是CEF创建的顶层窗口的子窗口,当顶层窗口关闭时,也会触发关闭DoClose回调函数。点击网页的关闭按钮后,网页不会立刻关闭,而是会调用两次CloseBrowser()或TryCloseBrowser(),提供了一个让CEF处理JS的onbeforeunload事件和选择性取消关闭网页的机会。
-
CefLoadHandler是网页加载处理类,在一个网页中加载内容,或者在网页中打开一个子frame,都可以拦截到iframe打开时的消息以及url等信息。可以拦截子网页url。
-
CefRequestHandler是网络请求处理类,当打开一个网页, CefRequestHandler的OnBeforeBrowser可以拦截网络请求,只有在新打开网页的时候,才会触发,如果网页已经打开,在网页内部点击查询按钮,查询内容,虽然也有request请求,但是OnBeforeBrowser拦截不到获取请求的URL,post请求的参数都可以获取到。OnResourceRedirect还可以拦截重定向请求。CefLoadHandler也可以拦截request请求,而且页面加载中调用很多的GET和POST请求都可以拦截到。测试发现CefRequestHandler页面内部的加载变化是获取不到的,只有打开页面的请求能获取到。而另外一个函数OnBeforeResourceLoad则可以拦截所有的请求,在浏览器中F12显示的所有请求,包括图片下载等请求都能一一获取。所以CefLoadHandler拦截的请求更详细一些,点击查询查询,OnLoadStart和OnLoadEnd 拦截不到,但是OnLoadingStateChange 可以拦截的到请求。
详细可以参考third_party\cef中源码注释。
ohos_nweb目录简介
在拉取到chromium源码并切换分支后,进入src/ohos_nweb即可。这部分就是NWeb.hap中在中间层的实现部分。
该目录为OHOS系统提供对底层web内核的一层封装。各子目录内容为:
- include:提供暴露给OHOS的接口和相关定义。OHOS侧可通过这些方法加载和使用web内核。
- src:对web内核的封装实现,其中各子目录中的内容表示对不同web内核的封装,其它部分为一些通用逻辑的实现。
- cef_delegate: 对cef接口的封装。
在chromium源码已整合到OpenHarmony之后,进入OpenHarmony\third_party\chromium中执行build.sh对nweb进行编译,可编译出libnweb_adapter.so,libweb_engine.so,web_render.so,libnweb_render.so,将.so文件推入开发板的/system/lib目录下,nwebview获得能力。
ohos_nweb\include下的nwebview层
这里的文件与OpenHarmony\base\web\webview\ohos_nweb\include下的文件是一致的,作用是给ohos提供接口以供开发者调用。前面已对这部分有过描述,在此不再赘述。
src/ohos_nweb中对web内核封装实现
在这个目录下,除了对web内核的封装,还有对nwebview接口的实现。这里选取部分文件进行展示。
-
nweb_impl.h 继承NWeb的NWeb并重写了接口,定义了init函数用于初始化SetNWebId,初始化web engine,创建input_handler对象和output_handler对象,定义OnDestroy函数,通过NWebDelegate关闭浏览器窗口并销毁NWebDelegate
//nweb_impl.h bool Init(const NWebCreateInfo& create_info); void OnDestroy() override; /* event interface */ void Resize(uint32_t width, uint32_t height) override; void OnTouchPress(int32_t id, double x, double y) override; void OnTouchRelease(int32_t id, double x, double y) override; void OnTouchMove(int32_t id, double x, double y) override; void OnTouchCancel() override; void OnNavigateBack() override; ... void ProcessInitArgs(const NWebInitArgs& init_args); void InitWebEngineArgs(const NWebInitArgs& init_args); bool InitWebEngine(const NWebCreateInfo& create_info); -
nweb_url_resource_error_impl.h 继承NWeb的NWebUrlResourceError并重写接口,以实现获取访问网页时可能产生的错误码和错误信息
//nweb_url_resource_error_impl.h const std::string& ErrorInfo() const override { return error_info_; } int ErrorCode() const override { return error_code_; } -
nweb_url_resource_request_impl.h 继承NWeb的NWebUrlResourceRequest并重写接口,以实现通过URL访问网页时的控制与管理
//nweb_url_resource_request_impl.h const std::string& Method() override; const std::map<std::string, std::string>& RequestHeaders() override; const std::string& Url() override; bool FromGesture() override; bool IsAboutMainFrame() override; bool IsRequestRedirect() override;
ohos_nweb\src\cef_delegate下对cef接口和nwebview接口的封装实现
在这个目录下,继承并实现了部分cef接口和nwebview接口。这里选取部分文件展示。
-
nweb_access_request_delegate.h 继承NWeb中的NWebAccessRequest并重写接口,以实现对访问请求的控制。
nweb_access_request_delegate.h std::string Origin() override; int ResourceAcessId() override; void Agree(int resourceId) override; void Refuse() override; -
nweb_application.h 继承CefApp并重写GetBrowserProcessHandler,GetRenderProcessHandler,继承CefBrowserProcessHandler并重写OnContextInitialized(在cef上下文初始化后立即在浏览器进程UI线程上调用),GetDefaultClient,定义GetURL,继承CefRenderProcessHandler并重写OnWebKitInitialized,在.cc中用cef.browser.h中的CefBrowserHost::CreateBrowser创建一个新的浏览器窗口。
//nweb_application.h /* CefApp methods begine */ CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override; CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override; /* CefApp methods end */ /* CefBrowserProcessHandler methods begin */ void OnContextInitialized() override; CefRefPtr<CefClient> GetDefaultClient() override; std::string GetURL(); /* CefBrowserProcessHandler methods end */ /* CefRenderProcessHandler methods begin */ void OnWebKitInitialized() override; /* CefRenderProcessHandler methods begin */ void CreateBrowser();//nweb_application.cc // Create the first browser window. CefBrowserHost::CreateBrowser(window_info, handler_delegate_, url,browser_settings, nullptr, nullptr); -
nweb_cookie_manager_delegate.h 继承nweb_cookie_manager_delegate_interface.h并重写其中接口,在.cc中继承cef中多个与cookie有关的delegate类,回调类,访问类等以实现对浏览器cookie的管理
//nweb_cookie_manager_delegate.h bool IsAcceptCookieAllowed() override; void PutAcceptCookieEnabled(bool accept) override; bool IsFileURLSchemeCookiesAllowed() override; void PutAcceptFileURLSchemeCookiesEnabled(bool allow) override; void ReturnCookie( const std::string& url, std::shared_ptr<NWebValueCallback<std::string>> callback) override; void SetCookie(const std::string& url, const std::string& value, std::shared_ptr<NWebValueCallback<bool>> callback) override; void ExistCookies(std::shared_ptr<NWebValueCallback<bool>> callback) override; void Store(std::shared_ptr<NWebValueCallback<bool>> callback) override; void DeleteSessionCookies( std::shared_ptr<NWebValueCallback<bool>> callback) override; void DeleteCookieEntirely( std::shared_ptr<NWebValueCallback<bool>> callback) override;//nweb_cookie_manager_delegate.cc class CookieCompletionCallback : public CefCompletionCallback ... class HasCookieVisitor : public CefCookieVisitor ... class ReturnCookieVisitor : public CefCookieVisitor ... -
nweb_delegate.h 继承NWebDelegateInterface并定义其中的接口,定义init函数以创建render_handler对象和event_handler对象并初始化cef框架,定义RunMessageLoop开启cef消息循环,定义InitializeCef初始化cef,并在InitializeCef时调用nweb_application.cc中的CreateBrowser
//nweb_delegate.h bool Init(void* window); bool IsReady() override; void OnDestroy(bool is_close_all) override; void RegisterDownLoadListener( std::shared_ptr<NWebDownloadCallback> downloadListener) override; void RegisterNWebHandler(std::shared_ptr<NWebHandler> handler) override; void RegisterRenderCb( std::function<void(const char*)> render_update_cb) override; void SetInputMethodClient( CefRefPtr<NWebInputMethodClient> client) override; void Resize(uint32_t width, uint32_t height) override; void OnTouchPress(int32_t id, double x, double y) override; void OnTouchRelease(int32_t id, double x, double y) override; void OnTouchMove(int32_t id, double x, double y) override; void OnTouchCancel() override; ... void RunMessageLoop(); void InitializeCef(std::string url, void* window);//nweb_delegate.cc void NWebDelegate::InitializeCef(std::string url, void* window) { ... if (is_initialized) { return nweb_app_->CreateBrowser(); } ... } -
nweb_event_handler.h 定义与触控滑动OnTouch相关函数,以实现对浏览器页面的滑动操作
//nweb_event_handler.h void OnTouchPress(int32_t id, double x, double y); void OnTouchMove(int32_t id, double x, double y); void OnTouchRelease(int32_t id, double x, double y); void OnTouchCancel(); void OnKeyBack(); -
nweb_handler_delegate.h 继承CefClient,CefLifeSpanHandler,CefLoadHandler,CefRequestHandler,CefResourceRequestHandler,CefDisplayHandler,CefDownloadHandler,CefFocusHandler,CefPermissionRequest,CefJSDialogHandler并重写其中一些函数, 并定义Create,OnDestroy,RegisterDownLoadListener,RegisterNWebHandler,RegisterNWebJavaScriptCallBack,CloseAllBrowsers,以实现对浏览器的各种控制,如创建新的浏览器窗口,销毁所有浏览器窗口,获取Download,LifeSpan,Load等Handler,以实现对浏览器生命周期的管理,加载页面状态及结果的管理,向服务器端发送请求及请求结果的管理,下载的管理,资源管理,诸如Title和ConsoleMessage的显示管理,焦点管理,定位权限的管理,JS执行日志的管理
//nweb_handler_delegate.h static CefRefPtr<NWebHandlerDelegate> Create( std::shared_ptr<NWebPreferenceDelegate> preference_delegate, CefRefPtr<NWebRenderHandler> render_handler, std::shared_ptr<NWebEventHandler> event_handler); ... void OnDestroy(); void RegisterDownLoadListener( std::shared_ptr<NWebDownloadCallback> download_listener); void RegisterNWebHandler(std::shared_ptr<NWebHandler> handler); void RegisterNWebJavaScriptCallBack( std::shared_ptr<NWebJavaScriptResultCallBack> callback); // Request that all existing browser windows close. void CloseAllBrowsers(bool force_close); bool IsClosing() const; const CefRefPtr<CefBrowser> GetBrowser(); ... /* CefClient methods begin */ CefRefPtr<CefDownloadHandler> GetDownloadHandler() override; CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override; CefRefPtr<CefLoadHandler> GetLoadHandler() override; ··· /* CefClient methods end */ /* CefLifeSpanHandler methods begin */ void OnAfterCreated(CefRefPtr<CefBrowser> browser) override; bool DoClose(CefRefPtr<CefBrowser> browser) override; void OnBeforeClose(CefRefPtr<CefBrowser> browser) override; ··· /* CefLifeSpanHandler methods end */ /* CefLoadHandler methods begin */ void OnLoadingStateChange(CefRefPtr<CefBrowser> browser, bool is_loading, bool can_go_back, bool can_go_forward) override; void OnLoadStart(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, TransitionType transition_type) override; void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int http_status_code) override; ··· /* CefLoadHandler methods end */ /* CefRequestHandler methods begin */ bool OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool user_gesture, bool is_redirect) override; bool OnCertificateError(CefRefPtr<CefBrowser> browser, cef_errorcode_t cert_error, const CefString& request_url, CefRefPtr<CefSSLInfo> ssl_info, CefRefPtr<CefRequestCallback> callback) override; ··· /* CefRequestHandler methods end */ /* CefDownloadHandler methods begin */ void OnBeforeDownload(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDownloadItem> download_item, const CefString& suggested_name, CefRefPtr<CefBeforeDownloadCallback> callback) override; /* CefDownloadHandler methods end */ /* CefResourceRequestHandler method begin */ ReturnValue OnBeforeResourceLoad( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, CefRefPtr<CefRequestCallback> callback) override; CefRefPtr<CefResourceHandler> GetResourceHandler( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request) override; /* CefResourceRequestHandler method end */ /* CefDisplayHandler method begin */ void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) override; void OnLoadingProgressChange(CefRefPtr<CefBrowser> browser, double progress) override; ··· /* CefDisplayHandler method end */ /* CefFocusHandler method begin */ bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) override; /* CefFocusHandler method end */ /* CefPermissionRequest method begin */ void OnGeolocationShow(const CefString& origin) override; void OnGeolocationHide() override; void OnPermissionRequest(CefRefPtr<CefAccessRequest> request) override; void OnPermissionRequestCanceled( CefRefPtr<CefAccessRequest> request) override; /* CefPermissionRequest method end */ /* CefJSDialogHandler method begin */ bool OnJSDialog(CefRefPtr<CefBrowser> browser, const CefString& origin_url, JSDialogType dialog_type, const CefString& message_text, const CefString& default_prompt_text, CefRefPtr<CefJSDialogCallback> callback, bool& suppress_message) override; ··· -
nweb_preference_delegate.h 继承NWeb的NWebPreference并重写这些接口,以实现对NWeb首选项的设置,如设置页面的FontFamily,是否允许通过JS创建新窗口,设置DarkMode等,并定义了RunningInsecureContentAllowed是否允许运行不安全内容,UseStricMixedContentCheckingAllowed是否允许使用限制混合内容检查(全部http或https),MixedContentAutoupgradesAllowed是否允许混合内容自动升级(http->https或https->http),PutHasInternetPermission是否具有访问网络权限
//nweb_preference_delegate.h void PutEnableContentAccess(bool flag) override; void PutEnableRawFileAccess(bool flag) override; void PutEnableRawFileAccessFromFileURLs(bool flag) override; ··· -
nweb_render_handler.h 继承CefRenderHandler并重写部分接口,以实现渲染操作,定义Create来创建NWebRenderHandler对象,RegisterRenderCb设置回调,Resize重新设置大小
//nweb_render_handler.h void RegisterRenderCb(std::function<void(const char*)> render_update_cb); void Resize(uint32_t width, uint32_t height); ... /* CefRenderHandler method begin */ virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) override; virtual void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirty_rects, const void* buffer, int width, int height) override; void OnRootLayerChanged(CefRefPtr<CefBrowser> browser, int height, int width) override; virtual void OnImeCompositionRangeChanged( CefRefPtr<CefBrowser> browser, const CefRange& selected_range, const RectList& character_bounds) override; virtual void OnTextSelectionChanged(CefRefPtr<CefBrowser> browser, const CefString& selected_text, const CefRange& selected_range) override; virtual void OnVirtualKeyboardRequested(CefRefPtr<CefBrowser> browser, TextInputMode input_mode) override; /* CefRenderHandler method end */ ... -
nweb_resource_handler.h 继承CefResourceHandler并重写部分接口,以实现对资源请求的处理
///* CefResourceHandler method begin */ bool Open(CefRefPtr<CefRequest> request, bool& handle_request, CefRefPtr<CefCallback> callback) override; bool Read(void* data_out, int bytes_to_read, int& bytes_read, CefRefPtr<CefResourceReadCallback> callback) override; void GetResponseHeaders(CefRefPtr<CefResponse> response, int64& response_length, CefString& redirectUrl) override; void Cancel() override; /* CefResourceHandler method end */ /* CefResourceHandler method begin */ bool Open(CefRefPtr<CefRequest> request, bool& handle_request, CefRefPtr<CefCallback> callback) override; bool Read(void* data_out, int bytes_to_read, int& bytes_read, CefRefPtr<CefResourceReadCallback> callback) override; void GetResponseHeaders(CefRefPtr<CefResponse> response, int64& response_length, CefString& redirectUrl) override; void Cancel() override; /* CefResourceHandler method end */
流程
简要流程
以etsWeb浏览器App浏览百度为例。
-
打开浏览器,加载默认的主页;
-
浏览器创建Browser进程和render进程;
-
在搜索栏或URL栏输入“百度”或百度的网址"www.baidu.com"(返回PC端网页)或"m.baidu.com"(返回移动端网页),向服务器发送请求,然后点击搜索按钮;
-
根据浏览器的选择,可能会在本页面展示目标网页,也可能会新建一个页面展示目标网页,这个需要看目标页面开发者如何定义;
-
获取到从服务器返回的数据后,Browser进程将数据发送给render进程,render进程负责渲染页面,然后展示页面内容;
-
用户进行浏览网页的行为;
-
如果用户新建一个网页,则会创立一个新的render进程来渲染新页面;
-
如果用户点击关闭单个网页的按钮,或者点击关闭整个浏览器,浏览器不会立刻关闭页面,而是会检查是否有与关闭页面相关的JS脚本,或提供取消关闭网页的机会,处理完毕后或选择确认关闭网页后,浏览器会关闭网页;如果被关闭的网页是最后一个网页或者用户选择关闭浏览器,那么浏览器会销毁Browser进程和render进程,然后退出。

启动流程
-
在启动时,首先调用NWeb的CreateNWeb,并在函数中定义nweb_id,然后创建NWebImpl对象nweb,然后对nweb初始化,若初始化成功,则nweb计数g_nweb_count加1。
-
在对nweb初始化时,调用NWebImpl::Init,并在函数中创建NWebOutputHandler的对象output_handler,并通过output_handler设置SetNWebId,然后初始化进程参数ProcessInitArgs,初始化WebEngine,最后创建NWebInputHandler的对象input_handler。在初始化WebEngine时,会获取窗口GetNativeWindowFromSurface,创建NWebDelegateAdapter的对象nweb_delegate,获取窗口信息output_handler->GetWindowInfo,重新设置页面大小nweb_delegate->Resize,注册渲染回调nweb_delegate->RegisterRenderCb,创建NWebInputMethodHandler对象inputmethod_handler,设置nweb_delegate->SetInputMethodClient,最后返回nweb_delegate已准备完毕。
-
在创建NWebDelegateAdapter对象nweb_delegate时,会对delegate初始化delegate->Init,在初始化时,会创建NWebRenderHandler对象render_handler和NWebEventHandler对象event_handler,然后初始化cef即InitializeCef。在初始化cef时,会创建NWebHandlerDelegate的对象handler_delegate和NWebApplication的对象nweb_app,若is_initialized为TRUE,则创建浏览器对象nweb_app_->CreateBrowser,若CefInitialize成功,则将is_initialized值改为TRUE。

融合渲染流程
当前NWeb已支持UI组件的融合渲染,web组件可以与native组件同时显示在屏幕上,并保持正确的相互关系。下面对支持融合渲染的流程进行说明,由于同时涉及NWeb、ArkUI和图形三个模块,因此将同时结合这三个模块进行描述。
融合渲染流程所涉及的模块间结构关系如下图所示。

其中:
-
ArkUI中的组件与图形侧的SurfaceNode一一对应,这些SurfaceNode保留了组件间的Z-序关系。
-
Web组件持有一个对应的NWeb实例。
-
NWeb实例中保存一份Web组件对应的SurfaceNode中的Surface对象。
基于这个结构关系,NWeb支持融合渲染的时序流程如下图所示
该流程的具体描述如下:
-
创建初始化。当hap应用声明使用了web组件时,ArkUI会进行web组件的创建及初始化,其中与融合渲染相关的主要流程有:
-
为web组件创建SurfaceNode作为图形后端。该SurfaceNode与组件一一对应,并基于ArkUI中各组件的Z-序关系保存在图形侧。
-
创建NWeb实例,并从SurfaceNode中获取Surface实例传递给NWeb实例,保存在NWeb交互层中。该Surface实例为producerSurface,NWeb实例则是该Surface内容的生产者。同时将完成web核心的初始化。
-

-
网页加载。当NWeb实例创建完成,web组件会获取开发者提供的src属性值作为URL,并调用NWeb实例进行网页加载和渲染输出。主要流程为: Web组件调用NWeb实例的LoadURL接口开始网页加载。
-
NWeb实例在核心中实现网页的解析、渲染、合成等一系列操作。
-
核心输出网页渲染结果,以bitmap的形式保存在cpu内存中。
-
NWeb交互层调用Surface的RequestBuffer获取到SurfaceBuffer,将渲染结果拷贝到SurfaceBuffer中,再调用Surface的FlushBuffer接口将渲染结果上传到相应SurfaceNode当中。至此图形侧收到了NWeb的网页渲染结果。
-

-
送显。图形侧接收到vsync信号时,将根据SurfaceNode之间的相互关系,对相应的Surface中的内容进行融合渲染,此时将消费保存在Surface中的NWeb网页渲染结果,进而完成送显。这样得到的hap应用渲染结果中,就实现了web内容与其它native组件内容的融合渲染。

如果想要验证融合渲染效果,可编写hap应用同时调用web组件及其它native组件,观察不同组件在屏幕上显示的层级关系是否符合预期。
销毁流程
-
从NWebImpl::OnDestroy开始,首先根据g_nweb_count计数是否为0,将is_close_all赋值为TRUE或FALSE,然后判断nweb_delegate是否为空,若不为空则销毁nweb_delegate即nweb_delegate_->OnDestroy,然后判断input_handler是否为空,若不为空则销毁input_handler即input_handler->OnDestroy。
-
在销毁nweb_delegate时,判断handler_delegate是否为空,若不为空则销毁handler_delegate即handler_delegate_->OnDestroy,判断preference_delegate是否为空,若不为空则销毁preference_delegate即preference_delegate->OnDestroy,然后判断is_close_all是否为TRUE,若是则关闭cef即CefShutdown。
-
在销毁handler_delegate时,判断main_browser是否为空,若不为空则销毁main_browser即main_browser_->GetHost()->CloseBrowser,判断event_handler是否为空,若不为空则销毁event_handler即event_handler->OnDestroy。

其他
目前web子系统还存在很多问题,如访问某些网站会因为验证证书失败而无法访问,浏览器APP所占用的内存会随着网页的增多而增加,但系统缺乏有效的回收内存的接口(此功能已在3.2beta2修复),下载功能尚不完善,对在线office支持较弱等。开发人员正在积极增强web子系统的功能,以便使开发者拥有更好的体验。在OpenHarmony社区上可以看到最新版本的web子系统中nwebview层的代码和NWeb.hap,如果有兴趣,可以自行研究。
OpenHarmony社区中webview模块 https://gitee.com/openharmony/web_webview/tree/master
参考文献
[1]web_webview. https://gitee.com/openharmony/web_webview
[2]CEF使用说明书(转).https://www.cnblogs.com/wxzai/p/16006770.html
更多推荐

所有评论(0)