鸿蒙——获取系统相册 并进行图片上传

1.相机拍照cameraPicker 流程:

1.打开相机后置摄像头得到拍照结果集 cameraPicker.pick

const pickerResult = cameraPicker.pick( 配置参数)

2.根据结果集的URI属性同步打开文件 openSync

const file = fs.openSync(pickerResult.resultUri)

3.以同步方法获取文件详细属性信息 fs.statSync

const stat = fs.statSync(file.fd)

4.定义缓冲区用于保存读取的文件

const buffer = new ArrayBuffer(stat.size)

5.开始同步读取内容到缓冲区

fs.readSync(file.fd, buffer)

6.读取完毕后关闭文件流 close

fs.closeSync(file)

7.借助util工具方法把读取的文件流转成base64编码的字符串

util.Base64Helper( )

import { camera, cameraPicker } from '@kit.CameraKit';
import fs from '@ohos.file.fs';
import { util } from '@kit.ArkTS';

class CameraPlugin {
   async pickerCamera(){
      // 1. 打开相机后置摄像头得到拍照结果集
      const pickerProfile: cameraPicker.PickerProfile = {
         cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
      };
      const pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(getContext(),
         [cameraPicker.PickerMediaType.PHOTO], pickerProfile);


      // 2. 根据结果集的URI属性同步打开文件
      const file = fs.openSync(pickerResult.resultUri)
      // 3. 同步读取文件的详情信息
      const stat = fs.statSync(file.fd)
      // 4. 定义缓冲区用于保存读取的文件
      const buffer = new ArrayBuffer(stat.size)
      // 5. 开始同步读取内容到缓冲区
      fs.readSync(file.fd, buffer)
      // 6. 读取完毕后关闭文件流
      fs.closeSync(file)


      // 7. 借助util工具方法把读取的文件流转成base64编码的字符串
      const helper = new util.Base64Helper()
      const str = helper.encodeToStringSync(new Uint8Array(buffer))
      console.log('mk-logger', 'pickerCamera', str)
      return str
   }
}

export const cameraPlugin = new CameraPlugin()

2.操作相册fs:

  1. 打开相册选择图片 得到拍照结果集 cameraPicker.pick

const photoSelectOptions = new picker.PhotoSelectOptions()

const photoPicker = new picker.PhotoViewPicker( );

const res = await photoPicker.select(photoSelectOptions)

——>获取照片的uri地址 const uri = res.photoUris[0]

      2.1根据结果集的URI属性同步打开文件 openSync

     const file = fs.openSync(uri)

    // 2.2 根据uri同步打开文件
    const file = fs.openSync(uri)
    // 2.3 同步获取文件的详细信息
    const stat = fs.statSync(file.fd)
    // 2.4 创建缓冲区存储读取的文件流
    const buffer = new ArrayBuffer(stat.size)
    // 2.5 开始同步读取文件流到缓冲区
    fs.readSync(file.fd, buffer)
    // 2.6 关闭文件流
    fs.closeSync(file)

    // 3. 转成base64编码的字符串
    const helper = new util.Base64Helper()
    const str = helper.encodeToStringSync(new Uint8Array(buffer))

import { picker } from '@kit.CoreFileKit'
import fs from '@ohos.file.fs';
import { util } from '@kit.ArkTS';

class PhotoPlugin {
  async pickerPhoto(){
     // 1. 打开相册选择图片
     const photoSelectOptions = new picker.PhotoSelectOptions()
         photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
         photoSelectOptions.maxSelectNumber = 1;

     const  photoPicker = new picker.PhotoViewPicker();
     const res = await photoPicker.select(photoSelectOptions)
     console.log('mk-logger', 'photoPlugin', JSON.stringify(res))

    // 2. 文件操作
    // 2.1 获取照片的uri地址
    const uri = res.photoUris[0]
    // 2.2 根据uri同步打开文件
    const file = fs.openSync(uri)
    // 2.3 同步获取文件的详细信息
    const stat = fs.statSync(file.fd)
    // 2.4 创建缓冲区存储读取的文件流
    const buffer = new ArrayBuffer(stat.size)
    // 2.5 开始同步读取文件流到缓冲区
    fs.readSync(file.fd, buffer)
    // 2.6 关闭文件流
    fs.closeSync(file)

    // 3. 转成base64编码的字符串
    const helper = new util.Base64Helper()
    const str = helper.encodeToStringSync(new Uint8Array(buffer))
    console.log('mk-logger', 'photoPlugin-str', str)

    return str
   }
}


export const photoPlugin = new PhotoPlugin()

3.获取系统相册 并进行图片上传:

picker选择系统相册图片,获取路径——>利用request.uploadFile方法完成应用程序缓存目录下的文件上传操作
        1.怎么获取的系统相册?( //picker选择系统相册图片,获取路径)

        我们这个项目里面有一个功能是上传头像,先使用picker这个API实现从系统上获取相册图片这个点的,首先要实例一个选择参数PhotoSelectOptions 里面需要设置媒体文件类型还有一个数量,然后—>实例一个选择器PhotoViewPicker,通过自带的——>select方法传入先前设置的选择参数即可完成选择。

        因为要上传嘛,所以我们通过上下文获取了一下应用缓存文件夹,然后使用fs.copyFileSync这个方法把图片拷贝到应用缓存文件夹里面。

——>把读取的文件保存到缓冲区buffer里面

const buffer = new ArrayBuffer(stat.size)

——>通过网络请求将Buffer中的数据上传到服务器。读取内容到缓冲区

fs.readSync(file.fd, buffer)

——>借助util工具方法把服务器读取的文件流(从二进制数据)转成base64编码的字符串

util.Base64Helper( )

        2.项目中图片上传是怎么做的?(利用request.uploadFile方法完成应用程序缓存目录下的文件上传操作)

        文件上传主要借助于鸿蒙request这个原生api的 uploadFile方法。

        但是这个方法不能直接读取相册中的内容,所以我们中间要做一个转换,用我们的fs和pick这两个api把我们相册的图片拷贝到了应用程序中来了。

        它需要传入两个参数,一个是当前应用的上下文(通过上下文,我们可以获取到拷贝到应用程序沙箱里面的文件的),一个是上传文件的配置参数,比如:接收文件的后端接口,文件路径设置等,还有在header里面要设置Content-Type为multipart/form-data,表示当前上传的是一个多部分表单数据,这是做上传时必须要设置的,后端会根据这个类型去做文件的接收处理。

 'Content-Type': 'multipart/form-data'
        3.request还有两个事件可以被我们监听,分别是progress 和 fail

        其中progress事件会返回上传文件的总大小totalSize 和当前上传的大小uploadSize,我们可以用来做上传进度的计算和展示,uploadSize === totalSize 表示上传完成

        当时碰到一个问题,就是CustomDialogController弹窗是不会因为调用方的状态属性值改变而改变的,后来通过研究使用emitter这个api来做的跨线程通信解决的。

        如果上传有错误,可以在fail的监听事件中来获取错误信息

有两个需要特别注意的地方是:

  1. 我们从系统相册中选择一个文件是没有权限读取的,需要利用上下文对象以及fs这个api将相册的文件拷贝到应用沙箱中,然后通过 internal://cache/再加上沙箱中的文件名才能正常做上传操作
  2. 需要再你的应用中开启intelnet访问权限

图片上传封装:

import { promptAction } from '@kit.ArkUI'
import { iLoginDataModel } from '../models/AccountModel'
import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import request from '@ohos.request';
import { Logger } from '../common/utils/Logger';

@Entry
@Component
struct ProfileEditPage {
  @StorageLink('user') currentUser: iLoginDataModel = {} as iLoginDataModel
  @StorageProp('topHeight') topHeight: number = 0

  // 1.选择系统相册图片,获取路径(picker):
  async pickerAvatar() {
    //  1.1 实例化选择参数对象:
    const options = new picker.PhotoSelectOptions()
    options.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE // 表示从相册中选择图片
    options.maxSelectNumber = 1 // 表示只选择一张

    //   1.2 实例化选择器对象:
    const pickerView = new picker.PhotoViewPicker()
    //   1.3 调用选择器对象上的 select 方法传入参数对象即可完成选择
    let res = await pickerView.select(options)
    // AlertDialog.show({ message: JSON.stringify(res.photoUris) })

    //   1.4 判断用户取消了选择图片,则组织下面代码的继续运行
    if (res.photoUris.length === 0) {
      promptAction.showToast({ message: "用户取消图片选择" })
      return
    }
    //   1.5 准备好一个图片的完整路径:
    let ext = 'jpg' // 图片扩展名
    let fileName = Date.now().toString() // 图片名称
    let cacheDir = getContext().cacheDir // 获取应用程序的缓存目录
    let fullPath = cacheDir + '/' + fileName + '.' + ext // 完整的图片路径
    let fullFileName = fileName + '.' + ext
    
    //   1.6 通过上面获取的文件路径 利用 fs.openSync 打开图片文件
       ——> fs.copyFileSync将图片拷贝到缓存目录:
    let file = fs.openSync(res.photoUris[0], fs.OpenMode.READ_ONLY)
    fs.copyFileSync(file.fd, fullPath)
    AlertDialog.show({ message: '图片拷贝成功' })

    //  2.利用request.uploadFile方法完成应用程序缓存目录下的文件上传操作
    //   2.1 通过上面的 fullFileName 获取缓存文件路径:
    let uploadFilePath = `internal://cache/${fullFileName}`
    //   2.2 准备reqeust.uploadFile :
    //需要传入两个参数:上下文 + 上传文件的配置参数
    let uploador = await request.uploadFile(getContext(), {
      method: 'POST',
      url: 'https://api-harmony-teach.itheima.net/hm/userInfo/avatar',
      header: {
        "Content-Type": "multipart/form-data",
        "Authorization": `Bearer ${this.currentUser.token}`
      },

      files: [{ name: 'file', uri: uploadFilePath, filename: fullFileName, type: ext }],
      // name:指的是接口中的body中的参数名称,不能写错一定要和接口保持一致
      // uri:指的是应用程序缓存中的图片 //filename:文件名称
      // type:文件类型,也就是扩展名
      data: []  // 因为本接口除了上传文件之外,无需接收其他文本数据,所以空着即可
    })

//3.注册uploador对象上的两个事件:一个progress监听上传进度,一个fail监听上传失败的异常获取
    uploador.on('progress', (uploadSize, totalSize) => {
//这个回调函数是随着文件的上传会被不间断的触发执行,每次的uploadSize的值会增加
//但是totalSize永远都是当前上传图片的大小
//可以通过判断 uploadSize === totalSize 表示上传完成,我们就可以做完成后端逻辑处理
      Logger.info('上传:',uploadSize + ' / '+ totalSize)
      if(uploadSize === totalSize){
        AlertDialog.show({message:'图片上传完成'})
      }
    //   由于此函数会被多次调用,所以我们可以在这个函数中计算处当前上传的进度百分比
      // Logger.info('上传:', uploadSize + ' / ' + totalSize)
      let parcentStr = ((uploadSize / totalSize) * 100).toFixed(0).toString()
      Logger.info('上传:', parcentStr)
    })

  //  监听上传失败的事件
    uploador.on('fail',(err)=>{
      AlertDialog.show({message:JSON.stringify(err)})
    })
  }

鸿蒙应用可以通过HTTP/HTTPS协议与后端进行通信,实现数据的传输和交互。具体步骤如下: 1.在应用中添加网络权限:在config.json文件中添加以下代码 ``` "requiredPermissions": [ "ohos.permission.INTERNET" ], ``` 2.使用HttpURLConnection或OkHttp等第三方库进行网络请求 例如,使用HttpURLConnection进行GET请求: ``` try { URL url = new URL("http://your.backend.api.com/data"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(5000); if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream inputStream = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); StringBuilder response = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { response.append(line); } reader.close(); inputStream.close(); connection.disconnect(); // 处理服务端返回的数据 // ... } } catch (IOException e) { e.printStackTrace(); } ``` 3.根据后端API的设计,构造请求参数并发送请求。通常来说,后端API会返回JSON格式的数据,需要使用JSON解析库对返回结果进行解析和处理,例如使用FastJson: ``` // 假设服务端返回的JSON数据格式如下: // { // "code": 200, // "data": { // "name": "张三", // "age": 25 // } // } JSONObject jsonObject = JSON.parseObject(response.toString()); int code = jsonObject.getIntValue("code"); if (code == 200) { JSONObject data = jsonObject.getJSONObject("data"); String name = data.getString("name"); int age = data.getIntValue("age"); // 处理服务端返回的数据 // ... } ``` 需要注意的是,网络请求可能会阻塞主线程,导致UI无法响应用户操作。因此,建议使用异步方式进行网络请求。可以使用Java原生的线程或者鸿蒙提供的异步任务机制进行处理。例如,使用鸿蒙提供的AsyncTask进行异步请求: ``` new AsyncTask<Void, Void, String>() { @Override protected void onPreExecute() { // 在UI线程执行,可以进行一些UI操作,比如显示进度条等 } @Override protected String doInBackground(Void... params) { // 在新线程中执行,进行网络请求等耗时操作 } @Override protected void onPostExecute(String result) { // 在UI线程执行,处理服务端返回的数据 } @Override protected void onCancelled() { // 在UI线程执行,任务被取消时执行的操作 } }.execute(); ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值