メインコンテンツへ飛ぶ

Electron ブラウザモジュールの新規作成

Electron API ガイドへようこそ! browser ディレクトリ内に新しい Electron API モジュールを作成することに慣れていない方向けに、このガイドでは実装が必要ないくつかのステップをチェックリストとして提供しています。

これは、Electron Browser API を作成するための包括的なつきっきりのガイドではなく、直感的ではないような手順について説明する概略です。

Electron のプロジェクト構成へのファイル追加

Electron は、コンパイラである Ninja 用のファイルを生成するためのメタビルドシステムとして GN を使用しています。 つまり、あなたのコードをコンパイルするよう Electron に指示するためには、その API のコードとヘッダーファイル名を 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 は、C++ オブジェクトがそれに対応する v8 ラッパーオブジェクトを保持するための基底クラスです。

ここでは、object_template_builderwrappable を API に組み込むために必要となるコードの基本的な例を示します。 参考までに、さらなる実装は こちら で紹介しています。

api_name.h ファイルでは、

api_name.h

#ifndef SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_
#define SHELL_BROWSER_API_ELECTRON_API_{API_NAME}_H_

#include "gin/handle.h"
#include "gin/wrappable.h"

namespace electron {

namespace api {

class ApiName : public gin::Wrappable<ApiName> {
public:
static gin::Handle<ApiName> Create(v8::Isolate* isolate);

// gin::Wrappable
static gin::WrapperInfo 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::WrapperInfo 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* isolate = context->GetIsolate();
gin_helper::Dictionary dict(isolate, exports);
dict.Set("apiName", electron::api::ApiName::Create(isolate));
}

} // namespace

Electron API と Node をリンクする

typings/internal-ambient.d.ts ファイルでは、Process インターフェイスに以下の新しいプロパティを追加する必要があります。

typings/internal-ambient.d.ts
interface Process {
_linkedBinding(name: 'electron_browser_{api_name}', Electron.ApiName);
}

api_name.cc ファイルのかなり下の方に以下の行があります。

api_name.cc
NODE_LINKED_MODULE_CONTEXT_AWARE(electron_browser_{api_name},Initialize)

shell/common/node_bindings.cc ファイルで、Electron の組み込みモジュールに Node のバインディング名を追加します。

shell/common/node_bindings.cc
#define ELECTRON_BUILTIN_MODULES(V)      \
V(electron_browser_{api_name})

注意: Node が Electron とどのようにリンクしているのか、より技術的な詳細は ブログ に記載してあります。

API を TypeScript に公開

API をモジュールとしてエクスポート

以下のパスに新しい TypeScript ファイルを作成する必要があります。

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

このファイルの内容のサンプルは こちら です。

モジュールを TypeScript に公開

"lib/browser/api/module-list.ts" にあるモジュールリストに、あなたのモジュールを以下のように追加してください。

lib/browser/api/module-list.ts
export const browserModuleList: ElectronInternal.ModuleEntry[] = [
{ name: 'apiName', loader: () => require('./api-name') },
];