创建新的 Electron 浏览器模块
🌐 Creating a New Electron Browser Module
欢迎阅读 Electron API 指南!如果你不熟悉如何在 browser 目录下创建新的 Electron API 模块,本指南可作为你需要实现的一些必要步骤的清单。
🌐 Welcome to the Electron API guide! If you are unfamiliar with creating a new Electron API module within the browser directory, this guide serves as a checklist for some of the necessary steps that you will need to implement.
这不是创建 Electron 浏览器 API 的全面的最终指南,而是记录了一些更不直观的步骤的大纲。
🌐 This is not a comprehensive end-all guide to creating an Electron Browser API, rather an outline documenting some of the more unintuitive steps.
将你的文件添加到 Electron 的项目配置中
🌐 Add your files to Electron's project configuration
Electron 使用 GN 作为元构建系统来为其编译器 Ninja 生成文件。这意味着为了让 Electron 编译你的代码,我们必须将你的 API 的代码和头文件名称添加到 filenames.gni 中。
🌐 Electron uses GN as a meta build system to generate files for its compiler, Ninja. This means that in order to tell Electron to compile your code, we have to add your API's code and header file names into filenames.gni.
你需要将 API 文件名按字母顺序附加到相应的文件中,如下所示:
🌐 You will need to append your API file names alphabetically into the appropriate files like so:
lib_sources = [
"path/to/api/api_name.cc",
"path/to/api/api_name.h",
]
lib_sources_mac = [
"path/to/api/api_name_mac.h",
"path/to/api/api_name_mac.mm",
]
lib_sources_win = [
"path/to/api/api_name_win.cc",
"path/to/api/api_name_win.h",
]
lib_sources_linux = [
"path/to/api/api_name_linux.cc",
"path/to/api/api_name_linux.h",
]
请注意,Windows、macOS 和 Linux 数组添加是可选的,仅当你的 API 具有特定平台实现时才应添加。
🌐 Note that the Windows, macOS and Linux array additions are optional and should only be added if your API has specific platform implementations.
创建 API 文档
🌐 Create API documentation
类型定义由 Electron 使用 @electron/docs-parser 和 @electron/typescript-definitions 生成。此步骤对于确保 Electron API 文档的一致性是必要的。这意味着为了让你的 API 类型定义出现在 electron.d.ts 文件中,我们必须创建一个 .md 文件。示例可以在 此文件夹 中找到。
🌐 Type definitions are generated by Electron using @electron/docs-parser and @electron/typescript-definitions. This step is necessary to ensure consistency across Electron's API documentation. This means that for your API type definition to appear in the electron.d.ts file, we must create a .md file. Examples can be found in this folder.
设置 ObjectTemplateBuilder 和 Wrappable
🌐 Set up ObjectTemplateBuilder and Wrappable
Electron 使用 object_template_builder 构建其模块。
🌐 Electron constructs its modules using object_template_builder.
[wrappable](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/gin/wrappable.h) 是一个 C++ 对象的基类,这些对象有对应的 v8 封装器对象。
这里是一个你可能需要添加的基本代码示例,以便将 object_template_builder 和 wrappable 集成到你的 API 中。更多实现可以参考这里。
🌐 Here is a basic example of code that you may need to add, in order to incorporate object_template_builder and wrappable into your API. For further reference, you can find more implementations here.
在你的 api_name.h 文件中:
🌐 In your api_name.h file:
#ifndef ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
#define ELECTRON_SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
#include "gin/handle.h"
#include "gin/wrappable.h"
namespace electron {
namespace api {
class ApiName : public gin::DeprecatedWrappable<ApiName> {
public:
static gin::Handle<ApiName> Create(v8::Isolate* isolate);
// gin::Wrappable
static gin::DeprecatedWrapperInfo kWrapperInfo;
gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
v8::Isolate* isolate) override;
const char* GetTypeName() override;
} // namespace api
} // namespace electron
在你的 api_name.cc 文件中:
🌐 In your api_name.cc file:
#include "shell/browser/api/electron_api_safe_storage.h"
#include "shell/browser/browser.h"
#include "shell/common/gin_converters/base_converter.h"
#include "shell/common/gin_converters/callback_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/object_template_builder.h"
#include "shell/common/node_includes.h"
#include "shell/common/platform_util.h"
namespace electron {
namespace api {
gin::DeprecatedWrapperInfo ApiName::kWrapperInfo = {gin::kEmbedderNativeGin};
gin::ObjectTemplateBuilder ApiName::GetObjectTemplateBuilder(
v8::Isolate* isolate) {
return gin::ObjectTemplateBuilder(isolate)
.SetMethod("methodName", &ApiName::methodName);
}
const char* ApiName::GetTypeName() {
return "ApiName";
}
// static
gin::Handle<ApiName> ApiName::Create(v8::Isolate* isolate) {
return gin::CreateHandle(isolate, new ApiName());
}
} // namespace api
} // namespace electron
namespace {
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
v8::Isolate* const isolate = v8::Isolate::GetCurrent();
gin_helper::Dictionary dict(isolate, exports);
dict.Set("apiName", electron::api::ApiName::Create(isolate));
}
} // namespace
将你的 Electron API 与 Node 链接
🌐 Link your Electron API with Node
在 typings/internal-ambient.d.ts 文件中,我们需要在 Process 接口上附加一个新属性,如下所示:
🌐 In the typings/internal-ambient.d.ts file, we need to append a new property onto the Process interface like so:
interface Process {
_linkedBinding(name: 'electron_browser_{api_name}'): Electron.ApiName;
}
在你的 api_name.cc 文件的最底部:
🌐 At the very bottom of your api_name.cc file:
NODE_LINKED_BINDING_CONTEXT_AWARE(electron_browser_{api_name},Initialize)
在你的 shell/common/node_bindings.cc 文件中,将你的节点绑定名称添加到 Electron 的内置模块中。
🌐 In your shell/common/node_bindings.cc file, add your node binding name to Electron's built-in modules.
#define ELECTRON_BROWSER_MODULES(V) \
V(electron_browser_{api_name})
有关 Node 如何与 Electron 连接的更多技术细节,可以在我们的博客中找到。
将你的 API 公开给 TypeScript
🌐 Expose your API to TypeScript
将你的 API 导出为模块
🌐 Export your API as a module
我们需要在以下路径中创建一个新的 TypeScript 文件:
🌐 We will need to create a new TypeScript file in the path that follows:
"lib/browser/api/{electron_browser_{api_name}}.ts"
该文件内容的示例可以在这里找到。
🌐 An example of the contents of this file can be found here.
将你的模块公开给 TypeScript
🌐 Expose your module to TypeScript
将你的模块添加到位于 "lib/browser/api/module-list.ts" 的模块列表中,如下所示:
🌐 Add your module to the module list found at "lib/browser/api/module-list.ts" like so:
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'apiName', loader: () => require('./api-name') }
];