深开鸿 技术专区 鸿蒙 next 实现选择图片并上传功能

鸿蒙 next 实现选择图片并上传功能

简述一下实现这个功能的心路历程,首先现在选择图片的功能是在https://ohpm.openharmony.cn/#/cn/detail/@pura%2Fharmony-utils库中的 PickerUtil.selectPhoto,这个方法可以实现从相册里面去选择图片,并获得 fileuri 链接,但是该库没有接口上传...

egzosn  ·  2024-12-19 16:12:30 发布

简述一下实现这个功能的心路历程,首先现在选择图片的功能是在 https://ohpm.openharmony.cn/#/cn/detail/@pura%2Fharmony-utils库中的 PickerUtil.selectPhoto,这个方法可以实现从相册里面去选择图片,并获得 fileuri 链接,但是该库没有接口上传图片的功能,所以去官方文档与论坛中去搜到可以使用:  https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-request-V5#requestuploadfile9 来实现接口的上传图片功能。下面是对上传方法的封装:

import { request, BusinessError } from '@kit.BasicServicesKit';
import { LogUtil } from '../common/utils/LogUtil';
import { PreferencesUtil } from '../common/utils/PreferencesUtil';
import UserCacheManager from '../common/utils/UserCacheManager';
import CommonHttp from './CommonHttp';
import Config from './Config';


function requestSrc(val: string) { //请求的地址兼容处理;
  let tlc = val.toLowerCase();
  if (tlc.startsWith("http://") || tlc.startsWith("https://")) {
    return val;
  } else {
    return Config.api_hosts + val;
  }
}

function reqParamsToData(params: ESObject = {}) {
  let data: Array<request.RequestData> = [];
  if (!params) {
    return data;
  }
  Object.keys(params).map(key => {
    if (params[key]) {
      data.push({
        name: key,
        value: params[key] + ''
      })
    }
  })

  LogUtil.info("reqParamsToData:" + JSON.stringify(data))
  return data;
}

export interface RequestUploadResp {
  uploadTask: request.UploadTask
  err?: Error
}

interface RequestUploadConfig {
  files: Array<request.File>
}

const globalRequestUpload =
  (url: string, params: ESObject = {}, config: RequestUploadConfig): Promise<RequestUploadResp> => {
    const cateId = UserCacheManager.getSubjectCatId() || PreferencesUtil.getStringSync('_subjectCatId');
    const subjectId = UserCacheManager.getSubjectId() || PreferencesUtil.getStringSync('_subjectId');
    const goodAppType = UserCacheManager.getSubAppType() || PreferencesUtil.getStringSync('_subAppType');

    params.cate_id = params.cate_id || cateId;
    params.subject_id = params.subject_id || subjectId;
    params.good_app_type = params.good_app_type || goodAppType;

    let urls = ''
    let paramsPost = CommonHttp.requestMd5Params({})
    urls = url + CommonHttp.formatGetUri(paramsPost)


    let token = UserCacheManager.getLoginToken() || PreferencesUtil.getStringSync('access_token');
    let reqUrl = requestSrc(urls);
    let reqData = reqParamsToData(params);

    // let uploadTask: request.UploadTask;
    let uploadConfig: request.UploadConfig = {
      url: reqUrl, // 需要手动将 url 替换为真实服务器的 HTTP 协议地址
      header: {
        // 'Accept': 'application/json',
        'Content-Type': 'multipart/form-data',
        'Authorization': token
      },
      method: "POST",
      files: config.files,
      data: reqData
      // files: [{
      //   filename: "test",
      //   name: "test",
      //   uri: "internal://cache/test.jpg",
      //   type: "jpg"
      // }],
      // data: [{ name: "name", value: "a123" }],
    };

    LogUtil.info("uploadConfig:" + JSON.stringify(uploadConfig))

    return new Promise((resolve, reject) => {
      try {
        request.uploadFile(getContext(), uploadConfig).then((data: request.UploadTask) => {
          // uploadTask = data;
          resolve({ uploadTask: data })
        }).catch((err: BusinessError) => {
          LogUtil.error(`Failed to request the upload. Code: ${err.code}, message: ${err.message}`);
          reject({
            err
          })
        });
      } catch (err) {
        LogUtil.error(`Failed to request the upload. err: ${JSON.stringify(err)}`);
        reject({
          err
        })
      }
    })


  }

export default globalRequestUpload;
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.

然后通过PickerUtil.selectPhoto拿到图片 uri 然后调用globalRequestUpload上传一直报错 404,通过仔细看文档与在论坛搜索发现上传的 uri 必须要以 [internal://cache/](internal://cache/)为开头的形式的 uri 才支持上传。将selectPhoto拿到的 uri 转换成 [internal://cache/](internal://cache/)开头的代码如下:

// 将图片地址转换为沙箱地址-上传图片方法只能使用沙箱地址
  static async toInternalCacheUrl(selImg: string, fileType: string = 'jpg') {
    if (!selImg) {
      throw new Error('没有图片uri地址');
    }

    // 拷贝文件
    let cacheDir = getContext().cacheDir
    let fileName = Date.now().toString()

    // 获取到需要打包的图片
    let originImg = await fileIo.open(selImg) // 打开照片
    // 因为打包实例需要的图片格式为ImageSource,所以需要先将图片转为ImageSource
    let source = image.createImageSource(originImg.fd) // 创建一个图片实例
    // 创建一个图片打包器实例
    let packer = image.createImagePacker() // 创建一个图片打包器实例
    // 压缩打包图片
    let arrayBuffer = await packer.packing(source, { quality: 10, format: 'image/jpeg' }) // 压缩打包图片
    // 创建一个文件实例
    let newFile = fileIo.openSync(cacheDir + '/' + fileName + '.' + fileType,
      fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE) // 打开文件并给予权限
    // 将图片的二进制数据流写入文件
    fileIo.writeSync(newFile.fd, arrayBuffer) // 写入文件
    const cacheUrl = 'internal://cache/' + fileName + '.' + fileType;

    return cacheUrl;
  }
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
Logo

更多推荐

  • 浏览量 423
  • 收藏 0
  • 0

所有评论(0)

查看更多评论 
已为社区贡献5条内容