feat: Android 4.2 兼容改造

- minSdk 19 -> 17(config.gradle)
- OkHttp 4.12 -> 3.12.0(app build.gradle 新老双栈统一锁定)
- Retrofit 2.11 -> 2.6.0 + Coroutines 1.8.1 -> 1.6.4
- SignRequestPolicy: toHttpUrlOrNull -> HttpUrl.parse(3.12 API 适配)
- HeaderInterceptor/SignAuthenticator: 属性访问改方法调用(url()/request()/priorResponse())
- VideoViewTv: SDK_INT<19 强制切 AndroidMediaPlayer 内核 + instanceof 短路保护
- AndroidManifest: overrideLibrary OAID 4.1.3(minSdk 19)
- 全局 resolutionStrategy.force 锁定 OkHttp/Retrofit 版本
This commit is contained in:
zhaogd
2026-08-25 11:35:34 +08:00
parent d11464d466
commit fca025383c
7 changed files with 46 additions and 22 deletions

View File

@@ -4,6 +4,10 @@
package="com.pukka.jiecheng"
tools:ignore="MissingLeanbackLauncher">
<!-- Android 4.2 兼容(minSdk 17):覆盖 minSdk>17 的依赖库声明,运行时兼容性靠
降级依赖版本 + 不触碰高版本 API 路径保证。清单随探测编译逐步补充。 -->
<uses-sdk tools:overrideLibrary="com.github.gzuliyujiang.oaid" />
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />

View File

@@ -26,7 +26,8 @@ class HeaderInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val original = chain.request()
val path = SignRequestPolicy.relativePath(original.url.toString())
// OkHttp 3.12 兼容:Java 版字段访问需用方法调用(url()),4.x 的 Kotlin val 语法不可用
val path = SignRequestPolicy.relativePath(original.url().toString())
val builder = original.newBuilder()

View File

@@ -55,7 +55,8 @@ class SignAuthenticator : Authenticator {
private var credentialBroken: Boolean = false
override fun authenticate(route: Route?, response: Response): Request? {
val path = SignRequestPolicy.relativePath(response.request.url.toString())
// OkHttp 3.12 兼容:Java 版 request()/priorResponse() 方法调用(4.x Kotlin val 语法不可用)
val path = SignRequestPolicy.relativePath(response.request().url().toString())
// 保护 1:首签/刷新接口 401 直接放行
if (!SignRequestPolicy.shouldTriggerRefresh(path)) {
@@ -63,12 +64,12 @@ class SignAuthenticator : Authenticator {
}
// 保护 2:刷新调用本身带 X-Refresh-Call=1 标记,Authenticator 见到放行
if (response.request.header(HEADER_REFRESH_CALL) == "1") {
if (response.request().header(HEADER_REFRESH_CALL) == "1") {
return null
}
// 保护 3:priorResponse 链上已有 X-Refresh-Marker,说明已刷新过一次仍 401,放弃
val prior = response.priorResponse
val prior = response.priorResponse()
if (prior != null && prior.header(HEADER_REFRESH_MARKER) != null) {
return null
}
@@ -104,7 +105,7 @@ class SignAuthenticator : Authenticator {
Network.tokenStore.refreshAndPersist(newSign)
// 重建原 Request:保留所有原有 headers,注入新 sign 头 + X-Refresh-Marker 标记
response.request.newBuilder()
response.request().newBuilder()
.header("sign", newSign)
.header(HEADER_REFRESH_MARKER, "1")
.build()

View File

@@ -1,6 +1,6 @@
package com.pukka.jiecheng.network.auth
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.HttpUrl
/**
* sign 头注入 / 401 刷新触发策略。
@@ -36,11 +36,14 @@ object SignRequestPolicy {
/**
* 提取相对 baseUrl 的 path(去掉 query/fragment),用于上述匹配。
*
* 注意:HttpUrl.parse 是 OkHttp 3.12 的 API(4.x 才有 toHttpUrlOrNull 扩展),
* 项目已为 Android 4.2 兼容全局锁定 OkHttp 3.12.0,勿改回扩展函数。
*/
fun relativePath(absoluteUrl: String): String {
val url = absoluteUrl.toHttpUrlOrNull() ?: return absoluteUrl
val url = HttpUrl.parse(absoluteUrl) ?: return absoluteUrl
// pathSegments.joinToString("/") 自动处理首尾斜杠
return url.encodedPath.trimStart('/').let {
return url.encodedPath().trimStart('/').let {
// 去掉 /api/ 前缀,匹配 Set<String> 中的相对路径
if (it.startsWith("api/")) it.removePrefix("api/") else it
}