文章目录
- CEF3—在网页加载前给js对象填值
- 前言
- 思路
- 代码
CEF3—在网页加载前给js对象填值
前言
记录一次笔者在实际开发中遇到的问题。在用cef做多页应用开发的时候,多个单页共享数据的问题。这个数据被前端称之为token,在多页应用中需要被共享。数据被使用和存的动作都是在render进程,而多个h5页面也就是多个 render进程中,但是存放的位置肯定是在browser进程,因为browser进程是后台进程,大家取数据都到同一个进程中去存取 数据也就被共享。
思路
笔者一开始设计的接口如下:
BB.SetToken(x); // 存token
BB.Token(function(x){console.log(x);}); // 取token
存 会去更新token。 取 需要通过回调函数取,这里需要在回调函数中去,因为数据并不在render进程中 只能异步取。看是去一切还很简单 美好。但是 前端并不想通过回调函数的方式取token,就想通过类似下面的方式去取。
// 前端想快速方便的取到token,类似下面这种方式
var token = BB.Token(); // 方法返回值方式
var token = BB.token; // 对象属性的方式
当然前端的要求并不过分,就得我们去想办法去实现了!这里如果用方法的返回值的话,必须使用全局的事件进行等待,等从browser取到了还要从共享内存或者其他方式把token数据取到。所以笔者当然也想用最简单方式去实现,这里是使用 BB.token对象属性值的方式。
如果用对象属性的方式的话,我们 token的填值 就是我们客户端作为主动方进行填值。如果 有单页使用SetToken方法更新token,那么此时 客户端要更新所有单页上的 BB.token。如果新开一个单页而且js代码要立即取到BB.token的值,这里也就是笔者遇到的问题。因为笔者 更新某个单页的上的BB.token逻辑已写好,当新单页打开加载后 直接给新开的单页 发送消息让其更新token即可,但是这样回有一个延时问题 在页码加载过程中 js代码取不到token而要等1s后才能取到。
代码
所以 不能等单页加载完后 去发送更新token的消息去进行更新。这里必须是在 创建单页或者在单页加载完前 类似window对象的内置属性一样 可以直接取到token。网上没找到参考的,所以笔者去仔细看了一下cef接口 果然找到了。主要用到下面几个接口。
// 创建单页会用到下面这个接口,对就是这个函数,仔细看这个函数的extra_info参数,该数据可以将browser进程的数据带到创建单页过程中的回调函数中CefRenderProcessHandler::OnBrowserCreated()
// CefBrowserHost的静态成员函数
///
// Create a new browser window using the window parameters specified by
// |windowInfo|. All values will be copied internally and the actual window
// will be created on the UI thread. If |request_context| is empty the
// global request context will be used. This method can be called on any
// browser process thread and will not block. The optional |extra_info|
// parameter provides an opportunity to specify extra information specific
// to the created browser that will be passed to
// CefRenderProcessHandler::OnBrowserCreated() in the render process.
///
/*--cef(optional_param=client,optional_param=url,
optional_param=request_context,optional_param=extra_info)--*/
static bool CreateBrowser(const CefWindowInfo& windowInfo,
CefRefPtr<CefClient> client,
const CefString& url,
const CefBrowserSettings& settings,
CefRefPtr<CefDictionaryValue> extra_info,
CefRefPtr<CefRequestContext> request_context);
// 所以就找到CefRenderProcessHandler中相关的回调函数
// CefRenderProcessHandler中可被重写的回调函数
// 该函数可以取到从browser进程中带过来的数据
///
// Called after a browser has been created. When browsing cross-origin a new
// browser will be created before the old browser with the same identifier is
// destroyed. |extra_info| is a read-only value originating from
// CefBrowserHost::CreateBrowser(), CefBrowserHost::CreateBrowserSync(),
// CefLifeSpanHandler::OnBeforePopup() or CefBrowserView::CreateBrowserView().
///
/*--cef()--*/
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDictionaryValue> extra_info) {}
// 下面这个函数注释写的很清楚,下面是Chrome V8环境一旦被创建好就会被回调,所以在下面回调函数中取我们的自定义对象或者 window对象一定是可以取到并能赋值的
///
// Called immediately after the V8 context for a frame has been created. To
// retrieve the JavaScript 'window' object use the CefV8Context::GetGlobal()
// method. V8 handles can only be accessed from the thread on which they are
// created. A task runner for posting tasks on the associated thread can be
// retrieved via the CefV8Context::GetTaskRunner() method.
///
/*--cef()--*/
virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Context> context) {}
关键代码如下:
// browser进程中创建单页
CefRefPtr<CefDictionaryValue> extra_info = CefDictionaryValue::Create();
extra_info->SetString("token",m_strToken);
CefBrowserHost::CreateBrowser(windowInfo, m_browserEvent, strUrl, browserSetting, extra_info, NULL);
// render进程中处理数据并给js对象进行属性赋值
static CefString m_strToken = "";
void CCefBrowserApp::OnBrowserCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefDictionaryValue> extra_info)
{
m_strToken = extra_info->GetString(CefString("token"));
}
void CCefBrowserApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context)
{
context->Enter();
CefRefPtr<CefV8Value> window = context->GetGlobal();
CefRefPtr<CefV8Value> BB = window->GetValue(CefString("BB"));
if(BB->IsObject())
{
CefRefPtr<CefV8Value> token = CefV8Value::CreateString(m_strToken);
BB->SetValue(_T("token"),token,CefV8Value::PropertyAttribute::V8_PROPERTY_ATTRIBUTE_DONTDELETE);
}
context->Exit();
}