Chrome Extension

Google ChromeのExtension作成メモ

基本的に自分がつくったextensionに必要な箇所のメモ

Manifest V2について

Content Security Policy (CSP) などをセキュリティの向上のため新しい拡張機能の実装ルールとしてManifest V2が定義されている。
Tutorial: Migrate to Manifest V2

この方式は拡張機能内のmanifestファイルに記載するバージョン ( "manifest_version": 2 ) を記述すると有効になる。この方式にそっていない拡張機能は新しくインストールできなくなり、すでにインストール済みの拡張機能もChromeのバージョンアップによって実行できなくなる見込み。従って新規に実装する場合はManifest V2にそって実装しないといけないし、既存の拡張機能もバージョンアップしないといけない。

Content Security Policy (CSP)

Content Security Policy (CSP) 自体はChromeの仕様でもChrome Extensionの仕様でもなくウェブサイトの仕様なのでChromeにウェブで検索すると情報が見つかる。 細かいルールはるが、大まかな対応としてはhtml内にcss,jsをインラインで記述せずに別のファイルにすること、外部ファイルのjs,cssを読み込む場合はそのurlを使うことを予め宣言する(manifestファイルに記載する)といったことになる。

Overview

http://developer.chrome.com/extensions/docs.html

  • HTML, CSS, JavaScript, 画像をzipでバンドルするという非常にWidgetに近いアーキテクチャーで
  • XMLHttpRequestやHTML5 local storageなどを使って機能を作成でき
  • さらにChromeからは browser actionsやpage actions、bookmarks、tabsなどの機能が提供される

ブラウザアクション

  • ブラウザに常駐するextensionは基本的にbackgroundページ(html)というのを持つ
  • さらにpopupを表示するなど別のページ(html)を持つことができ、別ページからbackgoundページの関数を実行したりできる
  • popupで表示するページはmanifestにてブラウザアクション(browser_action > default_popup)を定義することで呼び出せる
{
  "name": "My extension",
  ...
  "browser_action": {
    "default_icon": "images/icon19.png", // required
    "default_title": "Google Mail",      // optional; shown in tooltip
    "default_popup": "popup.html"        // optional
  },
  ...
}

つまりbackgounrd.htmlでアイコンで状態だけを表示しておいて、ユーザの呼び出し(クリック)によって詳細な情報だけをpopupで表示するということがextensionのひとつのやり方となる。

ページでの連携

popup, option -> background

  • extensionにとってbackgroundは親玉でありで以下で取れる
var background = chrome.extension.getBackgroundPage();
  • これでとれるのはbackground.htmlのwindowオブジェクトなので例えばbackground.htmlにあるグローバルな関数にアクセスするには以下のようにできる
// background.js
function foo() { alert("bar"); }
// popup.js
var background = chrome.extension.getBackgroundPage();
background.foo();
  • Google Calendar for Todayでは機能を別のオブジェクトにまとめており面倒くさいので以下のようにしてアクセスさせている
// background.js
(function($){
    $(document).ready(function() {
        var w = Blz.Widget, 
            gcal = Blz.Google.Calendar,
            app = MyGoogleCal.Application;
        // ....
        window.Blz = Blz;
        window.MyGoogleCal = app;
    });
})(jQuery);
// popup.js
var background = chrome.extension.getBackgroundPage(),
    Blz = background.Blz,
    w = Blz.Widget,
    app = background.MyGoogleCal

background > others

// background.js
function update() {
    chrome.extension.sendRequest({update:true});
}
// popup.js
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
    if (request.update) update();
});
function update() {
    ...
}
  • sendRequest() だと特定の宛先にメッセージを送れないのでメッセージを受け取った人が自分宛てのものかを判別しないといけない。ここではupdateというプロパティの有無でそれを判断している。

ページアクション

  • Chromeが開いているページに対して機能を提供する場合は、background.htmlを持たないでページアクションをつかって機能を提供できる
    • なおmanifestにはブラウザアクションとページアクションの両方を指定することはできない

Content Scripts

  • manifestに content_scripts を設定することで既存のHTMLにスクリプトをつっこんで操作することができる
{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://www.google.com/*"],
      "css": ["mystyles.css"],
      "js": ["jquery.js", "myscript.js"]
    }
  ],
  ...
}
  • matchesにどのURLのページにつっこむか、css,jsにextensionのどのファイルを突っ込むかを指定する
  • さらにrun_atにはいつスクリプトを実行するかを指定できる、指定できる値には以下のようなものがある
    • document_start: DOMが作成される前
    • document_end: DOMが作成されたあと
    • document_idle(デフォルト): window.loadの後

manifest

XMLHttpRequest

  • XMLHttpRequest で別ドメインにアクセスする場合はそのURLを予めmanifest.jsonの permission へ書いておく必要がある
{
  "name": "My extension",
  ...
  "permissions": [
    "http://www.google.com/"
  ],
  ...
}

設定について

  • Extensionは設定ページを持つことができてmanifest.jsonに options_page というのを指定してhtmlをつくればいい
{
  ...
  "options_page": "options.html",
  ...
}
  • デザインについてはhtmlなので単純にinput要素などつくればよい
  • データの読み書きについてはHTML5のlocalStorageで行うとよい
  • localStorage(Storage interface)は getItemsetItem もあるが属性でのアクセスもできるので以下のようにも書ける
localStorage["favorite_color"] = color;
 var favorite = localStorage["favorite_color"];
  • window.loadや保存ボタンのclickイベントをハンドリングするなどしてlocalStoragに読み書きするのがよいだろう

国際化について

  • _locales/localeCode/messages.jsonというファイルを作成すれば良い
  • 開発中のunpackageなextensionの場合、messages.jsonがおかしいと容赦なくChromeから削除されてしまう。再度起動するためにいちいちディレクトリを選択しないといけないのであらけじめjsonの検証ツールでチェックしておくのがよいと思われる
  • 日英なら _locales/en/messages.json , _locales/ja/messages.json を準備する
  • 文言はkey-valueの形で設定するらしいが文言自体は value["message"] に設定する
  • パラメータを埋め込みたい場合は、パラメータに名前をつけて文言の中に$で囲い埋め込む、で value["placeholders"][key]["content"] へ変数の何番目に指定してもらうかを $1 とかで入れる
  "hello": {
    "message": "Hello, $USER$",
    "description": "Greet the user",
    "placeholders": {
      "user": {
        "content": "$1",
        "example": "Cira"
      }
    }
  },
  • message.jsonで指定した文言をつかう場合、manifestなどでは __MSG_messagename__ で指定する、javascriptからは chrome.i18n.getMessage を使う
chrome.i18n.getMessage("messagename")
  • パラメータを渡す場合は第二引数に配列で渡す
 var message = chrome.i18n.getMessage("click_here", ["string1", "string2"]);

開発方法

  1. 適当なフォルダにファイル一式を置く
  2. Chromeの拡張機能を選択し、 デベロッパーモード を有効にする
  3. パッケージ化されていない拡張機能を読み込みます… からフォルダを選択
  4. 実行中は アクティブな閲覧数を確認: からDeveloper Toolsを起動する
    • Consoleよりログが確認できる
    • Consoleにログを出すにはjavascriptで console.log()を使う
    • Storageから保存したデータを参照できる

トラブルメモ

messages.jsonがおかしいとextensionが読み込めない

  • messages.jsonというファイルがちゃんとないと読み込めない
  • default_localeをmaniest.jsonに指定していないと読み込めない。
  • http://www.jsonlint.com/ でjsonpのチェックをするのが吉

ポップアップでaタグのリンクが開けない

どうやらtarget=_blankがいるらしい。

公開されているextensionのソースを読む技

インストールするとローカルのユーザデータに展開されているのでそれをテキストエディタで読むだけでいい

  • Windows
    • C:\Users\makoto_kw\AppData\Local\Google\Chrome\User Data\Default\Extensions
  • Mac OS X
    • /Users/makoto_kw/Library/Application Support/Google/Chrome/Default/Extensions