整理了一下之前写的cef推荐的关闭流程的文档
参考文档和实际demo来看,关闭流程离屏渲染和非离屏渲染时不同的,主要区别在于非离屏渲染有一个cef自建的窗口,非离屏渲染的退出和这个窗口密切相关。
CefBrowserHost::TryCloseBrowser
适用于窗口模式工作的CEF browser,如果是离屏渲染应该使用CloseBrowser(false)
来尝试关闭浏览器。
CefLifeSpanHandler::DoClose
CefLifeSpanHandler::DoClose
这个函数会在browser已经准备关闭时调用,意味着browser生命周期的关闭,关闭已经准备就绪,并且JS已经被卸载或者可以忽略。
这个函数的触发基本上是来自于CefBrowser::[Try]CloseBrowser()
的直接调用。如果承载browser的窗口已经被销毁(父窗口),DoClose
不会被调用,并且此时不再有机会去执行客制化关闭。
开发时应该避免承载browser窗口立刻关闭,而是通过CefBrowser::CloseBrowser()
函数或者CefBrowserHost::CloseBrowser(false)
来处理关闭通知。文档中提到,关闭承载浏览器的窗口应该通过CefBrowser::CloseBrowser()
函数或者CefBrowserHost::CloseBrowser(false)
来触发(实现一个从下到上的关闭,和平常的从父窗口开始关闭相反),或者也可以从上到下(如果可以处理关闭信号并Block关闭流程),但是要block一下父窗口的关闭流程。可以算是两种方案?
当时用有窗口模式的CEF时,CEF会创建一个窗口来承载浏览器,此时DoClose
返回false后会发送一个标准关闭通知到这个窗口的上层窗口(即用来承载browser时创建的窗口)。
当使用离屏渲染模式的时候,CEF就不会创建窗口了,此时DoClose
返回false后browser对象会立刻开始销毁(没有关闭信号通知了,开发者应该自行处理窗口的关闭销毁逻辑)。
如果承载browser的窗口需要一个非标准的关闭通知(非标准的自定义关闭流程?),此时DoClose
应该返回true,他不会继续处理浏览器的关闭流程,开发者需要后续自己主动关闭。
一般来说,返回值为false,由browser主导关闭主动权。
CefBrowserHost::CloseBrowser(bool force_close)
并不推荐使用的关闭函数,较为粗暴的关闭,force_close
参数为false时可能会被用户取消关闭,为true时会尽快关闭。但是最好还是关注一下各个生命周期会触发的回调函数。
CefLifeSpanHandler::OnBeforeClose()
CefLifeSpanHandler::OnBeforeClose()
这个函数会在browser对象销毁钱立刻被调用,当所有的browser对象都触发了这个函数之后,应用才可以安全退出。
该函数没有返回值,只是一个用于通知的回调函数。
关闭流程(非离屏渲染)使用TryCloseBrowser()
退出
- 用户点击APP业务窗口的关闭按钮,此时开始处理APP业务窗口的关闭触发函数
- 关闭流程开始调用
TryCloseBrowser()
,TryCloseBrowser()
返回false,代表cef client取消了窗口关闭,此时还不能直接关闭,但是已经将关闭请求发给Browser - JavaScript
onbeforeunload
回调被触发执行,并且展示关闭确认通知 - 用户同意关闭
- JavaScript的
onunload
被调用 - 应用层
DoClose()
被调用并且默认返回false - CEF发送一个关闭通知到APP业务窗口(因为
DoClose()
返回了false) - APP业务窗口收到了关闭通知,并且再次调用
TryCloseBrowser()
来检查,此时该函数返回true,客户端允许窗口关闭 - APP业务窗口被销毁,触发child browser窗口的销毁(这里是自上而下的窗口销毁)
- 应用的
OnBeforeClose
回调触发,browser对象被销毁,此时就可以安全的关闭APP业务窗口了 - 如果没有其他browser存在的话,就可以调用
CefQuitMessageLoop()
来退出了。
关闭流程(CloseBrowser(false)
退出)
依然需要实现DoClose()
回调,用于非正常关闭处理,或者一些不是由browser进程创建的窗口
- 用户点击窗口的关闭按钮,此时关闭通知发送到了browser业务窗口(以下简称上层窗口)
- 上层窗口收到了关闭通知,执行了如下操作
a. 调用CefBrowserHost::CloseBrowser(false)
b. 取消窗口关闭 - JavaScript
onbeforeunload
回调被触发执行,并且展示关闭确认通知 - 用户同意关闭
- JavaScript的
onunload
被调用 - 应用层
DoClose()
被调用,此时将
a. 设置一个flag标记位指明下一个上层窗口的关闭尝试将会被允许
b. return false - CEF发送一个关闭通知到上层窗口(因为
DoClose()
返回了false) - 上层窗口收到关闭通知并且允许窗口关闭(参考6.a.)
- 上层窗口被销毁,触发child browser窗口的销毁(这里是自上而下的窗口销毁)
- 应用的
OnBeforeClose
回调触发,browser对象被销毁 - 如果没有其他browser存在的话,就可以调用
CefQuitMessageLoop()
来退出了。
离屏渲染须知
使用离屏渲染模式进行CEF的开发时,调用TryCloseBrowser()
不会触发DoClose()
应该使用CloseBrowser(false)
关闭浏览器,DoClose()
中也无需返回false来处理窗口关闭信号的发送,直接返回true进入销毁的下一步骤,触发OnBeforeClose()
后就可以处理绘制窗口的关闭和清理了。
- 用户点击窗口的关闭按钮,此时关闭通知发送到了窗口
- 窗口收到通知,但是先不要执行关闭,调用
CloseBrowser(false)
来发起浏览器关闭 DoClose
被触发,返回true,直接走销毁流程OnBeforeClose()
触发后,就可以走窗口的关闭了- 关闭窗口
- 如果没有其他browser存在的话,就可以调用
CefQuitMessageLoop()
来退出了。