创建新的 Electron 浏览器模块

欢迎阅读 Electron API指南! 如果您对在 browser 目录内创建一个新的 Electron API 模块不太熟悉,本指南可作为您需要实施的一些必要步骤的清单。

这不是创建Electron Browser API的全面指南,而是记录一些更晦涩的步骤的大纲。

将您的文件添加到 Electron 的项目配置中

Electron使用 GN 作为元构建系统为其编译器 Ninja 生成文件。 这意味着,为了让Electron编译您的代码,我们必须将您的API的代码和头文件名添加到 filenames.gni

您需要按字母顺序将 API 文件名追加到相应的文件中,如下所示:

filenames.gni

  1. lib_sources = [
  2. "path/to/api/api_name.cc",
  3. "path/to/api/api_name.h",
  4. ]
  5. lib_sources_mac = [
  6. "path/to/api/api_name_mac.h",
  7. "path/to/api/api_name_mac.mm",
  8. ]
  9. lib_sources_win = [
  10. "path/to/api/api_name_win.cc",
  11. "path/to/api/api_name_win.h",
  12. ]
  13. lib_sources_linux = [
  14. "path/to/api/api_name_linux.cc",
  15. "path/to/api/api_name_linux.h",
  16. ]

请注意,Windows、 macOS 和 Linux 数组添加是可选的,只有当您的 API 有具体的平台实现时才应被添加。

创建 API 文档

类型定义由 Electron 使用 @electron/docs-parser@electron/typescript-definitions生成。 这个步骤对于确保Electron的 API 文档的一致性是必要的。 这意味着,要使 API 类型定义显示在 electron.d.ts 文件中,我们必须创建一个 .md 文件。 示例可以在此文件夹中找到。

设置 ObjectTemplateBuilderWrappable

Electron使用 object_template_builder构建其模块。

wrappable 是具有相应 v8 包装器对象C++对象的基类。

下面是您可能需要添加的代码的基本示例,以便将 object_template_builderwrappable 合并到 API 中。 如需进一步参考,您可以在此处找到更多实现。

api_name.h 文件中:

api_name.h

  1. #ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
  2. #define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
  3. #include "gin/handle.h"
  4. #include "gin/wrappable.h"
  5. namespace electron {
  6. namespace api {
  7. class ApiName : public gin::Wrappable<ApiName> {
  8. public:
  9. static gin::Handle<ApiName> Create(v8::Isolate* isolate);
  10. // gin::Wrappable
  11. static gin::WrapperInfo kWrapperInfo;
  12. gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
  13. v8::Isolate* isolate) override;
  14. const char* GetTypeName() override;
  15. } // namespace api
  16. } // namespace electron

api_name.cc 文件中:

api_name.cc

  1. #include "shell/browser/api/electron_api_safe_storage.h"
  2. #include "shell/browser/browser.h"
  3. #include "shell/common/gin_converters/base_converter.h"
  4. #include "shell/common/gin_converters/callback_converter.h"
  5. #include "shell/common/gin_helper/dictionary.h"
  6. #include "shell/common/gin_helper/object_template_builder.h"
  7. #include "shell/common/node_includes.h"
  8. #include "shell/common/platform_util.h"
  9. namespace electron {
  10. namespace api {
  11. gin::WrapperInfo ApiName::kWrapperInfo = {gin::kEmbedderNativeGin};
  12. gin::ObjectTemplateBuilder ApiName::GetObjectTemplateBuilder(
  13. v8::Isolate* isolate) {
  14. return gin::ObjectTemplateBuilder(isolate)
  15. .SetMethod("methodName", &ApiName::methodName);
  16. }
  17. const char* ApiName::GetTypeName() {
  18. return "ApiName";
  19. }
  20. // static
  21. gin::Handle<ApiName> ApiName::Create(v8::Isolate* isolate) {
  22. return gin::CreateHandle(isolate, new ApiName());
  23. }
  24. } // namespace api
  25. } // namespace electron
  26. namespace {
  27. void Initialize(v8::Local<v8::Object> exports,
  28. v8::Local<v8::Value> unused,
  29. v8::Local<v8::Context> context,
  30. void* priv) {
  31. v8::Isolate* isolate = context->GetIsolate();
  32. gin_helper::Dictionary dict(isolate, exports);
  33. dict.Set("apiName", electron::api::ApiName::Create(isolate));
  34. }
  35. } // namespace

In the typings/internal-ambient.d.ts file, we need to append a new property onto the Process interface like so:

typings/internal-ambient.d.ts

  1. interface Process {
  2. _linkedBinding(name: 'electron_browser_{api_name}'): Electron.ApiName;
  3. }

At the very bottom of your api_name.cc file:

api_name.cc

  1. NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_{api_name},Initialize)

In your shell/common/node_bindings.cc file, add your node binding name to Electron’s built-in modules.

shell/common/node_bindings.cc

  1. #define ELECTRON_BROWSER_MODULES(V) \
  2. V(electron_browser_{api_name})

Note: More technical details on how Node links with Electron can be found on our blog.

向 TypeScript 公开你的 API

将 API 导出为模块

我们需要在以下路径中创建一个新的 TypeScript 文件:

"lib/browser/api/{electron_browser_{api_name}}.ts"

An example of the contents of this file can be found here.

向 TypeScript 公开你的模块

Add your module to the module list found at "lib/browser/api/module-list.ts" like so:

lib/browser/api/module-list.ts

  1. export const browserModuleList: ElectronInternal.ModuleEntry[] = [
  2. { name: 'apiName', loader: () => require('./api-name') },
  3. ];