Hilt를 이용해서 인터셉터로 base url를 변경하는 방법을 코드를 보여드릴테니 참고하세요. 동작하는 코드이고 복잡하지 않으므로 코드를 보고 이애하시고 사용하시길 바라고 이 코드에 대한 추가적인 답은 하지 않겠습니다.
BaseURL을 개발환경에 따라 설정한다고 가정하고 아래처럼 개발환경을 enum으로 정의.
// StockExchange는 prod 환경만 존재하기 때문에 실제 테스트하면 DEV, STAGING은 에러가 나므로 BaseUlr이 잘 변경되었는지만 확인하시기 바람.
enum class BaseUrl(val value: String) {
DEV("https://dev-api.stackexchange.com/"),
STAGING("https://staging-api.stackexchange.com/"),
PROD("https://api.stackexchange.com/");
}
Retrofit을 생성하는 Hilt 모듈
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
private const val APP_SETTINGS = "appSettings"
@Provides
@Singleton
fun providesAppSettings(@ApplicationContext context: Context): SharedPreferences {
return context.getSharedPreferences(APP_SETTINGS, MODE_PRIVATE)
}
@Provides
@Singleton
fun provideOkHttpClient(loggingInterceptor: LoggingInterceptor, baseUrlInterceptor: BaseUrlInterceptor): OkHttpClient {
return OkHttpClient.Builder()
.addNetworkInterceptor(loggingInterceptor)
.addInterceptor(baseUrlInterceptor)
.build()
}
@Provides
@Singleton
fun providesRetrofit(okHttpClient: OkHttpClient): Retrofit {
return Retrofit.Builder()
.baseUrl(BaseUrl.PROD.value)
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build()
}
@Provides
@Singleton
fun providesStockExchangeApi(retrofit: Retrofit): StockExchangeApi {
return retrofit.create(StockExchangeApi::class.java)
}
}
private const val BASE_URL_KEY = "baseUrl"
fun SharedPreferences.getBaseUrlValue(): String {
return getBaseUrl().value
}
fun SharedPreferences.getBaseUrl(): BaseUrl {
val baseUrlName = getString(BASE_URL_KEY, BaseUrl.PROD.name) ?: BaseUrl.PROD.name
return BaseUrl.entries.find { it.name.equals(baseUrlName, ignoreCase = true) } ?: BaseUrl.PROD
}
fun SharedPreferences.setBaseUrl(baseUrl: BaseUrl) {
edit()
.putString(BASE_URL_KEY, baseUrl.name)
.commit()
}
BaseInterceptor
@Singleton
class BaseUrlInterceptor @Inject constructor(
private val preferences: SharedPreferences
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
val request = buildUrl(chain.request().url).toHttpUrlOrNull()?.let { newUrl ->
chain.request().newBuilder()
.url(newUrl)
.build()
} ?: chain.request()
return chain.proceed(request)
}
private fun buildUrl(url: okhttp3.HttpUrl): String {
val baseUrl = preferences.getBaseUrlValue()
return baseUrl.plus(url.toUrl().path.drop(1))
}
}
StockExchangeApi
interface StockExchangeApi {
@GET("2.3/posts?order=desc&sort=activity&site=stackoverflow")
suspend fun getPosts(): Response<Posts>
}
data class Item(
@SerializedName("content_license")
val contentLicense: String,
@SerializedName("creation_date")
val creationDate: Int,
@SerializedName("last_activity_date")
val lastActivityDate: Int,
@SerializedName("last_edit_date")
val lastEditDate: Int,
@SerializedName("link")
val link: String,
@SerializedName("owner")
val owner: Owner,
@SerializedName("post_id")
val postId: Int,
@SerializedName("post_type")
val postType: String,
@SerializedName("score")
val score: Int
)
data class Owner(
@SerializedName("accept_rate")
val acceptRate: Int,
@SerializedName("account_id")
val accountId: Int,
@SerializedName("display_name")
val displayName: String,
@SerializedName("link")
val link: String,
@SerializedName("profile_image")
val profileImage: String,
@SerializedName("reputation")
val reputation: Int,
@SerializedName("user_id")
val userId: Int,
@SerializedName("user_type")
val userType: String
)
data class Posts(
@SerializedName("has_more")
val hasMore: Boolean,
@SerializedName("items")
val items: List<Item>,
@SerializedName("quota_max")
val quotaMax: Int,
@SerializedName("quota_remaining")
val quotaRemaining: Int
)