refactor(net): 重构网络请求配置以支持动态域名切换

- 在 ApiServiceV2 中使用 @Url 注解实现动态 URL 配置
- 添加 DynamicBaseUrlInterceptor 拦截器用于实时替换基础 URL
- 更新环境切换对话框中的环境名称和对应的 URL 映射关系
- 修改 UrlConfig 中的常量为变量并包含完整的基础 URL 路径
- 在 HttpManager 中为两个 API 服务实例都添加动态域名拦截器
- 调整环境配置常量定义顺序以匹配新的环境切换逻辑
This commit is contained in:
2026-06-03 16:30:05 +08:00
parent d6ba6cf527
commit 4b8e5f84e6
6 changed files with 42 additions and 20 deletions
@@ -17,9 +17,9 @@ object GlobalData {
/** /**
* 具体业务 BaseUrl * 具体业务 BaseUrl
*/ */
// const val TEST_BASE_URL = "http://192.168.1.201:14801" // const val LOCAL_BASE_URL = "http://192.168.1.201:14801"
const val TEST_BASE_URL = "http://192.168.10.101:24801" const val LOCAL_BASE_URL = "http://192.168.10.101:24801"
const val UAT_BASE_URL = "https://dev.yixiong-tech.com:8081" const val TEST_BASE_URL = "https://dev.yixiong-tech.com:8081"
const val PROD_BASE_URL = "https://api.dm.yixiong-tech.com:8443" const val PROD_BASE_URL = "https://api.dm.yixiong-tech.com:8443"
} }
@@ -39,8 +39,8 @@ class EnvSwitchDialog(
override fun initView() { override fun initView() {
// 根据当前 appBaseUrl 预选对应 RadioButton,不匹配则不选 // 根据当前 appBaseUrl 预选对应 RadioButton,不匹配则不选
when (GlobalData.appBaseUrl) { when (GlobalData.appBaseUrl) {
GlobalData.TEST_BASE_URL -> binding.rbTest.isChecked = true GlobalData.LOCAL_BASE_URL -> binding.rbTest.isChecked = true
GlobalData.UAT_BASE_URL -> binding.rbUat.isChecked = true GlobalData.TEST_BASE_URL -> binding.rbUat.isChecked = true
GlobalData.PROD_BASE_URL -> binding.rbProd.isChecked = true GlobalData.PROD_BASE_URL -> binding.rbProd.isChecked = true
} }
@@ -55,8 +55,8 @@ class EnvSwitchDialog(
return@setOnClickListener return@setOnClickListener
} }
val newUrl = when (binding.rgEnv.checkedRadioButtonId) { val newUrl = when (binding.rgEnv.checkedRadioButtonId) {
binding.rbTest.id -> GlobalData.TEST_BASE_URL binding.rbTest.id -> GlobalData.LOCAL_BASE_URL
binding.rbUat.id -> GlobalData.UAT_BASE_URL binding.rbUat.id -> GlobalData.TEST_BASE_URL
binding.rbProd.id -> GlobalData.PROD_BASE_URL binding.rbProd.id -> GlobalData.PROD_BASE_URL
else -> return@setOnClickListener else -> return@setOnClickListener
} }
@@ -8,6 +8,7 @@ import retrofit2.http.Body
import retrofit2.http.GET import retrofit2.http.GET
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.Query import retrofit2.http.Query
import retrofit2.http.Url
interface ApiServiceV2 { interface ApiServiceV2 {
@@ -15,24 +16,27 @@ interface ApiServiceV2 {
* 4.1 货柜初始化 * 4.1 货柜初始化
* 设备启动、Token 刷新后、首页重试时调用 * 设备启动、Token 刷新后、首页重试时调用
*/ */
@GET(UrlConfig.CABINET_INIT) @GET
suspend fun initCabinet( suspend fun initCabinet(
@Url url: String = UrlConfig.CABINET_INIT,
@Query("cabinetId") cabinetId: String @Query("cabinetId") cabinetId: String
): RespData<CabinetInitResult> ): RespData<CabinetInitResult>
/** /**
* 4.2.1 净菜包下拉列表(itemType=1 * 4.2.1 净菜包下拉列表(itemType=1
*/ */
@GET(UrlConfig.CLEAN_PACKAGE_OPTIONS) @GET
suspend fun getCleanPackageOptions( suspend fun getCleanPackageOptions(
@Url url: String = UrlConfig.CLEAN_PACKAGE_OPTIONS,
@Query("keyword") keyword: String? = null @Query("keyword") keyword: String? = null
): RespData<List<CleanPackageOption>> ): RespData<List<CleanPackageOption>>
/** /**
* 4.2.2 餐品净菜包下拉列表(itemType=2) * 4.2.2 餐品净菜包下拉列表(itemType=2)
*/ */
@GET(UrlConfig.MEAL_PACKAGE_OPTIONS) @GET
suspend fun getMealPackageOptions( suspend fun getMealPackageOptions(
@Url url: String = UrlConfig.MEAL_PACKAGE_OPTIONS,
@Query("keyword") keyword: String? = null @Query("keyword") keyword: String? = null
): RespData<List<MealPackageOption>> ): RespData<List<MealPackageOption>>
@@ -40,8 +44,9 @@ interface ApiServiceV2 {
* 4.3 全量同步整柜数据(定时上报) * 4.3 全量同步整柜数据(定时上报)
* 警告:body.goodsList 为 null 或空列表时,后端会软删除整柜所有格口数据 * 警告:body.goodsList 为 null 或空列表时,后端会软删除整柜所有格口数据
*/ */
@POST(UrlConfig.CABINET_RECORD_SYNC) @POST
suspend fun syncCabinetData( suspend fun syncCabinetData(
@Url url: String = UrlConfig.CABINET_RECORD_SYNC,
@Body body: SyncBody @Body body: SyncBody
): RespData<Any?> ): RespData<Any?>
} }
@@ -4,6 +4,8 @@ import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import com.shuwei.intelligent.shelves.BuildConfig import com.shuwei.intelligent.shelves.BuildConfig
import com.shuwei.intelligent.shelves.GlobalData import com.shuwei.intelligent.shelves.GlobalData
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.Response
@@ -17,9 +19,22 @@ import java.security.SecureRandom
import java.security.cert.X509Certificate import java.security.cert.X509Certificate
import kotlin.apply import kotlin.apply
/** 动态域名拦截器:将 Retrofit 请求的 baseUrl 实时替换为 [GlobalData.appBaseUrl] */
class DynamicBaseUrlInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val newUrl = GlobalData.appBaseUrl.toHttpUrlOrNull() ?: return chain.proceed(request)
val url = request.url.newBuilder()
.scheme(newUrl.scheme)
.host(newUrl.host)
.port(newUrl.port)
.build()
return chain.proceed(request.newBuilder().url(url).build())
}
}
val apiService: ApiService = Retrofit.Builder() val apiService: ApiService = Retrofit.Builder()
// .baseUrl(UrlConfig.BASE_URL) .baseUrl("http://placeholder/")
.baseUrl(GlobalData.appBaseUrl)
.client(HttpManager.instance.client) .client(HttpManager.instance.client)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()
@@ -27,7 +42,7 @@ val apiService: ApiService = Retrofit.Builder()
/** v1.1 接口专用实例,使用轻量拦截器,不携带旧鉴权 Token */ /** v1.1 接口专用实例,使用轻量拦截器,不携带旧鉴权 Token */
val apiServiceV2: ApiServiceV2 = Retrofit.Builder() val apiServiceV2: ApiServiceV2 = Retrofit.Builder()
.baseUrl(GlobalData.appBaseUrl) .baseUrl("http://placeholder/")
.client(HttpManager.instance.cabinetClient) .client(HttpManager.instance.cabinetClient)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.build() .build()
@@ -43,6 +58,7 @@ class HttpManager private constructor() {
sslSocketFactory(createSSLSocketFactory(), TrustAllCerts()) sslSocketFactory(createSSLSocketFactory(), TrustAllCerts())
hostnameVerifier { _, _ -> true } hostnameVerifier { _, _ -> true }
// addInterceptor(LoggingInterceptor()) // addInterceptor(LoggingInterceptor())
addInterceptor(DynamicBaseUrlInterceptor())
addNetworkInterceptor(HttpLoggingInterceptor(logger = { addNetworkInterceptor(HttpLoggingInterceptor(logger = {
Log.d("HttpManager","okhttp logger ==>${it}") Log.d("HttpManager","okhttp logger ==>${it}")
}).apply { }).apply {
@@ -73,6 +89,7 @@ class HttpManager private constructor() {
writeTimeout(30, TimeUnit.SECONDS) writeTimeout(30, TimeUnit.SECONDS)
sslSocketFactory(createSSLSocketFactory(), TrustAllCerts()) sslSocketFactory(createSSLSocketFactory(), TrustAllCerts())
hostnameVerifier { _, _ -> true } hostnameVerifier { _, _ -> true }
addInterceptor(DynamicBaseUrlInterceptor())
addNetworkInterceptor(HttpLoggingInterceptor(logger = { addNetworkInterceptor(HttpLoggingInterceptor(logger = {
Log.d("HttpManager", "v2 okhttp ==>${it}") Log.d("HttpManager", "v2 okhttp ==>${it}")
}).apply { }).apply {
@@ -28,10 +28,10 @@ object UrlConfig {
"${GlobalData.appBaseUrl}/terminal/neglect/smartShelves/app/smartShelves/app/saveShelvesGoodsList" "${GlobalData.appBaseUrl}/terminal/neglect/smartShelves/app/smartShelves/app/saveShelvesGoodsList"
// v1.1 新接口 // v1.1 新接口
const val CABINET_INIT = "/nutrition/neglect/cabinet/init" var CABINET_INIT = "${GlobalData.appBaseUrl}/nutrition/neglect/cabinet/init"
const val CLEAN_PACKAGE_OPTIONS = "/nutrition/neglect/cabinet/clean-package-options" var CLEAN_PACKAGE_OPTIONS = "${GlobalData.appBaseUrl}/nutrition/neglect/cabinet/clean-package-options"
const val MEAL_PACKAGE_OPTIONS = "/nutrition/neglect/cabinet/meal-package-options" var MEAL_PACKAGE_OPTIONS = "${GlobalData.appBaseUrl}/nutrition/neglect/cabinet/meal-package-options"
const val CABINET_RECORD_SYNC = "/nutrition/neglect/cabinet/record/sync" var CABINET_RECORD_SYNC = "${GlobalData.appBaseUrl}/nutrition/neglect/cabinet/record/sync"
} }
@@ -38,7 +38,7 @@
android:layout_height="72dp" android:layout_height="72dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="16dp" android:paddingStart="16dp"
android:text="测试环境" android:text="本地环境"
android:textColor="#ff141428" android:textColor="#ff141428"
android:textSize="28sp" /> android:textSize="28sp" />
@@ -48,7 +48,7 @@
android:layout_height="72dp" android:layout_height="72dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingStart="16dp" android:paddingStart="16dp"
android:text="UAT 环境" android:text="测试环境"
android:textColor="#ff141428" android:textColor="#ff141428"
android:textSize="28sp" /> android:textSize="28sp" />