ArkWeb 手记 07|H5 文件上传:对接鸿蒙文件选择器
前面 01~06,我们搞定生命周期、JS 双向通信、rawfile 资源、调试缓存、请求劫持、window.open 页面跳转拦截。
这一期解决混合开发里刚需功能:H5 里<input type="file">上传文件。
直接跑项目你会发现,H5 的文件选择按钮点了没反应。浏览器里 input file 自带弹窗,ArkWeb 不会自动唤起系统文件选择器,必须手动实现onShowFileSelector回调接管文件选择逻辑。
当初踩坑:简单写回调返回文件路径,结果 H5 接收不到文件,调试很久才明白,这里要求返回Uri 数组,不是本地绝对文件路径,格式不对直接上传失效。
核心误区:H5 的 file 输入框触发时,ArkWeb 默认不处理文件选择;需要在onShowFileSelector回调里唤起鸿蒙原生文件选择,再把文件 Uri 交给 ArkWeb。

核心概念一句话讲清
onShowFileSelector 就是 H5 <input type="file"> 点击后的回调。
H5 触发文件选择,回调被调用;我们在回调拉起鸿蒙文件选择器,用户选中文件后,把文件 Uri 数组返回给 ArkWeb,H5 就能拿到文件继续上传。
类比:H5 只负责 “发起选文件请求”,真正打开文件浏览窗口、读取文件,全部交给鸿蒙原生能力。
前置条件:HarmonyOS7,DevEco Studio,沿用前面工程,需要申请文件访问权限。
第一步:工程权限配置
module.json5 添加权限,否则文件选择器无法读取文件
"requestPermissions": [
{
"name": "ohos.permission.READ_MEDIA",
"reason": "用于ArkWeb H5上传,读取媒体文件",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
第二步:ArkTS 完整代码
import { ArkWeb, ArkWebController, FileSelectorResult } from '@kit.ArkWeb';
import { pick } from '@kit.FilePicker';
@Entry
@Component
struct WebFileUploadDemo {
controller: ArkWebController = new ArkWebController();
aboutToAppear() {
this.controller.javascriptEnabled = true;
// 接管H5文件选择弹窗
this.controller.onShowFileSelector = async (): Promise<FileSelectorResult> => {
// 拉起鸿蒙文件选择器,单选图片
const result = await pick({
MIMEType: pick.MIMEType.IMAGE,
maxSelectNumber: 1
})
// 返回文件Uri给ArkWeb,交给H5 input file
return {
uris: result.uris
}
}
}
build() {
Column() {
ArkWeb({
src: $rawfile("index.html"),
controller: this.controller
})
.width('100%')
.layoutWeight(1)
}
}
}
配套 H5 index.html 测试代码
<!-- H5文件上传控件 -->
<input type="file" accept="image/*" id="fileInput">
<img id="previewImg" style="width:200px">
<script>
const fileInput = document.getElementById('fileInput');
const previewImg = document.getElementById('previewImg');
fileInput.onchange = function(e){
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = function(ev){
previewImg.src = ev.target.result;
}
reader.readAsDataURL(file);
}
</script>
关键语句拆解:
onShowFileSelector是异步 Promise 回调,必须返回FileSelectorResult对象,里面是 uris 数组。pick是文件选择器接口,可以限制图片 / 视频 / 文档,maxSelectNumber控制单选还是多选。- 返回的是系统 Uri,不是本地文件路径,不要手动拼接路径字符串。

第三步:支持多选文件 & 限制文件类型
修改 pick 参数,开启多选,支持图片 + 文档
this.controller.onShowFileSelector = async (): Promise<FileSelectorResult> => {
const result = await pick({
MIMEType: pick.MIMEType.ALL,
maxSelectNumber: 3
})
return { uris: result.uris }
}

高频踩坑清单(重点)
- ❌ 点击 H5 上传按钮,完全没有弹出文件选择器
✅ 没有实现onShowFileSelector回调,ArkWeb 不会处理 input file。 - ❌ 选完图片,H5 预览空白,拿不到文件
✅ 返回了本地绝对路径字符串,不是系统 Uri,必须使用文件选择器返回的 uris。 - ❌ 忘记申请 READ_MEDIA 权限,文件选择器能打开,但选中文件返回空 uri
✅ module.json5 配置媒体读取权限,真机运行还需要弹窗授权。 - ❌ 回调里面写复杂业务阻塞 Promise,界面卡死
✅ 文件选择是异步操作,不要在回调增加大量同步逻辑。

小扩展:取消选择场景处理
用户打开文件选择器但是不点文件、直接点取消,此时 result.uris 为空数组,H5 不会触发 onchange,无需额外处理。
this.controller.onShowFileSelector = async (): Promise<FileSelectorResult> => {
try {
const result = await pick({MIMEType: pick.MIMEType.IMAGE,maxSelectNumber:1})
return { uris: result.uris ?? [] }
}catch(err){
// 用户取消选择,返回空数组
return { uris: [] }
}
}

更多推荐




所有评论(0)