鉴于
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”是来自“Commons”项目的类,AndroidLibrary1和AndroidLibrary2都使用该类。
环境
Eclipse 3.7.1
android-sdk-windows_r15
任何想法如何解决这个问题?
修改 找到相关的discussion。
答案 0 :(得分: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="(?<=;|^)[^;]+\\libs\\([^\\;]+)(?:;|$)(?=(?:(?<=;|^)[^;]+(?:;|$))*(?<=;|^)[^;]+\\\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,则此代码将根据文件名从构建系统中删除重复的条目。
我将在libs文件夹中使用“library”一词用于JAR,而在其他项目可能依赖的Android库项目中使用“library project”。问题是,当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="(?<=;|^)[^;]+\\libs\\([^\\;]+)(?:;|$)(?=(?:(?<=;|^)[^;]+(?:;|$))*(?<=;|^)[^;]+\\\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。希望我的解决方案有所帮助。