/ CHROME-EXTENSION

逆引きChrome extension開発

DeepLopenerなどを作ってそれなりにChrome extensionに関する知見がたまってきたのでメモ.

Chrome extensionの基本的な概念

Chrome拡張の開発方法まとめ その1:概念編
Chrome Extension の作り方 (その1: 3つの世界)
Chrome Extension の作り方 (その2: Contents Script)
Chrome Extension の作り方 (その3: Browser Action / Page Action)
Chrome Extension の作り方 (その4: Event Page / Background Page)
Chrome Extension の作り方 (最終話: メッセージパッシング)

Chrome extensionにおける基本的なことは上記のページでかなり勉強できる.

現在開いているタブの情報を取得する

ここで現在開いているタブとは,現在選択しているウィンドウで開いているタブのことを示す.

  
["tabs","activeTab"]

chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
  active_url = tabs[0].url;
});

<解説>
chrome.tabs.query(object queryInfo, function callback)を使う.
active:trueで実行したウィンドウ内でのアクティブなタブを指定し,currentWindow:trueで現在選択しているウィンドウを指定する.
queryのcallbackはarray of Tabであり,今取得しようとしているタブの情報はtabs[0]に格納されている.
URL以外にも以下のような情報も含まれている.

  • id
    タブのID.browser session内で固有の値を持つので,sendMessageなどでメッセージパッシングを行う際にこれを指定することにより,任意のタブへメッセージを送ることができるようになる.
  • windowId
    そのタブを含むウィンドウのID.
  • title
    タイトル.
  • pendingUrl

The URL the tab is navigating to, before it has committed. This property is only present if the extension’s manifest includes the “tabs” permission and there is a pending navigation.
https://developer.chrome.com/extensions/tabs#property-Tab-pendingUrl

参考:https://developer.chrome.com/extensions/tabs#type-Tab

タブのURLを取得できない


chrome.tabs.onCreated.addListener(function (tab) {
  alert(tab.url);//sometimes ""
  alert(tab.pendingUrl);
  if(tab.pendingUrl.match(/.*.pdf$/)){
    //URLが.pdfで終わるような場合にのみ実行する
  };
}

<解説>
TabからURLを取得できない場合は,タブを開いたばかりだとtab.urlを取得できないことがある(確定?)ので,pendingUrlを確認してみるとよい.

選択しているテキストを取得

<解説>

  
winodw.getSelection().toString()

contents.jsではこのように簡単に取得できる.一方,ContextMenusでは以下のような方法でも取得できる.

  
["contextMenus"]
  
chrome.contextMenus.create({
  title: "selectiontext>:%s",
  type: "normal",
  contexts: ["selection"],
  onclick: function (info) {
    alert(info.selectionText)
  },
});

titleにある%sは選択中のテキストに置き換わる.
infoに含まれる他の情報など詳細はchrome.contextMenusを参照されたい.
余談だが,PDF上の選択したテキストはwindow.getSelection().toString()で拾うのは難しい.
私は諦めてonclickinfoから拾う実装にした.

タブを開く

  
chrome.tabs.create({
  url: "http://www.google.co.jp/search?hl=ja&source=hp&q=how_to_create_tabs",
  active: false,
});

<解説>
chrome.tabs.create(object createProperties, function callback)を使う.
ここではactive:falseとしてタブを開いた際に現在開いているタブの選択状態が変わらないように指定した.createPropertiesにはwindowIdなども指定できる(デフォルトは現在のウィンドウ).

タブを消す

  
chrome.tabs.getSelected(null, function (tab) {
  chrome.tabs.remove((tabIds = tab.id));
});

<解説>
chrome.tabs.remove(integer or array of integer tabIds, function callback)を使用する.
現在選択しているタブのTab Objectsをchrome.tabs.remove((tabIds))により選択したIDを持つタブを削除する.tabIdsにはIDのリストを渡すこともできる.

参考:https://developer.chrome.com/extensions/tabs#method-remove

popupのウィンドウを消す

  
window.close();

<解説>
cssでdisplay:none;を指定しても完全には消えずに小さなウィンドウが残ってしまうのでclose()してしまえばよい.ただし,sendMessagebackgroundにメッセージを送っていた場合は,sendResponse()から返ってくる前に消してしまうと正常に処理を終えられなくなることに注意したい.
あくまですべての処理を終えてから消すこと.

background.jsにメッセージを送る

  
chrome.runtime.sendMessage({ message: "from_contents" }, function (res) {
  alert("Hello "+res);
});
  
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  if (request.message == "from_contents") {
   sendResponse("World!")
  }
});

<解説>
background.jsにメッセージを送るにはchrome.runtime.sendMessage(string extensionId, any message, object options, function responseCallback)を用いる.
chrome.tabs.sendMessage(integer tabId, any message, object options, function responseCallback)は,バックグラウンドをtabIdで指定できないので使用できない.
つまり,background.jsに向けたメッセージはすべてchrome.runtime.sendMessage()を用いる.

contents.jsからpopup.jsにメッセージを送る

  
chrome.runtime.sendMessage({ message: "from_contents" }, function (res) {
  alert("Hello "+res);
});
  
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  if (request.message == "from_contents") {
   sendResponse("World!")
}
});

<解説>
popup.jsはアイコンをクリックしたウィンドウ上に現れるので,一見するとそのタブのIDを持っていそうだが,実際は持っていない.
そのため,chrome.runtime.sendMessage()を用いる.この辺の使い分けを理解するのに時間がかかった.

sendResponse()で複数の値を渡したい

  
chrome.runtime.sendMessage({ message: "test" }, function (resjson) {
  var obj = JSON.parse(resjson);
  alert(obj.count);
  alert(obj.result);
});
  
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
  if (request.message == "test") {
    var result=true;
    var count=42;
    sendResponse('{"result":result,"count":count}');
  }
});

<解説>
sendResponse()の引数はJSON objectであるので,JSONの形に成形すれば複数引数の値を渡すことができる.
公式ドキュメントにはしっかり記載されているが,外部解説サイトではsendResponse(result)のように一つの変数の値しか渡していない例が多かったので,ここで強調して紹介しておきたい.

終わりに

chromeにデータを保存できるchrome.storageや,Options Pageはまだ使用したことがないので勉強次第追記する.

jsやhtml周りを勉強する必要はありますが,思っている以上にChrome拡張機能は簡単に作れる.
はじめに紹介した分かりやすい解説記事や公式サンプルを参考に作ってみてはいかがでしょう.

オマケ

最後に私が作成した簡単な作例を紹介して終わる.

DeepLopener

DeepLを用いたページ翻訳や,PDF上に翻訳結果を表示する拡張機能
https://github.com/T3aHat/DeepLopener
layout-oriented.gif
icon-text-oriented.gif
pdfmode.gif

Who-acts-this-character

アニメ作品を見ていて”このキャラクターのCV誰?”となったとき,Wikipediaを開いてすぐキャスト情報にたどりつける.
https://github.com/T3aHat/Who-acts-this-character

beforebefore
after.pngafter 出典:[https://ja.wikipedia.org/wiki/Re:ステージ!]

GoogleScholar

選択したテキストを大学からのリモートアクセスとしてGoogleScholarに投げるContextMenusを追加する.
scholar.png

  
chrome.contextMenus.create({
  title: "GoogleScholar : %s",
  type: "normal",
  contexts: ["selection"], //選択時のみ出現
  onclick: move(),
});
function move() {
  return function (info) {
    var selection_text = info.selectionText;
    chrome.tabs.create({
      url:
        "https://scholar-google-co-jp.ezproxy.hogeuniv/scholar?hl=ja&q=" +
        encodeURI(selection_text),
    });
  };
}

Mixbox

ある音楽再生サイトにプレイリストを追加する.
https://github.com/T3aHat/MixBox

before.pngbefore
after.pngafter

teahat

teahat

I'm t3ahat.

Read More

Tags

Latest Posts