Harry Zhang
Harry Zhang

Reputation: 91

how can i use jectpack datastore in okhttp Interceptor? it need a context object

i wanna add a token to request headers in Interceptor . but now i dont now what should i do.

here is my datastore


val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")

class SettingsManager(context: Context) {
    private val dataStore = context.dataStore

    val getToken = dataStore.data
        .catch {
            if (it is IOException) {
                it.printStackTrace()
                emit(emptyPreferences())
            } else {
                throw it
            }
        }.map { preference ->
            preference[token] ?: ""
        }

    suspend fun setToken(tokenStr: String) {
        dataStore.edit { preferences ->
            preferences[token] = tokenStr
        }
    }

    companion object {
        val token = stringPreferencesKey("token")
    }
}

i can not get the context object in Interceptor 。

so i try to use hilt to fix it

class RequestInterceptor(private val settingsManager: SettingsManager) : Interceptor {

    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        runBlocking {
            val first = settingsManager.getToken.first()
            LogUtil.i("token " + first)
            request.newBuilder().addHeader("token", first).build();
        }
        return chain.proceed(request)
    }
}

i dont know the next step @AndroidEntryPoint cant use on Interceptor class .

plz guys , give me some solutions

Upvotes: 9

Views: 1635

Answers (3)

Antonio Guerra
Antonio Guerra

Reputation: 145

This works for me

    override fun intercept(chain: Interceptor.Chain): Response {
    return runBlocking {
        val token = dataStorePreferences.getAuthToken().first()
        val request = chain.request().newBuilder().addHeader(AUTHORIZATION_HEADER, "$BEARER $token").build()
        val response = chain.proceed(request)
        if (response.code == UNAUTHORIZED_CODE) {
            try {
                dataStorePreferences.setAuthToken(token)
                chain.proceed(request.newBuilder().addHeader(AUTHORIZATION_HEADER, "$BEARER $token").build())
            } catch (exeption: Exception) {
                dataStorePreferences.setAuthToken("")
                response
            }
        } else {
            response
        }
    }
}

Upvotes: 1

Prabudda Fernando
Prabudda Fernando

Reputation: 509

I just used this way.

  suspend fun getToken() : String? {
    val preference = dataStore.data.first()
    return preference[PREF_JWT_TOKEN]
} // this is inside the datastore local repository.

and inside the intercepter you can get runBlocking UI as this.

val builder = Retrofit.Builder()
        .baseUrl(Constants.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
    val client = OkHttpClient.Builder()
        .addInterceptor { chain ->
            val original = chain.request()
            var token: String? = null
            runBlocking {
                token = dataStorePreferenceRepository.getToken()
                if (!token.isNullOrEmpty()) {
                    val authorized = original.newBuilder()
                        .addHeader("Authorization", "Bearer $token")
                        .build()
                    chain.proceed(authorized)
                } else {
                    chain.proceed(original)
                }
            }
        }.addNetworkInterceptor(StethoInterceptor()).build()
    return builder.client(client).build().create(ApiInterface::class.java)

and inside the Module class use like this.

@Module                                                                                                            
@InstallIn(SingletonComponent::class)                                                                              
object AppModule {                                                                                                 
                                                                                                                   
                                                                                                                   
    @Provides                                                                                                      
    @Singleton                                                                                                     
    fun getDataStorePreferenceRepository(@ApplicationContext appContext: Context): DataStorePreferenceRepository { 
        return DataStorePreferenceRepository(context = appContext)                                                 
    }                                                                                                              
                                                                                                               }

Upvotes: 4

Barry Irvine
Barry Irvine

Reputation: 13887

You should be able to see it in Hilt if you just add the @Inject constructor to your RequestInterceptor.

E.g.

class RequestInterceptor @Inject constructor(private val settingsManager: SettingsManager) : Interceptor {...

And I'm not sure if you can do your SettingsManager like that but you can try class SettingsManager @Inject constructor(@ApplicationContext context: Context) {

Upvotes: 1

Related Questions