Dagger не может создавать граф объектов, хотя может создавать точечный файл

Я борюсь с настройкой Dagger (1.0.1) в существующем приложении. Он был настроен на использование ProGuard, но я отключил его для этого теста с помощью -dontobfuscate.

Когда я включаю dagger-compiler, он может успешно сгенерировать точечный файл с графом зависимостей, но когда я удаляю компилятор и создаю приложение в режиме выпуска, он падает во время запуска, жалуясь, что не может создать граф объектов.

java.lang.RuntimeException: Unable to start activity 
  ComponentInfo{com.corp.myapp/com.corp.myapp.ui.activity.MainActivity}: 
  java.lang.IllegalStateException: Errors creating object graph:

No injectable members on com.corp.myapp.core.services.ConnectionMonitor. Do 
  you want to add an injectable constructor? required by 
  com.corp.myapp.core.services.ConnectionMonitor 
  com.corp.myapp.ui.activity.MyAppBaseActivity.connectionManager

No injectable members on com.corp.myapp.ui.crouton.CroutonManager. Do you want 
  to add an injectable constructor? required by 
  com.corp.myapp.ui.crouton.CroutonManager 
  com.corp.myapp.ui.activity.MyAppBaseActivity.croutonManager

No injectable members on com.corp.core.assembler.ResourceAssembler. Do you want 
  to add an injectable constructor? required by 
  com.corp.core.assembler.ResourceAssembler 
  com.corp.myapp.ui.activity.MyAppBaseActivity.resourceAssembler

Я вижу MyAppBaseActivity и его зависимости с CroutonManager или ConnectionMonitor, отображаемыми в сгенерированном точечном файле, поэтому согласно этому комментарию Я ожидал, что это сработает. Насколько я знаю, если что-то было не так, это должно быть обнаружено сборкой с поддержкой компилятора, которую я использовал для создания файла точек.


ОБНОВЛЕНИЕ:

Я ранее заявлял, что

В режиме отладки никогда не происходит сбой

но это не совсем так после дальнейшего тестирования: в режиме Debug он не дает сбоев, потому что ProGuard отключен, тогда как в режиме Release он включен по умолчанию. Если я соберу приложение в режиме выпуска, но пропущу ProGuard, я также не получу ошибок и приложение успешно запустится. Так что проблема определенно связана с моей конфигурацией ProGuard.


person David Santiago Turiño    schedule 07.08.2013    source источник
comment
Почему вы удаляете компилятор для режима выпуска? Компилятор предназначен для ускорения работы, поскольку во время выполнения не требуется обработка аннотаций. Для меня нет смысла замедлять работу приложения в релизе, удаляя кинжал-компилятор.   -  person deekay    schedule 07.08.2013
comment
Да, я знаю, что компилятор обеспечивает такое улучшение производительности (помимо проверки графика во время компиляции). Я отключил его, потому что я также использую ProGuard, и, по словам ребят из Square, способ избежать проблем состоял в том, чтобы отключить компилятор и позволить Dagger генерировать весь необходимый код во время выполнения.   -  person David Santiago Turiño    schedule 07.08.2013


Ответы (4)


Dagger во многом полагается на отражение и имена классов, которые жестко закодированы и обрабатываются как строки. Это затрудняет сокращение/оптимизацию/обфускацию кода.

Следующая конфигурация работает для примера dagger/examples/simple в Dagger 1.1.0< /а>:

-keepattributes *Annotation*

-keepclassmembers,allowobfuscation class * {
    @javax.inject.* *;
    @dagger.* *;
    <init>();
}

-keep class **$$ModuleAdapter
-keep class **$$InjectAdapter
-keep class **$$StaticInjection

-keepnames !abstract class coffee.*

-keepnames class dagger.Lazy

В конфигурации сохраняются все поля и методы с аннотациями javax.inject или dagger, а также все конструкторы без параметров. В противном случае ProGuard может удалить их, если они кажутся неиспользуемыми, но Dagger на самом деле внедряет/доступ к ним посредством отражения. Это похоже на RoboGuice.

Он также должен хранить все классы адаптеров, сгенерированные Dagger.

Он также должен сохранить все имена классов, связанные с этими классами адаптеров, чтобы имена по-прежнему совпадали. В этом примере это почти все классы в пакете coffee, поэтому проще всего использовать подстановочный знак. Эта строка будет отличаться для других приложений.

Наконец, он также должен сохранить имя класса dagger.Lazy, так как его имя жестко запрограммировано в виде строки в сгенерированном коде.

person Eric Lafortune    schedule 11.08.2013
comment
Эрик, спасибо за исчерпывающий ответ! - person David Santiago Turiño; 10.09.2013
comment
Что касается записи keepnames для ваших собственных классов приложений, я сократил их до двух возможных сценариев: 1) всякий раз, когда вы добавляете какую-либо привязку к модулю Dagger для новой зависимости с помощью соответствующего метода ProvideXXX, необходимо добавить возвращаемый тип к конфигу. 2) Если у вас есть класс с аннотированным конструктором @Inject, который расширяет другой класс, еще не отфильтрованный в конфигурации ProGuard, этот базовый класс необходимо добавить в конфигурацию. - person David Santiago Turiño; 22.01.2014
comment
Дэвид, если я использую кинжал-компилятор, у меня сложилось впечатление, что он не должен использовать отражение. в этом случае, какие конфигурации я должен реализовать в своем файле proguard? - person superjugy; 14.02.2014
comment
Если, как и я, вы плохо знаете ProGuard и попытались скопировать вышеприведенное, добавление секунды * к coffee.* заставит его работать рекурсивно (coffee.** будет соответствовать coffee.gui.whatever). Мне потребовалось немного, чтобы понять. - person Torque; 17.05.2014

Приложение запустилось после добавления -dontshrink в файл конфигурации ProGuard. Иметь -dontobfuscate в начале было недостаточно.

На самом деле, если я уберу -dontobfuscate, это тоже сработает.

Мне определенно нужен более точный контроль для этого, но это отправная точка. Мои текущие настройки ProGuard для Dagger:

#############
#   Dagger  #
#############

-keep class dagger.** { *; }
-dontwarn dagger.internal.codegen.**
person David Santiago Turiño    schedule 07.08.2013
comment
К вашему сведению: это работает для dagger 1.0.1, но не для 1.1.0, где я получаю ошибку инициализации приложения, связанную с запутанным кодом при доступе к адаптерам модуля. - person David Santiago Turiño; 06.09.2013

Dagger не требует, чтобы @Inject был в классе для передачи в graph.inject(myActivity), потому что некоторые действия могут не иметь никаких внедрений. Однако они выглядят как восходящие зависимости, что означает, что они должны быть предоставлены ComponentInfo и, следовательно, должны быть предоставлены Dagger. Он не может этого сделать, если не может создать эти классы, и не может этого сделать, если они не аннотированы, если он не предоставляет их через метод @Provides.

Таким образом, вам нужно либо создать @Module-аннотированный класс, который возвращает эти типы из @Provides-аннотированных методов, либо вам нужно добавить @Inject в их конструктор.

-keep class * extends dagger.internal.Binding

Тем не менее, в этом случае вы используете proguard в режиме «релиз»? А не прогардить в режиме отладки? Если это так, я подозреваю, что Proguard удаляет аннотации. Вам нужно будет сделать какой-то вариант:

-keep class javax.inject.** { *; }

... чтобы Proguard не удалял аннотации.

person Christian Gruber    schedule 07.08.2013
comment
Кристиан. Я тестирую другие варианты конфигурации, пытаясь изолировать проблему, но пока единственный способ избежать сбоя приложения — это полностью пропустить ProGuard. Я подумаю о вашей рекомендации по конфигурации ProGuard, связанной с инъекцией, и обновлю вопрос, добавив более подробную информацию. Спасибо за ваш отзыв! - person David Santiago Turiño; 07.08.2013
comment
Кроме того, меня беспокоит тот факт, что Dagger должен нормально работать с ProGuard, если dagger-compiler отключен, поэтому он должен делать это во время выполнения, теряя прирост производительности от предварительной компиляции. Мне кажется, что это не так :/ - person David Santiago Turiño; 07.08.2013
comment
Ага, кинжал не должен нормально работать в любом случае, если компилятор отключен. Начиная с 1.0 (я думаю, или 1.1) генерация кода является обязательной для модулей (но не для классов @Inject). Мы пытаемся решить эту проблему, не сохраняя строки явно, и немного умнее в том, как мы с этим справляемся. Будьте в курсе основного проекта, и вскоре вы увидите материалы об этом. - person Christian Gruber; 21.08.2013
comment
Хм, я не ожидал этого, согласно последнему комментарию Джесси на plus.google.com/117210567825404150882/posts. /HGjnJJHbfMj -› Если вы удалите dagger-compiler из своей сборки, он должен быть безопасным для proguard. - person David Santiago Turiño; 06.09.2013

В итоге я прожёг неделю+, пытаясь заставить это работать. В конце концов я потерпел неудачу и решил попробовать DexGuard. Он прекрасно работал прямо из коробки. Да, это коммерческий продукт, но у DexGuard отличная поддержка, и благодаря этому мы наконец смогли выпустить его. Я определенно рекомендую DexGuard, если вам абсолютно необходимо решить эту проблему.

person Donn Felker    schedule 22.01.2014
comment
DexGuard написан одним и тем же парнем. Знаете в чем разница? Я думал, что они требуют одинаковой конфигурации, но DexGuard обеспечивает дополнительную оптимизацию и безопасность. - person tasomaniac; 30.12.2015