2013/05/27

Titanium SDK をMIPS 対応にする(完成か?)

Titanium SDK のMIPS対応の続報です。


前回問題になっていた
libtiverify
libtiprofiler
のMIPS版が存在しない問題ですが、ないなら使わないようにSDKを修正することで対処可能です。今のところこれらがなくても、作成されたアプリは支障なく動作するようです。libtiverifyはおそらくTi アプリ起動時にライセンス等々を確認するためのもの、libprofilerはTiアプリのプロフィリングのためのものだと思われます。

その他、いろいろワーニングがでている箇所を、新しいV8のお作法通りにきれいにして、これで、無事解決と思ったのですが、そうはいかず、ハマってしまいました。

全般的に何となく動いているのですが、Ti.Media.vibrate()など、オブジェクトに対するメソッドを呼んだ場合、実行時に
illegal invocation
になって、肝心の登録された関数本体が呼ばれなくなっていました。あれこれ原因を探るのに時間を浪費してしまいました。
しかし、
[v8] r13131 committed - Change deprecated semantics of function template signatures....
によれば、新しいV8では、元になるFunctionTemplateのプロトタイプがHiddenでなければならないという仕様になったとのことです。

ということで、この修正を加えて、無事オブジェクトに対するメソッドも完動するようになりました。
これで、外部モジュール以外の部分は、問題なく動作するようになっていると思います。
MIPS以外の端末でも、新しいV8の効果が期待できるので、皆さんお試しください。


ソースコード
https://github.com/isis/v8_titanium/tree/gyp
https://github.com/isis/titanium_mobile/tree/mips
バイナリ(テスト用)
https://www.dropbox.com/s/3gn0qfdjzcwd1ld/mobilesdk-3.2.0-osx.zip


2013/05/19

Titanium SDK をMIPS 対応にする(研究中)

MIPSベースのAndroid端末がかなりの数に上るのに、Titanium Mobileは対応していません。とても残念なので、なんとかしようとトライしています。まだ研究途中ですが、Titanium SDKのビルドまではできる状態になったので、情報を公開しておきます。
(いろいろツール類のインストール作業等を伴いますが、うるさくなるのでそれらの説明は割愛します)


歴史


* Android SDK のMIPS対応は API Level 9以降。
* Googleの公式NDKがMIPS対応したのは r8 (May 2012) 以降。
* V8 (https://code.google.com/p/v8/)がMIPS対応したのは、3.7以降だが、いろいろ問題があったので、V8 for MIPS (paul99 / v8m-rb) というプロジェクトが存在し、現在はこちらのコードが本家に適応されている。 
* V8 のビルドシステムはsconsベースからgypベースに変更されました。
* Titanium SDK の使用しているV8のバージョンは3.9.24.29で、Acceleratorが作ったTitanium Mobile 用のsconsベースのビルドツール (appcelerator / v8_titanium) を使って作成される。


v8_titaniumのビルド


v8 のライブラリの作成ができないことには、何もはじまらないので、まず、これに取りかかります。
問題は、AppceleratorがTi SDKに導入しているV8 v3.9.23.24 は古いので、そのままではMIPS対応できないようだということです。そして、新しいV8 はsconsベースではなくてgypベースのビルドシステムになっているので、v8_titaniumのビルドツールの修正が必要だということです。 しばらく自力でがんばろうとしましたが、世の中よくしたもので、既にgypベースのV8に対応するブランチを作成しているプロジェクトがありました。
     joshthecoder / v8_titanium
のgypブランチを使えば、最新のV8からもビルドできます。このブランチを元にMIPS対応を付け加えたブランチを作成しました。
     isis / v8_titanium
のgypブランチです。 リポジトリ取得後gypブランチをチェックアウトしてください。

V8のサブモジュールは、3.9.23.24を指しているので、最新版(2013/05/18時点で3.19.3)をフェッチしてください。

ビルドには build_v8.shを使います。
./build_v8.sh -j 4 -p android-9 -l all -s on 

とすると、armeabi armeabi-v7a x86 mipsel という4つのアーキテクチャ毎のライブラリが作成されます(ビルド時間はかなりかかります)。
./build_v8.sh -t 

とすると、上記のライブラリと必要な情報ファイルを含むtarballが作成されます。


Titanium SDKの修正


やらなければならないのは
  • MIPSアーキテクチャーの追加
  • 独自ビルドV8 ライブラリの導入
  • V8 のNew APIに対応
です。 
titanium_mobileの scons をたどって、適宜 mips を追加していきます。
Appcelerator の提供する titanium_mobile では、ビルド時に、V8 のライブラリをサーバーから取得し導入するようになっています。まずこの機能を削除して、手動で独自ビルドのV8 ライブラリを導入できるようにしなければなりません。
   <titanium_mobile>/android/build/common.xml

<condition property="libv8.latest">
<equals arg1="${libv8.current.version}" arg2="${libv8.version}"/>
</condition><antcall target="download.libv8"/>
<antcall target="download.libv8"/>

の部分をコメントアウトしておきます。

次にV8 ライブラリを
<titanium_mobile>/dist/android/libv8/

以下に展開します。ライブラリの tarbar を展開すると、必要な配置と違っているので、手動で以下のように配置します。V8のバージョン番号を示すディレクトリを起点にして
<titanium_mobile>/dist/android/libv8/
    3.19.3/
        release/
            libv8.json
            include/
            libs/
               mips/
               x86/
               armeabi-v7a/
               armeabi/

のようになります(gitからフェッチした直後はdistディレクトリ以下は存在しないので自前でディレクトリを作成する必要があります)。
libs以下の各ディレクトリにはアーキテクチャー毎のライブラリを配置します。
新しいV8のライブラリは、旧来1つのlibv8.aとして生成されていたのが、base, snapshot,nonsnapshotと3つのファイルに分かれて生成されるようになりました。Titanium で必要なbaseとsnapushotのライブラリを追加します。baseについては、ファイル名がアーキテクチャ名つきで生成されるので(なぜ?)、面倒なので、リネームします。また、V8生成時にMIPS用はmipsel (MIPSのリトルエンディアン)として生成されますが、titanium_mobileのビルドシステムを修正するのは面倒なので、mipsという名前に修正しておきます。mips/x86/armeabi-v7a/armeabi/ には、それぞれ、少なくとも
libv8_base.a
libv8_snapshot.a

2つのファイルが必要です。
sconsからたどって、libv8のバージョン番号の指定も適宜修正しておく必要があります。
V8のAPIがかわったので、Titanium からV8を呼び出している箇所で、コンパイルエラーがでます。New APIに置き換えてやる必要があります。
一応、ビルドが通る程度には置き換えてありますが、置き換えた正しいか検証はこれからです。
v8::Stringは非推奨になりましたが、現状ままにしてあります(なのでワーニングが大量にでます)。
以上まとめたものは、
isis / titanium_mobile
のmipsブランチに置いてあります。
ところで、出来上がったTitanium SDKを展開してみると、mipsのNDK関連のディレクトリに、
libtiverify
libtiprofiler
が欠けているのがわかります。これらのライブラリはTitanium Mobileのオープンソース部分ではないので、ビルド時に生成されません。このままの状態で出来上がったSDKでMIPSアプリを作成すると、起動時にクラッシュすると思われます。
どうしたものでしょうね ....
現時点では、最新のV8をもとにMIPS対応を含んだTitanium SDKのビルドができるようになった段階です。それを元に作成したアプリを検証等していません。
MIPSに対応しないとしても、新しいV8を利用できるのでJavaScriptの実行は高速になると期待できます(ただし実行コードのサイズも大きくなりいます)。
これを元に多くの方がトライされることを期待します。

2013/05/15

Titanium Mobile Tizen Alloy でエミュレータでアプリが起動しない

Titanium SDK 3.1.0.GA の最初の時点では、Alloy ベースのアプリを Tizen 向けにビルド、エミュレータ実行することができたのですが、最近試したところ、

[INFO] :   compressing ok
[INFO] :   Tizen SDK found at: /Users/k-ishida/tizen-sdk
[INFO] :   Executing: /Users/k-ishida/tizen-sdk/tools/ide/bin/web-uninstall -t 10 -i 62WvUifqkC --device=emulator-26100
[INFO] :   Uninstall failed, '62WvUifqkC' widget is not installed.
[INFO] :   CLI command failed with error output:
[INFO] :   
[INFO] :   Executing: /Users/k-ishida/tizen-sdk/tools/ide/bin/web-install -t 10  --widget="/Users/k-ishida/Documents/AlloyProj/test/build/tizen/tizenapp.wgt" --device=emulator-26100
[INFO] :   'tizenapp.wgt' file transfer successful.
Enable developer mode.
'62WvUifqkC' install successful.
[INFO] :   Executing: /Users/k-ishida/tizen-sdk/tools/ide/bin/web-run -t 10 -i 62WvUifqkC --device=emulator-26100'62WvUifqkC' launch failed.
[INFO] :   CLI command failed with error output:
[INFO] :   
[INFO] :   Project built successfully in 13s 428ms

となって、転送には成功したことになっているのですが、アプリ起動失敗といわれてしまいます。しかし実際は転送はうまくいってもエミュレータへのインストールがうまくいっていないようです(tizen sdk の web-list コマンドで確認できます)。

いろいろ調べた結果、作成される wgt ファイルに . のついた不可視ファイルがある場合、wgt ファイルが転送されるものの、インストールできない、にもかかわらずweb-install コマンドはそれを報告できない ... ということが判明しました。

で、なぜに、いつの間にかTi側で隠しファイルができてしまうか?
Alloy プロジェクト作成時に Alloy のプロジェクトディレクトリで
/app/assets/blackberry/.npmignore
というファイルが作成されています。
必要ないよね、これ。

Alloy プロジェクトを作成したら blackberry のディレクトリごと削除しておけば、問題なくなります。

注)Ti SDK 3.1.0.GA のリリース以降どの時点でblackberryディレクトリが作成されてしまうようになったのかは、気力がないので、誰か確認してください。



2013/05/04

Titanium Alloyのカスタムwidgetで、Androidでは、addEventListenerがエラーになる

Alloy である程度まとまった view を作るのには、独自の widgetを 作るのが便利だと思われます。
Titanium Studio でプロジェクトを右クリックして、New > Alloy widget を選択して、新しい widget を作成できます。
CLI では、プロジェクトのルートディレクトリで、
$ alloy generate widget NAME
とすると、同様に作成できます。

さて、この widget に利用する側からイベントを追加したいのですが、通常の view に対してと同じように
$.mywidget.on( EVENTNAME, FUNCTION);
を使っても、iOSでは何の効果もありません。
Android では、
05-04 11:45:58.802: E/V8Exception(4776): Exception occurred at ti:/events.js:172: Uncaught TypeError: Object #<Controller> has no method '_hasListenersForEventType'
という実行時エラーになります。

また、作成された widget の widget.js に、
exports['addEventListener'] = $.label['addEventListener'];
を追加した上で(label は、widget 内で追加されたラベルなどの view の id です)、
$.mywidget.addEventListener( EVENTNAME, FUNCTION);
してみます。これは、iOS では正しく働くようですが、Android の場合、
05-04 11:45:58.802: E/V8Exception(4776): Exception occurred at ti:/events.js:172: Uncaught TypeError: Object #<Controller> has no method '_hasListenersForEventType'
という実行時エラーになります。



多分バグです。

ということで、いろいろ思案したあげく、現状の Alloy (1.1.0とか、1.1.1) では、
$.mywidget.label.addEventListener( EVENTNAME, FUNCTION);
のような書き方をせざるをえないようです。
(widget 内の view がカプセル化されていないのは、なんだか解せない気もしないでもないですが ... )

widget にも on が使えるようになってるのが一番いいんですけどねぇ。

プロジェクト一式

widgeteventtest