debug(file): 添加文件下载功能的调试日志
- 在 FileSDK 的 saveBlobDownload 方法中添加解码、目录创建和文件写入的日志记录 - 在 XWebViewView 的 readBlobAndPost 函数中添加 JavaScript 端的数据读取和错误处理日志 - 添加锚点拦截和消息传递过程中的日志记录 - 在 blobdownload 处理流程中添加成功和失败的状态日志 - 增加文件保存到相册操作的结果日志记录
这个提交包含在:
父节点
d8c0abe510
当前提交
2bd497ead4
@ -251,7 +251,9 @@ object FileSDK {
|
|||||||
fileName: String,
|
fileName: String,
|
||||||
destination: FileDownloadDestination = FileDownloadDestination.Sandbox,
|
destination: FileDownloadDestination = FileDownloadDestination.Sandbox,
|
||||||
): File {
|
): File {
|
||||||
|
android.util.Log.d("XWV", "saveBlobDownload: fileName=$fileName, dest=$destination, b64Len=${base64Data.length}")
|
||||||
val bytes = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT)
|
val bytes = android.util.Base64.decode(base64Data, android.util.Base64.DEFAULT)
|
||||||
|
android.util.Log.d("XWV", "saveBlobDownload: decoded ${bytes.size} bytes")
|
||||||
val baseDir = when (destination) {
|
val baseDir = when (destination) {
|
||||||
FileDownloadDestination.PublicDownloads -> {
|
FileDownloadDestination.PublicDownloads -> {
|
||||||
val appName = context.applicationInfo.loadLabel(context.packageManager).toString()
|
val appName = context.applicationInfo.loadLabel(context.packageManager).toString()
|
||||||
@ -260,14 +262,21 @@ object FileSDK {
|
|||||||
android.os.Environment.DIRECTORY_DOWNLOADS
|
android.os.Environment.DIRECTORY_DOWNLOADS
|
||||||
),
|
),
|
||||||
appName,
|
appName,
|
||||||
).apply { mkdirs() }
|
).apply {
|
||||||
|
val created = mkdirs()
|
||||||
|
android.util.Log.d("XWV", "saveBlobDownload: PublicDownloads dir=$absolutePath, created=$created, exists=${exists()}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FileDownloadDestination.Sandbox -> {
|
FileDownloadDestination.Sandbox -> {
|
||||||
context.getExternalFilesDir(null) ?: context.filesDir
|
(context.getExternalFilesDir(null) ?: context.filesDir).also {
|
||||||
|
android.util.Log.d("XWV", "saveBlobDownload: Sandbox dir=${it.absolutePath}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val target = uniqueFile(baseDir, fileName.takeIf { it.isNotBlank() } ?: "download.bin")
|
val target = uniqueFile(baseDir, fileName.takeIf { it.isNotBlank() } ?: "download.bin")
|
||||||
|
android.util.Log.d("XWV", "saveBlobDownload: writing to ${target.absolutePath}")
|
||||||
target.writeBytes(bytes)
|
target.writeBytes(bytes)
|
||||||
|
android.util.Log.d("XWV", "saveBlobDownload: done, size=${target.length()}")
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -100,17 +100,29 @@ internal fun buildDialogOverrideJs(bridgeName: String) = """
|
|||||||
URL.revokeObjectURL = function() {};
|
URL.revokeObjectURL = function() {};
|
||||||
|
|
||||||
function readBlobAndPost(blobUrl, filename) {
|
function readBlobAndPost(blobUrl, filename) {
|
||||||
|
console.log('[XWV] readBlobAndPost start, url=' + blobUrl + ', filename=' + filename);
|
||||||
fetch(blobUrl)
|
fetch(blobUrl)
|
||||||
.then(function(r) { return r.blob(); })
|
.then(function(r) {
|
||||||
|
console.log('[XWV] fetch ok, size=' + r.size);
|
||||||
|
return r.blob();
|
||||||
|
})
|
||||||
.then(function(blob) {
|
.then(function(blob) {
|
||||||
|
console.log('[XWV] blob ok, size=' + blob.size + ', type=' + blob.type);
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
reader.onloadend = function() {
|
reader.onloadend = function() {
|
||||||
var b64 = reader.result.split(',')[1];
|
var b64 = reader.result.split(',')[1];
|
||||||
|
console.log('[XWV] base64 ready, len=' + (b64 ? b64.length : 0));
|
||||||
post({ __xwv: 'blobdownload', url: blobUrl, filename: filename, data: b64 });
|
post({ __xwv: 'blobdownload', url: blobUrl, filename: filename, data: b64 });
|
||||||
|
console.log('[XWV] blobdownload posted');
|
||||||
|
};
|
||||||
|
reader.onerror = function(e) {
|
||||||
|
console.log('[XWV] FileReader error: ' + String(e));
|
||||||
|
post({ __xwv: 'bloberror', msg: 'FileReader error: ' + String(e) });
|
||||||
};
|
};
|
||||||
reader.readAsDataURL(blob);
|
reader.readAsDataURL(blob);
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
|
console.log('[XWV] readBlobAndPost ERROR: ' + String(err));
|
||||||
post({ __xwv: 'bloberror', msg: String(err) });
|
post({ __xwv: 'bloberror', msg: String(err) });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -125,6 +137,7 @@ internal fun buildDialogOverrideJs(bridgeName: String) = """
|
|||||||
var hasDownloadAttr = el.hasAttribute('download');
|
var hasDownloadAttr = el.hasAttribute('download');
|
||||||
var dlName = el.getAttribute('download') || '';
|
var dlName = el.getAttribute('download') || '';
|
||||||
var isDL = hasDownloadAttr || dlRe.test(href);
|
var isDL = hasDownloadAttr || dlRe.test(href);
|
||||||
|
console.log('[XWV] tryInterceptAnchor href=' + href + ', hasDownload=' + hasDownloadAttr + ', isDL=' + isDL);
|
||||||
if (isDL) {
|
if (isDL) {
|
||||||
if (e) { e.preventDefault(); e.stopPropagation(); }
|
if (e) { e.preventDefault(); e.stopPropagation(); }
|
||||||
if (href.startsWith('blob:')) {
|
if (href.startsWith('blob:')) {
|
||||||
@ -180,9 +193,11 @@ internal class XWebViewJsBridge(
|
|||||||
) {
|
) {
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
fun postMessage(data: String) {
|
fun postMessage(data: String) {
|
||||||
|
android.util.Log.d("XWV", "postMessage: ${data.take(200)}")
|
||||||
mainHandler.post {
|
mainHandler.post {
|
||||||
val json = runCatching { JSONObject(data) }.getOrNull()
|
val json = runCatching { JSONObject(data) }.getOrNull()
|
||||||
val xwv = json?.optString("__xwv")?.takeIf { it.isNotEmpty() }
|
val xwv = json?.optString("__xwv")?.takeIf { it.isNotEmpty() }
|
||||||
|
android.util.Log.d("XWV", "postMessage parsed: xwv=$xwv")
|
||||||
if (xwv != null && json != null) {
|
if (xwv != null && json != null) {
|
||||||
onXwvMessage()?.invoke(xwv, json)
|
onXwvMessage()?.invoke(xwv, json)
|
||||||
} else {
|
} else {
|
||||||
@ -229,6 +244,7 @@ fun XWebViewView(
|
|||||||
|
|
||||||
// Handles __xwv: 'download' / 'blobdownload' messages from the injected JS.
|
// Handles __xwv: 'download' / 'blobdownload' messages from the injected JS.
|
||||||
val xwvMessageHandler: (String, JSONObject) -> Unit = handler@{ type, payload ->
|
val xwvMessageHandler: (String, JSONObject) -> Unit = handler@{ type, payload ->
|
||||||
|
android.util.Log.d("XWV", "xwvMessage type=$type, payload=${payload.toString().take(200)}")
|
||||||
when (type) {
|
when (type) {
|
||||||
"download" -> {
|
"download" -> {
|
||||||
val url = payload.optString("url").takeIf { it.isNotBlank() } ?: return@handler
|
val url = payload.optString("url").takeIf { it.isNotBlank() } ?: return@handler
|
||||||
@ -267,19 +283,26 @@ fun XWebViewView(
|
|||||||
"blobdownload" -> {
|
"blobdownload" -> {
|
||||||
val url = payload.optString("url")
|
val url = payload.optString("url")
|
||||||
val filename = payload.optString("filename").takeIf { it.isNotBlank() } ?: "download.bin"
|
val filename = payload.optString("filename").takeIf { it.isNotBlank() } ?: "download.bin"
|
||||||
val b64 = payload.optString("data").takeIf { it.isNotBlank() } ?: return@handler
|
val b64 = payload.optString("data").takeIf { it.isNotBlank() } ?: run {
|
||||||
|
android.util.Log.e("XWV", "blobdownload: empty data")
|
||||||
|
return@handler
|
||||||
|
}
|
||||||
|
android.util.Log.d("XWV", "blobdownload: filename=$filename, b64Len=${b64.length}, dest=${config.downloadDestination}")
|
||||||
coroutineScope.launch(Dispatchers.IO) {
|
coroutineScope.launch(Dispatchers.IO) {
|
||||||
runCatching {
|
runCatching {
|
||||||
FileSDK.saveBlobDownload(context, b64, filename, config.downloadDestination)
|
FileSDK.saveBlobDownload(context, b64, filename, config.downloadDestination)
|
||||||
}.onSuccess { file ->
|
}.onSuccess { file ->
|
||||||
|
android.util.Log.d("XWV", "blobdownload saved: ${file.absolutePath}, size=${file.length()}")
|
||||||
// For image files, save to the system gallery (相册) so they appear in Photos
|
// For image files, save to the system gallery (相册) so they appear in Photos
|
||||||
val savedToGallery = runCatching { FileSDK.saveImageToGallery(context, file) }.getOrDefault(false)
|
val savedToGallery = runCatching { FileSDK.saveImageToGallery(context, file) }.getOrDefault(false)
|
||||||
|
android.util.Log.d("XWV", "blobdownload savedToGallery=$savedToGallery")
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
dispatchDownloadEvent("__xwvDownloadDone", url, ",success:true")
|
dispatchDownloadEvent("__xwvDownloadDone", url, ",success:true")
|
||||||
// Only open with file viewer when not saved to gallery (e.g. zip, docx)
|
// Only open with file viewer when not saved to gallery (e.g. zip, docx)
|
||||||
if (!savedToGallery) FileSDK.openFile(context, file)
|
if (!savedToGallery) FileSDK.openFile(context, file)
|
||||||
}
|
}
|
||||||
}.onFailure { e ->
|
}.onFailure { e ->
|
||||||
|
android.util.Log.e("XWV", "blobdownload FAILED", e)
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
dispatchDownloadEvent("__xwvDownloadDone", url, ",success:false,error:'${e.message?.escapeJs()}'")
|
dispatchDownloadEvent("__xwvDownloadDone", url, ",success:false,error:'${e.message?.escapeJs()}'")
|
||||||
}
|
}
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户