この記事で取り上げているAPIは現在と使い方が異なっていたり、
特にToolstrips APIは最新のChromeでは使用できなくなっています。詳しくは
前回はChromeのバージョンの違いとExtensionsの導入と概要について説明しました。今回はExtensionsの作り方からドキュメント、
【2009/
最初のExtension
まず始めにHello worldをExtensionで実装してみます。Extensionの最小構成は manifest.
{
"name": "Hello World",
"version": "1.0",
"toolstrips": ["toolstrip.html"]
}
manifest.
続いて、
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div class="toolstrip-button">
<span>Hello, World!</span>
</div>
</body>
</html>
toolstripには専用のCSSが自動的に挿入されるので、
なお、
さて、
C:\HelloWorld manifest.json toolstrip.html
あとはChromeにload-extensionオプションを付けて起動します。
chrome.exe --load-extension=C:\HelloWorld
起動に成功していれば、

なお、
Packaging
Extensionsの作成
Packagingには pack-extension という起動オプションを使用します。さきほどのHelloWorldをパッケージするコマンドは下記の通りです。
chrome.exe --pack-extension=C:\HelloWorld
これでHelloWorld.
pemファイルは下記のようにpack-extension-keyオプションとして指定します。
chrome.exe --pack-extension=C:\HelloWorld --pack-extension-key=HelloWorld.pem
やはり、
最後に --enable-extensions を付けて起動した状態のChromeにcrxファイルをドラッグ&ドロップすればインストールダイアログが出て、
Extensionsのドキュメント
Chromium
2009年9月前半の時点で、
本稿では公式のドキュメントを参照できるように、
Extensions API
それでは、
- Content Scripts
Content Scriptsは 対象ページを表示する際に、
そのページのコンテキスト上でJavaScriptを実行するAPIです。FirefoxのAdd-onのGreasemonkeyと同じような挙動で、 DOMContentLoadedのタイミングで実行、 ページ側のwindowオブジェクトに直接触れることはできないといった特徴があります。ただし、 このContent Scriptsから直接クロスドメイン通信などを行うことはできません。Content Scriptsは後述のToolstripsやBackground Pagesとメッセージのやり取りをすることができますので、 それを介してクロスドメイン通信などを行うことになります。 対象ページと実行するスクリプトの組み合わせは、
manifest. jsonファイルで定義します。 www. google. com用のContent Scripts定義サンプル "content_
scripts" : [ { "css": [ "google.css" ], "js": [ "google.js" ], "run_at" : "document_start" , "matches": [ "http://www. ] } ]google. com/*" "run_
at": "document_ start" はScriptの実行タイミングをdocumentの読み込みを開始したタイミングにするための指定です。より速くスクリプトを実行したい場合に指定します。デフォルト値は"document_ end"で、 通常は省略します。 - Toolstrips
ToolstripsはExtensions用のツールバー領域です。中身はHTML
(とCSS,JavaScript) で記述します。ボタンを設置したり、 簡単なメッセージを表示することができます。現在はステータスバーのような領域に表示されますが、 将来的にはブックマークバーと統合される予定となっています。 - Background Pages
Background PagesはChromeの起動中、
バックグラウンドでJavaScriptを実行させておくことができるAPIです。manifest. jsonにバックグランドで読み込むHTMLを指定します。 - Page Actions
Page Actionsはアドレスバーの中にボタンを表示するAPIで、
「今見ているページについて~~する」 といった機能を提供することができます。manifest. jsonでアクションを定義し、 Background Pagesなどで対応するアクションを実装します。 Page Actions定義サンプル "page_
actions" : [ { "id": "bookmark", "name": "このページをブックマークする", "icons": ["favicon.png" ] } ]- Cross-Origin XHR
クロスオリジン通信
(クロスドメイン通信) を行うAPIです。manifest. jsonで通信を許可するドメインを指定します。 Chrome 3ではこの指定は機能していないため、
permissionsを指定してもしなくても Extensionsのhtmlからはクロスドメイン通信を行うことが可能となっています。セキュリティの問題に注意が必要です。 permissions定義のサンプル "permissions": [ "http://
www. ],google. com/" - Tabs
Chromeのタブを操作するAPIです。Chrome 4 ではpermissionsでtabsと記述されていないと、
このAPIを使用することができません。なお、 Chrome 3ではtabsを指定することができません。そのため、 Chrome 3とChrome 4の両方で動くExtensionを作る場合には注意が必要です。 permissions定義のサンプル "permissions": [ "tabs" ],
- Windows
Chromeのウィンドウを操作するAPIです。Tabsと同じく、
permissionsでtabsと記述されていないとこのAPIを使用することができません。permissions 定義はTabsと共有しています。 - Bookmarks
Chromeのブックマークを操作するAPIです。やはり、
Chrome 4 ではpermissionsで "bookmarks" と記述する必要があります。
これら以外にも、
Google Chrome の開発ツール
ここで、
このWeb Inspectorは高機能で、
ChromeのWeb Inspectorもほぼ同等の機能を実現できていますが、
Web Inspectorを使用する方法はいくつかあり、

画面左下のShow ConsoleをクリックするとJavaScriptのコンソールが表示され、

また、
実用的なExtensionの作成
ここまででExtensionの開発に必要な知識は一通り学びました。ここで復習も兼ねて、
どういったExtensionが実用的であるかは悩ましいところですが、
FirefoxのAdd-onではSBMカウンタなどがあります。また、
ToolstripのHTML/CSS
まずは、
<ul id="sbmlist">
<li class="add">
<a id="add_hatena" target="_blank" title="はてなブックマークに追加">
<img src="hatena.favicon.gif" id="icon_hatena">
</a>
</li>
<li class="counter">
<a id="text_hatena" target="_blank"> </a>
</li>
<li class="add">
<a id="add_delicious" target="_blank" title="Save this bookmark">
<img src="delicious.small.gif" id="icon_delicious">
</a>
</li>
<li class="counter">
<a id="text_delicious" target="_blank"> </a>
</li>
</ul>
#sbmlist{
display:table;
margin:5px 3px;
list-style-type:none;
height:18px;
min-width:8em;
}
#sbmlist li{
display:table-cell;
vertical-align:middle;
}
#sbmlist li.counter{
min-width:2.5em;
text-align:center;
padding:0 3px 0 0;
}
HTMLはulとliのリストで構成し、
APIを処理するJavaScriptの実装
続いて、
ページのURLの取得⇒リクエスト⇒アップデート処理と、
function SBM(service){
this.text = document.getElementById('text_' + service.id);
this.icon = document.getElementById('icon_' + service.id);
this.add = document.getElementById('add_' + service.id);
this.api_get = service.api_get;
this.api_link = service.api_link;
this.api_add = service.api_add;
this.responceFilter = service.responceFilter;
this._cache = {};
}
SBM.prototype = {
request:function _sbm_request(only_request){
var self = this, xhr = new XMLHttpRequest();
var api_url = this.replace(this.api_get);
xhr.open('GET', api_url, true);
xhr.onload = function(){
var count = self.responceFilter(xhr.responseText);
self._cache[self.url] = {count:count};
if (!only_request) self.update(count);
};
xhr.send();
},
set:function _sbm_set(url, force_request, only_request){
if (!only_request) {
this.text.textContent = '-';
}
this.url = url;
this.encoded_url = encodeURIComponent(url);
if ((force_request || only_request) || !this._cache[url]) {
this.request(only_request);
} else {
this.update(this._cache[url].count);
}
},
update:function _sbm_update(count){
this.text.textContent = count;
this.text.href = this.replace(this.api_link);
this.add.href = this.replace(this.api_add);
},
replace:function _sbm_replace(str){
var self = this;
return str.replace(/#\{([^}]+)\}/g, function(_, _$){
return self[_$] || '';
});
}
};
まずsetメソッドでURLを設定し、
APIのレスポンスの形式は各サービスごとに異なるので、
var Services = [
{
id:'hatena',
api_get:'http://b.hatena.ne.jp/entry.count?url=#{encoded_url}',
api_link:'http://b.hatena.ne.jp/entry/#{url}',
api_add:'http://b.hatena.ne.jp/add?&url=#{encoded_url}',
responceFilter:function(text){
if (/\D/.test(text)) {
return '';
} else {
return text;
}
}
},
{
id:'delicious',
api_get:'http://badges.del.icio.us/feeds/json/url/blogbadge?url=#{encoded_url}',
api_link:'http://delicious.com/url/#{hash}',
api_add:'http://delicious.com/save?v=5&jump=close&url=#{encoded_url}',
responceFilter:function(text){
try {
var r = JSON.parse(text);
if (r.length === 0) {
return '';
}
this.hash = r[0].hash;
return r[0].total_posts;
} catch (e) {
console.error(e);
return '';
}
}
}
];
var services = Services.map(function(service, i){
return new SBM(service);
});
ChromeではJSON.
ここまでは一般的なJavaScriptの実装です。ここからは本題であるExtensions APIの使い方を見ていきます。
tabs APIの使い方
今回のケースはタブの更新時とタブの切り替え時に、
tabs APIにはタブ選択の変更
まずは、
var run_on_tab = function(tab, force_request, only_request){
var url = tab.url;
if (!/^http/.test(url)) return;
if (url.length > 255) return;
services.forEach(function(service){
service.set(tab.url, force_request, only_request);
});
};
続いて、
chrome.tabs.onSelectionChanged.addListener(function(tabid){
chrome.tabs.get(tabid, function(tab){
run_on_tab(tab);
});
});
最後に、
var current_window;
chrome.windows.getCurrent(function(window){
current_window = window;
});
chrome.tabs.onUpdated.addListener(function(tabid){
chrome.tabs.getSelected(current_window.id, function(tab){
if (tab.id === tabid) {
run_on_tab(tab, true);
} else {
run_on_tab(tab, true, true);
}
});
});
onUpdatedが発生したタブと現在選択されているタブが同じ場合、
以上でExtensionの実装は完了しました。仕上げとしてmanifest.
{
"name": "SBM Counter",
"description": "SBM Counter",
"toolstrips": [ "toolstrip.html" ],
"version": "1.0"
}
toolstripsしか使用していないため、
{
"name": "SBM Counter",
"description": "SBM Counter",
"permissions": [ "http://*/" ,"tabs" ],
"toolstrips": [ "toolstrip.html" ],
"version": "1.0"
}
本来であれば、
また、
以上をパッケージしたファイルは下記にあります。
まとめ
今回はExtensionsの作成からAPI仕様の概略とデバッグツール、