ブログ
Objective-Cを使用してElectronアプリでMacOSのアクティブウィンドウを追跡する
Objective-Cを使用してElectronアプリでMacOSのアクティブウィンドウを追跡する
この記事では、Objective-C++を使用してMacOSでElectronアプリのアクティブウィンドウを簡単に追跡する方法を紹介します。Electronなしでネイティブにも使用できます。
執筆者
Gáspár Balázsi
(ChatGPTによる翻訳)
最終更新日
OCT 05, 2022
トピック
#dev
所要時間
7 min read
背景
Electron アプリケーション内で MacOS のネイティブコード(Objective-C)を使用して、アクティブウィンドウの追跡機能を実装し、NAPI を介して Electron アプリにバインドします。これは、ユーザーが一つのウィンドウから別のウィンドウに切り替えるたびに、ネイティブ側から常にアプリに通知することを意味します。ユーザーがウィンドウ間でどのように切り替えるか(例:CMD + Tab、一つのアプリから別のアプリにクリックで切り替えるなど)に関係なく、このチュートリアルの終わりには、Javascript の世界でアクティブウィンドウの ID を取得できるようになります。後でウィンドウ ID を使用し、スクリーンレコーディングを行うなどのことも可能ですが、それはこのチュートリアルの範囲外です。
<br />カバーする内容:
- electron-react-boilerplateを使用して Electron アプリを作成します(すでに既存の Electron アプリがある場合は、それを出発点として使用しても構いません)。執筆時点での Electron のバージョンは
v20.0.2です。 - ネイティブコードを書きます。
- 必要なファイルを作成します(
activeWindowObserver.h、activeWindowObserver.mm、nativeWindows.mm) activeWindowObserver.hを書きますactiveWindowObserver.mmを実装しますnativeWindows.mmを実装します
electron-rebuildでビルドスクリプトをセットアップします。- ネイティブコードのための Typescript ラッパーを作成します。
mainJavascript プロセスからそれを呼び出し、結果をコンソールにログします。
前提条件:
- アプリは
Accessibility権限が必要ですので、ターミナルから実行する場合は、ターミナルにAccessibility権限を付与し、後でスタンドアロンアプリとしてビルドする場合は、アプリに付与してください。
VSCode のターミナルから実行する場合は、VSCode に権限が与えられていることを確認してください。これは、ターミナルを生成するオーナープロセスとして VSCode が機能するためです。他の統合ターミナルにも同様のことが適用されます。
- ある程度、Typescript と Electron に精通していることが前提となります。
1. Electron のボイラープレートを作成する
あなたは基本的な Electron のボイラープレートを持っており、そのフォルダのルートに位置しているはずです。
2. ネイティブコードを書く
NAPI をインストール
このチュートリアルでは、ObjectiveC++コードを Node にバインドするためにnode-addon-apiを使用します。このチュートリアルではv4.3.0を使用します。すぐにビルドのための必要なファイルを作成しますが、設定について詳しく読みたい場合は、GitHub で読むことが可能です。
ネイティブモジュールのフォルダ構造を作成する
私たちのモジュールはnative-windowsと呼び、その中にmacosフォルダを作成します。これは、Windows にも拡張する可能性があるためです。
NAPI をセットアップする
src/native-modules/native-windowsに、以下の内容でbinding.gypという名前のファイルを作成します:
.gypファイルは基本的に、ObjectiveC++プログラムをコンパイルするために使用される Makefiles を生成するための JSON ファイルです。これはnode-gypによって消費され、これは私たちが使用するビルドツールです。私たちのアプリは MacOS でビルドされると想定しています。MacOS 特有の API を使用するためには Cocoa フレームワークが必要になります。Node-gyp は、モジュールのバインディングを含む.nodeファイルを私たちのObjectiveC++ソースコードからコンパイルし、それをjsファイルにインポートすることができます。
また、以下の内容でここにpackage.jsonファイルを追加します:
このファイルは基本的に、このモジュールが NodeJS にバインドするC++モジュールであることを示しています。
必要なファイルを作成する
src/native-modules/native-windows/macosフォルダに、activeWindowObserver.h、activeWindowObserver.mm、およびnativeWindows.mmファイルを作成します。
.hファイルはヘッダーファイルです。C++に慣れていない場合は、.hファイルをインターフェースと考え、この場合.mmファイルで実装されているものを定義するものと考えてください。
activeWindowObserver.mmは、.hファイルで定義されているものの実装を含んでいます。.mm拡張子はObjectiveC++ための特有なものです。
nativeWindows.mmファイルには、JS からモジュールを使用できるようにするバインディングが含まれています。
activeWindowObserver.hを書く
activeWindowObserver.mmを実装する
上記コードの説明:
windowChangedCallbackは、同じアプリケーションに属するウィンドウ間の変更を追跡するために使用されます。「なぜ 30ms の遅延が最前面のウィンドウを再度フェッチする前にあるのか」と疑問に思うかもしれません。遅延なしでは、常に前の状態の順序でウィンドウを取得するため、実際にユーザーが見ているものよりも常に 1 ステップ遅れていました。おそらくこれは、使用している API の同期の欠如によるものですが、これは単なる推測です。しかし、これがバグかもしれないため、この奇妙な動作について Apple に問題を報告しました。この問題の今後に興味がある場合は、次のリンクで追跡できます:Apple フォーラムdeallocは、オブザーバーを削除するために使用されますinitでは、アプリケーション間の変更を確認するために、共有ワークスペースの通知センターにオブザーバーを追加しますreceiveAppChangeNotificationは、init でアタッチされたハンドラー自体です。このハンドラーで、同じアプリケーションに属するウィンドウの変更を購読する別のオブザーバーを定義します(windowChangeCallback)。getActiveWindowは、最前面のウィンドウの ID を取得する責任がありますremoveWindowObserverはオブザーバーをデタッチしますcleanUpは、ウィンドウの変更オブザーバーとアプリの変更オブザーバーを削除しますinitActiveWindowObserverは、上記のクラスのインスタンスの初期化をトリガーします。これは、JS から呼び出す NAPI でラップする関数ですstopActiveWindowObserverは、私たちのインスタンスの破壊をトリガーし、すべてのリスナーを削除します
nativeWindows.mmを実装する
かなり簡単で、モジュールから公開した 2 つのメソッドをラップして JS から利用可能にします。
3. electron-rebuildでビルドスクリプトをセットアップする
Electron プロジェクトのルートにあるメインのpackage.jsonファイルに、以下の行を追加します。
ネイティブコードにエラーがない場合、ルートフォルダでnpm run native-modules:rebuildまたはnpm run native-modules:rebuild:armを実行することで、モジュールを正しくビルドできるはずです。これは、ビルドするプラットフォームに依存します。
これには、次のような出力があるはずです:
![]()
4. ネイティブコードのための Typescript ラッパーを作成する
electron-react-boilerplate から始めた場合は、以下の行を.eslintrc.jsに追加してください以下をsrc/native-modules/native-windows/index.tsに追加します
nativeWindows変数をエクスポートします。これは、コンパイルされたコードからネイティブコードをaddonとしてインポートする、正しく型付けされたインスタンス化されたクラスです。
5. main.tsからモジュールを呼び出す
main.tsに以下のインポートを追加します:
下記のコードを、アプリが準備完了した後のどこかに追加して、これまでの作業をテストします:
その後、npm startでアプリを起動します。
次のようなログが表示されるはずです:
![]()
🎉 これで完了です。これで MacOS でアクティブなウィンドウを追跡できるようになるはずです。🎉
完全なコードは、以下のリンクの Github で利用可能です: https://github.com/scriptide-tech/blog-tracking-active-window-macos-objective-c-electron
Scriptideは、高度なスキルを持つソフトウェア開発会社であり、複雑なカスタムB2Bソリューションの提供を専門としています。デジタルトランスフォーメーション、Web・モバイル開発、AI、ブロックチェーンなど、幅広いサービスを提供しています。無料のIT相談を承っております。ぜひお気軽にお問い合わせください。
無料のIT相談をぜひご利用ください。。皆さまからのご相談を心よりお待ちしております。
こちらの記事もおすすめです!
詳細はこちら
Lighthouseスコア改善:WebサイトのSEOスコアを最大化する方法
Google LighthouseやGoogle PageSpeed Insightsは、Webアプリケーションのパフォーマンス測定における業界標準ツールとなっています。本記事では、それらのツールの役割やスコアの重要性、そしてScriptideのWebサイトにおけるスコア改善の取り組みについて紹介します。
#dev
•
JUL 01, 2025
•
6 min read
詳細はこちら
フルスタック開発の利点
フルスタック開発は、近年多くのテック企業で注目を集めています。しかし理由は何でしょうか?従来の「バックエンドとフロントエンドを分離する」手法と比べて、どのような優位性があるのでしょうか?本記事では、分離型モデルと比較しながら、フルスタック開発のメリットについて詳しく解説します。本記事は2回構成の第1回目です。次回は、バックエンドとフロントエンド間の型安全性とコード共有が、開発体験の向上、開発期間の短縮、そして品質の高いプロダクト実現にどう貢献するかを紹介します。
#dev
•
JUN 04, 2025
•
5 min read