鸿蒙系统开发【网络-上传和下载(ArkTS)】基本功能

网络-上传和下载(ArkTS)

介绍

本示例使用@ohos.request接口创建上传和下载任务,实现上传、下载功能,hfs作为服务器,实现了文件的上传和下载和任务的查询功能。

效果预览

1

使用说明

1.本示例功能需要先配置服务器环境后使用,具体配置见[上传下载服务配置]。

2.首页展示上传和下载两个入口组件,点击进入对应的页面,如果要使用后台下载任务,请开启后台任务开关。

3.上传页面(请先在图库中确定已开启图库权限):

​ 点击**+**,从相册选择拉起图库选择照片,图片选择页面支持拍照,选择照片后点击发表进行上传。

​ 在首页中打开后台任务开关后,上传页面开启的是后台上传任务,后台任务在应用退出到后台时可以在通知栏看到任务状态。

4.下载页面:

​ 点击文件列表选择要下载的文件后,点击下载选择指定路径后开始下载。

​ 点击查看下载文件进入下载文件页面,点击文件夹查看文件夹内的文件。

​ 在首页中打开后台任务开关后,下载页面开启的是后台下载任务,后台任务在应用退出到后台时可以在通知栏看到任务状态。

​ 前台下载时只支持单文件下载,后台下载时支持选择多个文件下载。

具体实现

  • 该示例分为两个模块:

    • 上传模块

      • 使用@ohos.request中接口agent.create创建上传任务,调用@ohos.request中的Task相关接口实现上传任务的创建、取消、进度加载,失败的任务会调用查询接口获取失败原因并打印在日志中,支持多个文件上传。
  • 源码参考:[RequestUpload.ets]

/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';
import { request } from '@kit.BasicServicesKit';
import { urlUtils } from '../utils/UrlUtils';
import { logger } from '../utils/Logger';
import { MediaUtils } from '../utils/MediaUtils';
import { BackgroundTaskState, UPLOAD_TOKEN, TOAST_BOTTOM, TASK_MAX } from '../utils/Constants';

const TAG: string = 'RequestUpload';
const HEADER: Record<string, string> = { 'Content-Type': 'multipart/form-data' };

class Upload {
  private mediaUtils: MediaUtils = new MediaUtils();
  private config: request.agent.Config = {
    action: request.agent.Action.UPLOAD,
    headers: HEADER,
    url: '',
    mode: request.agent.Mode.FOREGROUND,
    method: 'POST',
    title: 'upload',
    network: request.agent.Network.ANY,
    data: [],
    token: UPLOAD_TOKEN
  }
  private context: common.UIAbilityContext | undefined = undefined;
  private uploadTask: request.agent.Task | undefined = undefined;
  private backgroundTask: request.agent.Task | undefined = undefined;
  private waitList: Array<string> = [];
  progressCallback: Function | undefined = undefined;
  completedCallback: Function | undefined = undefined;
  failedCallback: Function | undefined = undefined;

  constructor() {
    setInterval(() => {
      this.flushBackgroundTask()
    }, 2000);
  }

  async uploadFilesBackground(fileUris: Array<string>): Promise<void> {
    logger.info(TAG, `uploadFiles begin, ${JSON.stringify(fileUris)}`);
    this.context = getContext(this) as common.UIAbilityContext;
    if (fileUris.length === 0) {
      return;
    }
    fileUris.forEach((item: string) => {
      this.waitList.push(item);
    });
  }

  async flushBackgroundTask() {
    let tasks = await request.agent.search({
      state: request.agent.State.RUNNING
    });
    let state = AppStorage.get<number>('backTaskState');
    if (state === BackgroundTaskState.RUNNING) {
      if (tasks.length < TASK_MAX && this.waitList.length > 0) {
        this.createBackgroundTask(this.waitList);
        this.waitList = [];
      } else {
        if (this.backgroundTask === undefined || tasks.indexOf(this.backgroundTask.tid) === -1) {
          AppStorage.setOrCreate('backTaskState', BackgroundTaskState.NONE);
          this.backgroundTask = undefined;
        }
      }
    }
  }

  async createBackgroundTask(fileUris: Array<string>) {
    if (this.context === undefined) {
      return;
    }
    this.config.url = await urlUtils.getUrl(this.context);
    this.config.data = await this.getFilesAndData(this.context.cacheDir, fileUris);
    this.config.mode = request.agent.Mode.BACKGROUND;
    try {
      this.backgroundTask = await request.agent.create(this.context, this.config);
      await this.backgroundTask.start();
      let state = AppStorage.get<number>('backTaskState');
      if (state === BackgroundTaskState.PAUSE) {
        await this.backgroundTask.pause();
      }
      logger.info(TAG, `createBackgroundTask success`);
    } catch (err) {
      logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
    }
  }

  async uploadFiles(fileUris: Array<string>, callback: (progress: number, isSucceed: boolean) => void): Promise<void> {
    logger.info(TAG, `uploadFiles begin, ${JSON.stringify(fileUris)}`);
    if (fileUris.length === 0) {
      return;
    }
    // 查询到存在正在执行的上传任务,提示并返回
    let tasks = await request.agent.search({
      state: request.agent.State.RUNNING,
      action: request.agent.Action.UPLOAD,
      mode: request.agent.Mode.FOREGROUND
    });
    if (tasks.length > 0) {
      promptAction.showToast({ message: $r('app.string.have_upload_task_tips'), bottom: TOAST_BOTTOM });
      return;
    }
    let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    this.config.data = await this.getFilesAndData(context.cacheDir, fileUris);
    this.config.url = await urlUtils.getUrl(context);
    this.config.mode = request.agent.Mode.FOREGROUND;
    try {
      this.uploadTask = await request.agent.create(context, this.config);
      this.uploadTask.on('progress', this.progressCallback = (progress: request.agent.Progress) => {
        logger.info(TAG, `progress,  progress = ${progress.processed} ${progress.state}`);
        let processed = Number(progress.processed.toString()).valueOf();
        let size = progress.sizes[0];
        let process: number = Math.floor(processed / size * 100);
        if (process < 100) {
          callback(process, false);
        }
      });
      this.uploadTask.on('completed', this.completedCallback = (progress: request.agent.Progress) => {
        logger.info(TAG, `complete,  progress = ${progress.processed} ${progress.state}`);
        callback(100, true);
        this.cancelTask();
      });
      this.uploadTask.on('failed', this.failedCallback = async (progress: request.agent.Progress) => {
        if (this.uploadTask) {
          let taskInfo = await request.agent.touch(this.uploadTask.tid, UPLOAD_TOKEN);
          logger.info(TAG, `fail,  resean = ${taskInfo.reason}, faults = ${JSON.stringify(taskInfo.faults)}`);
        }
        callback(100, false);
        this.cancelTask();
      });
      await this.uploadTask.start();
    } catch (err) {
      logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
      callback(100, false);
    }
  }

  async cancelTask() {
    if (this.uploadTask === undefined) {
      return;
    }
    try {
      this.uploadTask.off('progress');
      this.progressCallback = undefined;
      this.uploadTask.off('failed');
      this.failedCallback = undefined
      this.uploadTask.off('completed');
      this.completedCallback = undefined
      await this.uploadTask.stop();
      await request.agent.remove(this.uploadTask.tid);
    } catch (err) {
      logger.info(TAG, `deleteTask fail,err= ${JSON.stringify(err)}`);
    }
    this.uploadTask = undefined;
  }

  async pauseOrResume() {
    let state = AppStorage.get<number>('backTaskState');
    if (state === BackgroundTaskState.RUNNING) {
      await this.pause();
      AppStorage.setOrCreate('backTaskState', BackgroundTaskState.PAUSE);
    } else if (state === BackgroundTaskState.PAUSE) {
      await this.resume();
      AppStorage.setOrCreate('backTaskState', BackgroundTaskState.RUNNING);
    } else {
      logger.info(TAG, 'this task state is error');
    }
  }

  async pause() {
    logger.info(TAG, 'pause');
    if (this.backgroundTask === undefined) {
      return;
    }
    try {
      await this.backgroundTask.pause();
    } catch (err) {
      logger.info(TAG, `pause fail,err= ${JSON.stringify(err)}`);
    }
  }

  async resume() {
    logger.info(TAG, 'resume');
    if (this.backgroundTask === undefined) {
      return;
    }
    try {
      await this.backgroundTask.resume();
    } catch (err) {
      logger.info(TAG, `resume fail,err= ${JSON.stringify(err)}`);
    }
  }

  private async getFilesAndData(cacheDir: string, fileUris: Array<string>): Promise<Array<request.agent.FormItem>> {
    logger.info(TAG, `getFilesAndData begin`);
    let files: Array<request.agent.FormItem> = [];
    for (let i = 0; i < fileUris.length; i++) {
      logger.info(TAG, `getFile fileUri = ${fileUris[i]}`);
      let imagePath = await this.mediaUtils.copyFileToCache(cacheDir, fileUris[i]);
      logger.info(TAG, `getFilesAndData ${JSON.stringify(imagePath)}`);
      let file: request.agent.FormItem = {
        name: imagePath.split('cache/')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值