在鸿蒙HarmonyOS5中从本地图库上传图片

在鸿蒙(HarmonyOS)中从本地图库选择并上传图片,主要涉及 ​​文件选择器(Picker)​ ​ 和 ​​网络请求(HTTP)​ ​ 两个核心模块。以下是详细步骤和代码示例(基于 ​​ArkTS/JS​​ 开发):

​1. 添加权限​

module.json5 中声明必要权限:

json 复制代码
{
  "module": {
    "requestPermissions": [
      {
        "name": "ohos.permission.READ_MEDIA" // 读取本地媒体文件
      },
      {
        "name": "ohos.permission.INTERNET"   // 网络访问
      }
    ]
  }
}

​2. 使用文件选择器(Picker)选择图片​

鸿蒙提供了 PhotoViewPicker 从图库中选择图片:

javascript 复制代码
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';

async function selectImageFromGallery(): Promise<string | undefined> {
  try {
    // 1. 创建图片选择器
    const photoSelectOptions: picker.PhotoSelectOptions = {
      MIMEType: picker.PhotoViewMIMETypes.IMAGE_TYPE, // 仅选择图片
      maxSelectNumber: 1, // 选择1张图片
    };

    const photoPicker = new picker.PhotoViewPicker();
    const result = await photoPicker.select(photoSelectOptions);

    // 2. 返回选择的图片URI(如:file://media/images/1.jpg)
    if (result && result.photoUris.length > 0) {
      return result.photoUris[0];
    }
  } catch (error) {
    console.error('选择图片失败:', error);
  }
  return undefined;
}

​3. 将图片转换为可上传的格式​

鸿蒙的 PhotoViewPicker 返回的 URI 不能直接用于上传,需通过 fileIOfs 模块读取文件内容:

javascript 复制代码
async function readFileData(uri: string): Promise<Uint8Array | undefined> {
  try {
    // 1. 将URI转换为实际路径(如:file:// -> /data/media/images/1.jpg)
    const filePath = uri.replace('file://', '');

    // 2. 读取文件二进制数据
    const file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
    const fileData = fs.readSync(file.fd);
    fs.closeSync(file);

    return fileData;
  } catch (error) {
    console.error('读取文件失败:', error);
  }
  return undefined;
}

​4. 上传图片到服务器​

使用 @ohos.net.http 发送 multipart/form-data 请求:

javascript 复制代码
import http from '@ohos.net.http';

async function uploadImage(fileData: Uint8Array, fileName: string): Promise<void> {
  const httpRequest = http.createHttp();

  // 1. 构造表单数据
  const formData = new FormData();
  formData.append('file', new Blob([fileData]), fileName);

  // 2. 发送请求
  const options = {
    method: 'POST',
    url: 'https://your-server.com/upload', // 替换为实际API地址
    header: {
      'Content-Type': 'multipart/form-data',
    },
    extraData: formData,
  };

  try {
    const response = await httpRequest.request(options);
    if (response.responseCode === 200) {
      console.info('上传成功:', response.result);
    } else {
      console.error('上传失败:', response.responseCode);
    }
  } catch (error) {
    console.error('网络请求错误:', error);
  }
}

​5. 完整流程整合​

在页面中绑定按钮点击事件,串联整个流程:

typescript 复制代码
import common from '@ohos.app.ability.common';

@Entry
@Component
struct ImageUploadPage {
  @State previewImage: string = ''; // 预览图片路径

  async onUploadClick() {
    // 1. 从图库选择图片
    const imageUri = await selectImageFromGallery();
    if (!imageUri) return;

    // 2. 预览图片
    this.previewImage = imageUri;

    // 3. 读取文件数据
    const fileData = await readFileData(imageUri);
    if (!fileData) return;

    // 4. 上传(文件名取时间戳)
    const fileName = `image_${new Date().getTime()}.jpg`;
    await uploadImage(fileData, fileName);
  }

  build() {
    Column() {
      // 图片预览
      if (this.previewImage) {
        Image(this.previewImage)
          .width(300)
          .height(300)
      }

      // 上传按钮
      Button('选择并上传图片')
        .onClick(() => this.onUploadClick())
    }
    .width('100%')
    .height('100%')
  }
}

​关键注意事项​

  1. ​动态权限申请​ ​:

    首次访问图库时需动态申请 READ_MEDIA 权限:

    javascript 复制代码
    import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
    
    async function requestPermissions() {
      const permissions: Array<string> = ['ohos.permission.READ_MEDIA'];
      const atManager = abilityAccessCtrl.createAtManager();
      await atManager.requestPermissionsFromUser(getContext(), permissions);
    }
  2. ​URI转换问题​​:

    • 鸿蒙返回的URI可能是 internal://media/images/1,需通过 @ohos.file.fs 转换为可读路径。
    • 使用 fs.openSync 时需确保路径合法。
  3. ​服务器兼容性​​:

    • 确保服务器支持 multipart/form-data 格式。
    • 若需HTTPS,需在 config.json 中配置网络安全策略。
相关推荐
杨进军9 分钟前
React 创建根节点 createRoot
前端·react.js·前端框架
ModyQyW23 分钟前
用 AI 驱动 wot-design-uni 开发小程序
前端·uni-app
说码解字30 分钟前
Kotlin lazy 委托的底层实现原理
前端
爱分享的程序员1 小时前
前端面试专栏-算法篇:18. 查找算法(二分查找、哈希查找)
前端·javascript·node.js
翻滚吧键盘1 小时前
vue 条件渲染(v-if v-else-if v-else v-show)
前端·javascript·vue.js
vim怎么退出1 小时前
万字长文带你了解微前端架构
前端·微服务·前端框架
你这个年龄怎么睡得着的1 小时前
为什么 JavaScript 中 'str' 不是对象,却能调用方法?
前端·javascript·面试
Java水解1 小时前
前端常用单位em/px/rem/vh/vm到底有什么区别?
前端
CAD老兵1 小时前
Vite 如何借助 esbuild 实现极速 Dev Server 体验,并支持无 source map 的源码调试
前端
南屿im1 小时前
JavaScript 手写实现防抖与节流:优化高频事件处理的利器
前端·javascript