在鸿蒙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 中配置网络安全策略。
相关推荐
Dream耀13 分钟前
CSS选择器完全手册:精准控制网页样式的艺术
前端·css·html
wordbaby13 分钟前
React 19 亮点:让异步请求和数据变更也能用 Transition 管理!
前端·react.js
月亮慢慢圆14 分钟前
VUE3基础之Hooks
前端
我想说一句15 分钟前
CSS 基础知识小课堂:从“选择器”到“声明块”,带你玩转网页的时尚穿搭!
前端·javascript·面试
红衣信25 分钟前
深入浅出 CSS 基础:从概念到选择器实战
前端·css
饮茶三千27 分钟前
五分钟!带你开发一个 VS Code 插件,实现状态栏文案轮播效果
前端
GIS之路27 分钟前
OpenLayers 地图投影转换
前端
用户48183772080328 分钟前
css grid实现流体布局
前端
Hanbox29 分钟前
探探React-找一个好看的组件库HeroUI(原NextUI)
前端