From c653e5b78dce0c53c1002e45cdeed88bc6c5c83a Mon Sep 17 00:00:00 2001 From: dongliang Date: Thu, 7 May 2026 13:15:52 +0930 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=9B=BE=E7=89=87=E5=92=8C=E8=AF=AD?= =?UTF-8?q?=E9=9F=B3=E6=94=B9=E7=94=A8=20app=20OkHttp=204.12=20=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=EF=BC=88=E5=BC=83=E7=94=A8=E7=B3=BB=E7=BB=9F=20HttpUR?= =?UTF-8?q?LConnection=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因:HttpURLConnection 底层是系统内置的 com.android.okhttp 2.x 即使 Conscrypt 替换了 TLS provider,系统 OkHttp 的 ALPN/连接管理 仍是旧逻辑,阿里云 OSS 不接受。 改用 app 自带的 OkHttp 4.12.0(有完整 ALPN/HTTP2 支持)+ Conscrypt Co-Authored-By: Claude Opus 4.6 (1M context) --- .../xiaoqu/watch/ui/task/TaskListFragment.kt | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt b/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt index b664b87..487dd8d 100644 --- a/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt +++ b/app/src/main/java/com/xiaoqu/watch/ui/task/TaskListFragment.kt @@ -517,19 +517,19 @@ class TaskListFragment : BaseFragment() { overlay.setOnTouchListener { _, event -> detector.onTouchEvent(event); true } } - /** 异步加载图片到 ImageView(使用系统 HttpURLConnection) */ + /** 异步加载图片到 ImageView(使用 app OkHttp 4.12 + Conscrypt) */ private fun loadImage(imageView: android.widget.ImageView, url: String) { viewLifecycleOwner.lifecycleScope.launch { try { val bitmap = kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.IO) { - val conn = java.net.URL(url).openConnection() as java.net.HttpURLConnection - conn.connectTimeout = 10000 - conn.readTimeout = 10000 - conn.connect() - if (conn.responseCode == 200) { - conn.inputStream.use { android.graphics.BitmapFactory.decodeStream(it) } + val request = okhttp3.Request.Builder().url(url).build() + val response = downloadClient.newCall(request).execute() + if (response.isSuccessful) { + response.body?.byteStream()?.use { + android.graphics.BitmapFactory.decodeStream(it) + } } else { - Timber.w("图片HTTP错误: ${conn.responseCode} $url") + Timber.w("图片HTTP错误: ${response.code} $url") null } } @@ -598,21 +598,27 @@ class TaskListFragment : BaseFragment() { } } - /** 下载音频文件到缓存目录(使用系统 HttpURLConnection) */ + /** 用于下载 OSS 资源的 OkHttp 客户端(无拦截器,配合 Conscrypt TLS) */ + private val downloadClient by lazy { + okhttp3.OkHttpClient.Builder() + .connectTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .readTimeout(15, java.util.concurrent.TimeUnit.SECONDS) + .build() + } + + /** 下载音频文件到缓存目录(使用 app OkHttp 4.12 + Conscrypt) */ private fun downloadToCache(url: String): java.io.File? { return try { - val conn = java.net.URL(url).openConnection() as java.net.HttpURLConnection - conn.connectTimeout = 15000 - conn.readTimeout = 15000 - conn.connect() - if (conn.responseCode != 200) { - Timber.w("语音下载HTTP错误: ${conn.responseCode}") + val request = okhttp3.Request.Builder().url(url).build() + val response = downloadClient.newCall(request).execute() + if (!response.isSuccessful) { + Timber.w("语音下载HTTP错误: ${response.code}") return null } // 写入缓存文件 val fileName = "voice_${url.hashCode()}.mp3" val cacheFile = java.io.File(requireContext().cacheDir, fileName) - conn.inputStream.use { input -> + response.body?.byteStream()?.use { input -> cacheFile.outputStream().use { output -> input.copyTo(output) }