1

I'm trying to create a RetrofitModule. I have an interceptor that adds dynamic headers using a AuthHeader object. I'm unsure how I can pass this object to the module class.

@Module
public class RetrofitModule {

    private static final String TAG = "RetrofitModule";


    //Do I create a constructor here for the RetrofitModule that accepts an AuthHeader object?
    
    @Provides
    @Singleton
    RequestInterceptor providesRequestInterceptor(@NonNull AuthHeader authHeader) {
        return new RequestInterceptor(authHeader);
    }

    @Provides
    @Singleton
    OkHttpClient.Builder provideOkHttp() {
        return new OkHttpClient.Builder();
    }

    @Provides
    @Singleton
    Retrofit provideRetrofit(OkHttpClient.Builder okHttpClient, RequestInterceptor requestInterceptor) {
        okHttpClient.addInterceptor(requestInterceptor);

        HttpLoggingInterceptor logging = new HttpLoggingInterceptor().setLevel(
                HttpLoggingInterceptor.Level.BASIC
        );
        okHttpClient.addInterceptor(logging);

        return new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .baseUrl(Constants.ENDPOINT)
                .client(okHttpClient.build())
                .build();
    }

    @Provides
    @Singleton
    LoginService provideLoginServer(Retrofit retrofit) {
        return retrofit.create(LoginService.class);
    }

}

This is the AuthHeader object I want to pass to the module so that I can add dynamic headers to the network call:

public class AuthHeader {
    private String idToken;
    private String idClient;
    private String idEmail;

    public AuthHeader(String idToken, String idClient, String idEmail) {
        this.idToken = idToken;
        this.idClient = idClient;
        this.idEmail = idEmail;
    }

    public String getIdToken() {
        return idToken;
    }

    public String getIdClient() {
        return idClient;
    }

    public String getIdEmail() {
        return idEmail;
    }
}
DIRTY DAVE
  • 2,523
  • 2
  • 20
  • 83
  • Is `AuthHeader` available when creating the component containing your module? – Alex Krupa Mar 09 '21 at 22:42
  • No it isnt. When I switch fragments I would have to call a method from GoogleSignIn which retrieves it from ```SharedPreferences``` I think – DIRTY DAVE Mar 09 '21 at 22:58

1 Answers1

1

based on your comment that you want to read the token from SharedPreferences, I provided a complete sample:

In addition to your code I've created AuthInfoProvider that can read and provide authentication info. It's used instead of passing an AuthHeader object.

class AuthInfoProvider {
    SharedPreferences preferences;

    public AuthInfoProvider(Context context) {
        preferences = context.getSharedPreferences("MyPreferences", Context.MODE_PRIVATE);
    }

    public String getToken() {
        return preferences.getString("MyToken", "");
    }
}

pass the AuthInfoProvider to interceptor:

It retrieves the token for each API call.

class RequestInterceptor implements Interceptor {
    private final AuthInfoProvider provider;

    public RequestInterceptor(AuthInfoProvider provider) {
        this.provider = provider;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
           Request request = chain.request().newBuilder()
                .addHeader("Authentication", provider.getToken())
                .build();
           return chain.proceed(request);
    }
}

Now we should pass it to our module

@Module
public class RetrofitModule {

    private static final String TAG = "RetrofitModule";

    @Provides
    @Singleton
    public static AuthInfoProvider providesAuthInfoProvider(Context context) {
        return new AuthInfoProvider(context);
    }

    @Provides
    @Singleton
    public static RequestInterceptor providesRequestInterceptor(@NonNull AuthInfoProvider authInfoProvider) {
        return new RequestInterceptor(authInfoProvider);
    }

    // other your methods
    // just make them static

}

and the component will be like:

@Singleton
@Component(modules = RetrofitModule.class)
interface NetworkComponent {

    @Component.Builder
    interface Builder {
        Builder bindContext(@BindsInstance Context context);

        NetworkComponent build();
    }

    void inject(SampleFragment fragment);
}

and pass context to component and build it like this:

DaggerNetworkComponent.builder()
        .bindContext(getContext())
        .build()
        .inject(this);
beigirad
  • 4,986
  • 2
  • 29
  • 52