JSCocoaのiPhone用インタラクティブコンソール

English version is available.

JSCocoaのページからリンクされたので日本語版をこっちにうつしました。

iviewで使っているUIViewtransformがなかなか思い通りに操れなくて困っていて、だったらアプリにSpiderMonkeyを入れてHTTP経由で通信して試行錯誤できるよにすればいいやとUIMonkeyというのを作り始めたところで、既にそういうのがいくつかあるのをJohn Resig – JavaScript iPhone Appsで知ってショックーというかアホだったのでJSCocoaベースにちょこっと書き直しました。viewの階層構造やサイズを調べるのに便利です。

ファイルのコピー

svn checkout http://jscocoa.googlecode.com/svn/trunk/ jscocoa-read-only

してjscocoa-read-only/JSCocoa/JSCocoaの中身を全部自分のプロジェクトにコピーします。class.jsだけプロジェクトに追加した時に、ただのリソースファイルとして認識してほしいんだけどソースファイルとして認識されてしまうので、いったんclass.gifという名前でプロジェクトに追加して後から名前を変えたらうまくいきました(どうやるのが正しいんでしょう…)。

JSCocoa本体のほかにHTTPサーバのためのHttpd.m, Httpd.h, console.htmlを追加してください。console.htmlCopy Bundle Reesourcesに入れてアプリケーションに組み込まれるようにしてください。

*_Prefix.pchの修正

JSCocoa用のヘッダファイルを追加します。
今回はインラインでUSE_JSCOCOAdefineしていますが、デバッグビルドの時だけdefineするようにしたりすればいちいち書き換えたりする手間がなくなります。

#define USE_JSCOCOA 1

#if USE_JSCOCOA
  #define JSCocoa_iPhone
  #include "JavascriptCore.h"
#endif

main.mの修正

JSCocoaのサンプルコードiPhoneTest2とおんなじようにmain.mで初期化します。クラスHttpdは自分で作ったなんちゃってHTTPサーバです(最後参照)。

#if USE_JSCOCOA
	// Fetch JS symbols
	[JSCocoaSymbolFetcher populateJavascriptCoreSymbols];

	// Load iPhone bridgeSupport
	[[BridgeSupportController sharedController] loadBridgeSupport:[NSString stringWithFormat:@"%@/iPhone.bridgeSupport", [[NSBundle mainBundle] bundlePath]]];
	// Load js class kit
	id c = [JSCocoaController sharedController];
	[c evalJSFile:[NSString stringWithFormat:@"%@/class.js", [[NSBundle mainBundle] bundlePath]]];

	[[[Httpd alloc] initWithPort:38880] autorelease];
#endif

リンクするライブラリの追加

JSCocoaは関数呼び出しにlibffiを使っているので、プロジェクトの設定を開いてOther linker flags-lffiを追加します。

CGAffineTransformの追加

JSCocoaの中にiPhoneでだけ使われる構造体を定義しているiPhone.bridgesupportというXMLファイルがあります。これにCGAffineTransformを追加します(CGAffineTransformを使わないのであれば必要ありません)。

せっかくXMLファイルなのに構造体メンバを"で区切ってしかもそれを実体参照で書くという酷い仕様。下の行をてきとうにCGSizeを定義している下くらいに追加します。

<struct name='CGAffineTransform' type='{CGAffineTransform=&quot;a&quot;f&quot;b&quot;f&quot;c&quot;f&quot;d&quot;f&quot;tx&quot;f&quot;ty&quot;f}'
type64='{CGAffineTransform=&quot;a&quot;d&quot;b&quot;d&quot;c&quot;d&quot;d&quot;d&quot;tx&quot;d&quot;ty&quot;d}' />

ヘッダファイルからマシンフレンドリーな形式で生成して実行時コストを下げるか、ヒューマンフレンドリーにして手で書きやすくするかどっちかにするべきだと思います。

ブラウザで接続

そうしたらあとはアプリをふつうに起動すれば http://localhost:38880/ でアプリの中のJSCocoaに接続できるので、好きなタイミングでブラウザからJSCocoaにjsのコードを送り込んでアプリを操作できます。

以下iviewLifeの写真を表示してのテスト。

original

JSCocoaではObjective-Cのクラス名、メソッド名でjsからもアクセスできるので、UIApplication.sharedApplicationからアプリ内のオブジェクトにアクセスできます。

メインウインドウのアルファを0.2に変えると

alpha=0.2alpha=0.2

背景が透けて、暗くなります。

CGAffineTransformで横に3倍引き延ばしてちょっと右に100ピクセルずらすと

transformtransform

こうなります。

こういう試行錯誤や、使ったことのないクラスを触ってみるときに、Objective-Cのコードの上でやろうと思ったら毎回コンパイルし直す必要があるので時間がかかりますがjavascriptからできると細かい調整がすごく楽です。

View Tree Walk

takuma104さんが前に

iPhoneにWindowsでいうSpy++みたいなのがほしい。viewの階層構造がわかるやつ。
Twitter / takuma mori: iPhoneにWindowsでいうSpy++みたいな …

と言われていたのを思い出して、UIApplication.sharedApplication.subviewsからviewを列挙してjavascriptオブジェクトとしてみられるようにしてみました。HTMLで視覚的に再構築できればベストなんですけど、とりあえずFirebugのコンソールで値を確認できるようにしてみました。inspect view treeのリンクをクリックすると下の画面みたいにしてviewの階層構造を見ることができます。

JSCocoa感想

JSCocoaがNSArrayを自動的にjavascriptの配列として扱ってくれるのですが、これがあんまりうまくいってないみたいでlengthの値が入ってなかったりするとか、そういう微妙に変なところを配慮してあげればわりと使えそうなかんじでした。
自分が普段SpiderMonkeyにどっぷり浸かっているのでunevalがないとかE4Xがないとか分割代入できないとかもありましたがそうでなければふつうにjavascriptです。


About this entry