前面 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>

关键语句拆解:

  1. onShowFileSelector 是异步 Promise 回调,必须返回FileSelectorResult对象,里面是 uris 数组。
  2. pick是文件选择器接口,可以限制图片 / 视频 / 文档,maxSelectNumber控制单选还是多选。
  3. 返回的是系统 Uri,不是本地文件路径,不要手动拼接路径字符串。

在这里插入图片描述

第三步:支持多选文件 & 限制文件类型

修改 pick 参数,开启多选,支持图片 + 文档

this.controller.onShowFileSelector = async (): Promise<FileSelectorResult> => {
  const result = await pick({
    MIMEType: pick.MIMEType.ALL,
    maxSelectNumber: 3
  })
  return { uris: result.uris }
}

在这里插入图片描述

高频踩坑清单(重点)

  1. ❌ 点击 H5 上传按钮,完全没有弹出文件选择器
    ✅ 没有实现onShowFileSelector回调,ArkWeb 不会处理 input file。
  2. ❌ 选完图片,H5 预览空白,拿不到文件
    ✅ 返回了本地绝对路径字符串,不是系统 Uri,必须使用文件选择器返回的 uris。
  3. ❌ 忘记申请 READ_MEDIA 权限,文件选择器能打开,但选中文件返回空 uri
    ✅ module.json5 配置媒体读取权限,真机运行还需要弹窗授权。
  4. ❌ 回调里面写复杂业务阻塞 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: [] }
  }
}

在这里插入图片描述

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐