网络-上传和下载(ArkTS)
先容
本示例利用@ohos.request接口创建上传和下载任务,实现上传、下载功能,hfs作为服务器,实现了文件的上传和下载和任务的查询功能。
效果预览
利用阐明
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/')[1],
- value: {
- path: './' + imagePath.split('cache/')[1]
- }
- }
- files.push(file);
- }
- logger.info(TAG, `getFilesAndData ${JSON.stringify(files)}`);
- return files;
- }
- }
- export const requestUpload = new Upload();
复制代码
- /*
- * 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 { picker } from '@kit.CoreFileKit';
- import { logger } from '@ohos/uploaddownload';
- import { BusinessError } from '@kit.BasicServicesKit';
- const TAG: string = 'AddPictures';
- @Extend(Image) function imageStyle() {
- .width('100%')
- .aspectRatio(1)
- .objectFit(ImageFit.Fill)
- .backgroundColor($r('app.color.light_gray'))
- .borderRadius(12)
- }
- const TEXT_WIDTH_FULL: Length = '100%';
- @Component
- export struct AddPictures {
- @Consume imageList: Array<string>;
- build() {
- Column() {
- Text($r('app.string.tip'))
- .fontColor($r('app.color.text_normal'))
- .fontWeight(400)
- .fontFamily('HarmonyHeiTi')
- .fontSize(14)
- .opacity(0.4)
- .margin({ top: $r('app.float.add_pictures_margin_top'), bottom: $r('app.float.add_pictures_margin_bottom') })
- .width(TEXT_WIDTH_FULL)
- GridRow({ columns: { sm: 3, md: 6, lg: 8 }, gutter: 12 }) {
- ForEach(this.imageList, (item: string) => {
- GridCol({ span: 1 }) {
- Image(item)
- .imageStyle()
- }
- })
- GridCol({ span: 1 }) {
- Row() {
- Image($r('app.media.ic_public_add'))
- .size({ width: 24, height: 24 })
- .objectFit(ImageFit.Contain)
- }
- .width('100%')
- .height('100%')
- .justifyContent(FlexAlign.Center)
- }
- .width('100%')
- .aspectRatio(1)
- .backgroundColor($r('app.color.white'))
- .borderRadius(12)
- .onClick(() => {
- this.showDialog();
- })
- }
- }
- .width('100%')
- }
- addImages = (images: Array<string>) => {
- images.forEach((item: string) => {
- if (!this.imageList.includes(item)) {
- this.imageList.push(item);
- }
- })
- logger.info(TAG, `addImages imageList=${JSON.stringify(this.imageList)}`);
- }
- showDialog() {
- AlertDialog.show({
- message: $r('app.string.pick_album'),
- alignment: DialogAlignment.Bottom,
- offset: { dx: 0, dy: -12 },
- primaryButton: {
- value: $r('app.string.cancel'),
- fontColor: $r('app.color.btn_text_blue'),
- action: () => {
- }
- },
- secondaryButton: {
- value: $r('app.string.ok'),
- fontColor: $r('app.color.btn_text_blue'),
- action: () => {
- try {
- let photoSelectOptions = new picker.PhotoSelectOptions();
- photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
- photoSelectOptions.maxSelectNumber = 5;
- let photoPicker = new picker.PhotoViewPicker();
- photoPicker.select(photoSelectOptions).then((photoSelectResult: picker.PhotoSelectResult) => {
- this.addImages(photoSelectResult.photoUris);
- }).catch((err: BusinessError) => {
- logger.error(TAG, `'PhotoViewPicker.select failed with err: ${JSON.stringify(err)}`);
- });
- } catch (err) {
- logger.error(TAG, `'PhotoViewPicker failed with err: ${JSON.stringify(err)}`);
- }
- }
- }
- })
- }
- }
复制代码
- /*
- * 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 { AddPictures } from '../components/AddPictures';
- import { BackgroundTaskState, requestUpload, TOAST_BOTTOM } from '@ohos/uploaddownload';
- const TIME_MAX: number = 5;
- @Entry
- @Component
- struct Upload {
- @StorageLink('isBackground') isBackground: boolean = false;
- @StorageLink('backTaskState') @Watch('stateChange') backTaskState: BackgroundTaskState = BackgroundTaskState.NONE;
- @State isBegin: boolean = false;
- @Provide imageList: Array<string> = [];
- @State progress: number = 0;
- @State countdown: number = 0;
- build() {
- Navigation() {
- Scroll() {
- AddPictures()
- }
- .padding({ left: 24, right: 24 })
- .width('100%')
- .layoutWeight(1)
- .align(Alignment.Top)
- Column() {
- Button() {
- if (this.isBackground && this.backTaskState !== BackgroundTaskState.NONE) {
- if (this.backTaskState === BackgroundTaskState.RUNNING) {
- Text($r('app.string.pause'))
- .fontSize(16)
- .fontWeight(500)
- .fontColor($r('app.color.white'))
- } else {
- Text($r('app.string.continue'))
- .fontSize(16)
- .fontWeight(500)
- .fontColor($r('app.color.white'))
- }
- } else if (this.isBegin && !this.isBackground) {
- Row() {
- Progress({ value: this.progress, type: ProgressType.Ring })
- .width(20)
- .height(20)
- .backgroundColor('#FFFFFF')
- .color('#558DFF')
- .style({ strokeWidth: 2, scaleCount: 100, scaleWidth: 2 })
- Text(`${this.getResourceString($r('app.string.uploading'))}${this.progress}%`)
- .fontSize(16)
- .fontColor('#FFFFFF')
- .fontWeight(500)
- .margin({ left: 12 })
- }.alignItems(VerticalAlign.Center)
- } else {
- if (this.countdown > 0) {
- Text(`${this.countdown}s`)
- .fontSize(16)
- .fontWeight(500)
- .fontColor($r('app.color.white'))
- } else {
- Text($r('app.string.upload'))
- .fontSize(16)
- .fontWeight(500)
- .fontColor($r('app.color.white'))
- }
- }
- }
- .id('publish')
- .width('100%')
- .height(40)
- .margin({ bottom: this.isBegin ? 16 : 24 })
- .enabled(this.countdown > 0 ? false : true)
- .backgroundColor($r('app.color.button_blue'))
- .onClick(() => {
- if (this.isBackground && this.backTaskState !== BackgroundTaskState.NONE) {
- requestUpload.pauseOrResume();
- } else {
- this.uploadFiles();
- }
- })
- if (this.isBegin) {
- Button() {
- Text($r('app.string.cancel'))
- .fontSize(16)
- .fontWeight(500)
- .fontColor($r('app.color.btn_text_blue'))
- }
- .id('cancel')
- .width('100%')
- .height(40)
- .margin({ bottom: 24 })
- .backgroundColor($r('app.color.button_light_gray'))
- .onClick(() => {
- // cancel task
- requestUpload.cancelTask();
- this.progress = 0;
- this.isBegin = false;
- })
- }
- }
- .width('100%')
- .padding({ left: 24, right: 24 })
- }
- .width('100%')
- .height('100%')
- .backgroundColor($r('app.color.light_gray'))
- .title($r('app.string.upload'))
- .hideBackButton(false)
- .titleMode(NavigationTitleMode.Mini)
- .mode(NavigationMode.Stack)
- }
- aboutToAppear() {
- this.isBegin = false;
- this.backTaskState = BackgroundTaskState.NONE;
- }
- stateChange() {
- if (this.backTaskState === BackgroundTaskState.NONE) {
- this.imageList = [];
- }
- }
- uploadFiles() {
- if (this.imageList.length === 0) {
- return;
- }
- if (this.isBackground) {
- AppStorage.setOrCreate('backTaskState', BackgroundTaskState.RUNNING)
- requestUpload.uploadFilesBackground(this.imageList);
- promptAction.showToast({ message: $r('app.string.background_task_start'), bottom: TOAST_BOTTOM });
- } else {
- this.isBegin = true;
- this.progress = 0;
- requestUpload.uploadFiles(this.imageList, (progress: number, isSucceed: boolean) => {
- this.progress = progress;
- if (this.progress === 100 && isSucceed) {
- this.isBegin = false;
- this.imageList = [];
- promptAction.showToast({ message: $r('app.string.upload_success'), bottom: TOAST_BOTTOM })
- }
- if (this.progress === 100 && isSucceed === false) {
- this.isBegin = false;
- this.countdown = TIME_MAX;
- let interval = setInterval(() => {
- if (this.countdown > 0) {
- this.countdown--;
- } else {
- clearInterval(interval);
- }
- }, 1000);
- promptAction.showToast({ message: $r('app.string.upload_fail'), bottom: TOAST_BOTTOM })
- }
- });
- }
- }
- getResourceString(resource: Resource) {
- let context = getContext(this) as common.UIAbilityContext;
- return context.resourceManager.getStringSync(resource.id);
- }
- }
复制代码
- 参考接口:@ohos.request,@ohos.file.picker
- 下载模块
- 利用@ohos.request中接口agent.create创建上传任务,调用@ohos.request中的Task相干接口实现上传任务的创建、取消、暂停、继续、进度加载,失败的任务会调用查询接口获取失败缘故起因并打印在日志中,前台下载任务只支持单个文件下载,背景下载任务支持多文件下载。利用@ohos.file.fs完成指定路径的创建和查询已下载的文件。
- 源码参考:[RequestDownload.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 { logger } from '../utils/Logger';
- import { TOAST_BOTTOM, TASK_MAX, TASK_PAUSE_MSG, TASK_NET_PAUSE_MSG, TASK_RESUME_MSG, TASK_NET_RESUME_MSG } from '../utils/Constants';
- const TAG: string = 'RequestDownload';
- let isNetPause = false;
- class RequestDownload {
- private context: common.UIAbilityContext | undefined = undefined;
- private waitList: Array<string[]> = [];
- private downloadTask: request.agent.Task | undefined = undefined;
- progressCallback: Function | undefined = undefined;
- completedCallback: Function | undefined = undefined;
- failedCallback: Function | undefined = undefined;
- constructor() {
- setInterval(() => {
- this.flushBackgroundTask()
- }, 2000);
- }
- async downloadFilesBackground(folder: string, files: Array<string>) {
- logger.info(TAG, 'downloadFiles');
- this.context = getContext(this) as common.UIAbilityContext;
- files.forEach((item: string) => {
- this.waitList.push([folder, item]);
- });
- }
- async flushBackgroundTask() {
- let tasks = await request.agent.search({
- state: request.agent.State.RUNNING
- });
- if (tasks.length < TASK_MAX && this.waitList.length > 0) {
- let downloadList: Array<string[]> = [];
- if (this.waitList.length <= TASK_MAX - tasks.length) {
- downloadList = this.waitList;
- this.waitList = [];
- } else {
- downloadList = this.waitList.slice(0, TASK_MAX - tasks.length);
- this.waitList = this.waitList.slice(TASK_MAX - tasks.length, this.waitList.length);
- }
- logger.info(TAG, `this.waitList = ${JSON.stringify(this.waitList)}`);
- this.createBackgroundTask(downloadList);
- }
- }
- async createBackgroundTask(downloadList: Array<string[]>) {
- if (this.context === undefined) {
- return;
- }
- for (let i = 0; i < downloadList.length; i++) {
- try {
- let splitUrl = downloadList[i][1].split('//')[1].split('/');
- let downloadConfig: request.agent.Config = {
- action: request.agent.Action.DOWNLOAD,
- url: downloadList[i][1],
- method: 'POST',
- title: 'download',
- mode: request.agent.Mode.BACKGROUND,
- network: request.agent.Network.ANY,
- saveas: `./${downloadList[i][0]}/${splitUrl[splitUrl.length-1]}`,
- overwrite: true,
- gauge: true
- }
- let downTask = await request.agent.create(this.context, downloadConfig);
- await downTask.start();
- } catch (err) {
- logger.error(TAG, `task err, err = ${JSON.stringify(err)}`);
- this.waitList.push(downloadList[i]);
- }
- }
- }
- async pause() {
- if (this.downloadTask) {
- let taskInfo = await request.agent.show(this.downloadTask.tid);
- logger.info(TAG, `task pause, taskInfo = ${JSON.stringify(taskInfo)}`);
- await this.downloadTask.pause();
- }
- }
- async resume() {
- if (this.downloadTask) {
- let taskInfo = await request.agent.show(this.downloadTask.tid);
- logger.info(TAG, `task resume, taskInfo = ${JSON.stringify(taskInfo)}`);
- await this.downloadTask.resume();
- }
- }
- async downloadFile(folder: string, url: string, callback: (progress: number, isSuccess: boolean) => void) {
- logger.info(TAG, 'downloadFile');
- // 查询到存在正在执行的下载任务,提示并返回
- let tasks = await request.agent.search({
- state: request.agent.State.RUNNING,
- action: request.agent.Action.DOWNLOAD,
- mode: request.agent.Mode.FOREGROUND
- });
- if (tasks.length > 0) {
- promptAction.showToast({ message: $r('app.string.have_download_task_tips'), bottom: TOAST_BOTTOM });
- return;
- }
- let splitUrl = url.split('//')[1].split('/');
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
- let downloadConfig: request.agent.Config = {
- action: request.agent.Action.DOWNLOAD,
- url: url,
- method: 'GET',
- title: 'download',
- mode: request.agent.Mode.BACKGROUND,
- retry: true,
- network: request.agent.Network.ANY,
- saveas: `./${folder}/${splitUrl[splitUrl.length-1]}`,
- overwrite: true
- }
- logger.info(TAG, `downloadFile, downloadConfig = ${JSON.stringify(downloadConfig)}`);
- try {
- this.downloadTask = await request.agent.create(context, downloadConfig);
- this.downloadTask.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.downloadTask.on('completed', this.completedCallback = (progress: request.agent.Progress) => {
- logger.info(TAG, `download complete, file= ${url}, progress = ${progress.processed}`);
- callback(100, true);
- this.deleteTask();
- })
- this.downloadTask.on('pause', this.failedCallback = async (progress: request.agent.Progress) => {
- if (this.downloadTask) {
- let taskInfo = await request.agent.show(this.downloadTask.tid);
- logger.info(TAG, `pause, resean = ${taskInfo.reason}, progress = ${progress.processed}, faults = ${JSON.stringify(taskInfo.faults)}`);
- isNetPause = taskInfo.faults === 0;
- if (isNetPause) {
- callback(TASK_NET_PAUSE_MSG, isNetPause);
- }
- else {
- callback(TASK_PAUSE_MSG, isNetPause);
- }
- }
- })
- this.downloadTask.on('resume', this.failedCallback = async (progress: request.agent.Progress) => {
- if (this.downloadTask) {
- let taskInfo = await request.agent.show(this.downloadTask.tid);
- logger.info(TAG, `resume, resean = ${taskInfo.reason}, progress = ${progress.processed}, faults = ${JSON.stringify(taskInfo.faults)}`);
- if (isNetPause) {
- isNetPause = false;
- callback(TASK_NET_RESUME_MSG, isNetPause);
- }
- else {
- callback(TASK_RESUME_MSG, isNetPause);
- }
- }
- })
- this.downloadTask.on('failed', this.failedCallback = async (progress: request.agent.Progress) => {
- if (this.downloadTask) {
- let taskInfo = await request.agent.show(this.downloadTask.tid);
- logger.info(TAG, `fail, resean = ${taskInfo.reason}, progress = ${progress.processed}, faults = ${JSON.stringify(taskInfo.faults)}`);
- }
- callback(100, false);
- this.deleteTask();
- })
- await this.downloadTask.start();
- } catch (err) {
- logger.error(TAG, `task err, err = ${JSON.stringify(err)}`);
- callback(100, false);
- }
- }
- async deleteTask() {
- if (this.downloadTask) {
- try {
- this.downloadTask.off('progress');
- this.progressCallback = undefined;
- this.downloadTask.off('completed');
- this.completedCallback = undefined
- this.downloadTask.off('failed');
- this.failedCallback = undefined
- await request.agent.remove(this.downloadTask.tid);
- } catch (err) {
- logger.info(TAG, `deleteTask fail, err= ${JSON.stringify(err)}`);
- }
- }
- this.downloadTask = undefined;
- }
- }
- export const requestDownload = new RequestDownload();
复制代码
- /*
- * 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 { promptAction } from '@kit.ArkUI';
- import { router } from '@kit.ArkUI';
- import { CustomDataSource } from '../components/CustomDataSource';
- import {
- FileModel,
- FileType,
- fileUtils,
- logger,
- requestFiles,
- requestDownload,
- TOAST_BOTTOM,
- TASK_PAUSE_MSG,
- TASK_RESUME_MSG,
- TASK_NET_PAUSE_MSG,
- TASK_NET_RESUME_MSG
- } from '@ohos/uploaddownload';
- import { SelectFolderDialog } from '../components/SelectFolderDialog';
- const TAG: string = 'Download';
- const OFFSET_DY: Length = -12;
- const OFFSET_DX: Length = 0;
- const LOADING_PROGRESS_WIDTH: Length = 100;
- const FULL_WIDTH: Length = '100%';
- const FULL_HEIGHT: Length = '100%';
- const LIST_WIDTH: Length = '100%';
- const LIST_HEIGHT: Length = 'auto';
- const LIST_BORDER_RADIUS: Length | BorderRadiuses = 24;
- const PADDING_TOP: Length = 4;
- const PADDING_BOTTOM: Length = 4;
- const STROKE_WIDTH: Length = 1;
- const START_MARGIN: Length = 44;
- const END_MARGIN: Length = 12;
- const COLUMN_PADDING_LEFT: Length = 12;
- const COLUMN_PADDING_RIGHT: Length = 12;
- const COLUMN_PADDING_BOTTOM: Length = 12;
- const BUTTON_FONT_SIZE = 16;
- const MARGIN_TOP: Length = 12;
- const MARGIN_LEFT: Length = 12;
- const MARGIN_RIGHT: Length = 12;
- const MARGIN_BOTTOM: Length = 12;
- const BUTTON_HEIGHT: Length = 45;
- @Entry
- @Component
- struct Download {
- private fileData: CustomDataSource = new CustomDataSource([]);
- @StorageLink('isBackground') isBackground: boolean = false;
- @Provide downloadFolder: Array<string> = [];
- @State isGetData: boolean = false;
- @State checkFile: Array<string> = [];
- @State checkList: Array<boolean> = [];
- @State isRunning: boolean = false;
- @State isPause: boolean = false;
- @State isNetPause: boolean = false;
- @State progress: number = 0;
- private selectFolder = (folder: string) => {
- logger.info(TAG, `selectFolder = ${folder}`);
- this.download(folder);
- }
- private folderDialogController: CustomDialogController = new CustomDialogController({
- builder: SelectFolderDialog({ selectFolder: this.selectFolder }),
- autoCancel: true,
- alignment: DialogAlignment.Bottom,
- offset: { dx: OFFSET_DX,
- dy: OFFSET_DY }
- });
- build() {
- Navigation() {
- Column() {
- if (this.isGetData) {
- LoadingProgress()
- .width(LOADING_PROGRESS_WIDTH)
- .layoutWeight(1)
- } else {
- List({ space: 12 }) {
- LazyForEach(this.fileData, (item: FileModel, index: number) => {
- ListItem() {
- this.FileItem(item, index)
- }
- }, (item: FileModel) => JSON.stringify(item))
- }
- .width(LIST_WIDTH)
- .height(LIST_HEIGHT)
- .scrollBar(BarState.Off)
- .backgroundColor(Color.White)
- .borderRadius(LIST_BORDER_RADIUS)
- .padding({ top: PADDING_TOP,
- bottom: PADDING_BOTTOM })
- .divider({ strokeWidth: STROKE_WIDTH,
- startMargin: START_MARGIN,
- endMargin: END_MARGIN })
- }
- Column().layoutWeight(1)
- this.BottomView()
- }
- .padding({ left: COLUMN_PADDING_LEFT,
- right: COLUMN_PADDING_RIGHT,
- bottom: COLUMN_PADDING_BOTTOM })
- .height(FULL_HEIGHT)
- }
- .width(FULL_WIDTH)
- .height(FULL_HEIGHT)
- .hideBackButton(false)
- .titleMode(NavigationTitleMode.Mini)
- .mode(NavigationMode.Stack)
- .backgroundColor($r('app.color.light_gray'))
- .hideToolBar(false)
- .title($r('app.string.download'))
- }
- @Builder
- FileItem(file: FileModel, index: number) {
- Row() {
- Row() {
- if (file.fileType === FileType.FOLDER) {
- Image($r('app.media.ic_files_folder'))
- .size({ width: 24, height: 24 })
- .objectFit(ImageFit.Contain)
- } else if (file.fileType === FileType.IMAGE) {
- Image($r('app.media.ic_public_picture'))
- .size({ width: 24, height: 24 })
- .objectFit(ImageFit.Contain)
- } else if (file.fileType === FileType.MUSIC) {
- Image($r('app.media.ic_public_music'))
- .size({ width: 24, height: 24 })
- .objectFit(ImageFit.Contain)
- } else if (file.fileType === FileType.Video) {
- Image($r('app.media.ic_public_video'))
- .size({ width: 24, height: 24 })
- .objectFit(ImageFit.Contain)
- } else {
- Image($r('app.media.ic_public_document'))
- .size({ width: 24, height: 24 })
- .objectFit(ImageFit.Contain)
- }
- Text(decodeURIComponent(file.name))
- .fontSize(16)
- .fontWeight(400)
- .layoutWeight(1)
- .maxLines(1)
- .textOverflow({ overflow: TextOverflow.Ellipsis })
- .margin({ left: 12 })
- }
- .layoutWeight(1)
- Checkbox({ name: '', group: 'checkboxGroup' })
- .select(this.checkList[index])
- .selectedColor($r('app.color.button_blue'))
- .margin({ left: 12 })
- .hitTestBehavior(HitTestMode.None)
- }
- .width('100%')
- .padding({ left: 12, right: 12 })
- .height(48)
- .onClick(() => {
- this.fileCheck(index);
- })
- }
- @Builder
- BottomView() {
- Column({ space: 12 }) {
- Button() {
- Row() {
- if (!this.isBackground && this.isRunning) {
- if (this.isPause || this.isNetPause) {
- Text($r('app.string.continue'))
- .fontColor(Color.White)
- .fontSize(BUTTON_FONT_SIZE)
- }
- else {
- Text(`${this.progress}%`)
- .fontColor(Color.White)
- .fontSize(BUTTON_FONT_SIZE)
- Text($r('app.string.downloading'))
- .fontColor(Color.White)
- .fontSize(BUTTON_FONT_SIZE)
- .margin({ left: MARGIN_LEFT })
- }
- } else {
- Text($r('app.string.download'))
- .fontColor(Color.White)
- .fontSize(BUTTON_FONT_SIZE)
- }
- }
- }
- .id('download_to')
- .type(ButtonType.Capsule)
- .height(BUTTON_HEIGHT)
- .width(FULL_WIDTH)
- .backgroundColor($r('app.color.button_blue'))
- .onClick(() => {
- if (!this.isRunning) {
- this.folderDialogController.open();
- }
- else {
- if (!this.isNetPause) {
- if (this.isPause) {
- requestDownload.resume();
- }
- else {
- requestDownload.pause();
- }
- }
- }
- })
- Button($r('app.string.view_download_files'))
- .id('view_download_files')
- .type(ButtonType.Capsule)
- .backgroundColor($r('sys.color.ohos_id_color_button_normal'))
- .width('100%')
- .fontSize(BUTTON_FONT_SIZE)
- .margin({ bottom: MARGIN_BOTTOM })
- .fontColor($r('app.color.btn_text_blue'))
- .onClick(() => {
- router.pushUrl({
- url: 'pages/DownloadFiles'
- });
- })
- }
- .margin({ top: MARGIN_TOP,
- left: MARGIN_LEFT,
- right: MARGIN_RIGHT })
- }
- aboutToAppear() {
- this.isRunning = false;
- this.isPause = false;
- this.isGetData = true;
- requestFiles.requestFiles().then((data: FileModel[]) => {
- this.checkList = [];
- this.isRunning = false;
- this.fileData.dataArray = data;
- this.fileData.dataArray.forEach(() => {
- this.checkList.push(false);
- })
- this.isGetData = false;
- this.fileData.notifyDataReload();
- })
- fileUtils.listFolders().then((folders: Array<string>) => {
- this.downloadFolder = folders;
- })
- }
- fileCheck(index: number) {
- if (!this.isBackground) {
- for (let i = 0; i < this.checkList.length; i++) {
- if (i !== index) {
- this.checkList[i] = false;
- }
- }
- }
- this.checkList[index] = !this.checkList[index];
- logger.info(TAG, `this.checkList = ${JSON.stringify(this.checkList)}`);
- }
- download(folder: string) {
- this.checkFile = [];
- if (this.checkList === undefined) {
- return;
- }
- logger.info(TAG, `this.checkList = ${JSON.stringify(this.checkList)}`);
- for (let i = 0; i < this.checkList.length; i++) {
- if (this.checkList[i]) {
- let fileModel = this.fileData.getData(i);
- logger.info(TAG, `fileModel = ${JSON.stringify(fileModel)}`);
- fileModel.files.forEach((url: string) => {
- let splitUrl = url.split('//')[1].split('/');
- if (splitUrl[splitUrl.length-1] !== '') {
- this.checkFile.push(url);
- }
- });
- }
- }
- logger.info(TAG, `this.checkFile = ${JSON.stringify(this.checkFile)}`);
- if (this.checkFile.length === 0) {
- promptAction.showToast({ message: $r('app.string.check_file_tips'), bottom: TOAST_BOTTOM });
- return;
- }
- this.progress = 0;
- if (this.isBackground) {
- this.isRunning = false;
- requestDownload.downloadFilesBackground(folder, this.checkFile);
- this.checkFile = [];
- this.checkList = [];
- this.fileData.dataArray.forEach(() => {
- this.checkList.push(false);
- })
- this.fileData.notifyDataReload();
- promptAction.showToast({ message: $r('app.string.background_task_start'), bottom: TOAST_BOTTOM });
- } else {
- this.isRunning = true;
- requestDownload.downloadFile(folder, this.checkFile[0], this.downloadFileCallback);
- }
- }
- downloadFilesCallback = (downloadCount: number, isSuccess: boolean) => {
- this.progress = downloadCount;
- if (downloadCount === this.checkFile.length) {
- this.downloadFinish(isSuccess);
- }
- }
- downloadFileCallback = (progress: number, isSuccess: boolean) => {
- logger.info(TAG, `downloadFileCallback = ${progress}`);
- if (progress === TASK_PAUSE_MSG) {
- this.isPause = true;
- }
- else if (progress === TASK_RESUME_MSG) {
- this.isPause = false;
- }
- else if (progress === TASK_NET_PAUSE_MSG) {
- this.isNetPause = true;
- let message = $r('app.string.net_pause');
- promptAction.showToast({ message: message, bottom: TOAST_BOTTOM });
- }
- else if (progress === TASK_NET_RESUME_MSG) {
- this.isNetPause = false;
- let message = $r('app.string.net_resume');
- promptAction.showToast({ message: message, bottom: TOAST_BOTTOM });
- }
- else {
- this.progress = progress;
- if (this.progress === 100) {
- this.downloadFinish(isSuccess);
- }
- }
- }
- downloadFinish(isSuccess: boolean) {
- this.isRunning = false;
- this.checkFile = [];
- this.checkList = [];
- this.fileData.dataArray.forEach(() => {
- this.checkList.push(false);
- })
- this.fileData.notifyDataReload();
- let message = isSuccess ? $r('app.string.download_finish') : $r('app.string.download_fail');
- promptAction.showToast({ message: message, bottom: TOAST_BOTTOM });
- }
- }
复制代码
- /*
- * 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 { fileIo } from '@kit.CoreFileKit';
- import { logger } from '../utils/Logger';
- const TAG: string = 'FileUtil';
- const ALBUMS: string[] = ['Pictures', 'Videos', 'Others'];
- class FileUtil {
- constructor() {
- }
- async initDownloadDir(): Promise<void> {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
- logger.info(TAG, `initDownloadDir cacheDir=${context.cacheDir}`);
- try {
- fileIo.mkdirSync(`${context.cacheDir}/${ALBUMS[0]}`);
- fileIo.mkdirSync(`${context.cacheDir}/${ALBUMS[1]}`);
- fileIo.mkdirSync(`${context.cacheDir}/${ALBUMS[2]}`);
- } catch (err) {
- logger.info(TAG, `initDownloadDir err =${JSON.stringify(err)}`);
- }
- }
- async listFolders(): Promise<Array<string>> {
- await this.initDownloadDir();
- return ALBUMS;
- }
- async clearFolder(folderName: string): Promise<void> {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
- try {
- let files: string[] = fileIo.listFileSync(`${context.cacheDir}/${folderName}`);
- logger.info(TAG, `listFiles listFileSync =${JSON.stringify(files)}`);
- for (let i = 0; i < files.length; i++) {
- fileIo.unlinkSync(`${context.cacheDir}/${folderName}/${files[i]}`);
- }
- } catch (err) {
- logger.info(TAG, `listFiles err =${JSON.stringify(err)}`);
- }
- }
- async listFiles(folderName: string): Promise<Array<string>> {
- let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
- let files: string[] = [];
- try {
- files = fileIo.listFileSync(`${context.cacheDir}/${folderName}`);
- logger.info(TAG, `listFiles listFileSync =${JSON.stringify(files)}`);
- } catch (err) {
- logger.info(TAG, `listFiles err =${JSON.stringify(err)}`);
- }
- return files;
- }
- }
- export const fileUtils = new FileUtil();
复制代码
- /*
- * 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 { fileUtils } from '../utils/FileUtils';
- @Preview
- @Component
- export struct FileBrowse {
- @State folders: Array<string> = ['folder'];
- @State files: Array<string> = [];
- @State currentFolder: string = '';
- aboutToAppear() {
- fileUtils.listFolders().then((folders: Array<string>) => {
- this.folders = folders;
- })
- }
- build() {
- Navigation() {
- List({ space: 12 }) {
- ForEach(this.folders, (item: string) => {
- ListItem() {
- NavRouter() {
- Row() {
- Image($r('app.media.ic_files_folder'))
- .size({ width: 32, height: 26 })
- .objectFit(ImageFit.Contain)
- Text(item)
- .fontSize(16)
- .width('100%')
- .margin({ left: 12 })
- }
- .height(56)
- .padding({ left: 16 })
- .backgroundColor(Color.White)
- .borderRadius(24)
- NavDestination() {
- this.FilesView()
- }
- .title(this.CustomTitle(item))
- .backgroundColor($r('app.color.light_gray'))
- }
- .onStateChange(async (isActivated: boolean) => {
- if (isActivated) {
- this.currentFolder = item;
- this.files = await fileUtils.listFiles(item);
- }
- })
- }
- })
- }
- .padding({ left: 12, right: 12 })
- }
- .hideBackButton(false)
- .titleMode(NavigationTitleMode.Mini)
- .title($r('app.string.download_files_title'))
- .mode(NavigationMode.Stack)
- .backgroundColor($r('app.color.light_gray'))
- }
- @Builder
- CustomTitle(title: string) {
- Row() {
- Text(title)
- .fontSize(20)
- .fontColor($r('app.color.text_normal'))
- .fontWeight(700)
- .margin({ left: 8 })
- }
- .width('100%')
- }
- @Builder
- FilesView() {
- Column() {
- List({ space: 12 }) {
- if (this.files.length === 0) {
- ListItem() {
- Text($r('app.string.folder_empty'))
- .fontSize(16)
- .width('100%')
- .margin({ top: 50 })
- .textAlign(TextAlign.Center)
- }
- }
- ForEach(this.files, (item: string) => {
- ListItem() {
- Text(decodeURIComponent(item))
- .fontSize(16)
- .width('100%')
- }
- .padding(12)
- .height(48)
- .backgroundColor(Color.White)
- .borderRadius(24)
- })
- }
- .padding({ left: 12, right: 12 })
- .layoutWeight(1)
- Column() {
- Button() {
- Image($r('app.media.ic_public_delete'))
- .objectFit(ImageFit.Cover)
- .size({ width: 24, height: 24 })
- }
- .type(ButtonType.Circle)
- .width(40)
- .height(40)
- .backgroundColor('#FF0000')
- .margin({ left: 5 })
- Text($r('app.string.clear_folder'))
- .fontSize(14)
- .fontColor($r('app.color.text_normal'))
- .opacity(0.6)
- .margin({ top: 8 })
- }
- .margin({ bottom: 24, top: 6 })
- .onClick(() => {
- fileUtils.clearFolder(this.currentFolder);
- this.files = [];
- })
- }
- .height('100%')
- .backgroundColor($r('app.color.light_gray'))
- }
- }
复制代码
- 参考接口:@ohos.request,@ohos.file.fs
以上就是本篇文章所带来的鸿蒙开辟中一小部分技能解说;想要学习完整的鸿蒙全栈技能。可以在末端找我可全部拿到!
下面是鸿蒙的完整学习蹊径,展示如下:
除此之外,根据这个学习鸿蒙全栈学习蹊径,也附带一整套完整的学习【文档+视频】,内容包含如下:
内容包含了:(ArkTS、ArkUI、Stage模型、多端摆设、分布式应用开辟、音频、视频、WebGL、OpenHarmony多媒体技能、Napi组件、OpenHarmony内核、鸿蒙南向开辟、鸿蒙项目实战)等技能知识点。资助大家在学习鸿蒙路上快速发展!
鸿蒙【北向应用开辟+南向系统层开辟】文档
鸿蒙【基础+实战项目】视频
鸿蒙面经
为了制止大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |