Add-on SDK to WebExtensions #5

ところが結局、Windows 上の Firefox で Selenium によるテストを行うところまで至っていない。現状では

  • Windows 上で
  • 任意の拡張を一時的に読み込ませつつ
  • そのプロファイルを使うよう Selenium に指示する

という術がないように思える。となるとテストのために一旦 xpi をビルドして、署名して、それを使うしかない。

ちなみに Selenium は現在 version 3 になっていて、Firefox に関しては Chrome の chromedriver.exe と同様 geckodriver.exe を介在させるようになっている。そのためにシステムプロパティ webdriver.gecko.driver に geckodriver.exe へのフルパスを書いておく必要がある。

ということで試してみたところ

File p = new File("C:\\path\\to\\profile");
WebDriver driver = new FirefoxDriver(p);

の呼び出し中に

Java heap space
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at org.openqa.selenium.remote.ProtocolHandshake.amendOssParamters(ProtocolHandshake.java:183)
at org.openqa.selenium.remote.ProtocolHandshake.createSession(ProtocolHandshake.java:61)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:141)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:82)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:601)
at org.openqa.selenium.remote.RemoteWebDriver.startSession(RemoteWebDriver.java:241)
at org.openqa.selenium.remote.RemoteWebDriver.(RemoteWebDriver.java:128)
at org.openqa.selenium.firefox.FirefoxDriver.(FirefoxDriver.java:259)
at org.openqa.selenium.firefox.FirefoxDriver.(FirefoxDriver.java:247)
at org.openqa.selenium.firefox.FirefoxDriver.(FirefoxDriver.java:242)
at org.openqa.selenium.firefox.FirefoxDriver.(FirefoxDriver.java:238)
at org.openqa.selenium.firefox.FirefoxDriver.(FirefoxDriver.java:131)
at WasaviTest.WasaviTest.createDriver(Unknown Source)
at WasaviTest.WasaviTest.beforeClass(Unknown Source)

……どうしろというのか。

 * * *

FirefoxDriver のコンストラクタに独自のプロファイルを与えるのではなくデフォルトのそれを使用するようにすると(要するに何も引数を与えないと)起動した。なにそれ。テストのためのツールである Selenium ががろくにテストされてない…。真面目にやってくださいよ本当に。

 * * *


FirefoxProfile p = new FirefoxProfile();
p.addExtension("/path/to/wasavi.xpi");
driver = new FirefoxDriver(p);

とやるととりあえず OutOfMemoryError で落ちることはないのだが、拡張を登録する処理で「アーカイブの中に install.rdf がないよ〜」的なエラーになる。この場合の wasavi.xpi は WebExtensions ベースの拡張なので install.rdf ではなく manifest.json を見に行ってくれないといけないのだが、Selenium 側がまだ WebExtensions ベースの拡張を知らない状態なのだろう。

うーん! だめじゃん。WebExtensions の拡張を Selenium でテストするのは時期尚早なのか。

Add-on SDK to WebExtensions #3

content script において window.Uint8Array を使おうとするとエラーになる。グローバルオブジェクトのそれを使わないといけない。両者は権限のドメインが違う、らしい。グローバルオブジェクトに Uint8Array が存在する場合はそれを、次に window に存在する場合はそれを使うようにした。

window. を前置するのをやめればいいじゃん、と思うかもしれないが、そうはいかない。赤福プラスでは window のプロパティを参照する際は必ず window を前置している。これは Presto Opera で動かすための措置で、Presto Opera の injected script では window がグローバルオブジェクトではないのである。したがって前置は必須なのだった。

それにしても、今 Presto Opera 使ってる人ってどんくらいいるのかなあ…? とはいえ赤福プラスはまだ Presto Opera もサポートしているので、動作確認のために新しい環境にも 12.16 を落としてインストール。

ところでメモやブックマークを同期しようとログインしようとしたらどうやっても弾かれるんですけど…。

Firefox の方は SDK 版から WebExtensions 版への自動更新が滞りなく行われることを確認。

さてこの SDK -> WebExtensions の作業において赤福プラスは前座でしかない。本丸は wasavi なのである。

Add-on SDK to WebExtensions #2

一通り動くようになった。

すでに上げた Port の引数の問題の他、content script で生成した XMLHttpRequest の動きが変。

  • Referer が吐かれない
  • Cookie が送出されない
  • open() の際、相対 URL を与えるとエラーになる

同様の問題を抱えている人がいた。そのやり取りによると、

try {
return XPCNativeWrapper(new window.wrappedJSObject.XMLHttpRequest());
}
catch(evt){
return new XMLHttpRequest();
}

こんな感じで Firefox に限り意味の分からない書き方をすることで解決できるそうな。確かにこれでうまく行くけど…早く直してほしい。

ところでもうひとつ、ID の問題がある。Chrome のエクステンションは基本的にそれを識別する ID というものを開発者が意識する必要はない。エクステンションをローカルで crx にパッケージングした際に生成される .pem ファイルは取り扱いに気をつける必要はあるが、今日ではローカルパッケージングは zip で事足りるので .pem ファイルを生成する必要自体が基本的にない。

WebExtensions の場合は一応その流儀に倣っているが、しかしやはり Firefox の拡張らしく、ID は裏で健在だったりする。というのも署名を mozilla のサーバにつけてもらうと .web-extension-id という ID が書かれたドットファイルをもれなくプレゼントされるのである。うーんなんかイケてなくないですか。

一方で陽に ID を取り扱うこともできる。manifest.json の applications に

"applications": {
"gecko": {
"id": "jid1-ytdk6oePtVeu1A@jetpack",
"strict_min_version": "42.0",
"update_url": "https://github.com/akahuku/akahukuplus/raw/master/dist/firefox.json"
}
},

とこんな感じに書けばいい。ただよく分かんないことに、こう明示したとしてもやはり .web-extensions-id ファイルはプレゼントされる。いらないんですけど!

ところで上記の ID、いかにも Add on SDK 製の拡張っぽい書式だが、実際に SDK 版の赤福プラスの ID だ。というのも、おそらく流用しないと SDK 版から WebExtensions 版へのスムーズな自動更新が行えないからだ。うーんなんだかかっこ悪いなあ…。

Add-on SDK to WebExtensions

Firefox の拡張は本格的に WebExtensions ベースへの移行が始まっていて、一応のロードマップでは来年の 11 月には Firefox 57 において WebExtensions ベースではない旧来の拡張の読み込みをしないようになるという

拙作について考えてみると、あべアニの拡張の Firefox 版は WebExtensions で新規に書いたのだけど、既存の Addon SDK ベースの拡張は移行作業というものをしないといけない。具体的には赤福プラスと wasavi だ。あとは Webliopane だけど…これはどうかな。そもそも人様のものだし。

で、赤福プラスと wasavi に関しては SDK ベースではあるが、もともと Kosian という Chrome の拡張に近づけて書くためのラッパをかましているので、それぞれの拡張自身のコードに関しては大掛かりに書き換える必要はない。Firefox においてはただ単に動作の基盤を WebExtensions に差し替えればいい、はず、だ。たぶん。

というわけで、とりあえず赤福プラスをちまちまといじり始めたのだが。実際アプリケーションとしてのコードの修正よりむしろ WebExtensions の微妙な発展途上さに振り回されている。

  • まず content script と background の間を long-lived port で接続している。この際、background では port の onMessage イベントハンドラを

    function handlePortMessage (message, port) {
    ;
    ;
    }

    という風に定義している。最初の引数が飛んできたメッセージ、次の引数が使用された runtime.Port オブジェクトだ。このイベントハンドラの引数リストは Chrome の API ドキュメントに記述してある。

    で、それを Firefox の WebExtensions で動かすと、第 2 引数である port が渡されてこないのであった。これはきっとバグだろう

箇条書きにした割に 1 つしか書いてないが、きっと開発を進めるごとにいろいろ出てくる。

ところで web-ext ツールというものがあり、これは従来の cfx とか jpm に相当する。これで [cci]web-ext run[/cci] とすると一時的なプロファイルによって Firefox が起動する。開発中の拡張は自動的に読み込まれている。そして面白いことに、その状態でソースファイルを更新すると拡張が自動的にリロードされる。これはちょっと便利。