登录页面和文件打开方式

This commit is contained in:
2026-07-31 16:38:01 +08:00
parent 09f4d3ba52
commit 314a714248
8 changed files with 413 additions and 297 deletions

124
utils/fileOpener.js Normal file
View File

@@ -0,0 +1,124 @@
/**
* 文件打开工具 - 强制弹出应用选择器
*
* uni.openDocument 的 showMenu 和 plus.runtime.openFile 在真机上
* 都可能直接跳转默认应用。用 Android 原生 Intent.createChooser
* 强制弹出"选择应用"对话框。
*
* Android 7.0+ 会阻止 file:// URI 暴露给其他应用,需要禁用此限制。
*/
/**
* 根据文件扩展名获取 MIME 类型
*/
function getMimeType(filePath) {
const ext = filePath.substring(filePath.lastIndexOf('.') + 1).toLowerCase()
const mimeMap = {
'pdf': 'application/pdf',
'doc': 'application/msword',
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls': 'application/vnd.ms-excel',
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'ppt': 'application/vnd.ms-powerpoint',
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'txt': 'text/plain',
'html': 'text/html',
'htm': 'text/html',
'xml': 'text/xml',
'json': 'application/json',
'csv': 'text/csv',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'png': 'image/png',
'gif': 'image/gif',
'bmp': 'image/bmp',
'webp': 'image/webp',
'mp4': 'video/mp4',
'mp3': 'audio/mpeg',
'wav': 'audio/wav',
'zip': 'application/zip',
'rar': 'application/x-rar-compressed',
'7z': 'application/x-7z-compressed',
'apk': 'application/vnd.android.package-archive'
}
return mimeMap[ext] || '*/*'
}
/**
* 打开文件,弹出应用选择器
* @param {string} filePath 本地文件路径
* @param {Function} onFail 打开失败时的回调
*/
export function openFile(filePath, onFail) {
// #ifdef APP-PLUS
try {
const main = plus.android.runtimeMainActivity()
const Intent = plus.android.importClass('android.content.Intent')
const Uri = plus.android.importClass('android.net.Uri')
const File = plus.android.importClass('java.io.File')
// Android 7.0+ 默认禁止 file:// URI禁用此限制
if (plus.os.sdkInt >= 24) {
const StrictMode = plus.android.importClass('android.os.StrictMode')
StrictMode.disableDeathOnFileUriExposure()
}
const file = new File(filePath)
if (!file.exists()) {
throw new Error('文件不存在: ' + filePath)
}
const uri = Uri.fromFile(file)
const mimeType = getMimeType(filePath)
const intent = new Intent(Intent.ACTION_VIEW)
intent.setDataAndType(uri, mimeType)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
// 核心createChooser 每次必弹选择器,无视已设置的默认应用
const chooser = Intent.createChooser(intent, '选择应用打开')
main.startActivity(chooser)
console.log('openFile success - chooser shown')
} catch (e) {
console.error('openFile native failed, fallback:', e)
uni.openDocument({
filePath: filePath,
showMenu: true,
fail: typeof onFail === 'function' ? onFail : () => {}
})
}
// #endif
// #ifndef APP-PLUS
uni.openDocument({
filePath: filePath,
showMenu: true,
fail: typeof onFail === 'function' ? onFail : () => {}
})
// #endif
}
/**
* 下载文件并打开(弹出应用选择器)
* @param {string} url 远程文件 URL
* @param {Function} onFail 失败回调
*/
export function downloadAndOpen(url, onFail) {
uni.downloadFile({
url: url,
success: (res) => {
if (res.statusCode === 200) {
openFile(res.tempFilePath, onFail)
} else {
console.error('下载失败, statusCode:', res.statusCode)
if (typeof onFail === 'function') onFail()
}
},
fail: (err) => {
console.error('downloadFile fail:', err)
if (typeof onFail === 'function') onFail()
}
})
}