在鸿蒙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 中配置网络安全策略。
相关推荐
YH丶浩几秒前
vue自定义数字滚动插件
开发语言·前端·javascript·vue
阿民_armin1 分钟前
Canvas 冷暖色分析工具
前端·javascript·vue.js
小岛前端2 分钟前
大小仅 1KB!超级好用!计算无敌!
前端·javascript·开源
没有鸡汤吃不下饭14 分钟前
Git将某个分支合并到开发(dev)、测试(test)后突然想撤销该分支的功能,怎么处理?
前端·git·github
文心快码BaiduComate15 分钟前
Comate分饰多角:全栈开发一个Python学习网站
前端·后端·python
90后的晨仔22 分钟前
Vue 插槽(Slots)全面解析与实战指南
前端·vue.js
我是日安25 分钟前
从零到一打造 Vue3 响应式系统 Day 20 - Reactive:reactive 极端案例
前端·vue.js
Slice_cy26 分钟前
📚 uniapp版本懒加载 + 不定高虚拟列表实现
前端
golang学习记27 分钟前
从0死磕全栈之Next.js API 路由实战:不用后端,前端也能写接口!
前端
Nathan2024061630 分钟前
Kotlin-Sealed与Open的使用
android·前端·面试