Подтвердить что ты не робот

ExceptionWithContext получает бросок при попытке создать приложение для Android с помощью Ant

Я пробовал искать как в Google, так и в stackoverflow для ответа на этот вопрос, но я не смог найти никого с точной проблемой, с которой я столкнулся. Я пытаюсь настроить сервер непрерывной интеграции (Bamboo, в частности) для обновления, сборки и экспорта APK каждый раз, когда кто-то вносит изменения в управление источником. Я сталкиваюсь с той же ошибкой, что и на моей локальной машине, когда я делаю каждый шаг за шагом и на сервере, когда я использую задание, которое я создал. Ошибка возникает, когда я достигаю шаг dex сборки. До сих пор я получал тот же результат с ant debug, ant release, ant clean debug и ant 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

В контексте я использую Ant v1.9.2 и Android-инструменты v18.0.1 на компьютере под управлением Windows, и я никак не редактировал сценарии сборки. Я создал один для приложения и один для библиотеки, используя android update project --path . в своих двух каталогах. Я также не пробовал настраивать его для автоматического использования правильного хранилища ключей для подписания, хотя для моего (ограниченного) понимания, которое не должно быть необходимым, по крайней мере, не для сборки отладки с Ant.

Кто-нибудь видел эту проблему раньше? Это проблема с созданным файлом .class? Файлы сборки? Это мой первый реальный набег на создание с помощью Ant (я обычно просто позволяю Eclipse делать всю тяжелую работу для меня), поэтому мне очень мало идти дальше. Любая помощь будет высоко оценена.

Обновление: Если кто-то обратил внимание на этот вопрос, мой вопрос, похоже, разрешился. Как и почему, я не знаю. Я попробовал обновить источник сегодня утром (у нас было несколько изменений), reran 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. Итак... Я здесь в недоумении. Что-то о взаимодействии между оператором if и телом в этом конкретном файле, когда DEBUG является ложным, вызывает проблемы. И другая странная часть состоит в том, что мы имеем то же самое, если блок в другом файле в приложении (действие, тогда как это - сервис).

4b9b3361

Ответ 1

У меня было то же исключение при компиляции проекта для выпуска. Мой код:

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

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

Поскольку BuildConfig.DEBUG является константой со значением false, код в блоке распознается как мертвый код и удаляется при оптимизации.

CfTranslator (Classfile Translator) хочет создать отдельный файл для анонимного класса внутри блока (класс 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

После нескольких месяцев борьбы с этой точной проблемой я наконец нашел решение, которое работает для меня. Возможно, это не так. Убедитесь, что ни один из классов, на которые вы ссылаетесь (возможно, настройки? Может быть, AndroidUncaughtExceptionHandler?) Является закрытым. Gradle не может обработать его и не может найти метод внутри класса. Просто измените его на общедоступный (или просто удалите флаг, чтобы сохранить его по умолчанию, если класс вложен), и вам должно быть хорошо идти.

Ответ 3

Другим решением, чем предлагал @Albert-Jan, было бы "обернуть" эту константу в методе. Что-то вроде

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

и в этом случае он не будет "разрешен" как константный на gradle, и во время сборки не будет проблем.

Вероятно, самым известным "эксплойтом" этого подхода был бы isUserAGoat() метод из класса UserManager в Android SDK. очень популярная дискуссия здесь о возможных применениях этого метода. Наслаждайтесь;)

Надеюсь, это будет полезно для кого-то с подобными проблемами.