Доброго времени суток, друзья. Занимаясь разработкой инструментов для разработчиков, я столкнулся с вопросом о взаимодействии вышеупомянутых инструмента, языка программирования и платформы. Если первые две сущности просто созданы друг для друга (SBT — основной, наиболее часто используемый build tool для разработки на Scala), то их применимость для платформы Andriod не является чем-то само собой разумеющимся. И тем не менее, в огромной и постоянно развивающейся индустрии ПО складываются и такие ситуации, когда данный набор технологий будет рациональным выбором. Вопрос — когда данный выбор рационален, не является предметом данной статьи. А расскажу я именно том, как это делать.
Я исследовал применимость данного подхода для работы в Android Studio и IntelliJ IDEA. Для этой цели, значимой разницы в средах практически нет. Есть нюансы — с ними я вас ознакомлю по ходу статьи. А в общем, технологии которые мы будем использовать в равной степени интегрированы как в Студию, так и в Идею. Ведь первая базируется на той же платформе IntelliJ что и Идея. Поэтому, ваш выбор скорее должен основываться на специфике проекта.
Первым инструментом в нашем деле станет Scala plugin, предназначенный для разработки на языке Scala в IntelliJ IDEA и Android Studio. Данный плагин так же предоставляет и SBT. Он не идёт в комплекте со средами разработки, поэтому нам потребуется его скачать из репозитория компании JetBrains.
Теперь мы можем создать базовый Scala SBT проект. И здесь имеет место первое различие между средами: Scala plugin предоставляет Мастер (Wizard) по созданию нового SBT проекта, доступный в Идее:
В мастере импорта указываем Android SDK (на данный момент 25), снимаем чек-боксы доп. действий и импортируем. В Идее, при создании нового SBT проекта нет возможности выбрать Android SDK — выбираем Java SDK (на данный момент 1.8) и Scala 2.11.* версии. А Android SDK сам подставится впоследствии, после включения Android Framework. SBT проект готов.
Далее следует адаптировать проект для запуска на Android платформе.
Результат:
На данный момент мы имеем работающим самое простое приложение. Если мы начнём его расширять, например хотя бы добавим в
то столкнёмся с проблемой. Android платформа имеет лимит на количество референсов — 64K. По причине особенностей Scala кода этот лимит достигается быстро. И уже просто включив данную библиотеку мы получим ошибку при запуске проекта:
Стандартный подход к решению этой задачи:
Как правило, если задачу можно решить только первым шагом, то только его и используют. А MultiDexing идёт уже если первого недостаточно. В рамках данной задачи ProGuard'a будет достаточно.
Включается инструмент в опциях Android Facet:
При обработке байт-кода библиотек Scala и Scaloid, ProGuard будет сыпать Warnings, которые в нашем случае не влияют на результат, но блокируют дальнейший процесс запуска. Поэтому опцией
При запуске я сталкивался двумя ошибками:
Более проблем я не наблюдал, и успешно запустил проект с включённой в него библиотекой Scaloid, который при запуске урезался ProGuard'ом. По достижению определённой сложности проекта, есть смысл включить в него плагин для работы с ProGuard'ом. Таковых есть несколько, но поддерживаемый на данный момент я нашёл один: sbt-proguard. По самому ProGuard'у так же есть мануал на его сайте.
На этом, друзья, я завершу данную статью. Если она вызовет интерес, я подробнее изучу и опишу использование библиотек для разработки под Android на Scala, таких как Scaloid или Macroid, и как, используя особенности языка Scala, решать распространённые задачи/проблемы на этой мобильной платформе. Во многом при изучении материала мне помогали ресурс Android SBT плагина и просто информационный сайт, посвящённый разработке на Scala под Android. Благодарю вас за внимание, буду раз конструктивной критике, вопросам, комментариям и пожеланиям. Спасибо!
Среда разработки
Я исследовал применимость данного подхода для работы в Android Studio и IntelliJ IDEA. Для этой цели, значимой разницы в средах практически нет. Есть нюансы — с ними я вас ознакомлю по ходу статьи. А в общем, технологии которые мы будем использовать в равной степени интегрированы как в Студию, так и в Идею. Ведь первая базируется на той же платформе IntelliJ что и Идея. Поэтому, ваш выбор скорее должен основываться на специфике проекта.
Создание базового проекта
Первым инструментом в нашем деле станет Scala plugin, предназначенный для разработки на языке Scala в IntelliJ IDEA и Android Studio. Данный плагин так же предоставляет и SBT. Он не идёт в комплекте со средами разработки, поэтому нам потребуется его скачать из репозитория компании JetBrains.
Теперь мы можем создать базовый Scala SBT проект. И здесь имеет место первое различие между средами: Scala plugin предоставляет Мастер (Wizard) по созданию нового SBT проекта, доступный в Идее:
[File > New > Project > Scala > SBT]
. Но Android Studio не даёт нам возможности выйти на выбор Мастера и сразу запускает свой (на основе другой build tool — Gradle). Поэтому, в Студию SBT проект мы можем только импортировать. В принципе, это дело 20 секунд: - В отдельной папке мы создаём файл
build.sbt
с содержимымname := "example"
.
- Консоль-командой
sbt compile
мы генерируем всё необходимое для базового проекта. (терминал запущен внутри Студии, чтобы был доступ к SBT)
- В окне приветствия 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 платформе.
- Первым делом добавляем в папку
project
файлplugins.sbt
и прописываем в него добавление плагина
addSbtPlugin("org.scala-android" % "sbt-android" % "1.7.7")
- Модифицируем
build.sbt
, добавляя в билд-процедуру включение плагина sbt-android и таски для запуска
name := "example" scalaVersion := "2.11.8" enablePlugins(AndroidApp) run <<= run in Android install <<= install in Android
- Добавляем в проект 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>
- Если мы работаем в Android Studio, создаём source root директорию scr (в Идее уже имеется
src/main/scala
). В ней создаём пакет com.example с файломMyActivity.scala
, с простой Activity
package com.example import android.app.Activity class MyActivity extends Activity { }
- Открываем и включаем Андроид-эмулятор
- Рефрешим проект для активации всех новых настроек. Если вы работаете в IDEA, то при данном действии автоматически включается ProGuard (о котором поговорим позже). Сейчас его следует отключить в
[Project Structure > Facets > Android > Proguard > Run proguard ...]
. - И запускаем имеющуюся по-умолчанию Run configuration
[Run -> Run ... -> MyActivity
Результат:
ProGuard Tool — адаптация Scala к платформе Android
На данный момент мы имеем работающим самое простое приложение. Если мы начнём его расширять, например хотя бы добавим в
build.sbt
библиотеку Scaloid (о которой поговорим далее)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.
Стандартный подход к решению этой задачи:
- Вырезание из проекта неиспользуемого кода посредством инструмента ProGuard;
- Разделение исходников проекта на несколько .dex файлов, каждый из которых будет содержать приемлемое количество методов. Имя процедуре — MultiDexing.
Как правило, если задачу можно решить только первым шагом, то только его и используют. А 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
. При запуске я сталкивался двумя ошибками:
Unsupported class version number [52.0] (maximum 51.0, Java 1.7)
. Причина её в том, что Android SDK основывается на Java 1.8, а ProGuard поддерживает максимум 1.7. Это решается обновлением ProGuard до версии 5 и выше, прямо внутри Android SDK;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. По самому ProGuard'у так же есть мануал на его сайте.
На этом, друзья, я завершу данную статью. Если она вызовет интерес, я подробнее изучу и опишу использование библиотек для разработки под Android на Scala, таких как Scaloid или Macroid, и как, используя особенности языка Scala, решать распространённые задачи/проблемы на этой мобильной платформе. Во многом при изучении материала мне помогали ресурс Android SBT плагина и просто информационный сайт, посвящённый разработке на Scala под Android. Благодарю вас за внимание, буду раз конструктивной критике, вопросам, комментариям и пожеланиям. Спасибо!
Поделиться с друзьями
Комментарии (6)
kozhevnikovv
02.05.2017 22:28-3<offtop> Картинка про троллейбус из буханки хлеба. </offtop>
Сколько весит hello world apk с добавленным рантаймом?
Насколько велики преимущества по сравнению с java/kotlin?lgorSL
02.05.2017 23:27Я не автор статьи и собираю плагином на gradle, apk приложения уровня "Hello world" без ужимания прогуардом весит около 3.3 мб.
jreznot
03.05.2017 20:09-1Вы читаете мой комментарий или сразу отвечаете? Я спросил только про Build Tool. SBT один из самых противоречивых инструментов сборки, который даже в родном Scala сообществе воспринимается как нечто не в меру странное. Чуть ли не половина разработчиков на Scala используют не его, а Gradle.
ymn
04.05.2017 09:56+1Чуть ли не половина разработчиков на Scala используют не его, а Gradle
Пруф? Если судить по трендам гитхаба, то из top10 софтин на скале 7 используют sbt и только 1 gradle.
Googolplex
03.05.2017 00:13+3Не нужно советовать вот это:
run <<= run in Android install <<= install in Android
Метод
<<=
подепрекейчен и в sbt 1.0 будет выкинут. Вместо этого следует использовать.value
или.evaluated
:
run := (run in Android).evaluated // т.к. run это InputTask install := (install in Android).value
Кроме того, особого смысла в этих переназначениях, имхо, вообще нет — эти таски по умолчанию будут доступны как
android:run
иandroid:install
.
jreznot
А почему бы и не Gradle? Зачем вам там SBT?