基于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规则)
按照"上层依赖下层抽象"的核心原则,密钥传递流程如下:
- 表现层(Activity/Fragment):用户输入密钥后,调用用例层的
SaveApiKeyUseCase,将密钥传入用例。 - 用例层:持有
KeyStorage抽象实例,调用其saveApiKey方法完成存储,无需关心具体存储细节。 - 数据层: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
相关产品推荐
相关产品推荐

