2015-05-17 50 views
8

我寫了一小部分小型庫供我內部使用。這是使用Maven構建的。這些庫的目標是「常規」Java,GWT和Android。其中一些是用Java 8編寫的,因爲我沒有任何打算在GWT或Android上運行它們的意圖,因此其他庫是用舊版Java 6編寫的,以支持這兩種。我有一個將我的庫完全遷移到Java 8(根據語言特性)的計劃,並且我還成功地在尚未發佈的GWT 2.8.0上運行Java 8重新編寫的庫。但是,我無法將Java 8重寫的庫編譯爲Android應用程序。問題是Retrolambda(retrolambda-maven-plugin插件)似乎只能處理當前的Maven模塊類,並完全忽略依賴類。因此,android-maven-plugin打破了目標應用程序構建具有:Maven:在裝有retrolambda-maven-plugin和DEX-ed的應用程序中使用Java 8庫與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可以歸咎於它,因爲它直接從Maven存儲庫中選擇未檢測到的JAR文件,而不是從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儀器的依賴關係。比方說:

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

STEP 2:儀器使用Retrolambda

調用retrolambda-maven-plugin

複製的依賴

STEP 3:編譯DEX文件

調用android-maven-plugin排除被複制到目標目錄的依賴,因爲他們都應該被定位在目標目錄

但這也失敗,因爲我無法找到一種方法來排除工件因android-maven-plugin而遭到DEX處理。

我該如何抑制工件從存儲在非工具狀態的存儲庫中獲取?

我的插件配置:

  • 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,其特點如下所述。請參閱插件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

+0

偉大的問題和解決方案!拯救了我的一天... – MWiesner

回答

5

四個月後發現,其調查一段時間後,我終於使它工作。首先,解決方案的關鍵是修補android-maven-plugin。我在GitHub中分支了原始插件,並添加了一些配置篩選器選項,允許按組ID,工件ID和它們各自的版本包含或排除工件。這對配置retrolambda-maven-plugin非常重要。整體工作流程與我在問題中提到的基本相同。它是:

  • maven-compiler-plugin啓用Java 8語言功能支持。可選,主要目標是處理Java 8依賴項。
  • maven-dependency-plugin將所有Java 8依賴關係解壓到當前項目構建目標目錄以供進一步處理。
  • retrolambda-maven-plugin使用Retrolambda插件處理所有獲得的類文件。
  • android-maven-plugin使用原始android-maven-plugin的叉子編譯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 

DONE。接下來,註冊叉在你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的魔力叉。

更新2

android-maven-plugin庫所有者merged我的提交,所以僞像濾波定於下一個版本。

+0

GWT + Retrolambda有什麼好運氣? – Namek

+1

@Namek這些組件是不相關的。GWT只處理原始源代碼,而Retrolambda處理字節碼。 GWT 2.8.0-SNAPSHOT可以使用Java 8 lambda表達式非常穩定。 –

+0

感謝您的出色工作!我希望你幫助解決我的問題與您的建議: 我有我依賴的_aar_ android庫。正如你可能已經猜到,構建因爲Maven的依賴關係的插件無法解開這類文物的失敗: **開箱\ [路徑] \ someLibrary.aar到\ [路徑] \目標\類。 未能執行目標org.apache.maven.plugins:Maven的依賴關係的插件:2.10:未知存檔類型:項目aquilax - 距離 - DROID運營商解開依賴性(默認)沒有這樣的歸檔:「AAR」。 ** – Amin

相關問題