Files
phone-app------test1-/utils/fileOpener.js

125 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 文件打开工具 - 强制弹出应用选择器
*
* 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()
}
})
}