Search code examples
javaandroiddagger-2androidinjector

how to provide dynamic String such as ( server response ) in module?


i recently used from New Android Injector with Dagger 2 in my project and i have an issue : i want provide a dynamic String with dagger and i don't know how do this; i receive a token from server and need to pass this as field to and instance of OkHttp3CookieHelper; how should i do this ?

i tried to pass this String into Module Constructor but i think this is not true! i think maybe should use from @BindsInstance !! please help ;)

this is my AppModule :

@Module(subcomponents = {MainActivityComponent.class})
    public class AppModule {

    private String cookie ;

    public AppModule(String Cookie){
        this.cookie = Cookie;
    }

    @Singleton
    @Provides
    Context provideContext(Application application) {
        return application;
    }

    @Singleton
    @Provides
    OkHttp3CookieHelper provideCookie(@Named("baseURL") String baseURL,
                                      @Named("csrfToken") String csrfToken) {
        OkHttp3CookieHelper cookieHelper = new OkHttp3CookieHelper();
        cookieHelper.setCookie(baseURL, csrfToken, cookie);
        return cookieHelper;
    }
    @Singleton
    @Provides
    OkHttpClient.Builder provideOkHttp(HttpLoggingInterceptor interceptor,
                                       OkHttp3CookieHelper cookieHelper) {
        final OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.connectTimeout(8, TimeUnit.SECONDS);
        httpClient.readTimeout(8, TimeUnit.SECONDS);
        httpClient.callTimeout(8, TimeUnit.SECONDS);
        httpClient.cookieJar(cookieHelper.cookieJar());
        httpClient.addInterceptor(interceptor);
        return httpClient;
    }
    @Singleton
    @Provides
    HttpLoggingInterceptor provideHttpInterceptor() {
        final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        return interceptor;
    }
    @Singleton
    @Provides
    GsonConverterFactory provideGsonConverterFactory() {
        return GsonConverterFactory.create();
    }
    @Singleton
    @Provides
    @Named("baseURL")
    String provideBaseURL() {
        return Const.BASE_URL;
    }
    @Singleton
    @Provides
    @Named("csrfToken")
    String provideCrfToken() {
        return Const.CRF_TOKEN;
    }
    @Singleton
    @Provides
    Api provideApi(Retrofit retrofit) {
        return retrofit.create(Api.class);
    }
    @Singleton
    @Provides
    Retrofit provideRetrofit(GsonConverterFactory converterFactory, OkHttpClient.Builder httpClient,
                             @Named("baseURL") String baseURL) {
        return new Retrofit.Builder().baseUrl(baseURL)
                                     .addConverterFactory(converterFactory)
                                     .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                                     .client(httpClient.build())
                                     .build();
    }
    @Singleton
    @Provides
    SharedPreferences provideSharedPreference(Context context) {
        return context.getSharedPreferences("myShp", Context.MODE_PRIVATE);
    }

    //and this is my AppComponent : 

       @Singleton
       @Component(modules = {AndroidInjectionModule.class, ActivityBuilder.class, AppModule.class, 
                 ViewModelFactoryModule.class})
       public interface AppComponent {
         @Component.Builder
         interface Builder {
         @BindsInstance
         Builder application(Application application);
         AppComponent build();
         }

      void inject(App app);
}

issue : dagger could not create instance from AppModule !


Solution

  • finally and after about 10 hours searching and read some articles i solved my issue:D

    NOTICE !

    no need to pass your response token by yourself also no need to bind dependency(in this case response token)into AppComponent but if u want to do this u can use @Component.Builder or @Component.Factory that u can use this useful article : Dagger2: @Component.Factory and @SubComponent.Factory

    But to solve issue:

    first should add this dependency to app.gradle file :

    implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
    

    then provide instance of PersistentCookieJar in appMoule class and pass to our OkHttpClient instance:

    @Singleton
    @Provides
    PersistentCookieJar ProvideCookieJar(Context context) {
        return new PersistentCookieJar(new SetCookieCache(),
                                       new SharedPrefsCookiePersistor(context));
    }
    
    @Singleton
    @Provides
    OkHttpClient.Builder provideOkHttp(HttpLoggingInterceptor interceptor,
                                       PersistentCookieJar persistentCookieJar) {
        final OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
        httpClient.connectTimeout(8, TimeUnit.SECONDS);
        httpClient.readTimeout(8, TimeUnit.SECONDS);
        httpClient.callTimeout(8, TimeUnit.SECONDS);
        httpClient.cookieJar(persistentCookieJar);
        httpClient.addInterceptor(interceptor);
        return httpClient;
    }
    

    don't forget to provide Context that need to create PersistentCookieJar instance :

    @Provides
    @Singleton
    Context provideContext(Application application) {
        return application;
    }
    

    and in your Appication class should bind your application class :

    DaggerAppComponent.builder()
                          .application(this)
                          .build()
                          .inject(this);
    

    and your AppComponent Shoud be like this :

    @Singleton
    @Component(modules = {AndroidInjectionModule.class, ActivityBuilder.class, 
                          AppModule.class, ViewModelFactoryModule.class})
    public interface AppComponent {
       @Component.Builder
       interface Builder {
          @BindsInstance
          Builder application(Application application);
          AppComponent build();
       }
     
      void inject(App app);
    }
    

    OK every thing Done ! now your request contain cookie and successfully can get server Response :)