Ускоряем приложение Android с помощью Golang

в 12:46, , рубрики: android, Go, golang, jni, Разработка под android

image

Разработка мобильных приложений — это всегда компромисс между тем, что хочется сделать и тем, что позволяет сделать платформа устройства. В этой статье рассказывается о том, как увеличить возможности приложения Android с помощью Golang.

Здесь вы не найдете утечки секретного api android. Используемые механизмы — это стандартные (или почти стандартные) инструменты android и golang, описание которых есть на официальных сайтах и профильных форумах. Но в виде единого плана действий, да еще и на русском языке — такое публикуется впервые и эксклюзивно для Хабра.

Предыстория

По многочисленным просьбам пользователей одного из приложений были разработаны предсказания текста. Предсказания обслуживал алгоритм radix tree, реализованный в отдельной android-библиотеке. Алгоритм показывал хорошую производительность наряду с экономным потреблением ресурсов — выдавал результат за десятки миллисекунд при потреблении 1,5 Мб памяти. Вполне рабочие показатели. Но так было только при изолированном тестировании библиотеки на JVM.

Проблемы начались при подключении библиотеки к приложению. На android алгоритм предсказаний стал тормозить, выдача результатов затянулась до 7-ми секунд. Ничего себе! Да за 7 секунд можно вручную набрать слово, стереть и набрать его правильно. Такие предсказания никуда не годились.

Проведенный анализ не выявил проблем кода. Алгоритм работал безупречно, памяти потреблял в строго отведенных количествах, не отвлекался на посторонние процессы, все асинхронно, аппаратных ресурсов предостаточно. Вывод напрашивался только один — виртуальная машина android dalvik имеет производительность, отличную от JVM, и в рамках dalvik данный код обречен на тормоза.

Тогда и было решено, что алгоритм предсказаний нужно выносить из dalvik. Для этого существует JNI — Java Native Interface. Механизм, позволяющий вызывать из java методы библиотек, написанных на C/C++. И обратно, — из библиотеки C/C++ вызывать методы java.

Решение

Для создания нативной библиотеки был выбран язык Go. Просто потому что имеется опыт работы с ним, в отличие от C/C++. Golang восхитителен, но этот путь имеет свои трудности, поскольку мы получаем дополнительный уровень сложности. Для чистого C/C++ достаточно использовать NDK и следовать инструкциям, описанным на сайте android developers. Для Golang придется изучить еще и компиляцию golang под android, начать можно здесь.

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

План

Среда разработки android:

  • ОС: Windows 7.
  • IDE: Eclipse with ADT. Но этот план подойдет и для Android Studio.

Среда разработки golang:

  • ОС: Для компиляции golang под android используется linux. Я использую Ubuntu 14.04, запущенную на VirtualBox.
  • Android SDK.
    — Cкачать архив с официального сайта android
    — Распаковать, допустим, в

    $HOME/android/android-sdk-linux
  • Java JDK.
    $ apt-get default-jdk
  • Go 1.5.
    Текущая версия релиза Go — 1.4. Но у меня не получилось скомпилировать библиотеку с его помощью, где-то ошибся при сборке toolchain. Поэтому использовал пакет gomobile из девелоперской версии Go 1.5, релиз которой еще только планируется. Пока нет релиза, установка Go 1.5 описана здесь:
    — Установить Go 1.4 golang.org/doc/install
    — Клонировать текущий репозиторий golang:

    $ git clone https://go.googlesource.com/go $HOME/go

    — Скомпилировать текущую версию Go с помощью Go 1.4

    $ export GOROOT_BOOTSTRAP=/usr/local/go
    $ cd $HOME/go/src && ./make.bash
    $ export PATH=$PATH:$HOME/go/bin
  • Установить и инициализировать пакет gomobile.
    $ go get golang.org/x/mobile/cmd/gomobile
    $ gomobile init

    Инициализация пакета занимает приличное время

Разработка библиотеки golang.

  • Разрабатывается обычный golang package, никаких дополнительных рекомендаций. Экспортные методы будут доступны из android.

Компиляция библиотеки golang в библиотеку android *.aar.

  • Использовать команду gomobile bind с указанием пути до android sdk
    $ cd <golang project folder>
    $ ANDROID_HOME=$HOME/android/android-sdk-linux gomobile bind

Подключение библиотеки *.aar к приложению:
Прежде всего, передать библиотеку *.aar на машину разработки android. Далее в зависимости от IDE.

для Eclipse:

  • Распаковать библиотеку *.aar во временный каталог
  • В Eclipse создать новый проект из существующего кода, указав временный каталог из п.1
  • Отметить, что данный проект является библиотекой android
  • Подключить каталог jni и файл classes.jar в Build Path нового проекта
  • Подключить новый проект как библиотеку в проект приложения
  • Скопировать содержимое папки jni в папку libs проекта приложения.
  • Скопировать содержимое proguard.txt библиотеки в proguard.txt проекта приложения (защита классов go* от обфускации)
  • При последующих обновлениях библиотеки *.aar достаточно обновить файлы в папках jni, libs и файл classes.jar

для Android Studio:

  • Подключить готовую библиотеку *.aar к проекту, используя стандартные средства Android Studio. К сожалению, у меня нет такого опыта, поэтому оставляю это в качестве домашнего задания.

Вызов методов нативной библиотеки из android.

  • Перед использованием нативной библиотеки в приложении, нужно выполнить её инициализацию. Подходящее для этого место — в методе onCreate:
    public class MyActivity extends Activity {
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_my);
           
            Go.init(getContext());
        }
    } 
    
  • Методы библиотеки golang доступны через package, одноименные с теми, что вы определили в golang. Например:
    golang:

    package radix
    …
    func Suggest(params string) string {
    	…
    }
    

    java:

        suggestions = Radix.Suggest(params);
    

Результат

После переноса алгоритма в нативную библиотеку, предсказания стали работать даже быстрее, чем в JVM — результат отдается менее чем за 10 мс. Также уменьшилось количество garbage collection, потому что часть ресурсов была передана на сторону нативного кода.

Эффект от внедрения JNI превзошел ожидания. С такими показателями клавиатура и отправилась в релиз.

Заключение

Ускорить приложение android с помощью golang — это вовсе не теория, а реальная возможность, которая уже используется в приложениях маркета.

Конечно, это усложняет разработку приложений, зоопарк инструментов удваивается. Но это даёт возможность реализовать интересные решения.

С выходом Go 1.5 ожидается, что интеграция android-golang станет еще доступнее, за счет инструментария gomobile, который сокращает весь процесс до 2-х команд.

Автор: ReshetnikovAF

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js