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 делать всю тяжелую работу за меня), так что у меня очень мало работы. Любая помощь приветствуется.

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


person Alex    schedule 28.08.2013    source источник
comment
Какую версию инструментов сборки вы используете? Я использую инструменты сборки 18.0.1. и ant 1.8.4 на mac и не получаю ошибок   -  person Varun    schedule 29.08.2013
comment
Я использую инструменты сборки версии 18.0.1 и делаю это на компьютере с Windows. Я обновлю вопрос, чтобы включить эту информацию.   -  person Alex    schedule 29.08.2013
comment
Может быть, просто создайте приветственный мир и попробуйте построить его с помощью муравья.   -  person Varun    schedule 29.08.2013
comment
Работало простое приложение Hello World. Я создал новый проект в Eclipse (как ни странно, действие по умолчанию, которое он создает для вас, просто отображает «Hello World!») и выполнил ту же процедуру (android update project path -- . и ant clean debug). Сборка прошла успешно, и я смог без проблем установить и запустить ее на своем телефоне.   -  person Alex    schedule 29.08.2013
comment
Возможно, дубликат stackoverflow.com/questions/17437430/   -  person Nick Caballero    schedule 10.01.2014


Ответы (3)


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

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
        }
    });
}
person Albert-Jan Verhees    schedule 25.02.2014
comment
Это очень убедительное объяснение, и я действительно хочу принять его как ответ, но кое-что осталось необъясненным. В отдельном файле у нас есть точно такой же блок кода (настройка обработчика на реализацию анонимного класса в условном выражении Settings.DEBUG), хотя и с немного другим телом для переопределения uncaughtException(), и это не вызывает никаких проблем. Можете ли вы придумать какую-либо причину, по которой один будет работать, а другой нет? - person Alex; 05.03.2014
comment
Работал и для меня. Странно то, что для меня это не было проблемой до Gradle 2.1. - person MinceMan; 03.10.2014
comment
вау, это было именно для меня - класс Anonymous за if(BuildConfig.DEBUG). с помощью плагина Android Gradle 1.0.1 - person rymo; 26.01.2015
comment
Потрясающий. Работал на меня. - person Eidan Spiegel; 01.11.2015
comment
Интересно, это gradle 2.1, но у нас есть блок точно такого же типа в других, и там все в порядке, за исключением того, что компонент, который имеет встроенный метод, является сторонней библиотекой, Apptimize, поэтому что-то там может вызвать исключение. - person JPM; 25.04.2016
comment
У меня в коде такого BuildConfig.DEBUG нет, и класс, и метод общедоступны! Проблема все еще существует. - person Dr.jacky; 08.08.2016
comment
@Mr.Hyde: ошибка возникает, если вы инициализируете анонимный класс в блоке кода, который удаляется в результате оптимизации. Константа, такая как BuildConfig.DEBUG, установленная в false в операторе if, является лишь одним из примеров. Объем классов и методов не имеет к этому никакого отношения. Если у вас есть возможность поделиться своим кодом, каждый здесь может присмотреться. - person Albert-Jan Verhees; 24.08.2016

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

person Johny_G    schedule 17.01.2014
comment
Ваш ответ спас мне жизнь. См. stackoverflow.com/a/33631228/576442. - person Tomcat; 10.11.2015
comment
И класс, и метод общедоступны, но проблема все еще существует! - person Dr.jacky; 08.08.2016

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

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

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

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

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

person Ewoks    schedule 21.07.2015
comment
У меня была аналогичная константа, и это решило проблему. Спасибо. - person jsstp24n5; 26.07.2015