Maven:在应用程序中使用Java 8库,使用retrolambda-maven-plugin和DEX-ed使用android-maven-plugin

我写了一小部分小型图书馆供我内部使用。 这是使用Maven构build的。 这些库的目标是“常规”Java,GWT和Android。 其中一些是用Java 8编写的,因为我没有任何意图在GWT或Android上运行它们,因此其他库是用旧的Java 6编写的,以支持这两种。 我有一个计划,将我的库完全迁移到Java 8(根据语言特性),并且我还成功地在尚未发布的GWT 2.8.0上运行Java 8重新编写的库。 但是,我无法将Java 8重写的库编译为Android应用程序。 问题是Retrolambda(retrolambda retrolambda-maven-plugin插件)似乎只能处理当前的Maven模块类,并完全忽略依赖类。 因此, android-maven-plugin打破目标应用程序的构build:

 [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-pluginconfiguration如下:

 <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> 

是否有可能configurationRetrolambda插件来处理库类以及所有的依赖关系? 或者,也许我只是可以使用另一个字节码处理工具?


更新#1

我认为我错了Retrolambda失败。 再深入挖掘一下,我发现android-maven-plugin可以被指责,因为它直接从Maven仓库中select没有插入的JAR文件,而不是从target目录中。 启用详细日志logging发现这个由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目录,让$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 ,因为它们都应该位于目标目录中

但是,这也失败了,因为我找不到一个方法来排除工件被android-maven-plugin DEXed。

我如何抑制工件从存储在非工具状态的存储库中获取?

我的插件configuration:

  • org.apache.maven.plugins:Maven的依赖关系的插件:2.10
  • net.orfjackal.retrolambda:retrolambda – Maven的插件:2.0.2
  • com.jayway.maven.plugins.android.generation2:Android的Maven的插件:3.9.0-rc.3

更新#2

Simpligility团队发布了Android Maven Plugin 4.4.1,其特点如下所述。 查看更多的插件更新日志 。

 <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.htmlfind。

Solutions Collecting From Web of "Maven:在应用程序中使用Java 8库,使用retrolambda-maven-plugin和DEX-ed使用android-maven-plugin"

四个月后,经过一段时间的调查,我终于做到了。 首先,解决scheme的关键是修补android-maven-plugin 。 我在GitHub中创build了原始插件,并添加了一些configuration筛选器选项,允许通过组ID,工件ID和它们各自的版本来包含或排除工件。 这对configurationretrolambda-maven-plugin非常重要。 总体工作stream程与我在问题中提到的基本相同。 这里是:

  • maven-compiler-plugin启用Java 8语言function支持。 可选的,主要目标是处理Java 8的依赖关系。
  • maven-dependency-plugin所有Java 8依赖关系解压缩到当前项目构build目标目录中,以供进一步处理。
  • retrolambda-maven-plugin使用Retrolambda插件处理所有获得的类文件。
  • android-maven-plugin使用原始的android-maven-plugin的fork编译DEX和APK文件。

安装叉子:

 #!/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注册fork并configuration构build插件:

 <!-- 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版本库所有者合并了我的提交,所以工件过滤被安排在下一个版本中。