Kishima's Hateda log

はてなダイアリー記事の保管庫

Ruboto-coreのReadmeをおおざっぱに訳してみた。

下記で訳してたものがまとまったので、こちらでも公開しておきます。
http://silentworlds.info/pukiwiki/?RubotoReadme
アップデートはwikiの方で行っていくのでご注意を。

オリジナル

2011/5/28最新のものを訳しています。
https://github.com/ruboto/ruboto-core/blob/master/README.md
ライセンス
古くなっていたり、翻訳が間違っている可能性もあるので、その点留意してご参照ください。
細かい表現を省いて訳している部分もありますので、ご注意ください。

Ruboto-CoreのReadme(日本語訳)

Ruby on Android.

インストール

$ gem install ruboto-core

はじめに

Rubotoを使う前に、次のことをやっておくこと。

  • JDKのインストール
  • jrubyのインストール

JRubyインストールはとても簡単。もしくはrvmも使える

基本的なこと

Rakefileはアプリのルートディレクトリで実行されることを想定しており、Rubotoコマンドも同様である。(`ruboto gen app`は除く)

RakefileJRubyのrakeを使って実行される必要がある。

コマンドラインツール

  • アプリ生成コマンド(railsのアプリケーション生成に似てる)
  • クラス生成コマンドは追加のActivity、BroadcastReceiver、Serviceなどを生成する
  • コールバック生成コマンドは、多くのAndroidAPIのアクセスのために必要なサブクラスを生成する
  • パッケージ処理はapkファイルを生成する
  • デプロイ処理は、エミュレータか接続されたデバイスに、生成されたパッケージをデプロイする
  • 変更のたびにコンパイルしないですむような開発
アプリ生成コマンド

$ ruboto gen app --package com.yourdomain.whatever --path path/to/where/you/want/the/app --name \
$ NameOfApp --target android-version --min_sdk another-android-version --activity MainActivityName
versionの値は、'android-'+SDKのレベル番号の形式をとること。(froyoの例 android-8 ).

クラス生成コマンド

rubotoのスクリプトで、Javaのクラス (Activity、Service、BroadcastReceiver) を生成する。同時にテストスクリプトも生成する。

$ ruboto gen class ClassName --name YourObjectName
Ex:
$ ruboto gen class BroadcastReceiver --name AwesomenessReceiver

コールバック生成コマンド

このコマンドで、特定のメソッドが呼ばれたときに、スクリプトに制御を渡せるようにどんなAndroid APIでもサブクラス化できるようにする。あなたがrubotoに制御を渡すAndroidインタフェースを実装することもできる。

サブクラス化する必要があるクラスの場合は、(例 PhoneStateListener, SQLiteOpenHelper, View)

$ ruboto gen subclass AndroidPackageAndClassName --name YourClassName --method_base all-on-or-none --method_include methods --method_exclude methods

実際の例:

$ ruboto gen subclass android.telephony.PhoneStateListener --name MyPhoneStateListener --method_base on

実装が必要なインタフェースの場合は、(例 OnClickListener or SensorListener)

$ ruboto gen interface AndroidPackageAndInterfaceName --name YourClassName

実際の例:

$ ruboto gen interface android.hardware.SensorListener --name MySensorListener

スクリプトの中で使う時は:

    # java_importとは違うことに注意
    ruboto_import "your.package.MySensorListener"

後ろの方で:

    # コールバックオブジェクトを生成
    @sensor_listener = MySensorListener.new
 
    # 呼び出しされるブロックの設定
    @sensor_listener.handle_sensor_changed do |sensor, values|
      # Do stuff
    end
    # リスナーの登録
パッケージ処理

apkファイルを生成

$ rake

apkを生成して、接続されたデバイス(またはエミュレータ)に一発でインストールするには、下記のコマンドを打つ。

$ rake install

デプロイ処理

マーケットで公開する準備ができたら、いくつかやることがある。

まず、`keytool`でアプリの署名を行うためのキーを生成する必要がある。いくつかのしっかりした初期値を使うつもりがあれば、

$ ruboto gen key --alias keyの名前

というコマンドを、`--keystore /path/to/keystore.keystore`というオプションと共に使うことができる。それは、`~/.android/production.keystore`のデフォルト値となる。(?)
途中、keystoreと、キーそれ自身のための、パスワードを聞かれる。その二つのパスワード、キーの名前をちゃんと覚えておくこと。

キーはセキュリティに気をつけつつ、バックアップをしておくようにしておくように。(鍵をなくすと、アップデートがリリースできなくなる)

あなたのキーがあれば、`rake publish`タスクを使って、マーケットに公開できるapkファイルを作成できる。その際、環境変数`RUBOTO_KEYSTORE`と`RUBOTO_KEY_ALIAS`にkeystoreのパスと、キーの名前を下記のように設定すること。

$ RUBOTO_KEYSTORE=~/.android/production.keystore RUBOTO_KEY_ALIAS=foo rake publish

または`~/.bashrc`やそれに準じるファイルに設定してもよい。
そして下記を実行する。

$ rake publish

マーケットに公開可能なapkのできあがり。

スクリプトの更新

これまでのAndroid開発では、変更があるたびに、アプリをビルドし直して、デバイス/エミュレータにインストールしていた。
遅くて退屈であった。

Rubotoでは、幸運にも、変更のほとんどはJavaコンパイルしないですむスクリプトの中だ。もし変更がRubyのみの場合、下記を実行するだけでよい。

$ rake update_scripts

このコマンドは、デバイスの中のスクリプトを更新する。

チャンバラのための言い訳を無くしてしまったとしたら、ごめんなさい。

http://imgs.xkcd.com/comics/compiling.png

注意:

これは変更が全てRubyの中に収まっているときだけ、上手く動作する。Javaの変更(一般的には新しいクラスを生成したとき)、またはXMLの変更があったときは、再コンパイルが必要である。

また、この処理を行うため、リードオンリーのディレクトリに書き込むことが必要になるようなときに、デバイスのroot権限が必要になる。rootを取れないときの、最も簡単な解決方法はエミュレータでテストするということだ。

Ruboto関連ファイルの更新

rubotoのコマンドで、生成されたアプリの色々な部分を更新できる。

  • JRubyの更新:
    • 1) JRubyの新しいバージョンがリリースされたら、gemを更新するべき (例えば sudo gem update jruby-jars)
    • 2) アプリのrootディレクトリで、次のコマンドを実行する

$ ruboto update jruby

$ ruboto update ruboto

  • 主要なクラスの更新(例えば RubotoActivity):
    • 1) これらのクラスはSDKに依存して生成されている。SDKバージョンは'gen app'の時に決まっている。(AndroidManifest.xmlに記録されている)
    • 2) 新しいSDKがリリースされたとき、ターゲットを変更したとき、コールバックに手を入れてより拡張しようとするときなどに、あなたは再生成することを望むだろう。
    • 3) アプリのrootディレクトリで、次のコマンドを実行する

$ ruboto gen core Activity --method_base all-on-or-none --method_include specific-methods-to-include --method_include specific-methods-to-exclude

    • 4) ジェネレータはSDKの除法を読み込み、指定のメソッドを見つけ出す。ジェネレータは、メソッドが追加されているか、指定のSDKレベルで非推奨であるときに処理を中断する。あなたは、それらのメソッドを除外するか、または--force を付けて強制的に生成できる(追加されたメソッドは既存のハードウェア上でクラッシュしないように、superを呼ばない形で生成される)

スクリプト

Rubotoがあなたに求める主なことは、Activity、BroadcastReceievers、Serviceの動作を定めるRubyスクリプトを書く能力である。(ゆくゆくは全てのクラスになるだろう。クラスが増えてもそれはさほど大変なことではない)

どんな風に動いているのか:

最初に、あなたのスクリプトは`assets/scripts/`にあり、スクリプトの名前はあなたのクラスと同じである。キャメルケース記法の代わりにアンダースコアを使っている。
Androidのクラスは、特定の状況で呼ばれるメソッドの全てを持っている。例えば、`Activity.onDestroy()`はActivityがkillされるときに呼ばれる。
変わった場合の対応として(JRubyのセットアップが必要な起動メソッドのような)、onFooBarを書くために、あなたはAndroidオブジェクトの中で、Rubyメソッド handle_foo_barを呼ぶ。(?)*1
あなたのスクリプトの中では、それらは`$class_name`として定義されている。これはまったくの概要なので、例を示す。

アプリを`--activity FooActivity`オプションを付けて生成するということは、rubotoはFooActivityを生成することを意味する。
`assets/scripts/foo_activity.rb`を好きなエディタで開いてみる。アプリが起動した時と破棄されたとき(onCreate、onDestroyのなかで)にLogを出すactivityが欲しいとき、スクリプトは下記のような感じである。

    require 'ruboto.rb' #これ抜きではスクリプトは動かない
    $activity.handle_create do |bundle|
      Log.v 'MYAPPNAME', 'onCreate got called!'
      handle_pause do
        Log.v 'MYAPPNAME', 'onPause got called!'
      end
    end

下記のようなやり方を選択することもできる。やっていることは同じである。

    require 'ruboto.rb' #これ抜きではスクリプトは動かない
    $activity.handle_create do |bundle|
      Log.v 'MYAPPNAME', 'onCreate got called!'
    end
    $activity.handle_pause do
      Log.v 'MYAPPNAME', 'onPause got called!'
    end

それぞれのクラスは、他の呼び出しをネストすることができるメソッドを一つだけ持つことができる(最初の例のように、二回目の`$activit.`の記述が不要になる)。(?)*2
ActivityとServiceのためには`handle_create`、BroadcastReceiverのためには`handle_receive`がある。
基本的なルールは、これはクラスのライフサイクルの最初のメソッドに依存している。
しかし、このようなことは気にするべきではない、それはジェネレータがクラスを作る時に、メソッド呼び出しのサンプルスクリプトを生成しているからである。

引数は`handle_`メソッドに与えたブロックに渡される。それらはJavaのメソッドが受け取った引数と同じである。(?)*3

Activityは、色々と簡単以するためにいくつか特別なメソッドをもっている。それらはdemo scriptsあたりを見れば分かるだろう。
合わせてruboto.rb fileを読めば、そこには全て定義されている。

テスト

それぞれの生成されたクラスについて、テストスクリプトはtest/assets/scriptsに生成される。
例えば、RubotoSampleAppActivityを生成したとすれば、test/assets/scripts/ruboto_sample_app_activity_test.rb がテストスクリプトのサンプルである。

    activity Java::org.ruboto.sample_app.RubotoSampleAppActivity

    setup do |activity|
      start = Time.now
      loop do
        @text_view = activity.findViewById(42)
        break if @text_view || (Time.now - start > 60)
        sleep 1
      end
      assert @text_view
    end

    test('initial setup') do |activity|
      assert_equal "What hath Matz wrought?", @text_view.text
    end

    test('button changes text') do |activity|
      button = activity.findViewById(43)
      button.performClick
      assert_equal "What hath Matz wrought!", @text_view.text
    end

Antまたはrakeを使って、テストを実行できる。

$ jruby -S rake test

$ cd test ; ant run-tests

プロジェクトへの協力

協力したいって?それは素晴らしい! irc.freenode.net の #ruboto で話そう。そしてプロジェクトをforkしてコーディングを始めよう。

「でも、プロジェクトをforkして協力していくほど、十分理解できてないのだけど」
気にすることは無い。下記のようなやり方もある。

  • Rubotoを使い、どうしていけばよいか教えてほしい
  • 何かよい考えがあれば、それをwikiに書いてほしい
  • 考えがまとまったら、プロジェクトをforkすることをもう一度考えてほしい

プロジェクトへコードを提供するなら、既にあるテストを走らせて、あなたの変更分についてのテストも追加して欲しい。テストは下記のようにやって実行できる。

$ jruby -S rake test

ヘルプ

小ネタ

エミュレータ

Androidでの開発を多くこなしているなら、多くのエミュレータを`emulator -avd name_of_emulator`コマンドで扱っているだろう。これをaliasで短くして便利にできる。

例として, あなたの `~/.bashrc`, `~/.zshrc`など、適切な設定に,

alias eclair="emulator -avd eclair"
alias froyo="emulator -avd froyo"

追記する。

代替になるもの

Rubotoのパフォーマンスが問題であるなら、またはRubotoがまだできてないAndroidAPIへの全体的なアクセスが欲しいなら、MirahGarrett をチェックアウトするとよい。

Dubyとして知られる、Mirahは、Rubyに似た文法を持ち、Javaファイルにコンパイルされる言語である。これはランタイムへの大きな依存を避け、Javaで書いたのと同等の性能を出せることを意味する。これは性能が大きな問題となるモバイルデバイスによく適合するだろう。

Garrettは”Android上でのMirah評価用の遊び場”である。

Domo Arigato

以下の皆様に感謝:

*1:Save weird cases (like the "launching" methods that need to setup JRuby), to script the method onFooBar, you call the Ruby method handle_foo_bar on the Android object.

*2:Each class has only one method that you can nest other calls inside of [例 what is happening in that first example that removes the need for the second `$activity.`].

*3:The arguments passed to the block you give `handle_` methods are the same as the arguments that the java methods take. Consult the Android documentation.