From 7b66fcf3332a887bbfc5be757d7cfb0229cbec60 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Tue, 23 Jun 2026 14:30:10 +0800 Subject: [PATCH] =?UTF-8?q?fix(webview):=20=E4=BF=AE=E5=A4=8D=20Office=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=80=89=E6=8B=A9=E5=90=8E=E6=97=A0=E5=93=8D?= =?UTF-8?q?=E5=BA=94=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ContentResolver.getType() 对 doc/docx/xls/xlsx 等 Office 文件经常 返回 "application/octet-stream" 而非精确 MIME 类型,导致 allowed 检查失败、文件被拒绝、H5 无响应。 修复:rawMime 为 null 或 application/octet-stream 时,从文件显示名 的扩展名推断精确 MIME(getMimeTypeFromExtension),使 .docx 能正确 匹配 accept 约束并进入缓存复制流程。 Co-Authored-By: Claude Sonnet 4.6 --- .../java/com/xuqm/sdk/webview/XWebViewView.kt | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt b/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt index fa48b27..2957acd 100644 --- a/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt +++ b/sdk-webview/src/main/java/com/xuqm/sdk/webview/XWebViewView.kt @@ -448,14 +448,28 @@ fun XWebViewView( // Validate that the selected file's actual MIME type is within the accepted list. // Some devices show extra file types in the picker (e.g. .doc when only .docx was // requested). Passing an unsupported type to the WebView renderer can cause a native - // crash. We accept the file only when its MIME type matches, or fall back to passing - // it through when we can't determine the type (to avoid blocking legitimate uploads). + // crash. val acceptedMimes = pendingAcceptMimes.value - val actualMime = context.contentResolver.getType(uri) + // ContentResolver returns "application/octet-stream" (or null) for most Office files + // from file-system / Downloads providers. Fall back to extension-based inference so + // .docx / .doc / .xls etc. are not incorrectly rejected. + val rawMime = context.contentResolver.getType(uri) + val actualMime: String? = if (rawMime == null || rawMime == "application/octet-stream") { + val name = context.contentResolver.query( + uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null + )?.use { cursor -> if (cursor.moveToFirst()) cursor.getString(0) else null } + val extMime = name?.substringAfterLast('.', "") + ?.lowercase(Locale.ROOT) + ?.takeIf { it.isNotEmpty() } + ?.let { ext -> MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext) } + extMime ?: rawMime + } else rawMime val allowed = acceptedMimes.isNullOrEmpty() || acceptedMimes.any { accepted -> accepted == "*/*" || - (actualMime != null && (actualMime == accepted || actualMime.startsWith(accepted.substringBefore("*")))) + actualMime == null || // truly unknown type — don't block + actualMime == accepted || + actualMime.startsWith(accepted.substringBefore("*")) } if (!allowed) { android.util.Log.w("XWV", "Rejected file: actualMime=$actualMime not in accepted=$acceptedMimes")