electron源码编译 添加builtin 内建 c++扩展

 

一、js层面

1,在D:\dev\electron7\src\electron\lib\browser\api\module-keys.js 中添加新的module:

// Browser side modules, please sort alphabetically.
module.exports = [
  { name: 'app' },
  { name: 'autoUpdater' },
  { name: 'BrowserCache' },
  { name: 'BrowserView' },
  { name: 'BrowserWindow' },

2,在 D:\dev\electron7\src\electron\lib\browser\api\module-list.js 中引入

browser-cache.js 文件。
module.exports = [
  { name: 'app', loader: () => require('./app') },
  { name: 'autoUpdater', loader: () => require('./auto-updater') },
  { name: 'BrowserCache', loader: () => require('./browser-cache') },

3,D:\dev\electron7\src\electron\lib\browser\api\browser-cache.js

这个js的

const { BrowserCache } = process.electronBinding('cache');

引入了c++模块注册的module cache。然后js封装了对外接口,提供外部调用。[外部调用 const { BrowserCache} = require('electron')]

module.exports = BrowserCache
'use strict';

const electron = require('electron');
const { WebContentsView, TopLevelWindow, deprecate } = electron;
const { BrowserCache } = process.electronBinding('cache');

Object.setPrototypeOf(BrowserCache.prototype, TopLevelWindow.prototype);

BrowserCache.prototype._init = function () {
  // Call parent class's _init.
  TopLevelWindow.prototype._init.call(this);

  // Avoid recursive require.
  const { app } = electron;

  // Create WebContentsView.
  this.setContentView(new WebContentsView(this.webContents));

  this.webContents.on('move', (event, size) => {
    this.setBounds(size);
  });

  // Hide the auto-hide menu when webContents is focused.
  this.webContents.on('activate', () => {
    if (process.platform !== 'darwin' && this.autoHideMenuBar && this.isMenuBarVisible()) {
      this.setMenuBarVisibility(false);
    }
  });

  const visibilityEvents = ['show', 'hide', 'minimize', 'maximize', 'restore'];
  for (const event of visibilityEvents) {
    this.on(event, visibilityChanged);
  }

  // Properties
  Object.defineProperty(this, 'fullScreenable', {
    get: () => this.isFullScreenable(),
    set: (full) => this.setFullScreenable(full)
  });

  Object.defineProperty(this, 'simple', {
    get: () => this.isSimple(),
    set: (simple) => this.setSimple(simple)
  });
};

const isBrowserCache = (cache) => {
    return cache && cache.constructor.name === 'BrowserCache';
};

// Helpers.
Object.assign(BrowserCache.prototype, {
  getURL (...args) {
    return this.webContents.getURL();
  },
  loadFile (...args) {
    return this.webContents.loadFile(...args);
  }
});

module.exports = BrowserCache;

如果直接导出c++接口,参照app.ts

// Only one app object permitted.
export default app;

 js文件改动后,需要动动module-list.js,才会重新生成js2c的文件。即js转成c文件存放。

二、C++扩展

1,添加文件 D:\dev\electron7\src\electron\shell\browser\api\atom_api_browser_cache.cc

// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#include "shell/browser/api/atom_api_browser_cache.h"

#include <iostream>
#include <memory>

#include "base/threading/thread_task_runner_handle.h"
#include "gin/converter.h"
#include "native_mate/dictionary.h"
#include "shell/common/api/constructor.h"
#include "shell/common/node_includes.h"

#include "shell/common/api/constructor.h"
#include "shell/common/application_info.h"
#include "shell/common/atom_command_line.h"
#include "shell/common/color_util.h"
#include "shell/common/native_mate_converters/callback.h"
#include "shell/common/native_mate_converters/file_path_converter.h"
#include "shell/common/native_mate_converters/gurl_converter.h"
#include "shell/common/native_mate_converters/once_callback.h"
#include "shell/common/native_mate_converters/value_converter.h"
#include "shell/common/node_includes.h"
#include "shell/common/options_switches.h"
#include "ui/gl/gpu_switching_manager.h"

#include "native_mate/object_template_builder.h"

namespace electron {

namespace api {

BrowserCache::BrowserCache(v8::Isolate* isolate,
                           v8::Local<v8::Object> wrapper,
                           const mate::Dictionary& options)
    : weak_factory_(this) {
  // Use options.webPreferences in WebContents.
  mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate);
  options.Get(options::kWebPreferences, &web_preferences);

  // Copy the backgroundColor to webContents.
  v8::Local<v8::Value> value;
  if (options.Get(options::kBackgroundColor, &value))
    web_preferences.Set(options::kBackgroundColor, value);

  // Copy the transparent setting to webContents
  v8::Local<v8::Value> transparent;
  if (options.Get("transparent", &transparent))
    web_preferences.Set("transparent", transparent);

  InitWith(isolate, wrapper);
}

BrowserCache::~BrowserCache() {}

v8::Local<v8::Value> BrowserCache::GetWebContents(v8::Isolate* isolate) {
  return v8::Null(isolate);
  // return v8::Local<v8::Value>::New(isolate, web_contents_);
}

std::string BrowserCache::GetHeader(mate::Arguments* args,
                                    const std::string& url) {
  // bool succeed = false;

  return "ok";
}

v8::Local<v8::Value> BrowserCache::GetContent(mate::Arguments* args,
                                              const std::string& url) {
  // bool succeed = false;
  std::string data = "hello world";  // Read(format_string);
  return node::Buffer::Copy(args->isolate(), data.data(), data.length())
      .ToLocalChecked();
}

// static
mate::WrappableBase* BrowserCache::New(mate::Arguments* args) {
  if (args->Length() > 1) {
    args->ThrowError();
    // return ;
  }

  mate::Dictionary options;
  if (!(args->Length() == 1 && args->GetNext(&options))) {
    options = mate::Dictionary::CreateEmpty(args->isolate());
  }

  return new BrowserCache(args->isolate(), args->GetThis(), options);
  //  return mate::CreateHandle(args->isolate(),  new
  //  BrowserCache(args->isolate(), args->GetThis(), options));
}

#if 0
// static
mate::Handle<BrowserCache> App::Create(v8::Isolate* isolate) {
  return mate::CreateHandle(isolate, new BrowserCache(isolate));
}
#endif

// static
void BrowserCache::BuildPrototype(v8::Isolate* isolate,
                                  v8::Local<v8::FunctionTemplate> prototype) {
  prototype->SetClassName(mate::StringToV8(isolate, "BrowserCache"));
  mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
      .SetMethod("getHeader", &BrowserCache::GetHeader)
      .SetMethod("getContent", &BrowserCache::GetContent)
      .SetProperty("webContents", &BrowserCache::GetWebContents);
}

}  // namespace api

}  // namespace electron

namespace {

using electron::api::BrowserCache;

void Initialize(v8::Local<v8::Object> exports,
                v8::Local<v8::Value> unused,
                v8::Local<v8::Context> context,
                void* priv) {
  std::cout << "xxxxxxx  BrowserCache "
               "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
            << std::endl;

  v8::Isolate* isolate = context->GetIsolate();
  mate::Dictionary dict(isolate, exports);

#if 0               
              
               dict.Set("BrowserCache", electron::api::App::GetConstructor(isolate)
                                   ->GetFunction(context)
                                   .ToLocalChecked());
               dict.Set("browserCache", electron::api::BrowserCache::Create(isolate));

#else

  dict.Set("BrowserCache",
           mate::CreateConstructor<BrowserCache>(
               isolate, base::BindRepeating(&BrowserCache::New)));

#endif
}

}  // namespace

NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_cache, Initialize)
View Code

 

// static  new一个object
mate::WrappableBase* BrowserCache::New(mate::Arguments* args) {

  if (args->Length() > 1) {
    args->ThrowError();
    return nullptr;
  }

  mate::Dictionary options;
  if (!(args->Length() == 1 && args->GetNext(&options))) {
    options = mate::Dictionary::CreateEmpty(args->isolate());
  }

  return new BrowserCache(args->isolate(), args->GetThis(), options); //new一个实例
}

// static 这里加入成员函数,属性。
void BrowserCache::BuildPrototype(v8::Isolate* isolate,
                                   v8::Local<v8::FunctionTemplate> prototype) {
  prototype->SetClassName(mate::StringToV8(isolate, "BrowserCache"));//设置对外类名
  mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
      .SetMethod("focusOnWebView", &BrowserCache::FocusOnWebView)
      .SetMethod("blurWebView", &BrowserCache::BlurWebView)
      .SetMethod("isWebViewFocused", &BrowserCache::IsWebViewFocused)
      .SetProperty("webContents", &BrowserCache::GetWebContents);
}

// static
v8::Local<v8::Value> BrowserCache::From(v8::Isolate* isolate,
                                         NativeWindow* native_window) {
  auto* existing = TrackableObject::FromWrappedClass(isolate, native_window);
  if (existing)
    return existing->GetWrapper();
  else
    return v8::Null(isolate);
}

}  // namespace api

}  // namespace electron

namespace {

using electron::api::BrowserCache;
using electron::api::TopLevelWindow;

void Initialize(v8::Local<v8::Object> exports,
                v8::Local<v8::Value> unused,
                v8::Local<v8::Context> context,
                void* priv) {
  v8::Isolate* isolate = context->GetIsolate();
  mate::Dictionary dict(isolate, exports);
  dict.Set("BrowserCache",//这个是类名,js这里会用到 const { BrowserCache } = process.electronBinding('cache');
           mate::CreateConstructor<BrowserCache>(
               isolate, base::BindRepeating(&BrowserCache::New)));    //字典名字,到New创建构造函数。会调用到buildtype加入成员函数。         
}

}  // namespace

NODE_LINKED_MODULE_CONTEXT_AWARE(atom_browser_cache, Initialize) //将atom_browser_cache的初始化绑定到initialize上。这个宏会生成register_xxx函数。然后将 atom_browser_cache 加入到node_binding.cc中,这样会调用这个注册函数。 这里的cache就是上面js require时的名字 ???

2,头文件

 

// Copyright (c) 2013 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.

#ifndef SHELL_BROWSER_API_ATOM_API_BROWSER_CACHE_H_
#define SHELL_BROWSER_API_ATOM_API_BROWSER_CACHE_H_

#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include "base/task/cancelable_task_tracker.h"
#include "native_mate/dictionary.h"
#include "native_mate/handle.h"

#include "base/threading/thread_task_runner_handle.h"
#include "gin/converter.h"
#include "native_mate/dictionary.h"
#include "shell/browser/browser.h"
#include "shell/browser/unresponsive_suppressor.h"
#include "shell/browser/web_contents_preferences.h"
#include "shell/browser/window_list.h"

#include "native_mate/dictionary.h"
#include "native_mate/handle.h"
#include "native_mate/object_template_builder.h"
#include "shell/common/application_info.h"
#include "shell/common/atom_command_line.h"
#include "shell/common/native_mate_converters/callback.h"
#include "shell/common/native_mate_converters/file_path_converter.h"
#include "shell/common/native_mate_converters/gurl_converter.h"
#include "shell/common/native_mate_converters/image_converter.h"
#include "shell/common/native_mate_converters/net_converter.h"
#include "shell/common/native_mate_converters/network_converter.h"
#include "shell/common/native_mate_converters/once_callback.h"
#include "shell/common/native_mate_converters/value_converter.h"
#include "shell/common/node_includes.h"
#include "shell/common/options_switches.h"
#include "ui/gl/gpu_switching_manager.h"

#include "shell/browser/api/event_emitter.h"
#include "shell/common/native_mate_converters/callback.h"
#include "shell/common/promise_util.h"

#include "shell/common/api/constructor.h"

namespace mate {
class Arguments;
}  // namespace mate

namespace electron {

namespace api {

class BrowserCache : public mate::EventEmitter<BrowserCache> {
 public:
  static mate::WrappableBase* New(mate::Arguments* args);

  static void BuildPrototype(v8::Isolate* isolate,
                             v8::Local<v8::FunctionTemplate> prototype);

  base::WeakPtr<BrowserCache> GetWeakPtr() {
    return weak_factory_.GetWeakPtr();
  }

 protected:
  BrowserCache(v8::Isolate* isolate,
               v8::Local<v8::Object> wrapper,
               const mate::Dictionary& options);
  ~BrowserCache() override;

  v8::Local<v8::Value> GetWebContents(v8::Isolate* isolate);

  std::string GetHeader(mate::Arguments* args, const std::string& url);
  v8::Local<v8::Value> GetContent(mate::Arguments* args,
                                  const std::string& url);

 private:
#if defined(OS_MACOSX)
  void OverrideNSWindowContentView(InspectableWebContents* iwc);
#endif

  // Helpers.

  base::WeakPtrFactory<BrowserCache> weak_factory_;

  DISALLOW_COPY_AND_ASSIGN(BrowserCache);
};

}  // namespace api

}  // namespace electron

#endif  // SHELL_BROWSER_API_ATOM_API_BROWSER_WINDOW_H_
View Code

 

3,加入 D:\dev\electron7\src\electron\shell\common\node_bindings.cc

#define ELECTRON_BUILTIN_MODULES(V)  \
  V(atom_browser_app)                \
  V(atom_browser_auto_updater)       \
  V(atom_browser_cache)       \

4,加入gn编译文件

d:\dev\electron7\src\electron\filenames.gni

  lib_sources = [
    "shell/browser/api/atom_api_browser_cache.cc",
    "shell/browser/api/atom_api_browser_cache.h", 
    "shell/app/atom_content_client.cc",
    "shell/app/atom_content_client.h",
    "shell/app/atom_main_delegate.cc",
    "shell/app/atom_main_delegate.h",

 

三、外围调用

const electron = require('electron')
const BrowserCache = electron.BrowserCache

var cache = new BrowserCache({width: 800})
console.log("========== cache generated:"+cache )
console.log("========== cache getHeader:"+cache.getHeader("will error") );
var cont=cache.getContent("will error");
console.log("========== cache getContent:"+cont );

 

四、原理部分

最终导出的 require(electron)是在 D:\dev\electron7\src\electron\lib\browser\api\exports\electron.js中导出的。

'use strict';

const common = require('@electron/internal/common/api/exports/electron');
// since browser module list is also used in renderer, keep it separate.
const moduleList = require('@electron/internal/browser/api/module-list');

// Import common modules.
common.defineProperties(exports);

for (const module of moduleList) {
  Object.defineProperty(exports, module.name, {
    enumerable: !module.private,
    get: common.handleESModule(module.loader)
  });
}

 

posted @ 2020-09-08 09:55  Bigben  阅读(773)  评论(0编辑  收藏  举报