跳转到主内容

创建新的 Electron 浏览器模块

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

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

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

Electron使用 GN 作为元构建系统为其编译器 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 文件名追加到相应的文件中,如下所示:

filenames.gni
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 有具体的平台实现时才应被添加。

创建 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

#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 文件中:

api_name.cc
#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

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
interface Process {
_linkedBinding(name: 'electron_browser_{api_name}'): Electron.ApiName;
}

At the very bottom of your api_name.cc file:

api_name.cc
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
#define ELECTRON_BROWSER_MODULES(V)      \
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
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'apiName', loader: () => require('./api-name') }
];