2015-05-17 11 views
8

Napisałem mały zestaw minilibli na mój wewnętrzny użytek. Ten zestaw jest zbudowany przy użyciu Maven. Biblioteki są adresowane do "zwykłej" Javy, GWT i Androida. Niektóre z nich są napisane w języku Java 8, ponieważ nie miałem zamiaru uruchamiać ich na GWT lub Androidzie, dlatego inne biblioteki są napisane w starej wersji 6, aby obsługiwać te dwa. Mam plan pełnej migracji moich bibliotek do Java 8 (pod względem funkcji językowych) i udało mi się uruchomić biblioteki przepisane w języku Java 8 na jeszcze nie wydanym GWT 2.8.0. Nie mogę jednak przepisać bibliotek Java 8 do kompilacji dla aplikacji na Androida. Problem polega na tym, że Retrolambda (wtyczka retrolambda-maven-plugin) wydaje się być w stanie przetworzyć tylko obecne klasy modułów Maven i całkowicie ignoruje klasy zależności. Zatem android-maven-plugin łamie aplikacja docelowa budować z:Maven: Używanie bibliotek Java 8 w aplikacjach wyposażonych w retrofambdę-maven-plugin i DEX-ed z androidem-maven-pluginem

[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 jest skonfigurowany w następujący sposób:

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

to możliwe, aby skonfigurować wtyczkę Retrolambda na przetwarzanie klas bibliotecznych jak dobrze więc wszystkie zależności ? A może po prostu mógłbym użyć innego narzędzia do przetwarzania kodu bajtowego?


Aktualizacja # 1

Chyba, że ​​się mylę o Retrolambda niepowodzeniem. Zagłębiając się w to jeszcze trochę, doszedłem do wniosku, że za to można winić android-maven-plugin, ponieważ wybiera bezpośrednio niesystemowe pliki JAR z repozytorium Maven, a nie z katalogu target. Umożliwiając pełne rejestrowanie odkryliśmy to polecenie pseudo-kod wywoływany przez 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 

Mój pomysł jest wykonywany wtyczki maven-dependency-plugin aby uzyskać te trzy artefakty do katalogu $BUILD_DIRECTORY/classes pozwolić instrumentu retrolambda-maven-plugin zależności. Powiedzmy:

KROK 1: Skopiuj zależności do katalogu docelowego

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

Krok 2: Instrument skopiowane zależności wykorzystujące Retrolambda

Invoke retrolambda-maven-plugin

KROK 3: Kompilacja pliku DEX

Invoke android-maven-plugin wyłączeniem zależności, które zostały skopiowane do katalogu docelowego, ponieważ wszystkie one są podobno znajdować się w katalogu docelowym

Ale to nie zbyt , ponieważ nie mogę znaleźć sposobu na wykluczenie artefaktów z DEXed z android-maven-plugin.

W jaki sposób mogę zablokować pobieranie artefaktów z repozytorium, w którym są przechowywane w stanie nieprzygotowanym?konfiguracja

Moi wtyczek:

  • org.apache.maven.plugins: Maven zależność-plugin: 2,10
  • net.orfjackal.retrolambda: retrolambda-maven-plugin: 2.0.2
  • com.jayway.maven.plugins.android.generation2: android-maven-plugin: 3.9.0-rc.3

UPDATE # 2

Zespół Simpligility wydał plugin Android Maven 4.4.1 ze scenariuszem opisanym poniżej. Zobacz więcej na wtyczce changelog.

<plugin> 
    <groupId>com.simpligility.maven.plugins</groupId> 
    <artifactId>android-maven-plugin</artifactId> 
    <version>4.4.1</version> 
</plugin> 

Przykładowy scenariusz można znaleźć na http://simpligility.github.io/android-maven-plugin/instrumentation.html

+0

świetne pytanie i rozwiązanie! uratowałeś mój dzień ... – MWiesner

Odpowiedz

5

cztery miesiące później, po trochę czasu na badania, mam w końcu działać. Przede wszystkim kluczową rzeczą w rozwiązaniu jest łatanie android-maven-plugin. Rozwinąłem oryginalną wtyczkę w GitHub i dodałem kilka opcji filtrów konfiguracji, które pozwalają na dołączanie lub wykluczanie artefaktów według identyfikatorów grup, identyfikatorów artefaktów i ich odpowiednich wersji. Jest to bardzo ważne, aby skonfigurować retrolambda-maven-plugin. Ogólny przepływ pracy jest w zasadzie taki sam, jak zauważyłem w pytaniu. Oto ona:

  • maven-compiler-plugin Włącz obsługę funkcji języka Java 8. Opcjonalne, ponieważ głównym celem jest przetwarzanie zależności Java 8.
  • maven-dependency-plugin Rozpakuj wszystkie zależności Javy 8 do bieżącego katalogu docelowego kompilacji projektu w celu dalszego przetwarzania.
  • retrolambda-maven-plugin Przetwarzaj wszystkie otrzymane pliki klas za pomocą wtyczki Retrolambda.
  • android-maven-plugin Skompiluj pliki DEX i APK widelcem oryginału android-maven-plugin.

Instalacja wideł:

#!/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 

zrobić. Następnie zarejestrować widelec w pom.xml i skonfigurować wtyczki produkcji:

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

To powinno działać.


Aktualizacja

Niedawno połatany widełki dla mojo Proguard Maven.

Aktualizacja 2

Właściciel android-maven-plugin repozytorium merged moje rewizje, więc filtrowanie artefakt planowane jest na następnej wersji.

+0

Powodzenia z GWT + Retrolambda? – Namek

+1

@Namek te składniki nie są powiązane.GWT przetwarza tylko oryginalny kod źródłowy, podczas gdy Retrolambda przetwarza kod bajtu. GWT 2.8.0-SNAPSHOT może pracować z wyrażeń lambda w języku Java 8 dość stabilnym. –

+0

Dzięki za wspaniałą pracę! Mam nadzieję, że pomożesz mi rozwiązać mój problem z twoją sugestią: Mam bibliotekę android, której jestem zależny. Jak można się domyślać, kompilacja nie powiedzie się, ponieważ Maven zależność-plugin nie może rozpakować tego typu artefaktów: ** Rozpakowanie \ [ścieżka] \ someLibrary.aar do \ [ścieżka] \ Classes \ docelowych. Nie udało się wykonać gol org.apache.maven.plugins: Maven zależność plugin: 2.10: Rozpakowywanie-Zależności (domyślne) na projekt aquilax-dist-droidów-Operator: Nieznany typ archiwizatora: Nie ma takiego Archiver: "AAR". ** – Amin

Powiązane problemy