Edited at

Chromeブラウザ拡張機能を作ってみた

More than 1 year has passed since last update.

一から作ってみた時の作業記録みたいなもの。


ディレクトリを作る

適当にディレクトリを作る


manifest.jsonを作る

以下のような内容でプラグインを作ってディレクトリに入れる。


manifest.json

{

"name": "テストプラグイン",
"version": "0.1",
"description": "テストプラグイン説明",
"manifest_version": 2
}

manifest.xmlの詳しい書き方は公式サイト参照。


拡張機能を入れてみる

Chromeでchrome://extensions/にアクセスし、右上から「デベロッパーモード」を有効にする。

b1.PNG

「パッケージ化されていない拡張機能を読み込む」から先程作ったディレクトリを指定する。

b2.PNG

するとこんな感じで読み込まれる。

b3.PNG


拡張のアイコンを設定してみる

manifest.jsonファイルに以下のように書き足す。


manifest.json

{

:,
"icons": {
"16": "images/icon16.png",
"32": "images/icon32.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
}

アイコンはもちろん対象の場所に用意する。

その後再度「読み込む」。

するとアイコンが適用される。

b1.PNG

ちなみに各アイコンのサイズは以下の通りらしい。

サイズ
使われる場所

16x16
拡張機能ページのfavicon

32x32
Windowsの場合、変倍がかかってしまうのでこのアイコンを48x48アイコンの代わりに利用しているらしい

48x48
拡張機能の管理ページに表示されるアイコン

128x128
Chrome ウェブストアで表示されるアイコン


ログだけ出力する機能を作る

適当にGitHubのユーザー名を書き換えるだけのものを作ってみる。

manifest.jsonファイルに以下のように書き足す。


manifest.json

{

:,
"background": {
"scripts": ["js/background.js"],
"persistent": false
}
}

そして以下のようなJavaScriptを書く。


js/background.js

chrome.runtime.onInstalled.addListener(function (details) {

console.log(details.reason);
});

その後再度「読み込む」。

すると「バックグラウンドページ」からDevToolsを起動するとupdateとログが出力されている。

b1.PNG

chrome.runtime.onInstalledは拡張機能がインストールされた時に呼ばれるイベントで、この時に初期化をしたりする。

これはバックグラウンドページと呼ばれている。

お察しの通り、配列なので複数のスクリプトを列挙することもできる。

persistentは基本的にfalseにして残り続けないようにする。


GitHubのページで動くようにする

github.comのタブの情報が得られるように、manifest.jsonファイルに以下のように書き足す。


manifest.json

{

:,
"permissions": ["tabs", "https://github.com/*"]
}

詳細な権限の一覧は公式サイト参照。実はtabsが入っていないようだけど…

URLのマッチングについてはこちら

background.jsをこんな感じで書き換える。


js/background.js

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {

if (changeInfo.status === 'complete') {
console.log(tabId);
console.log(changeInfo);
console.log(tab);
}
});

するとページをリロードする毎にこんな感じのログが出力される。

b2.PNG


GitHubのauthorを書き換えてみる

この部分を書き換える。

b3.PNG

authorノードの情報を取得する。

authorを右クリック→検証。

b6.png

更にDev Toolsから右クリック→Copy→Copy selector。

b5.png

background.jsからタブ内でbase.jsを呼ぶようにする。


js/background.js

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {

if (changeInfo.status === 'complete') {
chrome.tabs.executeScript(tab.id, { file: "js/base.js" });
}
});

chrome.tabs.executeScriptは、そのタブで指定したスクリプトを実行させる。

バックグラウンドページのスクリプトはそのページのスクリプトとは分離されていてページ内の情報を読み書きできないので、こういうかたちになる。

base.jsでは先程取得したセレクタをそのままquerySelectorに貼り付けて利用する。


js/base.js

var authorNode = document.querySelector('#js-repo-pjax-container > div.pagehead.repohead.instapaper_ignore.readability-menu.experiment-repo-nav > div > h1 > span.author > a');

if (authorNode) {
authorNode.innerHTML = 'hoge';
}

できた :tada:

b1.PNG


設定画面を作ってみる

次は設定画面を作ってみる。hogeだけだと微妙なので自分で設定できるようにする(そういう問題ではないが)。


manifest.json

{

:,
"options_page": "html/option.html"
}

適当にHTMLの設定画面を作る。


html/option.html

<!doctype html>

<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
<title>設定</title>
</head>
<body>
<div class="container">
<h1>設定</h1>
<form>
<div class="form-group">
<label for="author">Author</label>
<input class="form-control" type="text" name="author" id="author">
</div>
<div class="form-group">
<button class="btn btn-default" name="save" type="button">更新</button>
</div>
</form>
</div>
</body>
</html>

再読込してから「詳細」へ移動する。

b3.png

「拡張機能のオプション」ができているので、そこから「↗」マークをクリックする。

b4.PNG

すると先程作ったページが閲覧できる。

b2.PNG

次に、設定を読み書きしたいのでローカルストレージを利用する。

manifest.jsonに権限を追加してローカルストレージにアクセスできるようにする。


manifest.json

{

:,
"permissions": ["tabs", "https://github.com/*", "storage"]
}

オプションのページでJavaScriptを読み込む。


html/option.html

:

<script type="text/javascript" src="/js/option.js"></script>
<title>設定</title>
:

読み込み先のJavaScriptを書く。


js/option.js

document.addEventListener('DOMContentLoaded', function () {

chrome.storage.local.get("github_author", function (item) {
const author = item.github_author;
if (author) {
document.querySelector('[name="author"]').value = author;
}
});

document.querySelector('[name="save"]').addEventListener('click', function (e) {
const author = document.querySelector('[name="author"]').value;
chrome.storage.local.set({ "github_author": author }, function () {
alert('saved');
});
});
});


上半分でローカルストレージに値があったらフォームに初期値として入力している。

下半分で「保存」ボタン押下時にローカルストレージに値を保存している。

これで設定画面が機能するようになった。

ちなみにchrome.storage.localの場合、ローカルに保存されるのでマシンごとに値が異なる。

アカウントごとに同期したい場合は変わりにchrome.storage.syncを使うと良いらしい。

仕上げにbase.jsで値をローカルストレージから呼ぶように変更する。


js/base.js

var authorNode = document.querySelector(

"#js-repo-pjax-container > div.pagehead.repohead.instapaper_ignore.readability-menu.experiment-repo-nav > div > h1 > span.author > a"
);
if (authorNode) {
chrome.storage.local.get("github_author", function(item) {
const author = item.github_author;
if (author) {
authorNode.innerHTML = author;
}
});
}

拡張機能を再読込し、github.comのページにアクセスしてみる。

すると設定画面で設定した値に書き換わるようになる。

b1.PNG


右上のメニューに出してみる

更にmanifest.jsonに書き足す。


manifest.json

{

:,
"browser_action": {
}
}

するとこんな感じでアイコンが出る。何も指定していないので無反応。

b1.png

ポップアップするHTMLを指定する。


manifest.json

{

:,
"browser_action": {
"default_popup": "html/popup.html"
}
}

popup.htmlの中身はとりあえずほぼ同じにする。


html/popup.html

<!doctype html>

<html lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB"
crossorigin="anonymous">
<script type="text/javascript" src="/js/option.js"></script>
<title>設定</title>
</head>

<body>
<div class="container" style="width: 200px">
<form>
<div class="form-group">
<label for="author">Author</label>
<input class="form-control" type="text" name="author" id="author">
</div>
<div class="form-group">
<button class="btn btn-default" name="save" type="button">更新</button>
</div>
</form>
</div>
</body>

</html>


するとこんな感じでポップアップする。

b1.png


右クリックメニューを出してみる

次に右クリックメニュー(コンテキストメニュー)に追加してみる。

更に権限を足す。


manifest.json

{

:,
"permissions": [..., "contextMenus"]
}

background.jsに以下のように書き足す。


background.js

var parentId = chrome.contextMenus.create({

"id": "sampleParent",
"title" : "サンプル親"
});

するとこんな感じになる。

b2 - コピー.png

更にサブメニューを追加してみる。


background.js

chrome.contextMenus.create({

"id": "sampleChild",
"title" : "サンプル子",
"parentId" : parentId
});

するとこんな感じ。

b2.png

クリックした時のイベント登録はこんな感じ。

これでサンプル子をクリックした時にアラートダイアログが表示される。

chrome.contextMenus.onClicked.addListener( function(info, tab) {

alert(info.menuItemId + "をクリック");
});


参考

Getting Started Tutorial - Google Chrome

C:\Users\user_name\AppData\Local\Google\Chrome\User Data\Default\Extensionsにも自分のブラウザに入っている拡張機能がたくさんあるので、それらを参考にすると良いかもしれない。