Maven: использование библиотек Java 8 в приложениях, оснащенных retrolambda-maven-plugin и DEX-ed с android-maven-plugin
Я написал небольшой набор минибиблиотек для внутреннего пользования. Этот набор построен с использованием Maven. Библиотеки предназначены для "обычной" Java, GWT и Android. Некоторые из них написаны на Java 8, потому что я не собирался запускать их на GWT или Android, поэтому другие библиотеки написаны на старой Java 6 для поддержки этих двух. У меня есть план полной миграции моих библиотек на Java 8 (с точки зрения языковых возможностей), и мне удалось запустить переписанные библиотеки Java 8 на еще не выпущенном GWT 2.8.0. Однако я не могу переписать библиотеки Java 8 для компиляции приложений для Android. Проблема в том, что Ретроламбда (retrolambda-maven-plugin
плагин), кажется, может обрабатывать только текущие классы модулей Maven и полностью игнорирует классы зависимостей. Таким образом android-maven-plugin
разбивает целевую сборку приложения на:
[INFO] UNEXPECTED TOP-LEVEL EXCEPTION:
[INFO] com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
[INFO] at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
[INFO] at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
[INFO] at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
[INFO] at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
[INFO] at com.android.dx.command.dexer.Main.processClass(Main.java:665)
[INFO] at com.android.dx.command.dexer.Main.processFileBytes(Main.java:634)
[INFO] at com.android.dx.command.dexer.Main.access$600(Main.java:78)
[INFO] at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:572)
[INFO] at com.android.dx.cf.direct.ClassPathOpener.processArchive(ClassPathOpener.java:284)
[INFO] at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:166)
[INFO] at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
[INFO] at com.android.dx.command.dexer.Main.processOne(Main.java:596)
[INFO] at com.android.dx.command.dexer.Main.processAllFiles(Main.java:498)
[INFO] at com.android.dx.command.dexer.Main.runMonoDex(Main.java:264)
[INFO] at com.android.dx.command.dexer.Main.run(Main.java:230)
[INFO] at com.android.dx.command.dexer.Main.main(Main.java:199)
[INFO] at com.android.dx.command.Main.main(Main.java:103)
[INFO] ...while parsing foo/bar/FooBar.class
retrolambda-maven-plugin
настроен следующим образом:
<plugin>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>retrolambda-maven-plugin</artifactId>
<version>2.0.2</version>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>process-main</goal>
<goal>process-test</goal>
</goals>
</execution>
</executions>
<configuration>
<target>1.6</target>
<defaultMethods>true</defaultMethods>
</configuration>
</plugin>
Можно ли настроить плагин Retrolambda для обработки библиотечных классов, а также всех зависимостей? Или, может быть, я просто мог бы использовать другой инструмент для обработки байт-кода?
ОБНОВЛЕНИЕ № 1
Я думаю, что я ошибаюсь из-за провала Retrolambda. Покопавшись в этом немного больше, я понял, что android-maven-plugin
можно обвинить в этом, потому что он выбирает неинструментированные файлы JAR непосредственно из репозитория Maven, а не из target
каталог. Включение подробного ведения журнала обнаружило эту команду псевдокода, вызываемую android-maven-plugin
:
$JAVA_HOME/jre/bin/java
-Xmx1024M
-jar "$ANDROID_HOME/sdk/build-tools/android-4.4/lib/dx.jar"
--dex
--output=$BUILD_DIRECTORY/classes.dex
$BUILD_DIRECTORY/classes
$M2_REPO/foo1/bar1/0.1-SNAPSHOT/bar1-0.1-SNAPSHOT.jar
$M2_REPO/foo2/bar2/0.1-SNAPSHOT/bar2-0.1-SNAPSHOT.jar
$M2_REPO/foo3/bar3/0.1-JAVA-8-SNAPSHOT/bar3-0.1-JAVA-8-SNAPSHOT.jar
Моя идея заключается в выполнении maven-dependency-plugin
плагин, чтобы получить эти три артефакта в $BUILD_DIRECTORY/classes
каталог, чтобы позволить retrolambda-maven-plugin
инструмент зависимости. Скажем так:
ШАГ 1. Скопируйте зависимости в целевой каталог
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
ШАГ 2: Инструмент скопированных зависимостей, используя Retrolambda
взывать retrolambda-maven-plugin
ШАГ 3: Скомпилируйте файл DEX
взывать android-maven-plugin
исключая зависимости, которые были скопированы в целевой каталог, потому что все они должны находиться в целевом каталоге
Но и это не помогает, потому что я не могу найти способ исключить артефакты из DEXed с android-maven-plugin
,
Как я могу предотвратить выбор артефактов из хранилища, где они хранятся в неинструментированном состоянии?
Моя конфигурация плагинов:
- org.apache.maven.plugins: Maven-зависимость-плагин:2,10
- net.orfjackal.retrolambda: retrolambda-Maven-плагин:2.0.2
- com.jayway.maven.plugins.android.generation2: андроид-Maven-плагин:3.9.0-rc.3
ОБНОВЛЕНИЕ № 2
Команда Simpligility выпустила плагин Android Maven 4.4.1 со сценарием, описанным ниже. Смотрите больше в плагине changelog.
<plugin>
<groupId>com.simpligility.maven.plugins</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>4.4.1</version>
</plugin>
Пример сценария можно найти по адресу http://simpligility.github.io/android-maven-plugin/instrumentation.html
1 ответ
Четыре месяца спустя, после некоторого времени для расследования, я наконец заставил его работать. Прежде всего, решающее значение в решении является исправление android-maven-plugin
, Я разветвил оригинальный плагин на GitHub и добавил несколько опций фильтра конфигурации, которые позволяют включать или исключать артефакты по идентификаторам групп, идентификаторам артефактов и их соответствующим версиям. Это очень важно настроить retrolambda-maven-plugin
, Общий рабочий процесс в основном такой же, как я отметил в вопросе. Вот:
maven-compiler-plugin
Включить поддержку функций языка Java 8. Необязательно, так как основной целью является обработка зависимостей Java 8.maven-dependency-plugin
Распакуйте ВСЕ зависимости Java 8 в целевой каталог сборки текущего проекта для дальнейшей обработки.retrolambda-maven-plugin
Обработайте все полученные файлы классов с помощью плагина Retrolambda.android-maven-plugin
Скомпилируйте файлы DEX и APK с вилкой оригиналаandroid-maven-plugin
,
Установка вилки:
#!/bin/bash
# The last upstream merge revision
PLUGIN_COMMIT=a79e45bc0721bfea97ec139311fe31d959851476
# Clone the fork
git clone https://github.com/lyubomyr-shaydariv/android-maven-plugin.git
# Ensure proper revision
cd android-maven-plugin
git checkout $PLUGIN_COMMIT
# Build the forked plugin, no tests
mvn clean package -Dmaven.test.skip=true
# Clone plugin JAR
cd target
cp android-maven-plugin-4.3.1-SNAPSHOT.jar android-maven-plugin-4.3.1-SNAPSHOT-$PLUGIN_COMMIT.jar
# Clone and modify pom.xml
cp ../pom.xml pom-$PLUGIN_COMMIT.xml
sed -i "s/<version>4.3.1-SNAPSHOT<\\/version>/<version>4.3.1-SNAPSHOT-$PLUGIN_COMMIT<\\/version>/g" pom-$PLUGIN_COMMIT.xml
# Update the plugin descriptor
unzip android-maven-plugin-4.3.1-SNAPSHOT-$PLUGIN_COMMIT.jar META-INF/maven/plugin.xml
sed -i "s/<version>4.3.1-SNAPSHOT<\\/version>/<version>4.3.1-SNAPSHOT-$PLUGIN_COMMIT<\\/version>/g" META-INF/maven/plugin.xml
zip android-maven-plugin-4.3.1-SNAPSHOT-$PLUGIN_COMMIT.jar META-INF/maven/plugin.xml
# Install the plugin
mvn org.apache.maven.plugins:maven-install-plugin:2.5.2:install-file -DpomFile=pom-$PLUGIN_COMMIT.xml -Dfile=android-maven-plugin-4.3.1-SNAPSHOT-$PLUGIN_COMMIT.jar
Готово. Далее зарегистрируйте форк в вашем pom.xml
и настройте плагины сборки:
<!-- enable Java 8 for the current module -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- unpack Java 8 dependency classes to the current module build directory -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<includeGroupIds>foo-group,bar-group,baz-group</includeGroupIds>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- Convert Java 8 to Java 6 -->
<plugin>
<groupId>net.orfjackal.retrolambda</groupId>
<artifactId>retrolambda-maven-plugin</artifactId>
<version>2.0.6</version>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>process-main</goal>
<goal>process-test</goal>
</goals>
</execution>
</executions>
<configuration>
<defaultMethods>true</defaultMethods>
<target>1.6</target>
</configuration>
</plugin>
<!-- DEXify and build the APK excluding the Java 8 dependencies as they are already processed -->
<plugin>
<groupId>com.simpligility.maven.plugins</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>4.3.1-SNAPSHOT-a79e45bc0721bfea97ec139311fe31d959851476</version>
<executions>
<execution>
<phase>package</phase>
</execution>
</executions>
<configuration>
<androidManifestFile>${project.basedir}/src/main/android/AndroidManifest.xml</androidManifestFile>
<assetsDirectory>${project.basedir}/src/main/android/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/src/main/android/res</resourceDirectory>
<sdk>
<platform>19</platform>
</sdk>
<undeployBeforeDeploy>true</undeployBeforeDeploy>
<proguard>
<skip>true</skip>
<config>${project.basedir}/proguard.conf</config>
</proguard>
<excludes>
<exclude>foo-group</exclude>
<exclude>bar-group</exclude>
<exclude>baz-group</exclude>
</excludes>
</configuration>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>5.2.1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
Он должен работать.
Обновить
Недавно я залатал вилку для Proguard Maven Mojo.
Обновление 2
android-maven-plugin
Владелец хранилища объединил мои коммиты, поэтому фильтрация артефактов запланирована на следующую версию.