2012-01-31 109 views
3

鉴于“java.lang.IllegalArgumentException异常:已添加” 建设项目,该项目依赖于库项目

Commons - simple java project 
AndroidLibrary1 - android library 
AndroidLibrary2 - android library 
AndroidProject - android project 

何时该项目有这样的引用对方:

AndroidLibrary1 -> Commons 
AndroidLibrary2 -> Commons 
AndroidProject -> AndroidLibrary1, AndroidLibrary2 

问题

当我建立AndroidProject我得到这样的错误:

java.lang.IllegalArgumentException: already added: Lcom/test/Bar; 

其中“com.test.Bar”是一类由“共享”工程,即通过双方AndroidLibrary1和AndroidLibrary2使用。

环境

Eclipse 3.7.1 
android-sdk-windows_r15 

任何想法如何解决这一问题?

编辑: 找到相关discussion

+0

你如何定义你的依赖关系的引用。我用最新版本的ADT(r16)重新创建了你的设置,它编译得很好。 – Kingamajick 2012-02-01 03:05:56

+0

我刚才有一个类似的问题。我的主要Android项目引用了两个android库项目(通过project.properties)。我的主要项目使用兼容性包,它放在libs中。其中一个库项目也使用它,该包也在库项目的libs文件夹中。我从主项目中删除了这个包,并且工作。 alex2k8在他的两个库项目中都有相同的库,这就是为什么它失败了。但在我看来,Android构建系统已经崩溃,所以无法编辑构建文件就无法解决这个问题。 – Malcolm 2012-02-01 12:02:56

+0

@Kingamajick,我刚刚尝试r16,同样的问题。实际上,我的描述并不精确......当我做“构建”时,报告没有问题,但是当我尝试“运行”项目时,它会报告该问题。 – alex2k8 2012-02-01 17:46:35

回答

2

后相当长的时间和正则表达式的黑魔法我发现这个解决方案:

<target name="-post-compile"> 
    <macrodef name="dex-helper"> 
     <element name="external-libs" optional="yes" /> 
     <attribute name="nolocals" default="false" /> 
     <sequential> 
      <!-- sets the primary input for dex. If a pre-dex task sets it to 
       something else this has no effect --> 
      <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}" /> 

      <!-- set the secondary dx input: the project (and library) jar files 
       If a pre-dex task sets it to something else this has no effect --> 
      <if> 
       <condition> 
        <isreference refid="out.dex.jar.input.ref" /> 
       </condition> 
       <else> 
        <path id="out.dex.jar.input.ref"> 
         <path refid="jar.libs.ref" /> 
        </path> 
       </else> 
      </if> 

      <if> 
       <condition> 
        <length string="${toString:out.dex.jar.input.ref}" trim="true" when="greater" length="0"/> 
       </condition> 
       <then> 
        <echo message="${toString:out.dex.jar.input.ref}" file="antler.tmp" /> 
        <loadfile property="out.dex.jar.input.ref.fixed" srcFile="antler.tmp"> 
         <filterchain> 
          <tokenfilter> 
           <replaceregex 
            pattern="(?&lt;=;|^)[^;]+\\libs\\([^\\;]+)(?:;|$)(?=(?:(?&lt;=;|^)[^;]+(?:;|$))*(?&lt;=;|^)[^;]+\\\1(?:;|$))" 
            replace="" flags="g"/> 
          </tokenfilter> 
         </filterchain> 
        </loadfile> 
        <delete file="antler.tmp"/> 
        <path id="out.dex.jar.input.ref.fixed" path="${out.dex.jar.input.ref.fixed}"/> 
       </then> 
       <else> 
        <path id="out.dex.jar.input.ref.fixed" /> 
       </else> 
      </if> 

      <dex executable="${dx}" 
        output="${intermediate.dex.file}" 
        nolocals="@{nolocals}" 
        verbose="${verbose}"> 
       <path path="${out.dex.input.absolute.dir}"/> 
       <path refid="out.dex.jar.input.ref.fixed" /> 
       <external-libs /> 
      </dex> 
     </sequential> 
    </macrodef> 
</target> 

这是你应该<import file="${sdk.dir}/tools/ant/build.xml" />行前添加什么到你的build.xml 文件。如果您在几个项目的libs文件夹中有相同的JAR,则此代码将根据文件名从构建系统中删除重复条目。

现在,这是如何工作

我会用“图书馆”在库文件夹,JAR和“库项目”对这些其他项目可能取决于Android的库项目。问题是,当Android系统使用库项目构建项目时,它会将所有库合并为一个堆,而忽略可能存在重复的事实。所以我们必须修复路径。

所以当构建到达那里编译完成的时候,我们重新定义它负责将Java代码到DEX的部分。上面的代码是完全一样在Android构建工具,除了以下部分:

<if> 
    <condition> 
     <length string="${toString:out.dex.jar.input.ref}" trim="true" when="greater" length="0"/> 
    </condition> 
    <then> 
     <echo message="${toString:out.dex.jar.input.ref}" file="antler.tmp" /> 
     <loadfile property="out.dex.jar.input.ref.fixed" srcFile="antler.tmp"> 
      <filterchain> 
       <tokenfilter> 
        <replaceregex 
         pattern="(?&lt;=;|^)[^;]+\\libs\\([^\\;]+)(?:;|$)(?=(?:(?&lt;=;|^)[^;]+(?:;|$))*(?&lt;=;|^)[^;]+\\\1(?:;|$))" 
         replace="" flags="g"/> 
       </tokenfilter> 
      </filterchain> 
     </loadfile> 
     <delete file="antler.tmp"/> 
     <path id="out.dex.jar.input.ref.fixed" path="${out.dex.jar.input.ref.fixed}"/> 
    </then> 
    <else> 
     <path id="out.dex.jar.input.ref.fixed" /> 
    </else> 
</if> 

我们在out.dex.jar.input.ref不洁的路径,我们的目标是不重复的条目创建路径(它们将被存储在out.dex.jar.input.ref.fixed)。不幸的是,我们必须卸载文件的路径,将其更改并加载回去,因为ant出于某些奇怪的原因无法在属性中使用正则表达式(除非使用外部库,如ant-contrib)。

其中的伎俩正则表达式是(?<=;|^)[^;]+\\libs\\([^\\;]+)(?:;|$)(?=(?:(?<=;|^)[^;]+(?:;|$))*(?<=;|^)[^;]+\\\1(?:;|$))。这种可怕的符号的混乱与libs\<something.jar>结束,并且具有进一步某处与<something.jar>结束另一路径的路径相匹配。 我正则表达式使用Windows分离,所以如果你是Linux或Mac OS X下,你应该改变那些\\必要的分离器或使正则表达式普遍。对不起,我只是没有心情去修复它已经花费了太多时间。如果你想看看正则表达式的工作原理,你可以在Regexr上这样做。

当我们删除重复项后,我们只需将字符串加载回新路径out.dex.jar.input.ref.fixed并使用它来运行dex。希望我的解决方案有帮

+0

但我认为这只会在我选择使用ant构建项目时才起作用?如果我想继续使用eclipse构建过程怎么办? – alex2k8 2012-02-01 17:42:49

+0

您可以将Eclipse设置为使用Ant并应用此解决方案。否则,我认为你不能轻易修改ADT的行为。 – Malcolm 2012-02-01 18:42:21

+0

感谢您的解决方案!我使用Netbeans和nbandroid插件,并且你的补丁运行良好。 – Patrick 2012-02-27 04:54:12