Dagger не може да създаде обектна графика, въпреки че може да създаде точков файл

Затруднявам се с настройката на Dagger (1.0.1) в съществуващо приложение. Беше конфигуриран да използва ProGuard, но аз го деактивирах за този тест с -dontobfuscate.

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

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 се показват в генерирания файл с точки, така че според този коментар Очаквах това да работи. AFAIK, ако има нещо нередно, то трябва да бъде открито от активираната от компилатора компилация, която използвах за генериране на dot файла.


АКТУАЛИЗАЦИЯ:

Преди това го казах

В режим на отстраняване на грешки никога не се проваля

но всъщност не е вярно след допълнително тестване: В режим Debug не се проваля, защото ProGuard е деактивиран, докато в режим Release е активиран по подразбиране. Ако създам приложението в режим Release, но пропусна ProGuard, също не получавам грешките и приложението стартира успешно. Така че проблемът определено е свързан с моята конфигурация на ProGuard.


person David Santiago Turiño    schedule 07.08.2013    source източник
comment
Защо премахвате компилатора за режим на освобождаване? Компилаторът е предназначен да се използва за ускоряване на нещата, тъй като не трябва да се извършва обработка на анотация по време на изпълнение. За мен няма смисъл да карам приложението да работи по-бавно при пускане чрез премахване на компилатора на dagger.   -  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
Що се отнася до записа за запазване на имената за вашите собствени класове на приложения, досега ги сведох до два възможни сценария: 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
FYI: Това работи за 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 е деактивиран, така че трябва да прави тези неща по време на изпълнение, губейки печалбата от предварителната компилация. Това не изглежда да е така за мен :/ - person David Santiago Turiño; 07.08.2013
comment
Да - не би трябвало dagger да работи добре във всеки случай, ако компилаторът е деактивиран. От 1.0 (мисля, или 1.1) генерирането на код е задължително за модули (макар и не за @Inject класове). Опитваме се да се справим с това, като не съхраняваме изрично низове и сме малко по-умни в начина, по който управляваме това. Бъдете в крак с основния проект и скоро трябва да видите неща за него. - person Christian Gruber; 21.08.2013
comment
Хм, не очаквах това според последния коментар на Джеси в plus.google.com/117210567825404150882/posts /HGjnJJHbfMj -› Ако премахнете компилатора на dagger от вашата компилация, той трябва да е защитен от 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