- PVSM.RU - https://www.pvsm.ru -

О том как создать простое Scala SBT-приложение для Android

Доброго времени суток, друзья. Занимаясь разработкой инструментов для разработчиков, я столкнулся с вопросом о взаимодействии вышеупомянутых инструмента, языка программирования и платформы. Если первые две сущности просто созданы друг для друга (SBT — основной, наиболее часто используемый build tool для разработки на Scala), то их применимость для платформы Andriod не является чем-то само собой разумеющимся. И тем не менее, в огромной и постоянно развивающейся индустрии ПО складываются и такие ситуации, когда данный набор технологий будет рациональным выбором. Вопрос — когда данный выбор рационален, не является предметом данной статьи. А расскажу я именно том, как это делать.

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

Я исследовал применимость данного подхода для работы в Android Studio [1] и IntelliJ IDEA [2]. Для этой цели, значимой разницы в средах практически нет. Есть нюансы — с ними я вас ознакомлю по ходу статьи. А в общем, технологии которые мы будем использовать в равной степени интегрированы как в Студию, так и в Идею. Ведь первая базируется на той же платформе IntelliJ что и Идея. Поэтому, ваш выбор скорее должен основываться на специфике проекта.

Создание базового проекта

Первым инструментом в нашем деле станет Scala plugin [3], предназначенный для разработки на языке Scala в IntelliJ IDEA и Android Studio. Данный плагин так же предоставляет и SBT. Он не идёт в комплекте со средами разработки, поэтому нам потребуется его скачать из репозитория компании JetBrains.

О том как создать простое Scala SBT-приложение для Android - 1

Теперь мы можем создать базовый Scala SBT проект. И здесь имеет место первое различие между средами: Scala plugin предоставляет Мастер (Wizard) по созданию нового SBT проекта, доступный в Идее: [File → New → Project → Scala → SBT]. Но Android Studio не даёт нам возможности выйти на выбор Мастера и сразу запускает свой (на основе другой build tool — Gradle). Поэтому, в Студию SBT проект мы можем только импортировать. В принципе, это дело 20 секунд:

  1. В отдельной папке мы создаём файл build.sbt с содержимым name := "example".
  2. Консоль-командой sbt compile мы генерируем всё необходимое для базового проекта. (терминал запущен внутри Студии, чтобы был доступ к SBT)

    О том как создать простое Scala SBT-приложение для Android - 2

  3. В окне приветствия Android Studio делаем Import project и выбираем созданный нами build.sbt

В мастере импорта указываем Android SDK (на данный момент 25), снимаем чек-боксы доп. действий и импортируем. В Идее, при создании нового SBT проекта нет возможности выбрать Android SDK — выбираем Java SDK (на данный момент 1.8) и Scala 2.11.* версии. А Android SDK сам подставится впоследствии, после включения Android Framework. SBT проект готов.

Плагин для интеграции SBT и Android

Далее следует адаптировать проект для запуска на Android платформе.

  1. Первым делом добавляем в папку project файл plugins.sbt и прописываем в него добавление плагина [4]
    addSbtPlugin("org.scala-android" % "sbt-android" % "1.7.7")

  2. Модифицируем build.sbt, добавляя в билд-процедуру включение плагина sbt-android и таски для запуска
    name := "example"
    scalaVersion := "2.11.8"
    enablePlugins(AndroidApp)
    run <<= run in Android
    install <<= install in Android

  3. Добавляем в проект AndroidManifest.xml. В Студии можно положить этот файл в корень проекта. В Идее, т.к. визард уже создал структуру папок следует положить его на один уровень с Source root folder, т.е. в src/main. После создания файла, Идея/Студия подскажет нам включить в проект Android Framework. Принимаем предложение. Минимальное заполнение манифеста:
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example">
        <uses-sdk
            android:minSdkVersion="10"
            android:targetSdkVersion="25" />
        <application android:label="my_app">
            <activity
                android:name="MyActivity"
                android:label="MyActivityLabel">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    </manifest>

  4. Если мы работаем в Android Studio, создаём source root директорию scr (в Идее уже имеется src/main/scala). В ней создаём пакет com.example с файлом MyActivity.scala, с простой Activity
    package com.example
    import android.app.Activity
    
    class MyActivity extends Activity { }

  5. Открываем и включаем Андроид-эмулятор
  6. Рефрешим проект для активации всех новых настроек. Если вы работаете в IDEA, то при данном действии автоматически включается ProGuard (о котором поговорим позже). Сейчас его следует отключить в [Project Structure → Facets → Android → Proguard → Run proguard ...].
  7. И запускаем имеющуюся по-умолчанию Run configuration [Run -> Run ... -> MyActivity

Результат:

О том как создать простое Scala SBT-приложение для Android - 3

ProGuard Tool — адаптация Scala к платформе Android

На данный момент мы имеем работающим самое простое приложение. Если мы начнём его расширять, например хотя бы добавим в build.sbt библиотеку Scaloid [5] (о которой поговорим далее)

libraryDependencies += "org.scaloid" %% "scaloid" % "4.2"

то столкнёмся с проблемой. Android платформа имеет лимит на количество референсов — 64K. По причине особенностей Scala кода этот лимит достигается быстро. И уже просто включив данную библиотеку мы получим ошибку при запуске проекта:

Error:Android Pre Dex: [scaloid_2.11-4.2.jar] trouble writing output: Too many method references: 81694; max is 65536.

Стандартный подход к решению этой задачи:

  1. Вырезание из проекта неиспользуемого кода посредством инструмента ProGuard [6];
  2. Разделение исходников проекта на несколько .dex файлов, каждый из которых будет содержать приемлемое количество методов. Имя процедуре — MultiDexing [7].

Как правило, если задачу можно решить только первым шагом, то только его и используют. А MultiDexing идёт уже если первого недостаточно. В рамках данной задачи ProGuard'a будет достаточно.
Включается инструмент в опциях Android Facet: [Project Structure → Facets → Android → Proguard → Run proguard ...]. Отметим, что по-умолчанию уже указан текстовый файл с базовыми настройками: Студия включает файл из SDK .../Android/sdk/tools/proguard/proguard-android.txt, Идея включает и создаёт конфигурационный файл в корне проекта .../example/proguard-sbt.txt. Для успешного исполнения нашего проекта достаточно будет добавить в него три дополнительные опции:

-dontwarn scala.**
-dontwarn org.scaloid.**
-keep class com.example.**

При обработке байт-кода библиотек Scala и Scaloid, ProGuard будет сыпать Warnings, которые в нашем случае не влияют на результат, но блокируют дальнейший процесс запуска. Поэтому опцией -dontwarn мы их убираем. Так же, требуется указать чтоб ProGuard не вырезал наш рукописный код. Это обеспечивает опция -keep class.

При запуске я сталкивался двумя ошибками:

  1. Unsupported class version number [52.0] (maximum 51.0, Java 1.7). Причина её в том, что Android SDK основывается на Java 1.8, а ProGuard поддерживает максимум 1.7. Это решается обновлением [8] ProGuard до версии 5 и выше, прямо внутри Android SDK;
  2. Error:ProGuard: Cannot find file /Users/.../Caches/AndroidStudio2.3/compile-server/.../proguard.txt — это баг самой платформы, и решается он ручной или заскриптованой подкладкой файла proguard-android.txt из Android SDK в тот самый кэш, с последующим переименованием в proguard.txt. Не самый удобный способ, но всё таки, данная процедура используется не часто, особенно потому, что все эти опции пользователи, как правило, указывают в build.sbt файле.

Более проблем я не наблюдал, и успешно запустил проект с включённой в него библиотекой Scaloid, который при запуске урезался ProGuard'ом. По достижению определённой сложности проекта, есть смысл включить в него плагин для работы с ProGuard'ом. Таковых есть несколько, но поддерживаемый на данный момент я нашёл один: sbt-proguard [4]. По самому ProGuard'у так же есть мануал [9] на его сайте.

На этом, друзья, я завершу данную статью. Если она вызовет интерес, я подробнее изучу и опишу использование библиотек для разработки под Android на Scala, таких как Scaloid [5] или Macroid [10], и как, используя особенности языка Scala, решать распространённые задачи/проблемы на этой мобильной платформе. Во многом при изучении материала мне помогали ресурс [11] Android SBT плагина и просто информационный сайт [12], посвящённый разработке на Scala под Android. Благодарю вас за внимание, буду раз конструктивной критике, вопросам, комментариям и пожеланиям. Спасибо!

Автор: AntonYalyshev

Источник [13]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/android-development/254244

Ссылки в тексте:

[1] Android Studio: https://developer.android.com/studio/install.html

[2] IntelliJ IDEA: https://www.jetbrains.com/idea/

[3] Scala plugin: https://github.com/JetBrains/intellij-scala

[4] плагина: https://github.com/scala-android/sbt-android

[5] Scaloid: https://github.com/pocorall/scaloid

[6] ProGuard: https://developer.android.com/studio/build/shrink-code.html

[7] MultiDexing: https://developer.android.com/studio/build/multidex.html

[8] обновлением: https://sourceforge.net/projects/proguard/files/proguard/

[9] мануал: https://www.guardsquare.com/en/proguard/manual/introduction

[10] Macroid: https://github.com/47deg/macroid

[11] ресурс: http://scala-android.org/

[12] сайт: http://scala-on-android.taig.io/

[13] Источник: https://habrahabr.ru/post/327782/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox