7

Ho un problema con le librerie Android.Come risolvere un conflitto di libreria (apache commons-codec)

Vorrei utilizzare il metodo Hex.encodeHexString (array di byte) dalla libreria org.apache.commons.codec.binary.Hex (versione 1.6)

Sul mio piattaforma Android (SDK 2.3.1), esiste già la versione 1.3 della libreria di codec comuni, ma il metodo non esiste ancora in questa versione (solo encodeHex()).

ho aggiunto la biblioteca barattolo di versione 1.6 nel mio progetto Eclipse (in/directory libs), ma quando ho eseguito il progetto su emulatore, ottengo questo:

E/AndroidRuntime(1632): FATAL EXCEPTION: main 
E/AndroidRuntime(1632): java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Hex.encodeHexString 

Come posso indicare il sistema operativo in cui è la buona biblioteca?

Sto usando Eclipse Juno con Java 1.6.0 su Mac OS X

Ci dispiace per il mio cattivo inglese e grazie in anticipo!

MODIFICA: il problema potrebbe essere risolto apparentemente con lo strumento jarjar. http://code.google.com/p/google-http-java-client/issues/detail?id=75

Qualcuno potrebbe aiutarmi con questo strumento? Non so come creare un Manifest Ant o un file jar.

Grazie

+0

Come hai detto, una soluzione per questo problema è usare jarjar per creare un nuovo jar che non sia in conflitto con le classi di Android. Una spiegazione + soluzione + vaso creato (che ha risolto il problema per me) - http://priyanka-tyagi.blogspot.co.il/2013/03/dealing-with-java-hell-using-jarjar.html (grazie a bianca che ci ha fatto risparmiare tempo ...) –

risposta

8

risposta in ritardo, ma forse utile per qualcuno.

Problema risolto utilizzando Maven Shade Plugin

Questo plugin permette di rinominare i nomi dei pacchetti di libreria in conflitto a compilazione.

Usage:

<plugin> 
     <groupId>org.apache.maven.plugins</groupId> 
     <artifactId>maven-shade-plugin</artifactId> 
     <executions> 
      <execution> 
      <phase>package</phase> 
      <goals> 
       <goal>shade</goal> 
       </goals> 
      <configuration> 
        <relocations> 
         <relocation> 
           <pattern>org.apache.commons</pattern> 
            <shadedPattern>com.example.shaded.org.apache.commons</shadedPattern> 
         </relocation> 
        </relocations> 
         <promoteTransitiveDependencies>true</promoteTransitiveDependencies> 
      </configuration> 
      </execution> 
     </executions> 
    </plugin> 
+0

Questa sembra una grande risposta. Tuttavia, quando aggiungo questo nello script di build di Maven, l'APK risultante non verrà installato. Sta dicendo [INSTALL_PARSE_FAILED_NO_CERTIFICATES] e lì io uso jarsigner per verificare la build che dice "jarsigner: java.lang.SecurityException: digest di file di firma non valido per gli attributi principali di Manifest" Qualche idea perché? –

+0

La configurazione di configurazione di maven non firma l'APK. Io uso il Maven-jarsigner-plugin per fare questo: \t Maven-jarsigner-plugin \t 1,2 \t vero Si dovrebbe anche essere in grado di firmare con la chiave di debug configurando correttamente il plugin maven-android. –

+0

Ho configurato jarsigner, questo script di build funziona da mesi ormai. Ho incluso il plug-in di Shade sotto il mio plug-in maven-jarsigner nelle esecuzioni di build, e ora l'apk SHADED di output non è firmato. –

0

Hanno aggiunto la libreria al percorso di generazione del progetto? Quando hai finito dovresti essere in grado di chiamare il metodo dal file jar.

Se si costruisce OK senza aggiungere la libreria, è possibile che si stia sviluppando una versione più recente di Android e quindi si distribuisca efficacemente a una versione precedente, ho scoperto nel modo più rigido che String.isEmpty() non è in 2.1 ma quando scrivevo il codice build OK come stavo costruendo contro 4.1

Potrebbe essere necessario esportare il jar con il progetto (di nuovo è possibile farlo mentre si configura il percorso di generazione).

Spero che questo aiuti

+2

La libreria viene aggiunta al percorso di creazione. L'edificio funziona bene ma la mia app si interrompe in runtime. Ho già provato a utilizzare l'SDK di JB o ICS ma gli stessi problemi .. Grazie –

0

Per quanto riguarda plugin di Maven ombra di nbe_42, in cui il blocco plugin è messo nel file pom.xml è molto importante o Maven mancherà di esso.

Quello che ha funzionato per me è stato quello di mettere alla fine del blocco in <build> <plugins> pom.xml:

<build> 
<plugins> 
{all other plugins} 
... 
{shade plugin} 
</plugins> 
</build> 

Originariamente ho avuto all'inizio del blocco e Maven non hanno eseguirlo.

Per creare il file .jar, scaricare l'archivio .zip di commons-codec-1.8-src.zip da apache.org. Disimballalo. Il pom.il file xml si troverà nella directory di base dell'archivio. Inserire blocco dei plugin di nbe_42 nel file pom.xml come descritto in precedenza ed eseguire:

mvn install 

Questo sarà costruire, testare, sostituire e installare il plugin per voi.

di uscita in caso di successo dovrebbe essere simile a questo:

[INFO] --- maven-shade-plugin:2.2:shade (default) @ commons-codec --- 
[INFO] Replacing original artifact with shaded artifact. 
... 
[INFO] ------------------------------------------------------------------------ 
[INFO] BUILD SUCCESS 
...` 
2

versione ampliata della risposta di nbe_42, con documentazione completa ...

Il progetto vaso commons-codec-ombreggiata:

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>commons-codec</groupId> 
    <artifactId>commons-codec-shaded</artifactId> 
    <name>Apache Commons Codec (shaded)</name> 
    <!-- The version of this project specifies the Apache Commons Codec version which will 
     be used, it must therefore match an existing (and preferably current) version. --> 
    <version>1.9</version> 
    <packaging>jar</packaging> 

    <!-- 
     ************************************************************* 
     Rationale for this "shaded" version of Apache Commons Codec 
     ************************************************************* 

     Context: 
     Android includes an outdated version (v1.3) of commons-codec as an internal library. 
     This library is not exposed in the Android SDK so app developers who want to rely on 
     commons-codec need to treat it as an addition dependency and include it in the APK 
     of their app. However, at runtime Android will always favour its internal version of 
     the library which causes trouble when app code tries to call methods that don't 
     exist in v1.3 but do exist in the version the developer expected to be using. 

     Solution: 
     After experimenting with many different variations the current (and final) solution 
     to this problem is implemented in this project and does not require big hacks or 
     changes in projects which depend on commons-codec, expect for declaring dependency 
     on commons-codec-shaded (i.e. this project) instead of the original commons-codec. 
     What we do here is take the "original" commons-codec library (currently version 1.9) 
     and use the maven-shade-plugin to "shade" it, which means we modify the package name 
     of the library (both in the compiled classes and the sources jar) in order to avoid 
     the clash with Android's version. The package name is changes from 
     "org.apache.commons.codec" to "shaded.org.apache.commons.codec". The result is 
     published to the local Maven repository for other projects to use by simple 
     dependency declaration on this project. Because we only apply the shading to 
     commons-codec itself (and not to other classes using it; which is possible using the 
     shade plug-in but doesn't work in combination with android-maven-plugin) any client 
     classes which make use of commons-codec will have to import the new "shaded" package 
     name instead of the old one. 

     Issue on android-maven-plugin github which I posted to discuss all this: 
     https://github.com/jayway/maven-android-plugin/issues/487 
    --> 

    <description> 
    The Apache Commons Codec package contains simple encoder and decoders for 
    various formats such as Base64 and Hexadecimal. In addition to these 
    widely used encoders and decoders, the codec package also maintains a 
    collection of phonetic encoding utilities. 
    </description> 
    <url>http://commons.apache.org/proper/commons-codec/</url> 
    <organization> 
     <name>The Apache Software Foundation</name> 
     <url>http://www.apache.org/</url> 
    </organization> 
    <licenses> 
     <license> 
      <name>The Apache Software License, Version 2.0</name> 
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> 
      <distribution>repo</distribution> 
     </license> 
    </licenses> 

    <contributors> 
     <contributor> 
      <name>Matthias Stevens</name> 
      <email>m.stevens {at} ucl.ac.uk</email> 
      <roles> 
       <role>Shading for use on Android</role> 
      </roles> 
     </contributor> 
     <!-- see commons-codec:commons-codec pom for original contributors/developers --> 
    </contributors> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 
     <maven.compiler.source>1.6</maven.compiler.source> 
     <maven.compiler.target>1.6</maven.compiler.target> 
     <commons-codec-package>org.apache.commons.codec</commons-codec-package> 
     <shading.prefix>shaded</shading.prefix> 
     <shaded-commons-codec-package>${shading.prefix}.${commons-codec-package}</shaded-commons-codec-package> 
     <commons-codec-src-folder>${project.build.directory}/commons-codec-src</commons-codec-src-folder> 
     <commons-codec-res-folder>${project.build.directory}/commons-codec-res</commons-codec-res-folder> 
     <manifest.path>${project.build.directory}/MANIFEST.MF</manifest.path> 
     <!-- plugin versions --> 
     <dependency-plugin-version>2.9</dependency-plugin-version> 
     <compiler-plugin-version>3.2</compiler-plugin-version> 
     <antrun-plugin-version>1.7</antrun-plugin-version> 
     <jar-plugin-version>2.5</jar-plugin-version> 
     <source-plugin-version>2.4</source-plugin-version> 
     <shade-plugin-version>2.3</shade-plugin-version> 
     <bundle-plugin-version>2.5.3</bundle-plugin-version> 
     <!-- taken/modified from: http://svn.apache.org/repos/asf/commons/proper/commons-parent/trunk/pom.xml --> 
     <commons.osgi.symbolicName>${shaded-commons-codec-package}</commons.osgi.symbolicName> 
     <commons.osgi.export>${shaded-commons-codec-package}.*;version=${project.version};-noimport:=true</commons.osgi.export> 
     <commons.osgi.import>*</commons.osgi.import> 
     <commons.osgi.dynamicImport /> 
     <commons.osgi.private /> 
    </properties> 

    <build> 
     <finalName>${project.artifactId}</finalName> 
     <sourceDirectory>${commons-codec-src-folder}</sourceDirectory>  
     <resources> 
      <resource> 
       <!-- txt files in shaded\org\apache\commons\codec\language\bm --> 
       <directory>${commons-codec-res-folder}</directory> 
       <includes> 
        <include>${shading.prefix}/**/*.txt</include> 
       </includes> 
      </resource> 
      <resource> 
       <!-- LICENSE & NOTICE files --> 
       <directory>${commons-codec-res-folder}/META-INF</directory> 
       <targetPath>META-INF</targetPath> 
       <includes> 
        <include>*.txt</include> 
       </includes> 
      </resource> 
     </resources> 
     <plugins> 
      <plugin> 
       <!-- fetch & unpack commons-codec sources and resources --> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-dependency-plugin</artifactId> 
       <version>${dependency-plugin-version}</version> 
       <executions> 
        <execution> 
         <id>unpack_commons-codec_sources_and_resources</id> 
         <phase>process-sources</phase> 
         <goals> 
          <goal>unpack</goal> 
         </goals> 
         <configuration> 
          <artifactItems> 
           <!-- commons-codec sources --> 
           <artifactItem> 
            <groupId>commons-codec</groupId> 
            <artifactId>commons-codec</artifactId> 
            <!-- the project version specifies the commons-codec version to use: --> 
            <version>${project.version}</version> 
            <classifier>sources</classifier> 
            <overWrite>true</overWrite> 
            <excludes>**/*.txt,META-INF/*</excludes> 
            <outputDirectory>${commons-codec-src-folder}</outputDirectory> 
           </artifactItem> 
           <!-- commons-codec resources (in package) --> 
           <artifactItem> 
            <groupId>commons-codec</groupId> 
            <artifactId>commons-codec</artifactId> 
            <!-- the project version specifies the commons-codec version to use: --> 
            <version>${project.version}</version> 
            <classifier>sources</classifier> 
            <overWrite>true</overWrite> 
            <includes>org/**/*.txt</includes> 
            <!-- apply shading: --> 
            <outputDirectory>${commons-codec-res-folder}/${shading.prefix}</outputDirectory> 
           </artifactItem> --> 
           <!-- commons-codec resources (in META-INF) --> 
           <artifactItem> 
            <groupId>commons-codec</groupId> 
            <artifactId>commons-codec</artifactId> 
            <!-- the project version specifies the commons-codec version to use: --> 
            <version>${project.version}</version> 
            <classifier>sources</classifier> 
            <overWrite>true</overWrite> 
            <includes>META-INF/*.txt</includes> 
            <outputDirectory>${commons-codec-res-folder}</outputDirectory> 
           </artifactItem> --> 
          </artifactItems> 
         </configuration> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <!-- compile commons-codec sources --> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-compiler-plugin</artifactId> 
       <version>${compiler-plugin-version}</version> 
       <configuration> 
        <source>${maven.compiler.source}</source> 
        <target>${maven.compiler.target}</target> 
        <encoding>UTF-8</encoding> 
       </configuration> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-jar-plugin</artifactId> 
       <version>${jar-plugin-version}</version> 
       <executions> 
        <execution> 
         <!-- jar unshaded classes (& resources) --> 
         <id>jar-unshaded</id> 
         <phase>package</phase> 
         <goals> 
          <goal>jar</goal> 
         </goals> 
        </execution> 
        <execution> 
         <!-- rejar shaded classes (& resources), with proper manifest partially generated by bundle plugin --> 
         <id>jar-shaded</id> 
         <!-- runs after bundle plugin has done its work to generate bundle manifest --> 
         <phase>post-integration-test</phase> 
         <goals> 
          <goal>jar</goal> 
         </goals> 
         <configuration> 
          <archive> 
           <manifestFile>${manifest.path}</manifestFile> 
           <manifestEntries> 
            <Specification-Title>${project.name}</Specification-Title> 
            <Specification-Version>${project.version}</Specification-Version> 
            <Specification-Vendor>${project.organization.name}</Specification-Vendor> 
            <Implementation-Title>${project.name}</Implementation-Title> 
            <Implementation-Version>${project.version}</Implementation-Version> 
            <Implementation-Vendor>${project.organization.name}</Implementation-Vendor> 
            <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id> 
            <Implementation-Build>${implementation.build}</Implementation-Build> 
            <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK> 
            <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK> 
           </manifestEntries> 
          </archive> 
         </configuration> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <!-- attach sources jar --> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-source-plugin</artifactId> 
       <version>${source-plugin-version}</version> 
       <configuration> 
        <archive> 
         <manifest> 
          <addDefaultImplementationEntries>true</addDefaultImplementationEntries> 
          <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> 
         </manifest> 
        </archive> 
       </configuration> 
       <executions> 
        <execution> 
         <!-- jar unshaded sources --> 
         <id>attach-unshaded-sources</id> 
         <!-- <phase>package</phase> (default) --> 
         <goals> 
          <goal>jar</goal> 
         </goals> 
        </execution> 
        <execution> 
         <!-- rejar shaded sources --> 
         <id>attach-shaded-sources</id> 
         <phase>post-integration-test</phase> 
         <goals> 
          <goal>jar</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <!-- apply the shading to main jar and sources jar --> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-shade-plugin</artifactId> 
       <version>${shade-plugin-version}</version> 
       <executions> 
        <execution> 
         <id>shading-main-jar-and-sources-jar</id> 
         <phase>package</phase> 
         <goals> 
          <goal>shade</goal> 
         </goals> 
         <configuration> 
          <!-- (not needed as it is the one and only artifact/dependency) 
          <artifactSet> 
           <includes> 
            <include>commons-codec:*</include> 
           </includes> 
          </artifactSet> 
          --> 
          <relocations> 
           <relocation> 
            <pattern>${commons-codec-package}</pattern> 
            <shadedPattern>${shaded-commons-codec-package}</shadedPattern> 
           </relocation> 
          </relocations> 
          <createDependencyReducedPom>false</createDependencyReducedPom> 
          <!-- (only needed when dependency reduced pom is generated) 
          <dependencyReducedPomLocation>${project.build.directory}/dependency-reduced-pom.xml</dependencyReducedPomLocation> 
          <keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope> 
          <promoteTransitiveDependencies>true</promoteTransitiveDependencies> 
          --> 
          <createSourcesJar>true</createSourcesJar> 
          <shadeSourcesContent>true</shadeSourcesContent> 
         </configuration> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <groupId>org.apache.maven.plugins</groupId> 
       <artifactId>maven-antrun-plugin</artifactId> 
       <version>${antrun-plugin-version}</version> 
       <executions> 
        <execution> 
         <!-- unpack shaded classes & sources for manifest generation and re-jarring --> 
         <id>post-shading-tasks</id> 
         <phase>package</phase> 
         <goals> 
          <goal>run</goal> 
         </goals> 
         <configuration> 
          <target> 
           <!-- Unjar shaded classes for generation of manifest --> 
           <echo>Deleting unshaded classes...</echo> 
           <delete dir="${project.build.directory}/classes"/> 
           <echo>Unjarring shaded main jar...</echo> 
           <unzip src="${project.build.directory}/${project.artifactId}.jar" dest="${project.build.directory}/classes"/> 
           <!-- delete to prevent dual inclusion in new main jar --> 
           <delete dir="${project.build.directory}/classes/META-INF/maven"/> 
           <!-- Unjar shaded sources --> 
           <echo>Deleting unshaded sources...</echo> 
           <delete dir="${commons-codec-src-folder}"/> 
           <echo>Unjarring shaded sources jar...</echo> 
           <unzip src="${project.build.directory}/${project.artifactId}-sources.jar" dest="${commons-codec-src-folder}"/> 
           <!-- delete to prevent dual inclusion in new sources jar --> 
           <delete dir="${commons-codec-src-folder}/META-INF"/> 
          </target> 
         </configuration> 
        </execution> 
        <execution> 
          <id>delete-orginals</id> 
          <phase>verify</phase> 
          <goals> 
           <goal>run</goal> 
          </goals> 
          <configuration> 
           <target> 
            <echo>Deleting unshaded jar files...</echo> 
            <delete> 
             <fileset dir="${project.build.directory}" includes="**/original-*.jar" /> 
            </delete> 
           </target> 
          </configuration> 
        </execution> 
       </executions> 
      </plugin> 
      <plugin> 
       <!-- taken/modified from: http://svn.apache.org/repos/asf/commons/proper/commons-parent/trunk/pom.xml --> 
       <groupId>org.apache.felix</groupId> 
       <artifactId>maven-bundle-plugin</artifactId> 
       <version>${bundle-plugin-version}</version> 
       <configuration> 
        <archive> 
         <forced>true</forced> 
        </archive> 
        <excludeDependencies>true</excludeDependencies> 
        <manifestLocation>${project.build.directory}</manifestLocation> 
        <instructions> 
         <!-- stops the "uses" clauses being added to "Export-Package" manifest entry --> 
         <_nouses>true</_nouses> 
         <!-- Stop the JAVA_1_n_HOME variables from being treated as headers by Bnd --> 
         <_removeheaders>JAVA_1_3_HOME,JAVA_1_4_HOME,JAVA_1_5_HOME,JAVA_1_6_HOME,JAVA_1_7_HOME,JAVA_1_8_HOME</_removeheaders> 
         <Bundle-SymbolicName>${commons.osgi.symbolicName}</Bundle-SymbolicName> 
         <Export-Package>${commons.osgi.export}</Export-Package> 
         <Private-Package>${commons.osgi.private}</Private-Package> 
         <Import-Package>${commons.osgi.import}</Import-Package> 
         <DynamicImport-Package>${commons.osgi.dynamicImport}</DynamicImport-Package> 
         <Bundle-DocURL>${project.url}</Bundle-DocURL> 
        </instructions> 
       </configuration> 
       <executions> 
        <execution> 
         <id>bundle-manifest</id> 
         <!-- runs after the unjarring of the shaded classes --> 
         <phase>integration-test</phase><!-- default is: process-classes --> 
         <goals> 
          <goal>manifest</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 
</project> 

E nei progetti (apk/apklib/aar/jar) in cui si desidera utilizzare la libreria ombreggiata:

+0

Soluzione davvero eccezionale pronta all'uso. Prima stavo "oscurando" manualmente, il che funzionava bene, ma è molto più flessibile. Il convo continua qui: https://github.com/simpligility/android-maven-plugin/issues/487 Google dovrebbe occuparsi di questo problema (ad esempio una patch del compilatore?), O almeno fornire una soluzione come questa. – Atorian

1

Ciò è dovuto a una collisione di spazio dei nomi derivante dalla vecchia versione (1.2) di Commons Codec che viene compresso con Android in collisione con la versione più recente. Mentre l'ombreggiatura è una buona soluzione, a lungo andare non penso che sia una soluzione sostenibile. Questo è un problema sistemico che può sorgere con qualsiasi libreria open source inclusa in Android. Ho inviato un problema a Google. Se sei d'accordo, ti incoraggio a "interpretarlo" in modo da ottenere l'attenzione di cui ha bisogno. Ecco il link: https://code.google.com/p/android/issues/detail?id=160578

+0

Purtroppo Commons-codec non è l'unica libreria legacy utilizzata in Android. Ci sono molto di più (XML, JSON, Apache HTTP Client, Javax, bouncycastle, ...). Nel mio caso, l'ombreggiatura è la soluzione migliore dal momento che ho modularizzato il mio software in modo da avere codice comune tra il mio server e Android. Posso avere lo stesso codice in esecuzione con lo stesso comportamento su entrambe le piattaforme. –

Problemi correlati