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:
@@ -264,7 +264,8 @@ dependencies {
|
||||
|
||||
// implementation 'com.sensorsdata.analytics.android:SensorsAnalyticsSDK:6.8.3'
|
||||
implementation 'commons-codec:commons-codec:1.15'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
|
||||
// 3.12.0:3.12.1+(含 3.12.13)引入 Android10Platform 触发 Dalvik VerifyError,必须精确锁 3.12.0
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
|
||||
implementation 'com.google.code.gson:gson:2.8.9'
|
||||
implementation 'com.github.gzu-liyujiang:Android_CN_OAID:4.1.3'
|
||||
implementation('io.github.volcengine-tls:tls-android-producer:2.0.2-api16') {
|
||||
@@ -278,22 +279,28 @@ dependencies {
|
||||
implementation 'com.google.guava:guava:31.1-android'
|
||||
|
||||
// ===== 网络层(脚手架新引入,与既有 HttpUtils 双栈共存) =====
|
||||
// 为什么显式指定版本:app 模块此前未声明 retrofit/okhttp/moshi/coroutines,避免被根 config.gradle 隐式拉入不同版本。
|
||||
// Kotlin 1.9.22 -> KSP 1.9.22-1.0.17 已对齐。
|
||||
// 为什么用 `platform(enforcedPlatform)` 而非 `implementation`:okhttp-bom 是 Bill-of-Materials,本身仅提供版本对齐,
|
||||
// 不能被当作运行时产物拉到 runtime classpath(这正是上一个编译报错的根因)。
|
||||
implementation platform('com.squareup.okhttp3:okhttp-bom:4.12.0')
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.11.0'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.11.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor'
|
||||
// ===== Android 4.2 兼容(对齐 mediaapp 已验证组合,见 Android4.2兼容性改动文档)=====
|
||||
// - OkHttp 4.x 官方要求 API 21+;3.13+ 含 Android10Platform(API 10 SSL API)触发 Dalvik VerifyError。
|
||||
// 3.12.0 是支持 API 9-20 的长期分支(与 libcore/libdata 老栈版本一致),配合下方 force 全局锁定。
|
||||
// - Retrofit 2.6.0:suspend 函数 2.6.0 起支持;2.9+ 传递依赖 OkHttp 3.14.9(含 Android10Platform)。
|
||||
// - Coroutines 1.6.4:1.7+ 要求 minSdk 21,1.6.4 兼容 API 16+。
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
|
||||
implementation 'com.squareup.retrofit2:converter-moshi:2.6.0'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.0'
|
||||
implementation 'com.squareup.moshi:moshi:1.15.1'
|
||||
implementation 'com.squareup.moshi:moshi-kotlin:1.15.1'
|
||||
ksp 'com.squareup.moshi:moshi-kotlin-codegen:1.15.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
|
||||
|
||||
// 防止其他依赖(tls-producer/libdata 等)传递引入更高版本 OkHttp/Retrofit 破坏 4.2 兼容
|
||||
configurations.all {
|
||||
resolutionStrategy.force 'com.squareup.okhttp3:okhttp:3.12.0'
|
||||
resolutionStrategy.force 'com.squareup.retrofit2:retrofit:2.6.0'
|
||||
}
|
||||
|
||||
implementation 'net.jpountz.lz4:lz4:1.3.0'
|
||||
implementation 'org.slf4j:slf4j-android:1.7.36'
|
||||
//腾讯buggly
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user