OpenLayersをWebViewで貼り付ける

WebViewを貼り付けてJavaScriptアプリをDalvikアプリのようにみせるアプリの続き。

Leafletを使おうとして、手持ちの端末でうまくいかんかったので、OpenLayersを使うことにしました、までがこれまでのあらすじ。

しかしOpenLayersでも問題が発生。

アプリの一回目の起動は問題ないのですが、いったん閉じて(Androidではアプリを閉じてもプロセスまでは落ちない)再び開き直すと、何かうまくいかない。

コンソールを眺める

JavaScriptデバッグでは、とりあえずコンソールを見ます。が、WebViewからは通常は見えなくなっています。

WebView webView;
...
webView.setWebChromeClient(new WebChromeClient());

としてやると、コンソールログがLogCatに流れてくれるので便利です。ただし、配布アプリでWebViewのコンソールをLogCatから見られるのがイヤな場合には外しておいた方がいいように思います。

話をもどして、LogCatでコンソールを見ていると、OpenLayers側で、「wというプロパティが無い」だのなんだの言われた。

どうも Map内で this.size.w でひっかかってる模様。

遅延させてどうにかしてやろうかと画策

JavaScriptが先走っちゃってるんだろう、と。たとえば setTimeout(init,0) とかしてやると、なんとなくうまくいきました。ただしこれは標準のOpenLayers.jsでの話し。カスタムビルドして小さいスクリプトにしたったところ、setTimeout(init,0) だと失敗しました。ということは、setTimeoutの遅延期間をチューンしても、条件が違うと数字が違ってくるので、実質不可能。まあ1秒ぐらい待てばだいたいOKなんだろうけど、できればそういうのは避けたい。

clearCacheで遅延せざるをえなくする

次に考えたのは、WebView::clearCache を使うこと。onDestroyでWebViewからキャッシュを消し去ることで、2回目に開いても1回目と同じ環境であるはずだ、と。これ、意外とうまくいった、と思ったです。

しかし、次の日にはまたうまくいかなかった。前の日はうまくいってたのに。なんだよ…。

結局の回避策

初期化メソッドで、MAPを貼る対象の div を見て、clientWidth, clientHeight が正の数になったら初期化を始める、というようにしました。
とりあえずこれで動いているけれども、まだ不安ではある。

OpenLayersのカスタムビルド

OpenLayersのカスタムビルドをしているのは前述の通り。やはり速度が違う。

これで若干つまずいたのでここにメモを残す。

README読め

(root)/build/README.txt に書いてある通りにする。コンプレッサにはclosure-compilerを選択。で、zipを落として compiler.jar を抽出。(root)/tools に入れる。

そうすると失敗する。

compiler.jar を closure-compiler.jar にしないといけない。これ README.txt に書いてありました。ちゃんと読めよ…。

あとは、liteとかmobileとかサンプルがあるので、それをもとに作成。

ファイル名は (prefix).cfg として(サフィックス cfg は必須)、

python build.py -c closure (prefix) (出力ファイル)

としますが、".cfg"サフィックスは引数には入れません。

あと余談ですが、出力ファイルは OpenLayers.(prefix).js とするのが流儀っぽいので、そうしました。

Pythonバージョンに注意

OpenLayers-2.12 の話です。

エラーが出たのです、しかも Syntax Error が。これは文法自体がおかしい場合なので、根本的に間違っているのではないか、と思ったのです。

ただ Print "..." でエラーが出ました。となると、処理系のほうで、文法に手が入れられたのではないか、と。これを補強するように、Windows用のPythonを落とそうとした際に 3.x系と 2.x系とがありました。3.x系でなんらかの仕様変更があって、2.x系のスクリプトが多いので完全に移行仕切れてないのではないか、と。で、ちょっとgoogleさんに聞いてみたら、案の定、文法が変わった(というか許容される文法を絞った)模様。たとえば print "..." がアウトで print("...")と書く、except Exception, E: がアウトで except Exception as E: と書く、とか。

使っていたPythonは3.x系。うむこれはスクリプトを3.x系にしてやろうじゃないか、と思っていじってみましたが、build.pyは改めたったんですが、(root)/tools/*.py が控えてて、あきらめました。Python 2.x系を入れれば、即効解決です。あと、改めたbuild.pyはPython 2.x系でも通りました。

ProGuardを使ってみる

なんとなくAndroid SDKに添付されているProGuardを使って難読化を試みました。理由は隠したいものがコードに混じったから。

で、なんかエラーが出て失敗。googleさんに聞いたら、どうもパスに空白があるのがいけないらしい。またか…。で、eclipseのプロパティで短縮型のパスに切り替えたのですが、それでもうまくいかなかった。

ので、空白が入らない別のところにSDKをインストールしなおしました。そのうえで使うと素直にいきました。

eclipseからの使用方法は、project.propertiesに proguard.config=... を入れ、普通にapkをエクスポートすればOK。
ただしJavaScriptからDalvik側を呼ぶ場合には、proguard-project.txt で

-keepclassmembers class (JavaScriptから呼ばれるクラス)
  public *;
}

として、整理対象としない必要があります。こうしないと、JavaScrtip側から見て難読化されてアクセスできなくなります。

むしろ実行速度向上に目を奪われた

エクスポートしたapkを入れて実行してみると、ProGuardを実施していない場合と比べて、実行速度が上がりました。難読化が導入の理由で、それも重要なんですが、実行速度面もなかなかすげーと思いました。