まあだいたい Rubotoを使ってRubyでAndroidアプリをかく を追体験しただけなんですが。
まず動機ですが、別にRubyでAndroid appを書きたいわけではないです。やりたいのことは以下のふたつ。
- Ruby REPLからAndroid appを操作することと
- Android appのテストをRubyで書くこと
特にテスト。文字列操作とかリスト操作はRubyのほうが得意なので、得意なことを得意な言語でやれば効率いいんじゃないかと思うわけです。
ruboto setupがコケる
homebrewでandorid sdkをインストールしている場合、ruboto setupがコケます。
$ ruboto setup --target android-19
Java runtime : Found
Java Compiler : Found
Apache ANT : Found
Android Package Installer: Found
Android Emulator : Found
Android SDK Command adb : Found
Android SDK Command dx : Found
Platform SDK android-10 : Not found
!!! Ruboto setup is NOT OK !!!
Android platform SDK for android-10 not found.
Would you like to download and install it? (Y/n):
$ANDROID_HOME/tools
と$ANDROID_HOME/platform-tools
をPATHに追加するといけました。
export PATH="$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH"
Hello, woldまで
$ ruboto gen app --package com.example.rubotoexample
$ cd rubotoexample
$ rake install
$ rake start # start the app
これでとりあえずアプリは立ちあがってRUBOTOのロゴがでる。
アプリを書き換える
activity classはこんなの。けっこうゴツイ。
require 'ruboto/base'
require 'ruboto/package'
#######################################################
#
# ruboto/activity.rb
#
# Basic activity set up.
#
#######################################################
#
# Context
#
module Ruboto
module Context
def start_ruboto_dialog(class_name = nil, options = nil, &block)
if options.nil?
if class_name.is_a?(Hash)
options = class_name
class_name = nil
else
options = {}
end
end
unless options.key?(:java_class)
java_import 'org.ruboto.RubotoDialog'
options[:java_class] = RubotoDialog
end
options[:theme] = android.R.style::Theme_Dialog unless options.key?(:theme)
start_ruboto_activity(class_name, options, &block)
end
def start_ruboto_activity(class_name = nil, options = nil, &block)
if options.nil?
if class_name.is_a?(Hash)
options = class_name
class_name = nil
else
options = {}
end
end
# FIXME(uwe): Deprecated. Remove june 2014.
if options[:class_name]
puts "\nDEPRECATON: The ':class_name' option is deprecated. Put the class name in the first argument instead."
end
java_class = options.delete(:java_class) || RubotoActivity
theme = options.delete(:theme)
# FIXME(uwe): Remove the use of the :class_name option in june 2014
class_name_option = options.delete(:class_name)
class_name ||= class_name_option
# EMXIF
script_name = options.delete(:script)
extras = options.delete(:extras)
raise "Unknown options: #{options}" unless options.empty?
if class_name.nil? && block_given?
class_name =
"#{java_class.name.split('::').last}_#{source_descriptor(block)[0].split('/').last.gsub(/[.-]+/, '_')}_#{source_descriptor(block)[1]}"
end
class_name = class_name.to_s
if Object.const_defined?(class_name)
Object.const_get(class_name).class_eval(&block) if block_given?
else
Object.const_set(class_name, Class.new(&block))
end
i = android.content.Intent.new
i.setClass self, java_class.java_class
i.putExtra(Ruboto::THEME_KEY, theme) if theme
i.putExtra(Ruboto::CLASS_NAME_KEY, class_name) if class_name
i.putExtra(Ruboto::SCRIPT_NAME_KEY, script_name) if script_name
extras.each { |k, v| i.putExtra(k.to_s, v) } if extras
startActivity i
self
end
private
def source_descriptor(proc)
if md = /^#<Proc:0x[0-9A-Fa-f]+@(.+):(\d+)(?: \(lambda\))?>$/.match(proc.inspect)
filename, line = md.captures
return filename, line.to_i
end
end
end
end
java_import 'android.content.Context'
Context.class_eval do
include Ruboto::Context
end
#
# Basic Activity Setup
#
module Ruboto
module Activity
def method_missing(method, *args, &block)
return @ruboto_java_instance.send(method, *args, &block) if @ruboto_java_instance && @ruboto_java_instance.respond_to?(method)
super
end
end
end
def ruboto_configure_activity(klass)
klass.class_eval do
include Ruboto::Activity
end
end
java_import 'android.app.Activity'
java_import 'org.ruboto.RubotoActivity'
ruboto_configure_activity(RubotoActivity)
続く!