You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Clean Architecture:Android组件向Retrofit传API密钥的优雅方案

符合Clean Architecture的API密钥存储与传递方案

一、替代SharedPreferences的存储选择:DataStore

  • 用Preferences DataStore(适用于无需序列化对象的场景),它不强制依赖Android Context(可通过依赖注入在非UI层获取实例),且具备异步、线程安全特性,比SharedPreferences更稳定可靠。
  • 遵循依赖倒置原则,先在数据层定义存储抽象接口,再用DataStore实现具体逻辑,上层仅依赖抽象,不绑定Android具体存储实现。

示例代码:

// 数据层抽象契约
interface KeyStorage {
    suspend fun saveApiKey(key: String)
    suspend fun getApiKey(): String?
}

// DataStore具体实现(数据层内部类)
class DataStoreKeyStorage(private val dataStore: DataStore<Preferences>) : KeyStorage {
    private val API_KEY_KEY = stringPreferencesKey("api_key")

    override suspend fun saveApiKey(key: String) {
        dataStore.edit { it[API_KEY_KEY] = key }
    }

    override suspend fun getApiKey(): String? {
        return dataStore.data.first()[API_KEY_KEY]
    }
}

二、分层传递流程(符合Clean Architecture规则)

按照"上层依赖下层抽象"的核心原则,密钥传递流程如下:

  1. 表现层(Activity/Fragment):用户输入密钥后,调用用例层的SaveApiKeyUseCase,将密钥传入用例。
  2. 用例层:持有KeyStorage抽象实例,调用其saveApiKey方法完成存储,无需关心具体存储细节。
  3. 数据层:Retrofit实例创建依赖KeyStorage,通过OkHttp拦截器动态获取密钥并添加到请求头/参数中。

Retrofit与密钥结合示例

在数据层封装Retrofit创建逻辑,通过拦截器注入密钥:

class ApiServiceFactory(private val keyStorage: KeyStorage) {
    fun createApiService(): ApiService {
        val okHttpClient = OkHttpClient.Builder()
            .addInterceptor { chain ->
                val apiKey = runBlocking { keyStorage.getApiKey() }
                val request = chain.request().newBuilder()
                    .addHeader("Authorization", "Bearer $apiKey")
                    .build()
                chain.proceed(request)
            }
            .build()

        return Retrofit.Builder()
            .baseUrl("https://your-api-base-url.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

注:这里使用runBlocking是因为OkHttp拦截器为同步场景,若需更优雅的异步处理,可结合OkHttp的异步回调逻辑,但简单场景下runBlocking可满足需求(DataStore读取操作耗时极短)。

三、依赖注入的核心作用

用Hilt或Dagger完成各层组件的注入,确保依赖关系符合架构规范:

  • 在Hilt模块中提供DataStore与KeyStorage实例:
@Module
@InstallIn(SingletonComponent::class)
object StorageModule {
    @Provides
    fun providePreferencesDataStore(@ApplicationContext context: Context): DataStore<Preferences> {
        return context.createDataStore(name = "api_keys")
    }

    @Provides
    fun provideKeyStorage(dataStore: DataStore<Preferences>): KeyStorage {
        return DataStoreKeyStorage(dataStore)
    }
}
  • 表现层可直接注入SaveApiKeyUseCase,数据层的ApiServiceFactory可注入KeyStorage,全程无跨层直接依赖,完全遵循Clean Architecture的依赖规则。

四、额外注意事项

  • 密钥安全性:若为敏感API密钥,建议在KeyStorage实现中添加加密逻辑(如使用Jetpack Security的Encrypted DataStore),加密逻辑封装在数据层,上层无需感知。
  • 空值处理:在Retrofit拦截器中需处理密钥为空的情况,可通过抛出业务异常或通知用例层触发密钥输入流程,数据层仅负责存储与获取逻辑。

内容的提问来源于stack exchange,提问作者jvds01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 10:52:16