CEF小白人系列10-代码实现Command-Line模式

我们知道了如何使用命令行执行模式来增加参数。

Command-Line可以不可以在代码里进行修改呢?答案是可以的。

其实我只需要重载OnBeforeCommandLineProcessing就可以了。

下面给出片段的代码

class CCefClientApp : public CefApp, public CefBrowserProcessHandler
{
public:
    CCefClientApp();
    ~CCefClientApp();

    virtual CefRefPtr GetBrowserProcessHandler() override 
    {
        return this;
    }

    //重新这里用来在代码里执行command-line
    virtual void OnBeforeCommandLineProcessing(const CefString& process_type, CefRefPtr command_line) override;

    virtual void OnContextInitialized() override;

private:

    IMPLEMENT_REFCOUNTING(CCefClientApp);

private:

};

//cefclient.exe -ppapi-flash-path="flashplayer.dll" -url="http://www.163.com" 的效果一致
void CCefClientApp::OnBeforeCommandLineProcessing(const CefString & process_type, CefRefPtr command_line)
{
    //flash插件
    command_line->AppendSwitchWithValue("-ppapi-flash-path", "flashplayer.dll");
    //修改加载url
    command_line->AppendSwitchWithValue("-url", "http://www.163.com");

}

是不是很简单。

因为上一章我们搭建的干净cef项目的事例代码只是为了实现一个简单演示,存在某些网站打开会崩溃的问题,现在我提供一个稳定的事例代码。代码一共6个文件,可以直接拷贝到上一章搭建的干净项目内,删除main.cc。编译运行即可。

1.simple_app.h


#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_

#include "include/cef_app.h"

//CefApp接口提供了不同进程的可定制回调函数
class SimpleApp : public CefApp, public CefBrowserProcessHandler {
 public:
  SimpleApp();

  // CefApp 方法:返回定制Browser进程的Handler,该Handler包括了诸如OnContextInitialized的回调。
  virtual CefRefPtr GetBrowserProcessHandler()
      OVERRIDE {
    return this;
  }

  // CefBrowserProcessHandler 方法:
  virtual void OnContextInitialized() OVERRIDE;

 private:
  // 包括默认的引用计数实现。
  IMPLEMENT_REFCOUNTING(SimpleApp);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_

2.simple_handler.h


#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_

#include "include/cef_client.h"

#include 
// CefClient提供访问Browser实例的回调接口。一个CefClient实现可以在任意数量的Browser进程中共享。以下为几个重要的回调:
class SimpleHandler : public CefClient,
                      public CefDisplayHandler,
                      public CefLifeSpanHandler,
                      public CefLoadHandler {
 public:
  explicit SimpleHandler(bool use_views);
  ~SimpleHandler();

  // 工厂实例
  static SimpleHandler* GetInstance();

  // CefClient 方法:
  virtual CefRefPtr GetDisplayHandler() OVERRIDE {
    return this;
  }
  // CefLifeSpanHandler 类提供管理 Browser生命周期必需的回调。以下为相关方法和成员。
  virtual CefRefPtr GetLifeSpanHandler() OVERRIDE {
    return this;
  }

  virtual CefRefPtr GetLoadHandler() OVERRIDE { return this; }

  // CefDisplayHandler 方法:
  virtual void OnTitleChange(CefRefPtr browser,
                             const CefString& title) OVERRIDE;


  virtual void OnAfterCreated(CefRefPtr browser) OVERRIDE;
  virtual bool DoClose(CefRefPtr browser) OVERRIDE;
  virtual void OnBeforeClose(CefRefPtr browser) OVERRIDE;

  // CefLoadHandler 方法:
  virtual void OnLoadError(CefRefPtr browser,
                           CefRefPtr frame,
                           ErrorCode errorCode,
                           const CefString& errorText,
                           const CefString& failedUrl) OVERRIDE;

  // 请求所有现有的浏览器窗口关闭。
  void CloseAllBrowsers(bool force_close);

  bool IsClosing() const { return is_closing_; }

 private:
     // 平台的实现修改title。
  void PlatformTitleChange(CefRefPtr browser,
                           const CefString& title);

  // 是否使用视图框架
  const bool use_views_;

  // 现有浏览器窗口的列表。只在CEF UI线程上访问。
  typedef std::list> BrowserList;
  BrowserList browser_list_;

  bool is_closing_;

  // 包括默认的引用计数实现。
  IMPLEMENT_REFCOUNTING(SimpleHandler);
};

#endif  // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_

3.simple_app.cc

#include "simple_app.h"

#include <string>

#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
#include "simple_handler.h"

namespace {

    // 当使用Views框架时,这个对象提供了委托
    // CefWindow的实现承载基于Views的浏览器。
    class SimpleWindowDelegate : public CefWindowDelegate {
    public:
        explicit SimpleWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
            : browser_view_(browser_view) {}
        //窗口创建
        void OnWindowCreated(CefRefPtr<CefWindow> window) OVERRIDE {
            // 添加浏览器视图并显示窗口。
            window->AddChildView(browser_view_);
            window->Show();

            // 将键盘焦点置于浏览器视图。
            browser_view_->RequestFocus();
        }
        //窗口销毁
        void OnWindowDestroyed(CefRefPtr<CefWindow> window) OVERRIDE {
            browser_view_ = NULL;
        }

        bool CanClose(CefRefPtr<CefWindow> window) OVERRIDE {
            // 如果浏览器允许,让窗口关闭。
            CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
            if (browser)
                return browser->GetHost()->TryCloseBrowser();
            return true;
        }

    private:
        CefRefPtr<CefBrowserView> browser_view_;

        IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
        DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
    };

}  // namespace
   //-------------------------------------------------------
   /*SimpleApp 实现
   CefApp接口提供了不同进程的可定制回调函数。毕竟重要的回调函数如下:
   OnBeforeCommandLineProcessing 提供了以编程方式设置命令行参数的机会,更多细节,请参考Command Line Arguments一节。
   OnRegisterCustomSchemes 提供了注册自定义schemes的机会,更多细节,请参考Request Handling一节。
   GetBrowserProcessHandler 返回定制Browser进程的Handler,该Handler包括了诸如OnContextInitialized的回调。
   GetRenderProcessHandler 返回定制Render进程的Handler,该Handler包含了JavaScript相关的一些回调以及消息处理的回调。 更多细节,请参考JavascriptIntegration和Inter-Process Communication两节。
   */
SimpleApp::SimpleApp() {}

void SimpleApp::OnContextInitialized() {
    CEF_REQUIRE_UI_THREAD();

    CefRefPtr<CefCommandLine> command_line =
        CefCommandLine::GetGlobalCommandLine();

    const bool use_views = command_line->HasSwitch("use-views");


    // SimpleHandler实现浏览器级别的回调。
    CefRefPtr<SimpleHandler> handler(new SimpleHandler(use_views));

    // CefBrowser 设置
    CefBrowserSettings browser_settings;

    std::string url;

    // 检测 "--url=" command-line. 是否有值,有就使用
    url = command_line->GetSwitchValue("url");
    if (url.empty())
        //url = "https://tool.lu/useragent";
        url = "http://www.baidu.com";

    if (use_views) {
        //创建 BrowserView.主要用于Windows的窗口显示
        CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView(
            handler, url, browser_settings, NULL, NULL);

        //创建Windows窗口之后显现出来。
        CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view));
    }
    else {
        // 创建本机窗口时使用的信息。
        CefWindowInfo window_info;

#if defined(OS_WIN)
        //在Windows上,我们需要指定将传递给的某些标志
        // CreateWindowEx().
        window_info.SetAsPopup(NULL, "myclient");
#endif

        // 创建一个cefbrowser
        CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings,
            NULL);
    }
}

4.simple_handler.cc

#include "simple_handler.h"

#include 
#include 

#include "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
// CefClient提供访问Browser实例的回调接口。一个CefClient实现可以在任意数量的Browser进程中共享。以下为几个重要的回调:
/*
public CefClient,
public CefContextMenuHandler,
public CefDisplayHandler,
public CefDownloadHandler,
public CefDragHandler,
public CefGeolocationHandler,
public CefKeyboardHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
*/
namespace {

SimpleHandler* g_instance = NULL;

}  // namespace
   // 构造
SimpleHandler::SimpleHandler(bool use_views)
    : use_views_(use_views), is_closing_(false) {
  DCHECK(!g_instance);
  g_instance = this;
}
// 析构
SimpleHandler::~SimpleHandler() {
  g_instance = NULL;
}

// 静态工厂
SimpleHandler* SimpleHandler::GetInstance() {
  return g_instance;
}

// 修改CefBrowser的title
void SimpleHandler::OnTitleChange(CefRefPtr browser,
                                  const CefString& title) {
  CEF_REQUIRE_UI_THREAD();

  if (use_views_) {
      // 使用视图框架设置窗口的标题。
    CefRefPtr browser_view =
        CefBrowserView::GetForBrowser(browser);
    if (browser_view) {
      CefRefPtr window = browser_view->GetWindow();
      if (window)
        window->SetTitle(title);
    }
  } else {
      // 使用平台api设置窗口的标题。
    PlatformTitleChange(browser, title);
  }
}

void SimpleHandler::OnAfterCreated(CefRefPtr browser) {
  CEF_REQUIRE_UI_THREAD();

  //添加到现有浏览器的列表中。
  browser_list_.push_back(browser);
}

bool SimpleHandler::DoClose(CefRefPtr browser) {
  CEF_REQUIRE_UI_THREAD();

  // 关闭主窗口需要特殊处理。看到DoClose()
  if (browser_list_.size() == 1) {
      // 设置一个标志以表明应该允许关闭窗口。
    is_closing_ = true;
  }

  // 允许关闭。
  return false;
}
// 关闭browser 在之前
void SimpleHandler::OnBeforeClose(CefRefPtr browser) {
  CEF_REQUIRE_UI_THREAD();

  // 从现有的浏览器列表中删除。
  BrowserList::iterator bit = browser_list_.begin();
  for (; bit != browser_list_.end(); ++bit) {
    if ((*bit)->IsSame(browser)) {
      browser_list_.erase(bit);
      break;
    }
  }

  if (browser_list_.empty()) {
      // 所有的浏览器窗口都关闭了。退出应用程序消息循环。
    CefQuitMessageLoop();
  }
}
// 加载错误
void SimpleHandler::OnLoadError(CefRefPtr browser,
                                CefRefPtr frame,
                                ErrorCode errorCode,
                                const CefString& errorText,
                                const CefString& failedUrl) {
  CEF_REQUIRE_UI_THREAD();

  // 不要为下载的文件显示错误。
  if (errorCode == ERR_ABORTED)
    return;

  // 显示一个加载错误消息。
  std::stringstream ss;
  ss << ""
        "

Failed to load URL " << std::string(failedUrl) << " with error " << std::string(errorText) << " (" << errorCode << ").

"
; frame->LoadString(ss.str(), failedUrl); } // 关闭所有Browers void SimpleHandler::CloseAllBrowsers(bool force_close) { if (!CefCurrentlyOn(TID_UI)) { // 提交关闭任务 CefPostTask(TID_UI, base::Bind(&SimpleHandler::CloseAllBrowsers, this, force_close)); return; } if (browser_list_.empty()) return; BrowserList::const_iterator it = browser_list_.begin(); for (; it != browser_list_.end(); ++it) (*it)->GetHost()->CloseBrowser(force_close); }

5.simple_handler_win.cc

#include "simple_handler.h"

#include <windows.h>
#include <string>

#include "include/cef_browser.h"

void SimpleHandler::PlatformTitleChange(CefRefPtr<CefBrowser> browser,
                                        const CefString& title) {
  CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();
  SetWindowText(hwnd, std::wstring(title).c_str());
}

6.cefsimple_win.cc

#include 


#include "simple_app.h"
#include "include/cef_parser.h"
#include "include/cef_urlrequest.h"


//window 窗体入口函数
int APIENTRY wWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR lpCmdLine,
                      int nCmdShow) {
  UNREFERENCED_PARAMETER(hPrevInstance);
  UNREFERENCED_PARAMETER(lpCmdLine);

  // 启用High-DPI支持Windows 7或更新。
  //CefEnableHighDPISupport();

  void* sandbox_info = NULL;

  //1 声明command-line 参数
  CefMainArgs main_args(hInstance);

  //3 检测CEF其他子进程
  int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info);
  if (exit_code >= 0) {

    return exit_code;
  }
  //------------------------------------------1 设置------------------------------------------------------
  // 设置cef的全局配置
  CefSettings settings;

  //设置语言
  CefString(&settings.locale).FromString("zh - CN");

  //设置不使用沙盒
  settings.no_sandbox = true;

  // cefApp
  CefRefPtr app(new SimpleApp);

  CefInitialize(main_args, settings, app.get(), sandbox_info);

  // 循环消息
  CefRunMessageLoop();
  // 关闭cef
  CefShutdown();

  return 0;
}

编译生成运行即可。

预计下一篇:
CEF小白人系列11-构建编译CEF源代码

问题:
Q&A

学习交流:
QQ群:14764183
加入验证标注 cef入坑。

你可能感兴趣的:(CEF,cef)