简体   繁体   中英

Accessing DataStore Preferences inside Retrofit client [HILT]

I'm injecting retrofit instances using HILT, now my problem is that I want to add an authorization token to the request with is stored in Data Store Preferences. I'm new to coroutines and hilt so I'm confused about how to do the same. Previously I used to get the token using shared preferences which was pretty straightforward.

AppModule.kt

@Module
@InstallIn(SingletonComponent::class)
object AppModule {

    @Provides
    fun provideRetrofit(@ApplicationContext context: Context, sessionManager: SessionManager): Retrofit {

        //sessionManager.getToken() cannot call this as it requires provideRetrofit() to be a suspend function 

        val builder = OkHttpClient.Builder()
        //This is to check the logs of api request
        val logging = HttpLoggingInterceptor()
        logging.setLevel(HttpLoggingInterceptor.Level.BODY)

        builder.writeTimeout(60, TimeUnit.SECONDS)
        builder.readTimeout(60, TimeUnit.SECONDS)
        builder.connectTimeout(60, TimeUnit.SECONDS)

        //create network interceptor

        //create network interceptor

        Log.d("TAG", "provideRetrofit: $token")

        builder.addNetworkInterceptor(Interceptor { chain: Interceptor.Chain ->
            val request = chain.request()
            chain.proceed(request).newBuilder()
                .header("Cache-Control", "public")
                .removeHeader("Pragma")
                .build()
        })

        //create offline interceptor


        builder.addInterceptor(Interceptor { chain: Interceptor.Chain ->
            var request = chain.request()

            if (!Tools.checkInternet(context)) {
                val maxStale = 60 * 60 * 24 * 30 // Offline cache available for 30 days
                request = request.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=$maxStale")
                    .removeHeader("Pragma")
                    .build()
            }
            chain.proceed(request)
        })

        builder.addInterceptor(logging)

        //setup cache


        //setup cache
        val httpCacheDirectory: File = File(context.getCacheDir(), "responses")
        val cacheSize = 10 * 1024 * 1024 // 10 MB

        val cache = Cache(httpCacheDirectory, cacheSize.toLong())

        builder.cache(cache)


        return Retrofit.Builder()
            .baseUrl(BuildConfig.BASE_URL)
            .client(builder.build())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Provides
    fun provideApi(retrofit: Retrofit): ApiInterface = retrofit.create(ApiInterface::class.java)

    @Provides
    @Singleton
    fun provideSessionManager(@ApplicationContext context: Context) = SessionManager(context)

}

SessionManager.kt

class SessionManager @Inject constructor(@ApplicationContext private val context: Context) {

    private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = Constants.PREFERENCES)


    private val tokenPreferences = stringPreferencesKey(Constants.AUTH_TOKEN)

    suspend fun saveToken(token : String){

        context.dataStore.edit {
            it[tokenPreferences] = token
        }
    }

    fun getToken() = context.dataStore.data.map {
        it[tokenPreferences]
    }
}

I want to get the value of the token using getToken() function but this function returns flow of data which is suspend function which cannot be called from a function. Any kind of help will be appreciated.

You can use runBlocking to run a suspend function from a normal function. OkHttp interceptors run on a thread pool and not the main thread, so it should be safe to obtain the current token there.

        builder.addNetworkInterceptor(Interceptor { chain: Interceptor.Chain ->
            val token = runBlocking {
                sessionManager.getToken().first()
            }
            val request = chain.request().newBuilder()
                .addHeader("Authorization", "Bearer $token")
                .build()
            chain.proceed(request)
        })

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM