Pull to refresh

Пишем приложение для Android на Ruby (Ruboto)

Ruby *
Sandbox
Tutorial
Появилась у меня как-то идея (или рас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
Tags:
Hubs:
Total votes 34: ↑30 and ↓4 +26
Views 53K
Comments Comments 12