В этой статье я расскажу как создать библиотеку, которая использует другие библиотеки и при этом уместить всё в одном jar.
Допустим мы пишем библиотеку, она использует другие библиотеки и, в частности, для примера, support library. Если бы мы использовали maven, то в pom файле просто прописали зависимости и не парились. Но что если нашу библиотеку будут использовать люди, которые не пользуются системами сборок или пользуются ant' ом?
Мы можем положить зависимости рядом с нашим jar. Но тогда неизбежны конфликты библиотек разных версий, например, если мы используем одну версию support library, а в самом приложении другая. Тогда придется руками одну из них удалять.
Можно пойти другим путем, вспомним что jar это обычный zip файл. Мы распакуем все зависимости, получим байт-код в виде .class файлов, далее компилируем код нашей библиотеки, кладем все .class файлы в одно место и собираем из них jar. Но если в приложении используются те же библиотеки что и у нас, то получим ошибку что в проекте два одинаковых класса.
Для решения этой проблемы воспользуемся утилитой jarjar. Она переименовывает все классы в jar файле. На примере support library — все классы находятся в пакете android.support.v4
Пример использования:
java -jar jarjar.jar process <rulesFile> <inJar> <outJar>
rulesFile - файл с правилами переименования
inJar, outJar - тут все понятно
Создадим правило для переименования классов android.support.v4.* в inner.android.support.v4.*
rule android.support.v4.** inner.android.support.v4.@1
и сохраним в файл rules.txt
Запускаем
java -jar jarjar.jar rules.txt android-support-v4.jar android-support-v4-renamed.jar
В итоге получили jar'ку с переименованными классами. Далее мы распаковываем все наши зависимости с переименованными классами и компилируем. Получаем библиотеку, которая содержит весь код нужный для выполнения.
Наша библиотека содержит код всех зависимостей, которые могут весить немало. Чтобы уменьшить размер применим proguard для удаления неиспользуемых классов и методов.
И в заключение небольшой скрипт на gradle который всё это делает
apply plugin: 'java'
defaultTasks 'proguard'
task unpackJars(dependsOn: compileJava) {
//распаковываем классы из библиотек
file('libs').listFiles().each { File file ->
if (file.name.endsWith('.jar')) {
copy {
from(zipTree(file.path))
into('build/classes/main')
}
}
}
//собираем jar'ку
tasks.jar.execute()
}
task proguard(type: proguard.gradle.ProGuardTask, dependsOn: unpackJars) {
injars 'build/libs/library.jar'
outjars 'build/libs/proguard_library.jar'
libraryjars '/Applications/my/Android Studio.app/sdk/platforms/android-10/android.jar'
//укажем что классы нашей библиотеки удалять не нужно
keep 'class com.CasualSoftware.classloader.library.*'
}
dependencies {
compile 'com.google.android:android:2.2.1'
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Вои и всё, после выполнения скрипта мы получим proguard_library.jar, который можно добавлять к приложению и использовать.
В моём случае библиотека использует support library и dropbox sdk, и весит 522 байта.
Этим же способом можно уменьшать размер вашего apk, все зависимости можно подключать не как jar файлы, а распаковывать в .classes и применять proguard, тогда он удалит неиспользуемые классы из библиотек. Так можно подключать к проекту тяжелые фреймворки не боясь увеличения размера apk
Автор: anton9088