4千円しないAndroidタブレットを活用しないのはもったいない
Amazonプライムデーで4千円ださずに購入したkindle file。長男が操作をいつのまにか覚え、車のゲームを あれこれDLして遊んでるところを奥さんに見つかり、大目玉を喰らってます。
今回はそんなkindleにmrubyを動かそうとした記録です。
準備編
Androidの開発はプライベートでは既に奥さんの仕事向けにWebViewをつかったやつを大昔のEclipseで 作成したことがあるくらいなので、ぼんやりとは把握してるつもり。そして、イマドキはEclipseではなく、 Android Studioで行うのが一般的らしいというのは予習済み。
Android Studioの環境作成
OSXで主に今回の作業を進めた。Windows 10でも一部やったが、OracleのJDKを入れて、 Android Studioをインストールすれば、すぐに動く感じ。 (Android SDK、NDKのDLや仮想マシンのDLでかなり時間は掛かけど。)
SDKやNDKもAndroid Studioからインストール出来、これを使って作業をしている。
Android Studioを離れての作業でも、これらのパスを押さえておけば、大丈夫そうだった。
mrubyの組み込み
素のmrubyをAndroid向けにビルドするには簡単。
「mrubyをAndroid Studioのエミュレーターで動かすためのlibmruby.aを作る - Qiita」に書いたようにlibmruby.aを作って、 これをJNIな.soファイルにリンクして、呼び出せばOK。
挫折編
素のmrubyが簡単に組み込めたので、mruby-cliでのクロスコンパイルに対応してあるmruby-webcamを 組み込めば、
cam = Webcam.new cam.capture {|img| # img : JPEG format puts img.length } cam.snap
と言った具合に簡単にkindle fireのカメラにアクセス出来ると思い、作業を始めた。
現行のFireOSですら、カメラのアクセスはJavaを経由しないと難しい模様。 Nでは許可を得るのにJava必須な模様なので、FireOSがアップデートされたら、こちらもJavaが必須となりそう。
OpenCV無駄に古い2.7系を静的リンクしてるから更新せねば mrubyを動かすcordovaのプラグイン少し進んだ。 #cordova #mruby pic.twitter.com/8f634ENhOk
— kjunichi (@kjunichi) 2016年9月17日
Cordova(Android)編
当初はNDKを使えば、C言語で頑張れば、色々出来るから、それらを上手いこと mrbgemにすれば楽しそう!と考えていましたが、基本Javaを介さないとAndoridのサービス?等を 利用することができなそうなことが分かってきたので、方針転換
- C->Javaしなきゃ行けないなら、Java->JavaScriptも使ってしまえ! -> Cordovaがあるのか!
putsとgetsの実装
RubyPicoが目標だが
puts,getsが実装できれば、最低限mrubyを動かして、プログラムの実験が出来るのではと思い始めた 。すでにこの段階で、mrubyには2.7系ではあるが、opencvがリンクしてあり、mruby-webcamを 少し改造すれば、カメラで撮影した画像を顔検出位まではmrubyで出来そうな見込みであり、 早々にputs,getsを実装したいことろだった。
先人であるRubyPicoのコードが大いに参考になった。 Rubyはクラスの書換えも自由自在なので、puts、getsを書き換えることが簡単にでき、
- putsではDOMにdivタグで囲まれたテキストを追加する実装に変更
- getsではalertをwindow.promptで入力を取得する実装に変更
といった実装で進めた。
putsとgetsの実装がなんとなく出来そうな気がしてきたから気が早いが、リポジトリ確保w / “GitHub - kjunichi/cordova-plugin-mruby: mruby for cordova” https://t.co/bYJw1yPmcJ
— kjunichi (@kjunichi) 2016年9月15日
躓きポイント(puts実装時)
JavaからJavaScriptを呼ぶには
事前にAndroidでは昔からWebView#loadUrlはあまり望ましくないとの情報を 得ており、WebView#evaluateJavascriptがKitKat以降は使えるとの事だったが、
CordovaのAndroidでは簡単には使えない模様。loadUrlは使えたので、こちらでとりあえず実装を進めた。
mrubyを動かすcordovaプラグイン、putsの実装にハマった。java,c,mruby,javascriptと言語を色々使っての実装なのでなかなかこんがらがりそう https://t.co/oyoiDn6Y6P
— kjunichi (@kjunichi) 2016年9月18日
といった具合にputsですら苦戦して、getsなどは、スレッド絡んでホントに大変だった。
躓きポイント(gets実装時)
WebView#evaluateJavascriptが使えれば、window.promptへの入力後に呼んでもらうコールバックを設定できて 苦労がなかったはずだが、それが使えなかったので、プラグインのコードでwindow.promptの入力を待つのに苦戦
CordovaのプラグインはUIスレッドで動いているのを理解しておらず、 Thread.sleepして固まった。 これに対応する為に、別スレッドで動かし、window.prompt入力後に Js側のコールバックを実行するように非同期処理にして、getsが出来た。
やっと、uiスレッドと別のスレッドを非同期に動かして、getsの実装が出来た! #cordova #mruby pic.twitter.com/BRj2DnpwLL
— kjunichi (@kjunichi) 2016年9月19日
final CallbackContext cb = callbackContext; if (action.equals("mrbLoadString")) { final String script = args.getString(0); Thread th = new Thread(new Runnable(){ @Override public void run() { String jniString = MrubyJni.mrbLoadString(script); Mruby.setResult(jniString); String message = ". JNI says: " + _jniString; Mruby.mrbLoadString(message, cb); } }); th.start(); return true; } public static String gets() { Log.d("Mruby", "gets"); waitInput = true; inputString = "dummy"; final String js = "console.log(mruby.__jsGets())"; stdout.getView().post(new Runnable() { public void run(){ //stdout.sendJavascript(js); Log.d("Mruby", "gets/exec js = " + js); stdout.loadUrl("javascript:" + js); Log.d("Mruby", "gets/exec js done"); } }); Log.d("Mruby", "gets/wait"); while (waitInput) { try { Thread.sleep(200); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } Log.d("Mruby", "gets/rtn = "+inputString); return inputString; }
成果物
役に立ったこと
デバッグ文代わりのLogとCのマクロが役に立った。 コマンドラインでcordova runコマンドで動かして、AndroidStudioで適当なプロジェクト開いておくと、 出力したログが勝手に表示されて便利だった。
import android.util.Log; Log.d("Mruby", "gets/wait");
__android_log_print(ANDROID_LOG_DEBUG,"Init", "Java_com_hatenablog_abrakatabura_mruby_MrubyJni_initialize");
IDE環境でのCordovaのプラグイン作成方法が不明なので、improt文含めコピペ。
まとめ
去年書いた記事の「外部のライブラリに依存するmrbgemを使ってもmruby-cliでワンバイナリを作成できるようにした」の作業を通して、クロスビルドの経験が出来ているので、あまり臆せずNDK絡んでの開発が行えた気がする。経験大事。
また、HT-03Aの頃と違い、NDK関連も検索すれば、やりたいことに近い事例や、エラーメッセージへの 対応等サクサク出てて来る。ただ、kindle fireだとそもそもAndroidのバージョンいくつと同等なのか とか、それなりに取り組まないと把握が難しいと感じた。やり出せば、楽。ちなみに現時点では5.1のlollipop相当らしい。
ndk-buildコマンド or Android Studioのプラグイン
コマンドラインで生活してる場合、ndk-buildコマンドが楽な知見。
プラグインの設定が面倒。過去になんどか書き方が変更になっているので、検索に注意が必要。
Cordovaの感想
Cordova使ってみて、さくっと子供たちのゲーム教育用アプリを作ってkindleやAndroid端末で動かせるので、 お父さんはIT系の仕事やってる感を前面に押し出せそうで、心強いw。
ドキュメントがググると日本語で見つかるが、ザ機械翻訳なので、Androidが人造人間と訳されているなど、 読みづらい。とはいえ、無いよりずっと良い。
また、頻繁にAPIも変更なっているようで、既に出回っているプラグインのソースを呼んで 使い方を理解する等が出来ないと辛いが、それが出来れば、良い感じで楽できそうだった。
今後の課題
現状ではmrubyをEmscriptenでJsに変換して動かすWebrubyと比べて、なんらメリットがなさそうなので、 当初のカメラを使って簡単な画像処理あたりまでの実装。
あと、CordovaでiOSも試した。去年から無料で実機にデプロイ出来るようになったので、 実機で動かせた。iOS10も出たばかりで、こちらの新しい気のも試したい感はある。
参考資料
関連記事
- OpenCVをEmscriptenでJS化して動かせた
- Xperia SO-01Bで使用できるOpenGL ESのバージョンは?
- 端末の方向を変えたときに画面が毎回初期化される - 明日の鍵
- eclipseでAndroidアプリが動かなくなった
- VAIO type P でAndroidを動かす ~前編~
- VAIO type P でAndroidを動かす ~後編~
- VAIO type PでFroyoが動いた!
- type P gingerbreadへの道
- gingerbread-x86がtype Pで動いたが。。
- gingerbread-x86がtype PでWifi通信も可能に