如何利用CEF3創建一個簡單的應用程序 (Windows Platform)


說明

這篇文章主要講述如何利用CEF3來創建一個簡單的應用程序,引用的是1535及以上版本中包含的 Cefsimple 項目例子。如果想知道關於CEF3更多的使用方法,可以去訪問 GeneralUsage.

開始

首先,根據自身所使用的開發平台,可以去 這里 下載對應的發布版本。針對這個教程,我們需要下載1750或者更新的版本。當前支持的平台有Windows, Linux和Mac OS X。每一個版本都包含了當在特定平台上編譯特定版本CEF3時所需要的所有文件和資源。您可以通過包含在里邊的 REDME.txt 文件或者在Wiki上 GeneralUsage 中的 Getting Started,了解每個發布版本的具體內容和細節。

編譯發布版本中的項目

以CEF發布版本為基礎開發的應用程序可以使用標准的平台編譯工具進行編譯執行。包括 Windows 平台下的 Visual Studio, Mac OS X 平台下的 Xcode,  以及 Linux 平台下的 gcc/make。針對平台的不同,項目的編譯過程也有些許的不同和要求。

Windows

Windows 平台下編譯 Cefsimple 步驟:

1. 用對應的 Visual Studio 版本打開項目解決方案。舉個例子,如果你安裝的是 Visual Studio 2010, 那么,打開的就是 cesimple2010.sln。

2. 如果你下載的是 x64版本,請確保你選擇的是 x64的開發平台。

3. 開始編譯。

4. 如果編譯通過,那么,在當前解決方案的目錄下,將出現“out/Debug”(或者 “out/Release”)文件夾。

5. 執行文件夾下 cefsimple.exe, 確保能正確運行。

加載一個自定義URL

cefsimple項目中默認加載的URL是 google.com,當然,你也可以用自定義的 URL 去替代它,最方便的就是通過命令行搞定。

# Load the local file “c:\example\example.html”
cefsimple.exe --url=file://c:/example/example.html

除了命令行的方法,也可以通過直接修改在 cefsimple/simple.cpp 文件中的代碼,達到你的目的。

# Load the local file “c:\example\example.html”
…
  if (url.empty())
    url = file://c:/example/example.html;    

應用程序組成

所有的 CEF 應用程序都有一下主要組成部分:

1. CEF 的動態鏈接庫 。(在 Windows 平台下就是 libcef.dll)

2. 支持庫。(ICU, FFMPEG等)

3. 資源。(html/js/css, strings等)

4. 客戶端執行文件。(本教程中就是 cefsimple.exe.)

要點(必看)

1. CEF 使用的是多進程。應用程序主進程是瀏覽器進程,而其他子進程是由 renderer, plugins, GPU等創建。

2. 在 Windows 和 Linux 平台下的執行文件可以被主進程和子進程使用。

3. CEF 中所有進程都可以是多線程的。CEF提供了許多功能和接口在不同的線程中傳遞任務。

4. 一些回調方法和函數只能在特定的進程或者線程中使用。在你第一次使用新的回調方法或者函數之前,請確保你已經閱讀了 API 頭文件中源碼,看使用要求。

流程分析

cefsimple 應用程序首先初始化CEF,然后創建了一個簡單的彈出瀏覽器窗口。當關閉了所有的瀏覽器窗口,應用程序就會結束。程序執行流程如下:

1. 系統執行入口點函數(main or wWinMain),並創建瀏覽器進程。

2. 入口點函數:

1. 創建能夠處理進程級別的回調方法的 SimpleApp 實例。

2. 初始化 CEF,進入 CEF 消息循環。

3. 初始化 CEF 之后,調用 SimpleApp::OnContextInitialized() 。這個方法中:

1. 創建單例的 SimpleHandler 。

2. 由 CefBrowserHost::CreateBrowsersync() 方法創建一個瀏覽器窗口。

4. 所有的瀏覽器共享 SimpleHandler 實例, 此實例能定制瀏覽器行為、處理瀏覽器相關回調方法(life span, loading state, title display等)。

5. 當一個瀏覽器窗口關閉的時候,調用 SimpleHandler::OnBeforeClose() 。當所有的瀏覽器窗口全部關閉時,OnBeforeClose() 函數就會執行跳出 CEF 消息循環的行為,退出應用程序。

入口點函數

程序的運行開始於瀏覽器進程中的入口點函數。這個函數會初始化 CEF 以及所有跟操作系統有關的對象。

Windows

#include <windows.h>

#include "cefsimple/simple_app.h"
#include "include/cef_sandbox_win.h"


// Set to 0 to disable sandbox support.
#define CEF_ENABLE_SANDBOX 1

#if CEF_ENABLE_SANDBOX
// The cef_sandbox.lib static library is currently built with VS2010. It may not
// link successfully with other VS versions.
#pragma comment(lib, "cef_sandbox.lib")
#endif


// Entry point function for all processes.
int APIENTRY wWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR    lpCmdLine,
                      int       nCmdShow) {
  UNREFERENCED_PARAMETER(hPrevInstance);
  UNREFERENCED_PARAMETER(lpCmdLine);

  void* sandbox_info = NULL;

#if CEF_ENABLE_SANDBOX
  // Manage the life span of the sandbox information object. This is necessary
  // for sandbox support on Windows. See cef_sandbox_win.h for complete details.
  CefScopedSandboxInfo scoped_sandbox;
  sandbox_info = scoped_sandbox.sandbox_info();
#endif

  // Provide CEF with command-line arguments.
  CefMainArgs main_args(hInstance);

  // SimpleApp implements application-level callbacks. It will create the first
  // browser instance in OnContextInitialized() after CEF has initialized.
  CefRefPtr<SimpleApp> app(new SimpleApp);

  // CEF applications have multiple sub-processes (render, plugin, GPU, etc)
  // that share the same executable. This function checks the command-line and,
  // if this is a sub-process, executes the appropriate logic.
  int exit_code = CefExecuteProcess(main_args, app.get(), sandbox_info);
  if (exit_code >= 0) {
    // The sub-process has completed so return here.
    return exit_code;
  }

  // Specify CEF global settings here.
  CefSettings settings;

#if !CEF_ENABLE_SANDBOX
  settings.no_sandbox = true;
#endif

  // Initialize CEF.
  CefInitialize(main_args, settings, app.get(), sandbox_info);

  // Run the CEF message loop. This will block until CefQuitMessageLoop() is
  // called.
  CefRunMessageLoop();

  // Shut down CEF.
  CefShutdown();

  return 0;
}

SimpleApp

SimpleApp 負責處理進程級別的回調方法。它會曝露出一些在多進程中共享或者被特定進程使用的接口和方法。CefBrowserProcessHandler 接口,在瀏覽器進程中調用。還有一個被分離出 CefBrowserProcessHandler 接口(例子項目沒有展示)只會在渲染進程中被調用。由於 CefBrowserProcessHandler 不光實現了 CefApp, 同時還有 CefBrowserProcessHandler,所以它的返回值必須是[this]。

// simple_app.h
#include "include/cef_app.h"

class SimpleApp : public CefApp,
                  public CefBrowserProcessHandler {
 public:
  SimpleApp();

  // CefApp methods:
  virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
      OVERRIDE { return this; }

  // CefBrowserProcessHandler methods:
  virtual void OnContextInitialized() OVERRIDE;

 private:
  // Include the default reference counting implementation.
  IMPLEMENT_REFCOUNTING(SimpleApp);
};


// simple_app.cpp
#include "cefsimple/simple_app.h"

#include <string>

#include "cefsimple/simple_handler.h"
#include "cefsimple/util.h"
#include "include/cef_browser.h"
#include "include/cef_command_line.h"

SimpleApp::SimpleApp() {
}

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

  // Information used when creating the native window.
  CefWindowInfo window_info;

#if defined(OS_WIN)
  // On Windows we need to specify certain flags that will be passed to
  // CreateWindowEx().
  window_info.SetAsPopup(NULL, "cefsimple");
#endif

  // SimpleHandler implements browser-level callbacks.
  CefRefPtr<SimpleHandler> handler(new SimpleHandler());

  // Specify CEF browser settings here.
  CefBrowserSettings browser_settings;

  std::string url;

  // Check if a "--url=" value was provided via the command-line. If so, use
  // that instead of the default URL.
  CefRefPtr<CefCommandLine> command_line =
      CefCommandLine::GetGlobalCommandLine();
  url = command_line->GetSwitchValue("url");
  if (url.empty())
    url = "http://www.google.com";

  // Create the first browser window.
  CefBrowserHost::CreateBrowserSync(window_info, handler.get(), url,
                                    browser_settings, NULL);
}

SimpleHandler

SimpleHandler 負責處理瀏覽器級別的回調方法。這些回調方法會在瀏覽器進程中執行。在這個項目中,針對所有的瀏覽器使用相同的 CefClient 實例,但是如果你願意,可以在自己的應用程序中使用不同的 CefClient實例的。

// simple_handler.h
#include "include/cef_client.h"

#include <list>

class SimpleHandler : public CefClient,
                      public CefDisplayHandler,
                      public CefLifeSpanHandler,
                      public CefLoadHandler {
 public:
  SimpleHandler();
  ~SimpleHandler();

  // Provide access to the single global instance of this object.
  static SimpleHandler* GetInstance();

  // CefClient methods:
  virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
    return this;
  }
  virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
    return this;
  }
  virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE {
    return this;
  }

  // CefDisplayHandler methods:
  virtual void OnTitleChange(CefRefPtr<CefBrowser> browser,
                             const CefString& title) OVERRIDE;

  // CefLifeSpanHandler methods:
  virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
  virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;

  // CefLoadHandler methods:
  virtual void OnLoadError(CefRefPtr<CefBrowser> browser,
                           CefRefPtr<CefFrame> frame,
                           ErrorCode errorCode,
                           const CefString& errorText,
                           const CefString& failedUrl) OVERRIDE;

  // Request that all existing browser windows close.
  void CloseAllBrowsers(bool force_close);

 private:
  // List of existing browser windows. Only accessed on the CEF UI thread.
  typedef std::list<CefRefPtr<CefBrowser> > BrowserList;
  BrowserList browser_list_;

  // Include the default reference counting implementation.
  IMPLEMENT_REFCOUNTING(SimpleHandler);
};


// simple_handler.cpp
#include "cefsimple/simple_handler.h"

#include <sstream>
#include <string>

#include "cefsimple/util.h"
#include "include/cef_app.h"
#include "include/cef_runnable.h"

namespace {

SimpleHandler* g_instance = NULL;

}  // namespace

SimpleHandler::SimpleHandler() {
  ASSERT(!g_instance);
  g_instance = this;
}

SimpleHandler::~SimpleHandler() {
  g_instance = NULL;
}

// static
SimpleHandler* SimpleHandler::GetInstance() {
  return g_instance;
}

void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  // Add to the list of existing browsers.
  browser_list_.push_back(browser);
}

void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
  REQUIRE_UI_THREAD();

  // Remove from the list of existing browsers.
  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()) {
    // All browser windows have closed. Quit the application message loop.
    CefQuitMessageLoop();
  }
}

void SimpleHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
                                CefRefPtr<CefFrame> frame,
                                ErrorCode errorCode,
                                const CefString& errorText,
                                const CefString& failedUrl) {
  REQUIRE_UI_THREAD();

  // Don't display an error for downloaded files.
  if (errorCode == ERR_ABORTED)
    return;

  // Display a load error message.
  std::stringstream ss;
  ss << "<html><body bgcolor=\"white\">"
        "<h2>Failed to load URL " << std::string(failedUrl) <<
        " with error " << std::string(errorText) << " (" << errorCode <<
        ").</h2></body></html>";
  frame->LoadString(ss.str(), failedUrl);
}

void SimpleHandler::CloseAllBrowsers(bool force_close) {
  if (!CefCurrentlyOn(TID_UI)) {
    // Execute on the UI thread.
    CefPostTask(TID_UI,
        NewCefRunnableMethod(this, &SimpleHandler::CloseAllBrowsers,
                             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);
}


// simple_handler_win.cpp -- Windows-specific code.
#include "cefsimple/simple_handler.h"

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

#include "cefsimple/util.h"
#include "include/cef_browser.h"

void SimpleHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                  const CefString& title) {
  REQUIRE_UI_THREAD();

  CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();
  SetWindowText(hwnd, std::wstring(title).c_str());
}


// simple_handler_gtk.cc  -- Linux-specific code.
#include "cefsimple/simple_handler.h"

#include <gtk/gtk.h>
#include <string>

#include "cefsimple/util.h"
#include "include/cef_browser.h"

void SimpleHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                  const CefString& title) {
  REQUIRE_UI_THREAD();

  GtkWidget* window = gtk_widget_get_ancestor(
      GTK_WIDGET(browser->GetHost()->GetWindowHandle()),
      GTK_TYPE_WINDOW);
  std::string titleStr(title);
  gtk_window_set_title(GTK_WINDOW(window), titleStr.c_str());
}


// simple_handler_mac.mm -- OS X-specific code.
#include "cefsimple/simple_handler.h"

#import <Cocoa/Cocoa.h>

#include "cefsimple/util.h"
#include "include/cef_browser.h"

void SimpleHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                  const CefString& title) {
  REQUIRE_UI_THREAD();

  NSView* view = (NSView*)browser->GetHost()->GetWindowHandle();
  NSWindow* window = [view window];
  std::string titleStr(title);
  NSString* str = [NSString stringWithUTF8String:titleStr.c_str()];
  [window setTitle:str];
}

編譯步驟(Windows)

1. 編譯 libcef_dll_wrapper 靜態庫。

2. 編譯/鏈接項目。

1. 源文件:cefsimple_win.cpp, simple_app.cpp, simple_handler.cpp, simple_handler_win.cpp.

2. 鏈接庫:comctl32.lib, shlwapi.lib, rcprt4.lib, libcef_dll_wrapper.lib, libcef.lib, cef_sandbox.lib.  (cef_sandbox.lib 是 sandbox 支持,當前內部僅支持 VS2010, 如果使用其他VS版本,可以將 cefsimple_win.cpp 中 的 CEF_ENABLE_SANDBOX 設置為 0)

3. 將有關的庫和資源復制到輸出目錄。

4. 將 Debug/Release 文件夾下文件復制到輸出目錄。

輸出目錄的結構應該如下:

Application/
  cefsimple.exe  <= cefsimple application executable
  libcef.dll <= main CEF library
  icudt.dll <= ICU unicode support library
  ffmpegsumo.dll <= HTML5 audio/video support library
  libEGL.dll, libGLESv2.dll, … <= accelerated compositing support libraries
  cef.pak, devtools_resources.pak <= non-localized resources and strings
  locales/
    en-US.pak, … <= locale-specific resources and strings


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM