android - 如何使用 Dagger 柄向网络模块添加 retrofit 基本身份验证?

标签 android kotlin retrofit retrofit2 dagger-hilt

我是 Kotlin 的新手,我正在使用 Dagger 柄来编写干净的代码。

除了登录请求,我需要在所有请求中进行基本身份验证,因为 token 来自。登录请求。

我的问题是除了登录使用带有 Dagger 柄的基本身份验证之外,我该如何完成我的所有请求?

我的模块对象是这样的:

请提供任何建议或示例代码:)

@Module
@InstallIn(ApplicationComponent::class)
object NetworkingModule {

    @Provides
    fun providesBaseUrl(): String {
        return NetworkingConstants.BASE_URL
    }

    @Provides
    fun providesLoggingInterceptor(): HttpLoggingInterceptor {
        return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
    }

    @Provides
    fun provideOkHttpClient(loggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
        val okHttpClient = OkHttpClient().newBuilder()

        okHttpClient.callTimeout(40, TimeUnit.SECONDS)
        okHttpClient.connectTimeout(40, TimeUnit.SECONDS)
        okHttpClient.readTimeout(40, TimeUnit.SECONDS)
        okHttpClient.writeTimeout(40, TimeUnit.SECONDS)
        okHttpClient.addInterceptor(loggingInterceptor)
        okHttpClient.build()
        return okHttpClient.build()
    }

    @Provides
    fun provideConverterFactory(): Converter.Factory {
        return GsonConverterFactory.create()
    }

    @Provides
    fun provideRetrofitClient(okHttpClient: OkHttpClient, baseUrl: String, converterFactory: Converter.Factory): Retrofit {
        return Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addConverterFactory(converterFactory)
            .build()
    }

    @Provides
    fun provideRestApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

我想我应该使用 BasicAuthInterceptor 但我怎样才能将它添加到 hilt 模块?

最佳答案

如果您需要为其他一些请求添加另一个拦截器,这意味着您需要提供相同类型的不同实现(多个绑定(bind))

要告诉 Hilt 如何提供同一类型的不同实现(多个绑定(bind)),您可以使用限定符。

A qualifier is an annotation used to identify a binding. If you need to add another interceptor by implementing Intercepor interface, you can use the @Binds annotation on a function inside a Hilt module. But... you need to create another module for using @Binds.

Hilt Modules cannot contain both non-static and abstract binding methods, so you cannot place @Binds and @Provides annotations in the same class.

所以你的代码应该是这样的:

//首先:在 NetworkingModule 中为两种类型的 OkHttpClient 和两种不同的 retrofitClient 定义四个限定符:

        @Module
        @InstallIn(ApplicationComponent::class)
        object NetworkingModule {
            //FIRST: define four qualifiers in the NetworkingMoule
            @Qualifier  // define qualifier for LoginRetrofitClient
            @Retention(AnnotationRetention.BINARY)
            annotation class LoginRetrofitClient
    
            @Qualifier // define qualifier for OtherRetrofitClient
            @Retention(AnnotationRetention.BINARY)
            annotation class OtherRetrofitClient
    
            @Qualifier  // define qualifier for LoginOkHttpClient
            @Retention(AnnotationRetention.BINARY)
            annotation class LoginOkHttpClient
    
            @Qualifier // define qualifier for OtherOkHttpClient
            @Retention(AnnotationRetention.BINARY)
            annotation class OtherOkHttpClient
    
    
            @Provides
            fun providesBaseUrl(): String {
            return NetworkingConstants.BASE_URL
            }
    
            // make sure add qualifier for LoginRetrofitClient
            @LoggingInterceptor
            @Provides
            fun providesLoggingInterceptor(): HttpLoggingInterceptor {
            return HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
            }
    
            // add @LoginOkHttpClient for providerOkHttpClient which we add AuthBasicInterceptorto to
            @LoginOkHttpClient
            @Provides
            fun provideOkHttpClient(authBasicInterceptor: AuthBasicInterceptor): OkHttpClient {
            val okHttpClient = OkHttpClient().newBuilder()
    
            okHttpClient.callTimeout(40, TimeUnit.SECONDS)
            okHttpClient.connectTimeout(40, TimeUnit.SECONDS)
            okHttpClient.readTimeout(40, TimeUnit.SECONDS)
            okHttpClient.writeTimeout(40, TimeUnit.SECONDS)
            okHttpClient.addInterceptor(authBasicInterceptor)
            okHttpClient.build()
            return okHttpClient.build()
            }
    
            // add @OtherOkHttpClient for providerOkHttpClient which we add loggingInterceptor to
            @OtherOkHttpClient
            @Provides
            fun provideOkHttpClient(loggingInterceptor: HttpLoggingInterceptor): OkHttpClient {
            val okHttpClient = OkHttpClient().newBuilder()
    
            okHttpClient.callTimeout(40, TimeUnit.SECONDS)
            okHttpClient.connectTimeout(40, TimeUnit.SECONDS)
            okHttpClient.readTimeout(40, TimeUnit.SECONDS)
            okHttpClient.writeTimeout(40, TimeUnit.SECONDS)
            okHttpClient.addInterceptor(loggingInterceptor)
            okHttpClient.build()
            return okHttpClient.build()
            }
    
            @Provides
            fun provideConverterFactory(): Converter.Factory {
            return GsonConverterFactory.create()
            }
    
            // make sure add qualifier for LoginRetrofitClient
            @LoginRetrofitClient
            @Provides
            fun provideRetrofitClient(@LoginOkHttpClient okHttpClient: OkHttpClient,  // Remember to add @LoginOkHttpClient qualifier to distinguish OkHttpClient dependencies
            baseUrl: String, converterFactory: Converter.Factory): Retrofit {
            return Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addConverterFactory(converterFactory)
            .build()
            }
    
    
            @OtherRetrofitClient
            @Provides
            fun provideRetrofitClient(@OtherOkHttpClient okHttpClient: OkHttpClient, // Remember to add @OtherOkHttpClient qualifier to distinguish OkHttpClient dependencies
            baseUrl: String,
            converterFactory: Converter.Factory): Retrofit {
            return Retrofit.Builder()
            .baseUrl(baseUrl)
            .client(okHttpClient)
            .addConverterFactory(converterFactory)
            .build()
            }
    
           // also you need different flavors of ApiService by defining two more qualifiers for different retrofitClients which I commented that for simplicity
           // @Provides
            //fun provideRestApiService(retrofit: Retrofit): ApiService {
           // return retrofit.create(ApiService::class.java)
           // }
    
    
            }

现在我们需要添加AuthBasicInterceptor,我们需要创建一个名为AuthInterceptorModule.kt的新模块并添加一个 将 Interceptor 类型的 bindAuthInterceptor 函数抽象到它。

AuthInterceptorModule.kt

    
    @InstallIn(ApplicationComponent::class)
      @Module
      abstract class AuthInterceptorModule {
    
            @Binds
            abstract fun bindAuthInterceptor(basicAuthInterceptor: AuthBasicInterceptor): Interceptor
            }

并创建另一个名为 AuthBasicInterceptor.kt 的类实现拦截器:

            class AuthBasicInterceptor @Inject constructor() : Interceptor {
            ...
            }
    

就是这样,一切就绪。现在您可以将 retrofitClients 注入(inject)其他类,例如:

        @AndroidEntryPoint
        class MainActivity : AppCompatActivity() {

        @LoginRetrofitClient
        @Inject lateinit var loginRetrofit: Retrofit

        @OtherRetrofitClient
        @Inject lateinit var otherRetrofit: Retrofit

        override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

       ...
        }

        ...
        }

关于android - 如何使用 Dagger 柄向网络模块添加 retrofit 基本身份验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63115678/

相关文章:

android - 改造 - @Body 参数不能与表单或多部分编码一起使用。 (参数#1)

Android以最有效的方式将图片上传到服务器

android - 移动 videoView...使用平移动画

android - 在 android 中使用 Lame 库从 wav 转换 .mp3

unit-testing - 我应该重新实现基于属性的测试中的逻辑吗?

android - 改造 SocketTimeoutException - 上传图像

c# - 安卓 Xamarin C# : app runs in emulator but in actual device gets error: [INSTALL_PARSE_FAILED_BAD_MANIFEST]

java - tornadoFX 切换按钮没有文本属性

spring-boot - Spring Boot + Kotlin + Gradle - 错误 : Main method not found in class

android - 如何在Android中检查Retrofit API调用是否成功