uni-app x uni.openDocument 打开文档 API 完全指南:参数、错误码与跨端底层实现
uni.openDocument 是 uni-app x 提供的"打开文档"API,用于在 App 端和微信小程序端唤起系统/宿主能力浏览 PDF、Word、Excel、PPT 等本地文件。本文以仓库中的官方规范文档 docs/api/open-document.md 为主线,结合 uni-openDocument UTS 插件 的 Android、iOS、HarmonyOS 三端源码实现,完整讲解调用参数、失败错误码语义以及各平台底层打开文件的真实机制,帮助开发者在实际项目中正确接入并能自主排查问题。
功能定位与适用场景
uni.openDocument(options?) 的作用是打开一个本地文档文件,官方规范文档中的定位描述只有一句话:"打开文档",但其背后承载的是移动端最常见的"附件预览"诉求,典型应用场景包括:
- 从服务器下载合同、发票、报告等文件后,调用
uni.openDocument直接唤起系统能力进行浏览; - 配合
uni.downloadFile(见 docs/api/download-file.md)拿到临时文件路径后打开; - 打开
uni.getFileSystemManager()读写出的本地文件(参考 src/pages/API/get-file-system-manager/filemanage.uvue)。
需要特别注意的是:该 API 不支持 Web 端。官方示例页(src/pages/API/open-document/open-document.uvue)中明确提示"该 API 不支持 Web,请运行 hello uni-app x 到 App 平台体验",其页面模板中所有内容也都用 <!-- #ifdef APP --> 条件编译包裹。
平台兼容性一览
根据规范文档中的兼容性表格,uni.openDocument 的支持情况如下:
| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | x(不支持) | 4.41 | 4.71 | 4.71 | 4.61 |
其中数字代表 uni-app x(unix 版本)的最低支持版本。从 interface.uts 中大量 @uniPlatform 注释可以印证更细粒度的版本要求:
- App-Android / App-iOS:unixVer 4.71 起支持;iOS 同时标注
unixUtsPlugin: 4.71(即作为 UTS 插件被引入); - App-Harmony:unixVer 4.61 起支持,
unixVaporVer: 5.0; - 微信小程序:unixVer 4.41 起支持,宿主版本为
√(跟随微信宿主能力,showMenu参数额外要求基础库 2.11.0+); - 支付宝、百度、抖音、飞书、QQ、快手、京东等小程序:hostVer/uniVer/unixVer 均为
x,即不支持; - Web:全部为
x,不支持。
从插件声明文件 package.json 也能看到,其 uni-ext-api 中 app 平台分别声明了 kotlin: true、swift: true、arkts: true 三端原生实现,而 js: false,即该 API 在 App 端由原生代码实现,不经过 JS 引擎。
参数详解:OpenDocumentOptions
uni.openDocument 的参数类型为 OpenDocumentOptions,各字段定义在 interface.uts 中。完整字段如下:
| 名称 | 类型 | 必填 | 兼容性 | 描述 | | :- | :- | :- | :-: | :- | | options | OpenDocumentOptions | 否 | Web: x | uni.openDocument 参数定义 | | filePath | string | 是 | 全端 | 文件路径,仅支持本地路径 | | fileType | string | 否 | 全端 | 文件类型(扩展名),可指定文件类型打开 | | success | (res: OpenDocumentSuccess) => void | 否 | 全端 | 成功回调 | | fail | (res: OpenDocumentFail) => void | 否 | 全端 | 失败回调 | | complete | (res: any) => void | 否 | 全端 | 完成回调(成功、失败都会执行) | | showMenu | boolean | 否 | 仅微信小程序 | 是否显示右上角菜单,需基础库 2.11.0+ |
filePath:仅支持本地路径
filePath 是唯一必填参数,只接受本地路径。参考三端实现源码可确认其支持的路径形态:
- 普通本地绝对/相对路径:Android 端通过
UTSAndroid.convert2AbsFullPath转换为绝对路径后校验文件是否存在(app-android/index.uts);iOS 端通过UTSiOS.convert2AbsFullPath转换后调用FileManager.default.fileExists检查(app-ios/index.uts);HarmonyOS 端同样经UTSHarmony.convert2AbsFullPath转换并用fs.statSync判断存在性(app-harmony/index.uts); content://开头的 URI(仅 Android):源码中path.startsWith('content://')会直接Uri.parse并使用ContentResolver.openInputStream校验可读性;/android_asset/开头的应用内置资源(仅 Android):源码 isValidFile 会通过getAssets().open读取,并自动将其复制到应用外部缓存目录.../uni-document/下再打开——这解释了"仅支持本地路径"的同时仍能打开工程内置静态文件的原因。
因此不传 http(s) 网络地址直接调用:文档示例代码中凡是 http 开头的 URL,都会先走 uni.downloadFile 下载,再以 res.tempFilePath 作为 filePath 传入。
fileType:文件类型(扩展名)
fileType 用于显式指定文件类型,注意两端的语义差异:
- 微信小程序端:仅支持
doc, xls, ppt, pdf, docx, xlsx, pptx这 7 种类型,超出范围将无法打开; - App 端(Android/iOS/HarmonyOS):由系统根据文件内容决定由哪个应用打开,原则上可以打开任意文件。参数中的扩展名仅作为辅助信息用于推导 MIME 类型:
- Android:
MimeTypeMap.getSingleton().getMimeTypeFromExtension(options.fileType)推导 MIME 类型并intent.setDataAndType(uri, mimeType)(app-android/index.uts); - HarmonyOS:
uniformTypeDescriptor.getUniformDataTypeByFilenameExtension推导类型描述符并取出首个 MIME 类型,若传入的 fileType 无法识别会抛出错误码1300603(app-harmony/index.uts)。
- Android:
源码中该字段类型为 OpenDocumentSupportedTypes,即 string,且允许传 null(fileType ?: OpenDocumentSupportedTypes | null)。
三个回调与 showMenu
success、fail、complete与 uni-app 其他 API 的约定一致:成功只走success+complete,失败只走fail+complete。从源码看,OpenDocumentSuccess是一个空类型{}(interface.uts),成功回调不带业务数据;showMenu仅微信小程序支持(Web: x; 微信小程序: 4.41),控制打开文档页面右上角是否显示菜单,需要微信基础库2.11.0。
错误处理与 errCode 错误码
打开文档属于高风险调用(路径可能无效、文件可能被删、设备可能没有可处理该类型的应用),官方规范为失败回调定义了完整错误对象结构。
OpenDocumentFail 的结构
失败回调收到的 OpenDocumentFail 对象(对应源码中的 IOpenDocumentError,继承自 IUniError,参见 err-spec.md)包含以下字段:
| 名称 | 类型 | 必填 | 描述 | | :- | :- | :- | :- | | errCode | number | 是 | 错误码 | | errSubject | string | 是 | 统一错误主题(模块)名称 | | data | any | 否 | 错误信息中包含的数据 | | cause | Error | 否 | 源错误信息,可包含多个错误 | | errMsg | string | 是 | 错误信息 |
errCode 错误码速查
| 合法值 | 兼容性 | 描述 | 触发时机(依据源码) | | :- | :-: | :- | :- | | 1300601 | 全端 | 路径无效 | iOS 端路径转换后 isFileURL == false 时抛出(app-ios/index.uts) | | 1300602 | 全端 | 文件不存在 | Android 端 file.exists() 为 false、资源读取失败、content URI 不可读时抛出;iOS 端 fileExists 为 false 时抛出;HarmonyOS 端 fileExists 为 false 时抛出 | | 1300603 | 全端 | 不支持该文件类型 | Android 端 startActivity 抛异常(设备无应用可处理)时抛出;HarmonyOS 端 fileType 无法识别 MIME 类型时抛出 | | 1300604 | 全端 | 其他未知错误 | Android 端获取不到 Activity、资源复制异常时抛出;HarmonyOS 端兜底错误 |
这些错误码与错误消息映射定义在 unierror.uts:
export const OpenDocumentUniErrors : Map<number, string> = new Map([
[1300601, 'Invalid file path'],
[1300602, 'File not exist'],
[1300603, 'Not support this filetype'],
[1300604, 'Unkowned error']
]);
errSubject 与 errMsg
源码中错误主题(模块名)固定为 'uni-openDocument'(OpenDocumentUniErrorSubject),errMsg 默认取上述映射表中对应错误码的英文描述,用于统一错误上报与排查(unierror.uts)。
实战建议:在 fail 回调中不要只弹 errMsg,应把 errCode 一并展示(官方示例正是用 '错误码:' + err.errCode.toString() 弹 Toast),因为同一错误码在不同平台的触发路径不同,开发阶段能更快定位问题归属。
完整示例:从网络下载到打开文档
仓库中的官方示例页位于 src/pages/API/open-document/open-document.uvue,并在 src/pages.json 中注册为标题"uni.openDocument | 打开文档"。核心逻辑如下:
<template>
<page-head :title="title"></page-head>
<!-- #ifdef APP -->
<scroll-view direction="vertical" style="flex:1">
<!-- #endif -->
<view class="uni-common-mt">
<button v-for="(item, index) in fileList" :key="index" @click="openDocument(item)" style="margin: 10px;">
打开 {{item.type}} 文件
</button>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
type FileItem = {
type : string,
url : string
}
const title = 'openDocument'
const fileList = ref<Array<FileItem>>([
{ type: 'pdf', url: 'https://web-assets.dcloud.net.cn/unidoc/zh/helloworld.pdf' },
{ type: 'doc', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/helloworld.doc' },
{ type: 'docx', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/helloworld.docx' },
{ type: 'ppt', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/helloworld.ppt' },
{ type: 'pptx', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/helloworld.pptx' },
{ type: 'xls', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/helloworld.xls' },
{ type: 'xlsx', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/helloworld.xlsx' },
{ type: 'zip', url: 'https://web-ext-storage.dcloud.net.cn/uni-app-x/file/to.zip' },
{ type: 'br', url: '/static/filemanager/1.txt.br' },
{ type: 'mp3', url: '/static/test-audio/ForElise.mp3' },
{ type: 'mp4', url: '/static/test-video/10second-demo.mp4' },
{ type: 'svg', url: '/static/test-image/logo.svg' }
])
const openDocument = (item : FileItem) => {
if (item.url.startsWith('http')) {
uni.showLoading({ title: '下载中', mask: true })
uni.downloadFile({
url: item.url,
success: (res) => {
uni.openDocument({
filePath: res.tempFilePath,
success: () => {
uni.hideLoading()
console.log('打开文档成功')
},
fail: (err) => {
uni.hideLoading()
console.log('打开文档失败', err)
uni.showToast({ title: '错误码:' + err.errCode.toString(), icon: "error" })
}
})
},
fail: (err) => {
uni.hideLoading()
console.log('下载失败', err)
uni.showToast({ title: '下载失败:' + err.errCode.toString(), icon: "error" })
}
})
} else {
uni.openDocument({
filePath: item.url,
success: () => {
console.log('打开文档成功')
},
fail: (err) => {
console.log('打开文档失败', err)
uni.showToast({ title: '错误码:' + err.errCode.toString(), icon: "error" })
}
})
}
}
</script>
该示例覆盖了两类输入:
- 网络 URL:先
uni.showLoading提示下载中,uni.downloadFile下载成功后在success回调中把res.tempFilePath作为filePath调用uni.openDocument;下载失败同样弹 Toast 提示; - 本地路径(如
/static/...工程内置资源):直接调用uni.openDocument。
两种分支都完整处理了 success / fail,并在失败时展示错误码——这套模板可直接复制到实际业务中,只需替换文件列表来源(例如改为从 uni.getFileSystemManager 写入的本地文件路径)。
源码剖析:三端底层实现原理
uni.openDocument 在 App 端对应 uni_modules 插件 uni-openDocument,实现代码位于 utssdk 目录并按平台拆分(package.json 中声明其依赖 uni-fileSystemManager)。各端打开文件的机制差异很大,理解后有助于排查"打不开""没反应"类问题。
Android:ACTION_VIEW + FileProvider
Android 实现(app-android/index.uts)的核心链路:
- 取当前 Activity,通过
UTSAndroid.convert2AbsFullPath规范化路径; isValidFile做三重校验:普通文件校验File.exists();/android_asset/资源先经 Assets 读取并复制到外部缓存目录getExternalCacheDir()/uni-document/;content://URI 用ContentResolver.openInputStream验证;- Android 7.0(API 24)及以上使用
FileProvider.getUriForFile(activity, packageName + '.dc.fileprovider', file)生成content://URI 并授予读权限(FLAG_GRANT_READ_URI_PERMISSION),这是 Android N 之后"FileUriExposedException"问题的标准解法; - 构造
Intent.ACTION_VIEW,有fileType时用MimeTypeMap推导 MIME 类型setDataAndType,否则直接setData; startActivity若抛异常(说明设备上没有能打开该类型文件的应用),则回调错误1300603;- 插件还在
UniOpenDocumentHookProxy.onCreate中异步清理缓存目录残留文件,避免下载/复制的临时文档堆积(app-android/index.uts)。
iOS:QuickLook 预览控制器
iOS 实现(app-ios/index.uts)没有走"跳转第三方应用"的方案,而是在 App 内部以 QuickLook 框架的 QLPreviewController 展示文档:
- 将
filePath经UTSiOS.convert2AbsFullPath转为绝对路径并构造URL; - 非文件 URL(
isFileURL == false)报1300601,文件不存在报1300602; - 以单例
DocumentPreviewer作为dataSource/delegate,通过UTSiOS.getCurrentViewController().present(...)模态弹出QLPreviewController; UniPreviewItem实现QLPreviewItem协议提供预览 URL,numberOfPreviewItems返回 1 表示单文件预览;- 预览关闭后(
previewControllerDidDismiss)延迟 0.01 秒重新 present,以兼容 iOS 13+ 的 modal 呈现变化。
由于 QuickLook 原生支持 PDF、Office 文档等常见格式,iOS 端"原则上可打开任意文件"即指 QuickLook 能力范围内的格式。
HarmonyOS:Want 隐式意图 + uniformTypeDescriptor
HarmonyOS 实现(app-harmony/index.uts)通过系统 Want 隐式启动查看器:
UTSHarmony.convert2AbsFullPath转绝对路径,fs.statSync校验存在性,否则报1300602;- 若目标在
resourceDir(应用资源目录)内,先复制到临时目录TEMP_PATH/openDocumentCache下再打开,保证资源只读目录可被外部读取; - 用
uniformTypeDescriptor.getUniformDataTypeByFilenameExtension+getTypeDescriptor从扩展名推导 MIME 类型,识别失败报1300603; - 构造
Want:action: 'ohos.want.action.viewData',携带uri(fileUri.getUriFromPath生成)、type(MIME 类型)以及读写持久化权限 flags,最后startAbility拉起系统文档查看器或第三方应用。
源码注释中还记录了一个工程细节:传入 type 参数时只调起 2 个解压缩应用,不传反而能调起 4 个——说明某些类型显式传 fileType 反而会收窄可选应用范围,实际业务中可权衡是否传该参数。
统一错误对象
三端在失败时均构造 OpenDocumentErrorImpl(继承 UniError,见 err-spec.md),统一设置 errSubject = 'uni-openDocument'、errCode 与 errMsg(unierror.uts),因此在业务代码中无需关心平台差异,只需按错误码处理。
使用要点与常见问题
- Web 端不可用:页面若需同时支持 H5 与 App,应对
uni.openDocument做条件编译或能力判断(示例页全程#ifdef APP包裹),避免 H5 上报错; - filePath 必须本地化:网络文件先
uni.downloadFile;/static/内置资源在 Android 端会被自动复制到缓存目录(getExternalCacheDir()/uni-document/),iOS/HarmonyOS 同样有各自的临时目录处理,业务侧无需关心细节,但要注意缓存可能被系统清理; - fileType 语义差异:微信小程序仅 7 种类型(doc/xls/ppt/pdf/docx/xlsx/pptx);App 端传错扩展名在 HarmonyOS 上会触发
1300603,Android 上传了无法识别的类型时setDataAndType的 MIME 为 null,可能影响应用筛选,不必要时可不传; - 1300603 的另一层含义(Android):
startActivity抛异常说明设备上没有能打开该文件的应用,这与"类型不受支持"是同一错误码,需要向用户提示"未安装可打开该文件的应用"; - 失败诊断顺序:先看
errCode——1300601查路径格式、1300602查文件是否存在、1300603查类型与系统应用、1300604查平台异常(如 Android 获取 Activity 失败);再看errMsg/errSubject定位模块; - 完整可运行示例:官方演示工程中的 open-document.uvue 覆盖了从下载到打开的完整闭环,且示例文件在仓库
src/static/下均有对应资源(如filemanager/1.txt.br、test-audio/、test-video/、test-image/),可直接运行于 App 端验证多类型文件打开效果。
通过本文的参数表、错误码对照与三端源码解读,开发者可以准确地在 uni-app x 项目中集成"打开文档"能力,并在出现问题时依据 errCode 快速定位是路径、文件、类型还是系统环境问题。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



