Пользователь
0,0
рейтинг
8 января 2013 в 18:01

Разработка → Пишем приложение для Android на Ruby (Ruboto) из песочницы tutorial

Ruby*
Появилась у меня как-то идея (или расcчётка по мобильным платформам) написать приложения под android на своём любимом ruby. И тут я вспомнил про проект который несколько раз упоминался в RubyNoName подкасте, собственно речь пойдёт о Ruboto.


Ну что ж, приступим. Для программирования нам понадобится:
  1. JDK
  2. Android SDK
  3. JRuby
  4. Gem Ruboto

Расписывать установку я не стану, лучше приведу ссылку на достаточно подробную документацию
После того, как всё установили, генерируем основу нашего приложения.
ruboto gen app --package ru.nitrodev.demo_app

Переходим в директорию demo_app и любуемся заботливо подготовленной структурой приложения. В папке src уже лежит наше первое активити, собственно к нему мы и перейдём.
В качестве примера разберу такие базовые вещи как:
  1. Создание интерфейса
  2. Воспроизведение аудио с помощью MediaPlayer
  3. Создание активити
  4. Определение координат касания экрана
  5. Работа с Intent (открытие страницы, набор номера)
  6. Создание меню
Пойдём по порядку.

Создание интерфейса


В любом приложении нам понадобится интерфейс, мы можем использовать стандартный способ создания интерфейса с помощью XML ресурса, но тогда мы теряем всю гибкость ruby. Поэтому интерфейс будем описывать в коде, для этого мы можем вызывать Android API или использовать ruboto/widget.rb который является обвёрткой над API и предоставляет простой DSL для создания интерфейса.
Рассмотрим сначала первый способ на примере создания LinearLayout содержащего одно текстовое поле и 4 кнопки.
Первым делом импортируем нужные компоненты интерфейса
java_import "android.widget.Button"
java_import "android.widget.TextView"
java_import "android.widget.LinearLayout"

Описываем сам интерфейс
 ll = LinearLayout.new(@ruboto_java_instance)
  ll.orientation = LinearLayout::VERTICAL

  tv = TextView.new(@ruboto_java_instance)
  tv.text = "Прощай Java"
  ll.add_view tv #Добавляем наще TextView в LinearLayout
  params = tv.get_layout_params
  params.width = ViewGroup::LayoutParams::MATCH_PARENT

  btn1 = Button.new(@ruboto_java_instance)
  btn1.text = "Play"
  btn1.on_click_listener = proc{ Play } 
  ll.add_view btn1
  params = search_b.get_layout_params
  params.width = ViewGroup::LayoutParams::MATCH_PARENT

  btn2 = Button.new(@ruboto_java_instance)
  btn2.text = "Pause"
  btn2.on_click_listener = proc{ Pause } 
  ll.add_view btn2
  params = search_b.get_layout_params
  params.width = ViewGroup::LayoutParams::MATCH_PARENT

  btn3 = Button.new(@ruboto_java_instance)
  btn3.text = "Второй экран"
  btn3.on_click_listener = proc{ twoActivity } 
  ll.add_view btn3
  params = search_b.get_layout_params
  params.width = ViewGroup::LayoutParams::MATCH_PARENT

  btn4 = Button.new(@ruboto_java_instance)
  btn4.text = "Третий экран"
  btn4.on_click_listener = proc{ threeActivity } 
  ll.add_view btn4
  params = search_b.get_layout_params
  params.width = ViewGroup::LayoutParams::MATCH_PARENT

  setContentView ll

Вы должны признать, что данный код является таким же громоздким как java и вряд ли кому-то понравится в ruby сообществе. Более элегантным будет использовать DSL Ruboto. Рассмотрим аналогичный код, использующий путь Ruboto.

ruboto_import_widgets :Button, :LinearLayout, :TextView
self.content_view =
    linear_layout :orientation => :vertical do
      text_view :text => 'Только Ruby - только хардкор', :width => :match_parent
      button :text => 'Play', :width => :match_parent, :on_click_listener => proc { play }
      button :text => 'Pause', :width => :match_parent, :on_click_listener => proc { pause }
      button :text => 'Второй эран', :width => :match_parent, :on_click_listener => proc { twoActivity }
      button :text => 'Третий эран', :width => :match_parent, :on_click_listener => proc { threeActivity }
    end

Как видно, количество кода сократилось в 4-5 раз.
Результат этого кода


Воспроизведение аудио с помощью MediaPlayer


Для воспроизведения звука импортируем MediaPlayer и AudioManager
java_import "android.media.MediaPlayer"
java_import "android.media.AudioManager"
java_import "android.net.Uri" 

Затем получаем uri файла и создаём MediaPlayer

java_file = java.io.File.new("/mnt/sdcard/naive.mp3")
    uri = Uri.fromFile(java_file)
    @player = MediaPlayer.create(self, uri);

Работать с нашим плеером можем стандартными функциями
@player.start
@player.pause

Создание активити


Остальные пункты нашего манула создадим в отдельных активити.
Основным способом создания RubotoActivity является использование start_ruboto_activity.
start_ruboto_activity — это эквивалент Android startActivity в Ruboto. Он имеет два обязательных параметр: строка, содержащая глобальную ссылку на создаваемую активити и блок, который будет выполняться один раз при создании активити.
Создадим вторую активити

start_ruboto_activity("$activity_two") do
  def on_create(bundle)
    super
    setTitle 'Вторая активити'
  end
end

Определение координат касания экрана


Отслеживание касания осуществляется с помощью функции on_touch_event. Данный метод является эквивалентом андроид-метода onTouchEvent
Отслеживаем касание одним пальцем
def on_touch_event(event)
    index = event.find_pointer_index(0)
     x = event.getX(index)
    y = event.getY(index)
    toast "Position: #{x}, #{y}"
  true
end

Работа с Intent


Для работы с Intent импортируем соответствующие Android API
java_import "android.content.Intent"

Дальнейшая работа с Intent производится аналогично java

intent = Intent.new(Intent::ACTION_CALL)
          intent.setData(Uri.parse("tel:5551234"))
          startActivity(intent)

intent = Intent.new(Intent::ACTION_VIEW)
          intent.setData(Uri.parse("http://ruboto.org/"))
          startActivity(intent)

Добавим соответствующие разрешения в AndroidManifest
<uses-permission android:name="android.permission.CALL_PHONE" />

Создание меню


Для работы с меню используется стандартный коллбек on_create_options_menu. Тут всё просто: создаём пункты меню и вешаем на них слушателя, при клике в toast будет выводиться сообщение с названием пункта меню.
def on_create_options_menu(menu)
  m1 = menu.add('Action 1')
  m1.set_on_menu_item_click_listener do |menu_item|
    @text_view.text = menu_item_title
    toast menu_item.title
    true 
  end

  m2 = menu.add('Action 2')
  m2.set_on_menu_item_click_listener do |menu_item|
    @text_view.text = menu_item.title
    toast menu_item.title
    true 
  end
  true
end


Вот собственно и всё.
Весь данный код можно посмотреть на github
Ссылки для более глубокого погружения в Ruboto:
Wiki: github.com/ruboto/ruboto/wiki
Readme: github.com/ruboto/ruboto/blob/master/README.md
Отличная презентация с примерами: jay.mcgavren.com/files/presentations/ruboto
Пётр Степченко @Nitrino
карма
10,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (12)

  • +2
    А как по скорости по сравнению с нативными приложениями и каким ни будь Phonegap?
    • +3
      Так как используется jruby, то думаю получается нативное приложение.
      • 0
        Если ситуация обстоит такая же как с IronPython и Jython, то далеко не нативное. Быстрее разбора и интерпретации, но все же.
        • 0
          Дела у JRuby обстоят очень даже хорошо. Но к нативности я вроде отношение не имеет. В том же Rubymotion все так же быстро как и в нативном obj-c. Но это отдельная история.
    • 0
      Ruboto на данный момент медлителен, так что части для которых критична скорость лучше писать на java. Вот комментарий разработчика по этому поводу groups.google.com/d/msg/ruboto/zLlO_qwcyQU/2mXkOGXsVxEJ
      • 0
        Спасибо =) Тогда уж лучше Phonegap. Хотя попробовать надо в любом случае.
        • 0
          бьюсь об стол головой: фонегап. для тех частей, для которых критична скорость. фонегап. для тех частей, для которых критична скорость. фонегап. для тех частей, для которых критична скорость. ФОНЕГАП! УСКОРЬ СВОЕ ПРИЛОЖЕНИЕ!
  • +1
    Так же в свое время игрался с Ruboto, забавная штука, как и rubymotion. Только все равно руби-разработчику для освоения платформы нужно знать SDK и основы Java. Так что в паре с меньше производительностью серебрянной пули не получается, разве что написать какой-нибудь DSL для быстрой генерации активити или что-то в этом роде.
  • 0
    для запуска приложения, написанного на рубото, нужен какой-либо сторонний софт (аля библиотеки/нтерпретатора/итд)? или все запуститься через нативный андроид?
    • 0
      Для запуска нужен или Ruboto core (предлагается скачать при первом запуске приложения), или нужно включать jRuby в своё приложение с помощью ключа --with-jruby
  • 0
    Я правильно понимаю, чтобы запустить написанное требуется рутованное устройство?

    Указано в README…
    • 0
      Рут доступ нужен только для команды rake update_scripts которая позволяет обновлять ruby код без перекомпилирования java файлов. Это, так сказать, дополнительная фишка, позволяющая при разработке не переустанавливать каждый раз приложение на девайс. Для запуска приложения обычными способами рут доступ не нужен.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.