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)
// 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_
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) }); }