1

我的 Android 的 java 项目有几个配置。以前我切换它们并手动从 Eclipse 构建 apk,但最近我开发了几个 ant 任务以使我的生活更轻松:我启动 cmd 文件并构建所有配置(每次更改配置变量,移动资源,修改清单, ETC。)。

但是今天我发现ant(它使用javac)用android工作流(我的build.xml包括${sdk.dir}/tools/ant/build.xml)编译的代码与Eclipse中ADT工具生成的代码不同. 差异是致命的。

在编译阶段 javac 声称某些文件包含 BOM,并且一个类太大(对于许多静态数组)。我已经将所有文件转换为 utf8 w/o bom,将大类分成两个,javac 没有更多问题。很容易。

但是,如果我在 4.0.x 设备或模拟器上启动 ant-made apk(在 1.6、2.2、4.1、4.2 上工作),它会在运行时强制关闭并说:

03-01 09:15:16.247: W/dalvikvm(1993): VFY: register1 v3 type 17, wanted 18
03-01 09:15:16.247: W/dalvikvm(1993): VFY:  rejecting opcode 0xc8 at 0x0023
03-01 09:15:16.247: W/dalvikvm(1993): VFY:  rejected Lcom/myproj/MySomeClass;.doThing (I)V
03-01 09:15:16.247: W/dalvikvm(1993): Verifier rejected class Lcom/myproj/MySomeClass;
03-01 09:15:16.247: W/System.err(1993): java.lang.VerifyError: com/myproj/MySomeClass
...
<stack here>
...

但是 eclipse-adt-made apk 在 4.0.x 上运行得很好!此外 - 我从未在编译时看到关于 utf bom 或类大小的 adt 声明。

所以我认为我们应该在 ant build 中使用其他东西而不是 javac。但是谷歌在它的 build.xml 中完全使用了 javac。使用 ant 构建时,我们如何使用 ADT 编译器而不是 javac?

当然,我仍然可以在 eclipse 中构建,但是 ant 脚本在我花费 20 分钟时花费 1 分钟,并且在更改 cfg vars 时它永远不会犯愚蠢的错误(它们之间存在一些依赖关系)。

提前致谢!

UPDT:我怀疑它与我使用的 java 版本有某种联系。Ant 使用 1.7 x86 jdk 执行,而 eclipse 使用 jdk1.6.0_26 x64。有人说 Dalvik dex 不理解一些 java 1.7 字节码,但我应该检查一下。

UPDT1:不,我已经删除了所有 jdk,然后安装了 jdk 1.6.0_41 x86 和 x64,设置 eclipse 使用 1.6.0_41 x64 并将 JAVA_PATH 设置为 jdk 1.6.0_41 x86。同样的事情-在eclipse中编译的apk(Android工具->导出签名的apk)可以工作,ant-compiled apk说VerifyError。

4

1 回答 1

1

认为我已经解决了这个问题。

我花了几个小时切换 java 版本,重新定义默认的 google ant 任务,尝试从几个 jdk 中独立启动不同的 javac 来编译我的类。在过去的五年里,我从来没有使用控制台工具编译过 java,所以这既困难又令人困惑。我对任何 javac 都没有运气,同样的验证错误。

然后我阅读了Eclipse和Android的文档,发现当我们在eclipse中构建apk时,ADT使用Eclipse的JDT(Eclipse Compiler for Java)而不是javac将java代码编译成类,然后使用dx工具制作dalvik代码。所以我们需要启动 JDT 而不是正常的 -compile ant 任务,对吗?不,实际上一切都更容易。正如经常发生的那样,我从头开始,但是一旦我明白我需要这个编译工具,我就走对了。

Eclipse Compiler for Java (JDT ECJ) 是比实际的 javac 更智能的工具。对我来说这是一个带有大量参数的新工具,但 JDT 提供了非常酷的ant javac 适配器,我们可以在 javac ant 任务中使用它 - 设置“build.compiler”属性,然后启动正常的 android ant -compile 任务:

<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter" />

<javac encoding="${java.encoding}" source="1.6" target="1.6" debug="true" extdirs=""
                   includeantruntime="false" destdir="${out.classes.absolute.dir}"
                   bootclasspathref="project.target.class.path"
                   verbose="${verbose}" classpathref="project.javac.classpath"
                   fork="${need.javac.fork}" >
    <src path="${source.absolute.dir}" />
    <src path="${gen.absolute.dir}" />
    <compilerarg line="${java.compilerargs}" />
</javac>

但除非您有 ecj.jar,否则这将不起作用。而且eclipse中没有这样的文件!继续调查我发现 Eclipse Compiler for Java 可以单独下载。要完成这项工作,您需要将此 jar 复制到 ant/lib 文件夹。但奇怪的是 - ecj 4.2.2 编译的代码具有相同的验证问题。幸运的是,我尝试了 ecj 3.5.1 - 它奏效了!但是我不满意 - 我仍然不能说为什么 ecj 4.2.2 没有帮助,而 3.5.1 有帮助。如果我升级 eclipse 并且它会编译坏类怎么办?我比较了字节码——它的差别非常小(由 jd-gui 反编译),所以我认为问题出在生成的类文件中。我想知道到底是什么,但我什至无法想象要寻找什么。

无论如何,还有更多。当您查看 eclipse/plugins 文件夹时,您会看到一个名为“org.eclipse.jdt.core_3.6.2.v_A76_R36x.jar”的文件。它在内部保存 jdtCompilerAdapter.jar 文件(因为 jar 是一个 zip 存档)。如果将其复制到 ant/lib,然后复制 org.eclipse.jdt.core_xxxxxx.jar 文件本身,您将获得与当前 eclipse 版本完全相同的编译器!瞧!通过这种方式,您可以确定如果 eclipse 编写了一个“好”的代码 - ant 也可以。


所以最后一切都导致了两个简单的步骤:

  1. 将 org.eclipse.jdt.core_xxxxxx.jar 和 jdtCompilerAdapter.jar 从其中复制到您的 ant/lib 文件夹。

  2. 将以下内容添加到您的 project.properties 文件中:

    • java.target=1.6
    • java.source=1.6
    • build.compiler=org.eclipse.jdt.core.JDTCompilerAdapter

就这样!

但是,如果您知道为什么来自 eclipse juno 包(4.2.2)的 ecj 无法编译正确的代码,我想听听!

于 2013-03-02T00:12:41.827 回答