尝试使用Ant构建Android应用时,抛出ExceptionWithContext异常。

26

我尝试过在Google和stackoverflow上搜索答案,但无法找到与我遇到的完全相同的问题。 我正在尝试设置一个持续集成服务器(具体来说是Bamboo),以便在源代码控制中有更改时每次都更新、构建和导出APK。 我在本地机器上手动执行每个步骤时,以及使用我设置的作业时,在服务器上遇到相同的错误。 当我到达构建的dex步骤时,错误就会发生。 到目前为止,我使用ant debugant releaseant clean debugant clean release都得到了相同的输出。 包括错误的整个dex步骤的输出如下:

-dex:
      [dex] input: C:\Users\...\Android\bin\classes
      [dex] input: C:\Users\...\google-play-services_lib\bin\classes.jar
      [dex] input: C:\Program Files (x86)\Android\android-sdk\tools\support\annotations.jar
      [dex] input: C:\Users\...\Android\libs\FlurryAgent.jar
      [dex] input: C:\Users\...\Android\libs\gcm.jar
      [dex] input: C:\Users\...\Android\libs\android-support-v4.jar
      [dex] input: C:\Users\...\google-play-services_lib\libs\google-play-services.jar
      [dex] Pre-Dexing C:\Users\...\google-play-services_lib\bin\classes.jar -> classes-64c0adfe92ddc950c7ab8c5002ceabf2.jar
      [dex] Pre-Dexing C:\Program Files (x86)\Android\android-sdk\tools\support\annotations.jar -> annotations-62bab95d6948a2db17bbc7976160b014.jar
      [dex] Pre-Dexing C:\Users\...\Android\libs\FlurryAgent.jar -> FlurryAgent-499d43756a3ce626a64773e6dfd5eaec.jar
      [dex] Pre-Dexing C:\Users\...\Android\libs\gcm.jar -> gcm-ae2640f44640eb4fd7b13964b65d2d70.jar
      [dex] Pre-Dexing C:\Users\...\Android\libs\android-support-v4.jar -> android-support-v4-fa30b373a3e3ba9f2cf94900a9eb42fe.jar
      [dex] Pre-Dexing C:\Users\...\google-play-services_lib\libs\google-play-services.jar -> google-play-services-9efad6e9178399c185fae6c0b6bdc4c6.jar
      [dex] Converting compiled files and external libraries into C:\Users\...\Android\bin\classes.dex...
       [dx]
       [dx] UNEXPECTED TOP-LEVEL EXCEPTION:
       [dx] com.android.dx.util.ExceptionWithContext
       [dx]     at com.android.dx.util.ExceptionWithContext.withContext(ExceptionWithContext.java:46)
       [dx]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:344)
       [dx]     at com.android.dx.dex.cf.CfTranslator.translate0(CfTranslator.java:134)
       [dx]     at com.android.dx.dex.cf.CfTranslator.translate(CfTranslator.java:87)
       [dx]     at com.android.dx.command.dexer.Main.processClass(Main.java:487)
       [dx]     at com.android.dx.command.dexer.Main.processFileBytes(Main.java:459)
       [dx]     at com.android.dx.command.dexer.Main.access$400(Main.java:67)
       [dx]     at com.android.dx.command.dexer.Main$1.processFileBytes(Main.java:398)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:135)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processDirectory(ClassPathOpener.java:191)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:123)
       [dx]     at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:109)
       [dx]     at com.android.dx.command.dexer.Main.processOne(Main.java:422)
       [dx]     at com.android.dx.command.dexer.Main.processAllFiles(Main.java:333)
       [dx]     at com.android.dx.command.dexer.Main.run(Main.java:209)
       [dx]     at com.android.dx.command.dexer.Main.main(Main.java:174)
       [dx]     at com.android.dx.command.Main.main(Main.java:91)
       [dx] Caused by: java.lang.NullPointerException
       [dx]     at com.android.dx.cf.code.ConcreteMethod.<init>(ConcreteMethod.java:87)
       [dx]     at com.android.dx.cf.code.ConcreteMethod.<init>(ConcreteMethod.java:75)
       [dx]     at com.android.dx.dex.cf.CfTranslator.processMethods(CfTranslator.java:247)
       [dx]     ... 23 more
       [dx] ...while processing <init> (Lcom/.../android/LocationService;)V
       [dx] ...while processing com/.../android/LocationService$1.class
       [dx]
       [dx] 1 error; aborting

为了背景,我正在Windows机器上使用Ant v1.9.2和Android build-tools v18.0.1,没有对构建脚本进行任何修改。我在应用程序的目录和库的目录中分别使用android update project --path . 为其生成一个构建文件。我还没有尝试设置自动使用正确的密钥库进行签名,尽管据我(有限)的理解,这对于使用Ant进行调试构建来说不是必需的。

有人看到过这个特定的问题吗?它是生成的.class文件的问题吗?还是构建文件的问题?这是我第一次真正尝试使用Ant进行构建(通常我只让Eclipse替我做所有的重活),所以我几乎没有任何线索。任何帮助都将不胜感激。

更新:如果有人关注这个问题,那么我的问题似乎已经解决了。怎么解决的,为什么解决的,我不知道。今天早上我尝试更新源代码(我们有一些更改),重新运行了android update project -p .,尝试了ant clean debug,然后就奇迹般地工作了。甚至ant release也起作用了,它甚至使用我给它的密钥正确地签名了它。我的最佳猜测是LocationService类文件中有一些奇怪的东西,尽管我不知道是什么。

更新2:我在第一个更新中说的任何话现在都已经无效了。我已经确定了问题,但仍然无法理解它。这段代码是罪魁祸首:

if (Settings.DEBUG) {
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
            storeDebugNotification(AndroidUncaughtExceptionHandler.getStackTraceString(ex));
        }
    });
}

事情变得有点奇怪。当 Settings.DEBUG 标志为 true 时,使用 ant 构建没有问题。当它为 false 时,会失败,并显示上面的错误。当我将整个内容注释掉时,两种 DEBUG 设置都能正常工作。同样,对于将 if (Settings.DEBUG) 行及其大括号注释掉但保留主体,以及注释掉主体并仅保留 if 部分也是如此。所以……我不知道该怎么办了。在这个特定文件中,当 DEBUG 为 false 时,if 语句和主体之间的交互会导致问题。另一个奇怪的部分是,在应用程序的另一个文件中(活动文件,而不是服务文件),我们有相同的 if 块。


你使用的是哪个版本的构建工具?我在Mac上使用的是构建工具18.0.1和ant 1.8.4,没有出现错误。 - Varun
我正在使用版本为18.0.1的构建工具,并在Windows机器上进行此操作。我将更新问题以包含该信息。 - Alex
可以尝试创建一个"hello world"程序,并使用Ant构建它。 - Varun
一个简单的“Hello World”应用程序已经运行。我在Eclipse中创建了一个新项目(有趣的是,它为您创建的默认活动只显示“Hello World!”),并通过相同的过程运行它(android update project path -- .ant clean debug)。构建成功,我能够在我的手机上安装和运行它,没有任何问题。 - Alex
可能是一个重复的问题,参考链接:https://dev59.com/hnTYa4cB1Zd3GeqPpwRF - Nick Caballero
3个回答

39

编译项目以进行发布时,我遇到了同样的异常。我的代码是:

if (BuildConfig.DEBUG) {
    myView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // Do something
        }
    });
}

由于 BuildConfig.DEBUG 是一个常量且值为 false,所以该块中的代码被识别为 死代码 并在进行优化时被移除。

CfTranslator(类文件转换器)想要为块内部的 匿名类 创建一个单独的文件(SomeClass$1.class),但由于其被优化掉了,会导致错误发生。我将匿名类移到花括号外面,问题就解决了:

View.OnClickListener lClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Do something
    }
};

if (BuildConfig.DEBUG) {
    myView.setOnClickListener(lClickListener);
}

更新:解决此问题的另一种方法(由下面@Ewoks所述)是:

public boolean isInDeveloperMode() {
    return BuildConfig.DEBUG;
}

...

if (isInDeveloperMode()) {
    myView.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            // Do something
        }
    });
}

2
这是一个非常有说服力的解释,我真的很想接受它作为答案,但仍有一部分没有解释清楚。在一个单独的文件中,我们有完全相同的代码块(将处理程序设置为Settings.DEBUG条件下的匿名类实现),尽管uncaughtException()覆盖的主体略有不同,但那个代码块并没有引起任何问题。你能想到任何原因为什么一个可以工作而另一个不能? - Alex
2
也适用于我。奇怪的是,在 Gradle 2.1 之前,这对我来说从来没有成为问题。 - MinceMan
太棒了。对我有用。 - Eidan Spiegel
我在想是否是Gradle 2.1的问题,但我们在其他地方有完全相同类型的块,而且那里都没问题,唯一不同的是具有内联方法的组件是第三方库Apptimize,因此其中可能会引发异常。 - JPM
我的代码中没有BuildConfig.DEBUG,而且类和方法都是公共的!问题仍然存在。 - Dr.jacky
显示剩余2条评论

10

在经过数月对这个问题的斗争之后,我终于找到了适合我的解决方案。这可能不是你的情况。请确保您引用的所有类(也许是Settings?也许是AndroidUncaughtExceptionHandler?)都不是私有的。Gradle 无法处理它并且无法在类中找到该方法。只需将其更改为公共的(或者只需删除标志以保持默认值,如果类是嵌套的),您就可以继续前进了。


你的答案救了我的命。请参见 https://dev59.com/r5Dea4cB1Zd3GeqPhdzJ#33631228。 - Tomcat
类和方法都是公共的,但问题仍然存在! - Dr.jacky

2
除了@Albert-Jan提出的解决方案外,另一种解决方法是将该常量包装在一个方法中。类似于以下内容:
``` public boolean isInDeveloperMode(){ return BuildConfig.DEBUG; } ```
这样做的话,gradle不会将其“解析”为常量,在构建时也不会出现问题。
可能这种方法最著名的“漏洞”是Android SDK中UserManager类中的isUserAGoat()方法。这里有非常流行的讨论,讨论了此方法的可能用途。享受吧 ;)
希望这对有类似问题的人有所帮助。

2
我有一个类似的常量,这样做解决了问题。谢谢。 - jsstp24n5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接