ToB企服应用市场:ToB评测及商务社交产业平台

标题: 鸿蒙系统开辟【网络-上传和下载(ArkTS)】基本功能 [打印本页]

作者: 八卦阵    时间: 2024-10-16 18:08
标题: 鸿蒙系统开辟【网络-上传和下载(ArkTS)】基本功能
网络-上传和下载(ArkTS)

先容

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


利用阐明
1.本示例功能需要先配置服务器情况后利用,具体配置见[上传下载服务配置]。
2.首页展示上传和下载两个入口组件,点击进入对应的页面,如果要利用背景下载任务,请开启背景任务开关。
3.上传页面(请先在图库中确定已开启图库权限):
​ 点击**+**,从相册选择拉起图库选择照片,图片选择页面支持拍照,选择照片后点击发表进行上传。
​ 在首页中打开背景任务开关后,上传页面开启的是背景上传任务,背景任务在应用退出到背景时可以在关照栏看到任务状态。
4.下载页面:
​ 点击文件列表选择要下载的文件后,点击下载选择指定路径后开始下载。
​ 点击查看下载文件进入下载文件页面,点击文件夹查看文件夹内的文件。
​ 在首页中打开背景任务开关后,下载页面开启的是背景下载任务,背景任务在应用退出到背景时可以在关照栏看到任务状态。
​ 前台下载时只支持单文件下载,背景下载时支持选择多个文件下载。
具体实现


  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { common } from '@kit.AbilityKit';
  16. import { promptAction } from '@kit.ArkUI';
  17. import { request } from '@kit.BasicServicesKit';
  18. import { urlUtils } from '../utils/UrlUtils';
  19. import { logger } from '../utils/Logger';
  20. import { MediaUtils } from '../utils/MediaUtils';
  21. import { BackgroundTaskState, UPLOAD_TOKEN, TOAST_BOTTOM, TASK_MAX } from '../utils/Constants';
  22. const TAG: string = 'RequestUpload';
  23. const HEADER: Record<string, string> = { 'Content-Type': 'multipart/form-data' };
  24. class Upload {
  25.   private mediaUtils: MediaUtils = new MediaUtils();
  26.   private config: request.agent.Config = {
  27.     action: request.agent.Action.UPLOAD,
  28.     headers: HEADER,
  29.     url: '',
  30.     mode: request.agent.Mode.FOREGROUND,
  31.     method: 'POST',
  32.     title: 'upload',
  33.     network: request.agent.Network.ANY,
  34.     data: [],
  35.     token: UPLOAD_TOKEN
  36.   }
  37.   private context: common.UIAbilityContext | undefined = undefined;
  38.   private uploadTask: request.agent.Task | undefined = undefined;
  39.   private backgroundTask: request.agent.Task | undefined = undefined;
  40.   private waitList: Array<string> = [];
  41.   progressCallback: Function | undefined = undefined;
  42.   completedCallback: Function | undefined = undefined;
  43.   failedCallback: Function | undefined = undefined;
  44.   constructor() {
  45.     setInterval(() => {
  46.       this.flushBackgroundTask()
  47.     }, 2000);
  48.   }
  49.   async uploadFilesBackground(fileUris: Array<string>): Promise<void> {
  50.     logger.info(TAG, `uploadFiles begin, ${JSON.stringify(fileUris)}`);
  51.     this.context = getContext(this) as common.UIAbilityContext;
  52.     if (fileUris.length === 0) {
  53.       return;
  54.     }
  55.     fileUris.forEach((item: string) => {
  56.       this.waitList.push(item);
  57.     });
  58.   }
  59.   async flushBackgroundTask() {
  60.     let tasks = await request.agent.search({
  61.       state: request.agent.State.RUNNING
  62.     });
  63.     let state = AppStorage.get<number>('backTaskState');
  64.     if (state === BackgroundTaskState.RUNNING) {
  65.       if (tasks.length < TASK_MAX && this.waitList.length > 0) {
  66.         this.createBackgroundTask(this.waitList);
  67.         this.waitList = [];
  68.       } else {
  69.         if (this.backgroundTask === undefined || tasks.indexOf(this.backgroundTask.tid) === -1) {
  70.           AppStorage.setOrCreate('backTaskState', BackgroundTaskState.NONE);
  71.           this.backgroundTask = undefined;
  72.         }
  73.       }
  74.     }
  75.   }
  76.   async createBackgroundTask(fileUris: Array<string>) {
  77.     if (this.context === undefined) {
  78.       return;
  79.     }
  80.     this.config.url = await urlUtils.getUrl(this.context);
  81.     this.config.data = await this.getFilesAndData(this.context.cacheDir, fileUris);
  82.     this.config.mode = request.agent.Mode.BACKGROUND;
  83.     try {
  84.       this.backgroundTask = await request.agent.create(this.context, this.config);
  85.       await this.backgroundTask.start();
  86.       let state = AppStorage.get<number>('backTaskState');
  87.       if (state === BackgroundTaskState.PAUSE) {
  88.         await this.backgroundTask.pause();
  89.       }
  90.       logger.info(TAG, `createBackgroundTask success`);
  91.     } catch (err) {
  92.       logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
  93.     }
  94.   }
  95.   async uploadFiles(fileUris: Array<string>, callback: (progress: number, isSucceed: boolean) => void): Promise<void> {
  96.     logger.info(TAG, `uploadFiles begin, ${JSON.stringify(fileUris)}`);
  97.     if (fileUris.length === 0) {
  98.       return;
  99.     }
  100.     // 查询到存在正在执行的上传任务,提示并返回
  101.     let tasks = await request.agent.search({
  102.       state: request.agent.State.RUNNING,
  103.       action: request.agent.Action.UPLOAD,
  104.       mode: request.agent.Mode.FOREGROUND
  105.     });
  106.     if (tasks.length > 0) {
  107.       promptAction.showToast({ message: $r('app.string.have_upload_task_tips'), bottom: TOAST_BOTTOM });
  108.       return;
  109.     }
  110.     let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  111.     this.config.data = await this.getFilesAndData(context.cacheDir, fileUris);
  112.     this.config.url = await urlUtils.getUrl(context);
  113.     this.config.mode = request.agent.Mode.FOREGROUND;
  114.     try {
  115.       this.uploadTask = await request.agent.create(context, this.config);
  116.       this.uploadTask.on('progress', this.progressCallback = (progress: request.agent.Progress) => {
  117.         logger.info(TAG, `progress,  progress = ${progress.processed} ${progress.state}`);
  118.         let processed = Number(progress.processed.toString()).valueOf();
  119.         let size = progress.sizes[0];
  120.         let process: number = Math.floor(processed / size * 100);
  121.         if (process < 100) {
  122.           callback(process, false);
  123.         }
  124.       });
  125.       this.uploadTask.on('completed', this.completedCallback = (progress: request.agent.Progress) => {
  126.         logger.info(TAG, `complete,  progress = ${progress.processed} ${progress.state}`);
  127.         callback(100, true);
  128.         this.cancelTask();
  129.       });
  130.       this.uploadTask.on('failed', this.failedCallback = async (progress: request.agent.Progress) => {
  131.         if (this.uploadTask) {
  132.           let taskInfo = await request.agent.touch(this.uploadTask.tid, UPLOAD_TOKEN);
  133.           logger.info(TAG, `fail,  resean = ${taskInfo.reason}, faults = ${JSON.stringify(taskInfo.faults)}`);
  134.         }
  135.         callback(100, false);
  136.         this.cancelTask();
  137.       });
  138.       await this.uploadTask.start();
  139.     } catch (err) {
  140.       logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
  141.       callback(100, false);
  142.     }
  143.   }
  144.   async cancelTask() {
  145.     if (this.uploadTask === undefined) {
  146.       return;
  147.     }
  148.     try {
  149.       this.uploadTask.off('progress');
  150.       this.progressCallback = undefined;
  151.       this.uploadTask.off('failed');
  152.       this.failedCallback = undefined
  153.       this.uploadTask.off('completed');
  154.       this.completedCallback = undefined
  155.       await this.uploadTask.stop();
  156.       await request.agent.remove(this.uploadTask.tid);
  157.     } catch (err) {
  158.       logger.info(TAG, `deleteTask fail,err= ${JSON.stringify(err)}`);
  159.     }
  160.     this.uploadTask = undefined;
  161.   }
  162.   async pauseOrResume() {
  163.     let state = AppStorage.get<number>('backTaskState');
  164.     if (state === BackgroundTaskState.RUNNING) {
  165.       await this.pause();
  166.       AppStorage.setOrCreate('backTaskState', BackgroundTaskState.PAUSE);
  167.     } else if (state === BackgroundTaskState.PAUSE) {
  168.       await this.resume();
  169.       AppStorage.setOrCreate('backTaskState', BackgroundTaskState.RUNNING);
  170.     } else {
  171.       logger.info(TAG, 'this task state is error');
  172.     }
  173.   }
  174.   async pause() {
  175.     logger.info(TAG, 'pause');
  176.     if (this.backgroundTask === undefined) {
  177.       return;
  178.     }
  179.     try {
  180.       await this.backgroundTask.pause();
  181.     } catch (err) {
  182.       logger.info(TAG, `pause fail,err= ${JSON.stringify(err)}`);
  183.     }
  184.   }
  185.   async resume() {
  186.     logger.info(TAG, 'resume');
  187.     if (this.backgroundTask === undefined) {
  188.       return;
  189.     }
  190.     try {
  191.       await this.backgroundTask.resume();
  192.     } catch (err) {
  193.       logger.info(TAG, `resume fail,err= ${JSON.stringify(err)}`);
  194.     }
  195.   }
  196.   private async getFilesAndData(cacheDir: string, fileUris: Array<string>): Promise<Array<request.agent.FormItem>> {
  197.     logger.info(TAG, `getFilesAndData begin`);
  198.     let files: Array<request.agent.FormItem> = [];
  199.     for (let i = 0; i < fileUris.length; i++) {
  200.       logger.info(TAG, `getFile fileUri = ${fileUris[i]}`);
  201.       let imagePath = await this.mediaUtils.copyFileToCache(cacheDir, fileUris[i]);
  202.       logger.info(TAG, `getFilesAndData ${JSON.stringify(imagePath)}`);
  203.       let file: request.agent.FormItem = {
  204.         name: imagePath.split('cache/')[1],
  205.         value: {
  206.           path: './' + imagePath.split('cache/')[1]
  207.         }
  208.       }
  209.       files.push(file);
  210.     }
  211.     logger.info(TAG, `getFilesAndData ${JSON.stringify(files)}`);
  212.     return files;
  213.   }
  214. }
  215. export const requestUpload = new Upload();
复制代码

  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { picker } from '@kit.CoreFileKit';
  16. import { logger } from '@ohos/uploaddownload';
  17. import { BusinessError } from '@kit.BasicServicesKit';
  18. const TAG: string = 'AddPictures';
  19. @Extend(Image) function imageStyle() {
  20.   .width('100%')
  21.   .aspectRatio(1)
  22.   .objectFit(ImageFit.Fill)
  23.   .backgroundColor($r('app.color.light_gray'))
  24.   .borderRadius(12)
  25. }
  26. const TEXT_WIDTH_FULL: Length = '100%';
  27. @Component
  28. export struct AddPictures {
  29.   @Consume imageList: Array<string>;
  30.   build() {
  31.     Column() {
  32.       Text($r('app.string.tip'))
  33.         .fontColor($r('app.color.text_normal'))
  34.         .fontWeight(400)
  35.         .fontFamily('HarmonyHeiTi')
  36.         .fontSize(14)
  37.         .opacity(0.4)
  38.         .margin({ top: $r('app.float.add_pictures_margin_top'), bottom: $r('app.float.add_pictures_margin_bottom') })
  39.         .width(TEXT_WIDTH_FULL)
  40.       GridRow({ columns: { sm: 3, md: 6, lg: 8 }, gutter: 12 }) {
  41.         ForEach(this.imageList, (item: string) => {
  42.           GridCol({ span: 1 }) {
  43.             Image(item)
  44.               .imageStyle()
  45.           }
  46.         })
  47.         GridCol({ span: 1 }) {
  48.           Row() {
  49.             Image($r('app.media.ic_public_add'))
  50.               .size({ width: 24, height: 24 })
  51.               .objectFit(ImageFit.Contain)
  52.           }
  53.           .width('100%')
  54.           .height('100%')
  55.           .justifyContent(FlexAlign.Center)
  56.         }
  57.         .width('100%')
  58.         .aspectRatio(1)
  59.         .backgroundColor($r('app.color.white'))
  60.         .borderRadius(12)
  61.         .onClick(() => {
  62.           this.showDialog();
  63.         })
  64.       }
  65.     }
  66.     .width('100%')
  67.   }
  68.   addImages = (images: Array<string>) => {
  69.     images.forEach((item: string) => {
  70.       if (!this.imageList.includes(item)) {
  71.         this.imageList.push(item);
  72.       }
  73.     })
  74.     logger.info(TAG, `addImages imageList=${JSON.stringify(this.imageList)}`);
  75.   }
  76.   showDialog() {
  77.     AlertDialog.show({
  78.       message: $r('app.string.pick_album'),
  79.       alignment: DialogAlignment.Bottom,
  80.       offset: { dx: 0, dy: -12 },
  81.       primaryButton: {
  82.         value: $r('app.string.cancel'),
  83.         fontColor: $r('app.color.btn_text_blue'),
  84.         action: () => {
  85.         }
  86.       },
  87.       secondaryButton: {
  88.         value: $r('app.string.ok'),
  89.         fontColor: $r('app.color.btn_text_blue'),
  90.         action: () => {
  91.           try {
  92.             let photoSelectOptions = new picker.PhotoSelectOptions();
  93.             photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
  94.             photoSelectOptions.maxSelectNumber = 5;
  95.             let photoPicker = new picker.PhotoViewPicker();
  96.             photoPicker.select(photoSelectOptions).then((photoSelectResult: picker.PhotoSelectResult) => {
  97.               this.addImages(photoSelectResult.photoUris);
  98.             }).catch((err: BusinessError) => {
  99.               logger.error(TAG, `'PhotoViewPicker.select failed with err: ${JSON.stringify(err)}`);
  100.             });
  101.           } catch (err) {
  102.             logger.error(TAG, `'PhotoViewPicker failed with err: ${JSON.stringify(err)}`);
  103.           }
  104.         }
  105.       }
  106.     })
  107.   }
  108. }
复制代码

  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { common } from '@kit.AbilityKit';
  16. import { promptAction } from '@kit.ArkUI';
  17. import { AddPictures } from '../components/AddPictures';
  18. import { BackgroundTaskState, requestUpload, TOAST_BOTTOM } from '@ohos/uploaddownload';
  19. const TIME_MAX: number = 5;
  20. @Entry
  21. @Component
  22. struct Upload {
  23.   @StorageLink('isBackground') isBackground: boolean = false;
  24.   @StorageLink('backTaskState') @Watch('stateChange') backTaskState: BackgroundTaskState = BackgroundTaskState.NONE;
  25.   @State isBegin: boolean = false;
  26.   @Provide imageList: Array<string> = [];
  27.   @State progress: number = 0;
  28.   @State countdown: number = 0;
  29.   build() {
  30.     Navigation() {
  31.       Scroll() {
  32.         AddPictures()
  33.       }
  34.       .padding({ left: 24, right: 24 })
  35.       .width('100%')
  36.       .layoutWeight(1)
  37.       .align(Alignment.Top)
  38.       Column() {
  39.         Button() {
  40.           if (this.isBackground && this.backTaskState !== BackgroundTaskState.NONE) {
  41.             if (this.backTaskState === BackgroundTaskState.RUNNING) {
  42.               Text($r('app.string.pause'))
  43.                 .fontSize(16)
  44.                 .fontWeight(500)
  45.                 .fontColor($r('app.color.white'))
  46.             } else {
  47.               Text($r('app.string.continue'))
  48.                 .fontSize(16)
  49.                 .fontWeight(500)
  50.                 .fontColor($r('app.color.white'))
  51.             }
  52.           } else if (this.isBegin && !this.isBackground) {
  53.             Row() {
  54.               Progress({ value: this.progress, type: ProgressType.Ring })
  55.                 .width(20)
  56.                 .height(20)
  57.                 .backgroundColor('#FFFFFF')
  58.                 .color('#558DFF')
  59.                 .style({ strokeWidth: 2, scaleCount: 100, scaleWidth: 2 })
  60.               Text(`${this.getResourceString($r('app.string.uploading'))}${this.progress}%`)
  61.                 .fontSize(16)
  62.                 .fontColor('#FFFFFF')
  63.                 .fontWeight(500)
  64.                 .margin({ left: 12 })
  65.             }.alignItems(VerticalAlign.Center)
  66.           } else {
  67.             if (this.countdown > 0) {
  68.               Text(`${this.countdown}s`)
  69.                 .fontSize(16)
  70.                 .fontWeight(500)
  71.                 .fontColor($r('app.color.white'))
  72.             } else {
  73.               Text($r('app.string.upload'))
  74.                 .fontSize(16)
  75.                 .fontWeight(500)
  76.                 .fontColor($r('app.color.white'))
  77.             }
  78.           }
  79.         }
  80.         .id('publish')
  81.         .width('100%')
  82.         .height(40)
  83.         .margin({ bottom: this.isBegin ? 16 : 24 })
  84.         .enabled(this.countdown > 0 ? false : true)
  85.         .backgroundColor($r('app.color.button_blue'))
  86.         .onClick(() => {
  87.           if (this.isBackground && this.backTaskState !== BackgroundTaskState.NONE) {
  88.             requestUpload.pauseOrResume();
  89.           } else {
  90.             this.uploadFiles();
  91.           }
  92.         })
  93.         if (this.isBegin) {
  94.           Button() {
  95.             Text($r('app.string.cancel'))
  96.               .fontSize(16)
  97.               .fontWeight(500)
  98.               .fontColor($r('app.color.btn_text_blue'))
  99.           }
  100.           .id('cancel')
  101.           .width('100%')
  102.           .height(40)
  103.           .margin({ bottom: 24 })
  104.           .backgroundColor($r('app.color.button_light_gray'))
  105.           .onClick(() => {
  106.             // cancel task
  107.             requestUpload.cancelTask();
  108.             this.progress = 0;
  109.             this.isBegin = false;
  110.           })
  111.         }
  112.       }
  113.       .width('100%')
  114.       .padding({ left: 24, right: 24 })
  115.     }
  116.     .width('100%')
  117.     .height('100%')
  118.     .backgroundColor($r('app.color.light_gray'))
  119.     .title($r('app.string.upload'))
  120.     .hideBackButton(false)
  121.     .titleMode(NavigationTitleMode.Mini)
  122.     .mode(NavigationMode.Stack)
  123.   }
  124.   aboutToAppear() {
  125.     this.isBegin = false;
  126.     this.backTaskState = BackgroundTaskState.NONE;
  127.   }
  128.   stateChange() {
  129.     if (this.backTaskState === BackgroundTaskState.NONE) {
  130.       this.imageList = [];
  131.     }
  132.   }
  133.   uploadFiles() {
  134.     if (this.imageList.length === 0) {
  135.       return;
  136.     }
  137.     if (this.isBackground) {
  138.       AppStorage.setOrCreate('backTaskState', BackgroundTaskState.RUNNING)
  139.       requestUpload.uploadFilesBackground(this.imageList);
  140.       promptAction.showToast({ message: $r('app.string.background_task_start'), bottom: TOAST_BOTTOM });
  141.     } else {
  142.       this.isBegin = true;
  143.       this.progress = 0;
  144.       requestUpload.uploadFiles(this.imageList, (progress: number, isSucceed: boolean) => {
  145.         this.progress = progress;
  146.         if (this.progress === 100 && isSucceed) {
  147.           this.isBegin = false;
  148.           this.imageList = [];
  149.           promptAction.showToast({ message: $r('app.string.upload_success'), bottom: TOAST_BOTTOM })
  150.         }
  151.         if (this.progress === 100 && isSucceed === false) {
  152.           this.isBegin = false;
  153.           this.countdown = TIME_MAX;
  154.           let interval = setInterval(() => {
  155.             if (this.countdown > 0) {
  156.               this.countdown--;
  157.             } else {
  158.               clearInterval(interval);
  159.             }
  160.           }, 1000);
  161.           promptAction.showToast({ message: $r('app.string.upload_fail'), bottom: TOAST_BOTTOM })
  162.         }
  163.       });
  164.     }
  165.   }
  166.   getResourceString(resource: Resource) {
  167.     let context = getContext(this) as common.UIAbilityContext;
  168.     return context.resourceManager.getStringSync(resource.id);
  169.   }
  170. }
复制代码

  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { common } from '@kit.AbilityKit';
  16. import { promptAction } from '@kit.ArkUI';
  17. import { request } from '@kit.BasicServicesKit';
  18. import { logger } from '../utils/Logger';
  19. import { TOAST_BOTTOM, TASK_MAX, TASK_PAUSE_MSG, TASK_NET_PAUSE_MSG, TASK_RESUME_MSG, TASK_NET_RESUME_MSG } from '../utils/Constants';
  20. const TAG: string = 'RequestDownload';
  21. let isNetPause = false;
  22. class RequestDownload {
  23.   private context: common.UIAbilityContext | undefined = undefined;
  24.   private waitList: Array<string[]> = [];
  25.   private downloadTask: request.agent.Task | undefined = undefined;
  26.   progressCallback: Function | undefined = undefined;
  27.   completedCallback: Function | undefined = undefined;
  28.   failedCallback: Function | undefined = undefined;
  29.   constructor() {
  30.     setInterval(() => {
  31.       this.flushBackgroundTask()
  32.     }, 2000);
  33.   }
  34.   async downloadFilesBackground(folder: string, files: Array<string>) {
  35.     logger.info(TAG, 'downloadFiles');
  36.     this.context = getContext(this) as common.UIAbilityContext;
  37.     files.forEach((item: string) => {
  38.       this.waitList.push([folder, item]);
  39.     });
  40.   }
  41.   async flushBackgroundTask() {
  42.     let tasks = await request.agent.search({
  43.       state: request.agent.State.RUNNING
  44.     });
  45.     if (tasks.length < TASK_MAX && this.waitList.length > 0) {
  46.       let downloadList: Array<string[]> = [];
  47.       if (this.waitList.length <= TASK_MAX - tasks.length) {
  48.         downloadList = this.waitList;
  49.         this.waitList = [];
  50.       } else {
  51.         downloadList = this.waitList.slice(0, TASK_MAX - tasks.length);
  52.         this.waitList = this.waitList.slice(TASK_MAX - tasks.length, this.waitList.length);
  53.       }
  54.       logger.info(TAG, `this.waitList = ${JSON.stringify(this.waitList)}`);
  55.       this.createBackgroundTask(downloadList);
  56.     }
  57.   }
  58.   async createBackgroundTask(downloadList: Array<string[]>) {
  59.     if (this.context === undefined) {
  60.       return;
  61.     }
  62.     for (let i = 0; i < downloadList.length; i++) {
  63.       try {
  64.         let splitUrl = downloadList[i][1].split('//')[1].split('/');
  65.         let downloadConfig: request.agent.Config = {
  66.           action: request.agent.Action.DOWNLOAD,
  67.           url: downloadList[i][1],
  68.           method: 'POST',
  69.           title: 'download',
  70.           mode: request.agent.Mode.BACKGROUND,
  71.           network: request.agent.Network.ANY,
  72.           saveas: `./${downloadList[i][0]}/${splitUrl[splitUrl.length-1]}`,
  73.           overwrite: true,
  74.           gauge: true
  75.         }
  76.         let downTask = await request.agent.create(this.context, downloadConfig);
  77.         await downTask.start();
  78.       } catch (err) {
  79.         logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
  80.         this.waitList.push(downloadList[i]);
  81.       }
  82.     }
  83.   }
  84.   async pause() {
  85.     if (this.downloadTask) {
  86.       let taskInfo = await request.agent.show(this.downloadTask.tid);
  87.       logger.info(TAG, `task pause, taskInfo  = ${JSON.stringify(taskInfo)}`);
  88.       await this.downloadTask.pause();
  89.     }
  90.   }
  91.   async resume() {
  92.     if (this.downloadTask) {
  93.       let taskInfo = await request.agent.show(this.downloadTask.tid);
  94.       logger.info(TAG, `task resume, taskInfo  = ${JSON.stringify(taskInfo)}`);
  95.       await this.downloadTask.resume();
  96.     }
  97.   }
  98.   async downloadFile(folder: string, url: string, callback: (progress: number, isSuccess: boolean) => void) {
  99.     logger.info(TAG, 'downloadFile');
  100.     // 查询到存在正在执行的下载任务,提示并返回
  101.     let tasks = await request.agent.search({
  102.       state: request.agent.State.RUNNING,
  103.       action: request.agent.Action.DOWNLOAD,
  104.       mode: request.agent.Mode.FOREGROUND
  105.     });
  106.     if (tasks.length > 0) {
  107.       promptAction.showToast({ message: $r('app.string.have_download_task_tips'), bottom: TOAST_BOTTOM });
  108.       return;
  109.     }
  110.     let splitUrl = url.split('//')[1].split('/');
  111.     let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  112.     let downloadConfig: request.agent.Config = {
  113.       action: request.agent.Action.DOWNLOAD,
  114.       url: url,
  115.       method: 'GET',
  116.       title: 'download',
  117.       mode: request.agent.Mode.BACKGROUND,
  118.       retry: true,
  119.       network: request.agent.Network.ANY,
  120.       saveas: `./${folder}/${splitUrl[splitUrl.length-1]}`,
  121.       overwrite: true
  122.     }
  123.     logger.info(TAG, `downloadFile, downloadConfig = ${JSON.stringify(downloadConfig)}`);
  124.     try {
  125.       this.downloadTask = await request.agent.create(context, downloadConfig);
  126.       this.downloadTask.on('progress', this.progressCallback = (progress: request.agent.Progress) => {
  127.         logger.info(TAG, `progress,  progress = ${progress.processed} ${progress.state}`);
  128.         let processed = Number(progress.processed.toString()).valueOf();
  129.         let size = progress.sizes[0];
  130.         let process: number = Math.floor(processed / size * 100);
  131.         if (process < 100) {
  132.           callback(process, false);
  133.         }
  134.       })
  135.       this.downloadTask.on('completed', this.completedCallback = (progress: request.agent.Progress) => {
  136.         logger.info(TAG, `download complete, file= ${url}, progress = ${progress.processed}`);
  137.         callback(100, true);
  138.         this.deleteTask();
  139.       })
  140.       this.downloadTask.on('pause', this.failedCallback = async (progress: request.agent.Progress) => {
  141.         if (this.downloadTask) {
  142.           let taskInfo = await request.agent.show(this.downloadTask.tid);
  143.           logger.info(TAG, `pause,  resean = ${taskInfo.reason}, progress = ${progress.processed}, faults = ${JSON.stringify(taskInfo.faults)}`);
  144.           isNetPause = taskInfo.faults === 0;
  145.           if (isNetPause) {
  146.             callback(TASK_NET_PAUSE_MSG, isNetPause);
  147.           }
  148.           else {
  149.             callback(TASK_PAUSE_MSG, isNetPause);
  150.           }
  151.         }
  152.       })
  153.       this.downloadTask.on('resume', this.failedCallback = async (progress: request.agent.Progress) => {
  154.         if (this.downloadTask) {
  155.           let taskInfo = await request.agent.show(this.downloadTask.tid);
  156.           logger.info(TAG, `resume,  resean = ${taskInfo.reason}, progress = ${progress.processed}, faults = ${JSON.stringify(taskInfo.faults)}`);
  157.           if (isNetPause) {
  158.             isNetPause = false;
  159.             callback(TASK_NET_RESUME_MSG, isNetPause);
  160.           }
  161.           else {
  162.             callback(TASK_RESUME_MSG, isNetPause);
  163.           }
  164.         }
  165.       })
  166.       this.downloadTask.on('failed', this.failedCallback = async (progress: request.agent.Progress) => {
  167.         if (this.downloadTask) {
  168.           let taskInfo = await request.agent.show(this.downloadTask.tid);
  169.           logger.info(TAG, `fail,  resean = ${taskInfo.reason}, progress = ${progress.processed}, faults = ${JSON.stringify(taskInfo.faults)}`);
  170.         }
  171.         callback(100, false);
  172.         this.deleteTask();
  173.       })
  174.       await this.downloadTask.start();
  175.     } catch (err) {
  176.       logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
  177.       callback(100, false);
  178.     }
  179.   }
  180.   async deleteTask() {
  181.     if (this.downloadTask) {
  182.       try {
  183.         this.downloadTask.off('progress');
  184.         this.progressCallback = undefined;
  185.         this.downloadTask.off('completed');
  186.         this.completedCallback = undefined
  187.         this.downloadTask.off('failed');
  188.         this.failedCallback = undefined
  189.         await request.agent.remove(this.downloadTask.tid);
  190.       } catch (err) {
  191.         logger.info(TAG, `deleteTask fail, err= ${JSON.stringify(err)}`);
  192.       }
  193.     }
  194.     this.downloadTask = undefined;
  195.   }
  196. }
  197. export const requestDownload = new RequestDownload();
复制代码

  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { promptAction } from '@kit.ArkUI';
  16. import { router } from '@kit.ArkUI';
  17. import { CustomDataSource } from '../components/CustomDataSource';
  18. import {
  19.   FileModel,
  20.   FileType,
  21.   fileUtils,
  22.   logger,
  23.   requestFiles,
  24.   requestDownload,
  25.   TOAST_BOTTOM,
  26.   TASK_PAUSE_MSG,
  27.   TASK_RESUME_MSG,
  28.   TASK_NET_PAUSE_MSG,
  29.   TASK_NET_RESUME_MSG
  30. } from '@ohos/uploaddownload';
  31. import { SelectFolderDialog } from '../components/SelectFolderDialog';
  32. const TAG: string = 'Download';
  33. const OFFSET_DY: Length = -12;
  34. const OFFSET_DX: Length = 0;
  35. const LOADING_PROGRESS_WIDTH: Length = 100;
  36. const FULL_WIDTH: Length = '100%';
  37. const FULL_HEIGHT: Length = '100%';
  38. const LIST_WIDTH: Length = '100%';
  39. const LIST_HEIGHT: Length = 'auto';
  40. const LIST_BORDER_RADIUS: Length | BorderRadiuses = 24;
  41. const PADDING_TOP: Length = 4;
  42. const PADDING_BOTTOM: Length = 4;
  43. const STROKE_WIDTH: Length = 1;
  44. const START_MARGIN: Length = 44;
  45. const END_MARGIN: Length = 12;
  46. const COLUMN_PADDING_LEFT: Length = 12;
  47. const COLUMN_PADDING_RIGHT: Length = 12;
  48. const COLUMN_PADDING_BOTTOM: Length = 12;
  49. const BUTTON_FONT_SIZE = 16;
  50. const MARGIN_TOP: Length = 12;
  51. const MARGIN_LEFT: Length = 12;
  52. const MARGIN_RIGHT: Length = 12;
  53. const MARGIN_BOTTOM: Length = 12;
  54. const BUTTON_HEIGHT: Length = 45;
  55. @Entry
  56. @Component
  57. struct Download {
  58.   private fileData: CustomDataSource = new CustomDataSource([]);
  59.   @StorageLink('isBackground') isBackground: boolean = false;
  60.   @Provide downloadFolder: Array<string> = [];
  61.   @State isGetData: boolean = false;
  62.   @State checkFile: Array<string> = [];
  63.   @State checkList: Array<boolean> = [];
  64.   @State isRunning: boolean = false;
  65.   @State isPause: boolean = false;
  66.   @State isNetPause: boolean = false;
  67.   @State progress: number = 0;
  68.   private selectFolder = (folder: string) => {
  69.     logger.info(TAG, `selectFolder = ${folder}`);
  70.     this.download(folder);
  71.   }
  72.   private folderDialogController: CustomDialogController = new CustomDialogController({
  73.     builder: SelectFolderDialog({ selectFolder: this.selectFolder }),
  74.     autoCancel: true,
  75.     alignment: DialogAlignment.Bottom,
  76.     offset: { dx: OFFSET_DX,
  77.       dy: OFFSET_DY }
  78.   });
  79.   build() {
  80.     Navigation() {
  81.       Column() {
  82.         if (this.isGetData) {
  83.           LoadingProgress()
  84.             .width(LOADING_PROGRESS_WIDTH)
  85.             .layoutWeight(1)
  86.         } else {
  87.           List({ space: 12 }) {
  88.             LazyForEach(this.fileData, (item: FileModel, index: number) => {
  89.               ListItem() {
  90.                 this.FileItem(item, index)
  91.               }
  92.             }, (item: FileModel) => JSON.stringify(item))
  93.           }
  94.           .width(LIST_WIDTH)
  95.           .height(LIST_HEIGHT)
  96.           .scrollBar(BarState.Off)
  97.           .backgroundColor(Color.White)
  98.           .borderRadius(LIST_BORDER_RADIUS)
  99.           .padding({ top: PADDING_TOP,
  100.             bottom: PADDING_BOTTOM })
  101.           .divider({ strokeWidth: STROKE_WIDTH,
  102.             startMargin: START_MARGIN,
  103.             endMargin: END_MARGIN })
  104.         }
  105.         Column().layoutWeight(1)
  106.         this.BottomView()
  107.       }
  108.       .padding({ left: COLUMN_PADDING_LEFT,
  109.         right: COLUMN_PADDING_RIGHT,
  110.         bottom: COLUMN_PADDING_BOTTOM })
  111.       .height(FULL_HEIGHT)
  112.     }
  113.     .width(FULL_WIDTH)
  114.     .height(FULL_HEIGHT)
  115.     .hideBackButton(false)
  116.     .titleMode(NavigationTitleMode.Mini)
  117.     .mode(NavigationMode.Stack)
  118.     .backgroundColor($r('app.color.light_gray'))
  119.     .hideToolBar(false)
  120.     .title($r('app.string.download'))
  121.   }
  122.   @Builder
  123.   FileItem(file: FileModel, index: number) {
  124.     Row() {
  125.       Row() {
  126.         if (file.fileType === FileType.FOLDER) {
  127.           Image($r('app.media.ic_files_folder'))
  128.             .size({ width: 24, height: 24 })
  129.             .objectFit(ImageFit.Contain)
  130.         } else if (file.fileType === FileType.IMAGE) {
  131.           Image($r('app.media.ic_public_picture'))
  132.             .size({ width: 24, height: 24 })
  133.             .objectFit(ImageFit.Contain)
  134.         } else if (file.fileType === FileType.MUSIC) {
  135.           Image($r('app.media.ic_public_music'))
  136.             .size({ width: 24, height: 24 })
  137.             .objectFit(ImageFit.Contain)
  138.         } else if (file.fileType === FileType.Video) {
  139.           Image($r('app.media.ic_public_video'))
  140.             .size({ width: 24, height: 24 })
  141.             .objectFit(ImageFit.Contain)
  142.         } else {
  143.           Image($r('app.media.ic_public_document'))
  144.             .size({ width: 24, height: 24 })
  145.             .objectFit(ImageFit.Contain)
  146.         }
  147.         Text(decodeURIComponent(file.name))
  148.           .fontSize(16)
  149.           .fontWeight(400)
  150.           .layoutWeight(1)
  151.           .maxLines(1)
  152.           .textOverflow({ overflow: TextOverflow.Ellipsis })
  153.           .margin({ left: 12 })
  154.       }
  155.       .layoutWeight(1)
  156.       Checkbox({ name: '', group: 'checkboxGroup' })
  157.         .select(this.checkList[index])
  158.         .selectedColor($r('app.color.button_blue'))
  159.         .margin({ left: 12 })
  160.         .hitTestBehavior(HitTestMode.None)
  161.     }
  162.     .width('100%')
  163.     .padding({ left: 12, right: 12 })
  164.     .height(48)
  165.     .onClick(() => {
  166.       this.fileCheck(index);
  167.     })
  168.   }
  169.   @Builder
  170.   BottomView() {
  171.     Column({ space: 12 }) {
  172.       Button() {
  173.         Row() {
  174.           if (!this.isBackground && this.isRunning) {
  175.             if (this.isPause || this.isNetPause) {
  176.               Text($r('app.string.continue'))
  177.                 .fontColor(Color.White)
  178.                 .fontSize(BUTTON_FONT_SIZE)
  179.             }
  180.             else {
  181.               Text(`${this.progress}%`)
  182.                 .fontColor(Color.White)
  183.                 .fontSize(BUTTON_FONT_SIZE)
  184.               Text($r('app.string.downloading'))
  185.                 .fontColor(Color.White)
  186.                 .fontSize(BUTTON_FONT_SIZE)
  187.                 .margin({ left: MARGIN_LEFT })
  188.             }
  189.           } else {
  190.             Text($r('app.string.download'))
  191.               .fontColor(Color.White)
  192.               .fontSize(BUTTON_FONT_SIZE)
  193.           }
  194.         }
  195.       }
  196.       .id('download_to')
  197.       .type(ButtonType.Capsule)
  198.       .height(BUTTON_HEIGHT)
  199.       .width(FULL_WIDTH)
  200.       .backgroundColor($r('app.color.button_blue'))
  201.       .onClick(() => {
  202.         if (!this.isRunning) {
  203.           this.folderDialogController.open();
  204.         }
  205.         else {
  206.           if (!this.isNetPause) {
  207.             if (this.isPause) {
  208.               requestDownload.resume();
  209.             }
  210.             else {
  211.               requestDownload.pause();
  212.             }
  213.           }
  214.         }
  215.       })
  216.       Button($r('app.string.view_download_files'))
  217.         .id('view_download_files')
  218.         .type(ButtonType.Capsule)
  219.         .backgroundColor($r('sys.color.ohos_id_color_button_normal'))
  220.         .width('100%')
  221.         .fontSize(BUTTON_FONT_SIZE)
  222.         .margin({ bottom: MARGIN_BOTTOM })
  223.         .fontColor($r('app.color.btn_text_blue'))
  224.         .onClick(() => {
  225.           router.pushUrl({
  226.             url: 'pages/DownloadFiles'
  227.           });
  228.         })
  229.     }
  230.     .margin({ top: MARGIN_TOP,
  231.       left: MARGIN_LEFT,
  232.       right: MARGIN_RIGHT })
  233.   }
  234.   aboutToAppear() {
  235.     this.isRunning = false;
  236.     this.isPause = false;
  237.     this.isGetData = true;
  238.     requestFiles.requestFiles().then((data: FileModel[]) => {
  239.       this.checkList = [];
  240.       this.isRunning = false;
  241.       this.fileData.dataArray = data;
  242.       this.fileData.dataArray.forEach(() => {
  243.         this.checkList.push(false);
  244.       })
  245.       this.isGetData = false;
  246.       this.fileData.notifyDataReload();
  247.     })
  248.     fileUtils.listFolders().then((folders: Array<string>) => {
  249.       this.downloadFolder = folders;
  250.     })
  251.   }
  252.   fileCheck(index: number) {
  253.     if (!this.isBackground) {
  254.       for (let i = 0; i < this.checkList.length; i++) {
  255.         if (i !== index) {
  256.           this.checkList[i] = false;
  257.         }
  258.       }
  259.     }
  260.     this.checkList[index] = !this.checkList[index];
  261.     logger.info(TAG, `this.checkList = ${JSON.stringify(this.checkList)}`);
  262.   }
  263.   download(folder: string) {
  264.     this.checkFile = [];
  265.     if (this.checkList === undefined) {
  266.       return;
  267.     }
  268.     logger.info(TAG, `this.checkList = ${JSON.stringify(this.checkList)}`);
  269.     for (let i = 0; i < this.checkList.length; i++) {
  270.       if (this.checkList[i]) {
  271.         let fileModel = this.fileData.getData(i);
  272.         logger.info(TAG, `fileModel = ${JSON.stringify(fileModel)}`);
  273.         fileModel.files.forEach((url: string) => {
  274.           let splitUrl = url.split('//')[1].split('/');
  275.           if (splitUrl[splitUrl.length-1] !== '') {
  276.             this.checkFile.push(url);
  277.           }
  278.         });
  279.       }
  280.     }
  281.     logger.info(TAG, `this.checkFile = ${JSON.stringify(this.checkFile)}`);
  282.     if (this.checkFile.length === 0) {
  283.       promptAction.showToast({ message: $r('app.string.check_file_tips'), bottom: TOAST_BOTTOM });
  284.       return;
  285.     }
  286.     this.progress = 0;
  287.     if (this.isBackground) {
  288.       this.isRunning = false;
  289.       requestDownload.downloadFilesBackground(folder, this.checkFile);
  290.       this.checkFile = [];
  291.       this.checkList = [];
  292.       this.fileData.dataArray.forEach(() => {
  293.         this.checkList.push(false);
  294.       })
  295.       this.fileData.notifyDataReload();
  296.       promptAction.showToast({ message: $r('app.string.background_task_start'), bottom: TOAST_BOTTOM });
  297.     } else {
  298.       this.isRunning = true;
  299.       requestDownload.downloadFile(folder, this.checkFile[0], this.downloadFileCallback);
  300.     }
  301.   }
  302.   downloadFilesCallback = (downloadCount: number, isSuccess: boolean) => {
  303.     this.progress = downloadCount;
  304.     if (downloadCount === this.checkFile.length) {
  305.       this.downloadFinish(isSuccess);
  306.     }
  307.   }
  308.   downloadFileCallback = (progress: number, isSuccess: boolean) => {
  309.     logger.info(TAG, `downloadFileCallback = ${progress}`);
  310.     if (progress === TASK_PAUSE_MSG) {
  311.       this.isPause = true;
  312.     }
  313.     else if (progress === TASK_RESUME_MSG) {
  314.       this.isPause = false;
  315.     }
  316.     else if (progress === TASK_NET_PAUSE_MSG) {
  317.       this.isNetPause = true;
  318.       let message = $r('app.string.net_pause');
  319.       promptAction.showToast({ message: message, bottom: TOAST_BOTTOM });
  320.     }
  321.     else if (progress === TASK_NET_RESUME_MSG) {
  322.       this.isNetPause = false;
  323.       let message = $r('app.string.net_resume');
  324.       promptAction.showToast({ message: message, bottom: TOAST_BOTTOM });
  325.     }
  326.     else {
  327.       this.progress = progress;
  328.       if (this.progress === 100) {
  329.         this.downloadFinish(isSuccess);
  330.       }
  331.     }
  332.   }
  333.   downloadFinish(isSuccess: boolean) {
  334.     this.isRunning = false;
  335.     this.checkFile = [];
  336.     this.checkList = [];
  337.     this.fileData.dataArray.forEach(() => {
  338.       this.checkList.push(false);
  339.     })
  340.     this.fileData.notifyDataReload();
  341.     let message = isSuccess ? $r('app.string.download_finish') : $r('app.string.download_fail');
  342.     promptAction.showToast({ message: message, bottom: TOAST_BOTTOM });
  343.   }
  344. }
复制代码

  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { common } from '@kit.AbilityKit';
  16. import { fileIo } from '@kit.CoreFileKit';
  17. import { logger } from '../utils/Logger';
  18. const TAG: string = 'FileUtil';
  19. const ALBUMS: string[] = ['Pictures', 'Videos', 'Others'];
  20. class FileUtil {
  21.   constructor() {
  22.   }
  23.   async initDownloadDir(): Promise<void> {
  24.     let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  25.     logger.info(TAG, `initDownloadDir cacheDir=${context.cacheDir}`);
  26.     try {
  27.       fileIo.mkdirSync(`${context.cacheDir}/${ALBUMS[0]}`);
  28.       fileIo.mkdirSync(`${context.cacheDir}/${ALBUMS[1]}`);
  29.       fileIo.mkdirSync(`${context.cacheDir}/${ALBUMS[2]}`);
  30.     } catch (err) {
  31.       logger.info(TAG, `initDownloadDir err =${JSON.stringify(err)}`);
  32.     }
  33.   }
  34.   async listFolders(): Promise<Array<string>> {
  35.     await this.initDownloadDir();
  36.     return ALBUMS;
  37.   }
  38.   async clearFolder(folderName: string): Promise<void> {
  39.     let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  40.     try {
  41.       let files: string[] = fileIo.listFileSync(`${context.cacheDir}/${folderName}`);
  42.       logger.info(TAG, `listFiles listFileSync =${JSON.stringify(files)}`);
  43.       for (let i = 0; i < files.length; i++) {
  44.         fileIo.unlinkSync(`${context.cacheDir}/${folderName}/${files[i]}`);
  45.       }
  46.     } catch (err) {
  47.       logger.info(TAG, `listFiles err =${JSON.stringify(err)}`);
  48.     }
  49.   }
  50.   async listFiles(folderName: string): Promise<Array<string>> {
  51.     let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  52.     let files: string[] = [];
  53.     try {
  54.       files = fileIo.listFileSync(`${context.cacheDir}/${folderName}`);
  55.       logger.info(TAG, `listFiles listFileSync =${JSON.stringify(files)}`);
  56.     } catch (err) {
  57.       logger.info(TAG, `listFiles err =${JSON.stringify(err)}`);
  58.     }
  59.     return files;
  60.   }
  61. }
  62. export const fileUtils = new FileUtil();
复制代码

  1. /*
  2. * Copyright (c) 2023 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. *     http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { fileUtils } from '../utils/FileUtils';
  16. @Preview
  17. @Component
  18. export struct FileBrowse {
  19.   @State folders: Array<string> = ['folder'];
  20.   @State files: Array<string> = [];
  21.   @State currentFolder: string = '';
  22.   aboutToAppear() {
  23.     fileUtils.listFolders().then((folders: Array<string>) => {
  24.       this.folders = folders;
  25.     })
  26.   }
  27.   build() {
  28.     Navigation() {
  29.       List({ space: 12 }) {
  30.         ForEach(this.folders, (item: string) => {
  31.           ListItem() {
  32.             NavRouter() {
  33.               Row() {
  34.                 Image($r('app.media.ic_files_folder'))
  35.                   .size({ width: 32, height: 26 })
  36.                   .objectFit(ImageFit.Contain)
  37.                 Text(item)
  38.                   .fontSize(16)
  39.                   .width('100%')
  40.                   .margin({ left: 12 })
  41.               }
  42.               .height(56)
  43.               .padding({ left: 16 })
  44.               .backgroundColor(Color.White)
  45.               .borderRadius(24)
  46.               NavDestination() {
  47.                 this.FilesView()
  48.               }
  49.               .title(this.CustomTitle(item))
  50.               .backgroundColor($r('app.color.light_gray'))
  51.             }
  52.             .onStateChange(async (isActivated: boolean) => {
  53.               if (isActivated) {
  54.                 this.currentFolder = item;
  55.                 this.files = await fileUtils.listFiles(item);
  56.               }
  57.             })
  58.           }
  59.         })
  60.       }
  61.       .padding({ left: 12, right: 12 })
  62.     }
  63.     .hideBackButton(false)
  64.     .titleMode(NavigationTitleMode.Mini)
  65.     .title($r('app.string.download_files_title'))
  66.     .mode(NavigationMode.Stack)
  67.     .backgroundColor($r('app.color.light_gray'))
  68.   }
  69.   @Builder
  70.   CustomTitle(title: string) {
  71.     Row() {
  72.       Text(title)
  73.         .fontSize(20)
  74.         .fontColor($r('app.color.text_normal'))
  75.         .fontWeight(700)
  76.         .margin({ left: 8 })
  77.     }
  78.     .width('100%')
  79.   }
  80.   @Builder
  81.   FilesView() {
  82.     Column() {
  83.       List({ space: 12 }) {
  84.         if (this.files.length === 0) {
  85.           ListItem() {
  86.             Text($r('app.string.folder_empty'))
  87.               .fontSize(16)
  88.               .width('100%')
  89.               .margin({ top: 50 })
  90.               .textAlign(TextAlign.Center)
  91.           }
  92.         }
  93.         ForEach(this.files, (item: string) => {
  94.           ListItem() {
  95.             Text(decodeURIComponent(item))
  96.               .fontSize(16)
  97.               .width('100%')
  98.           }
  99.           .padding(12)
  100.           .height(48)
  101.           .backgroundColor(Color.White)
  102.           .borderRadius(24)
  103.         })
  104.       }
  105.       .padding({ left: 12, right: 12 })
  106.       .layoutWeight(1)
  107.       Column() {
  108.         Button() {
  109.           Image($r('app.media.ic_public_delete'))
  110.             .objectFit(ImageFit.Cover)
  111.             .size({ width: 24, height: 24 })
  112.         }
  113.         .type(ButtonType.Circle)
  114.         .width(40)
  115.         .height(40)
  116.         .backgroundColor('#FF0000')
  117.         .margin({ left: 5 })
  118.         Text($r('app.string.clear_folder'))
  119.           .fontSize(14)
  120.           .fontColor($r('app.color.text_normal'))
  121.           .opacity(0.6)
  122.           .margin({ top: 8 })
  123.       }
  124.       .margin({ bottom: 24, top: 6 })
  125.       .onClick(() => {
  126.         fileUtils.clearFolder(this.currentFolder);
  127.         this.files = [];
  128.       })
  129.     }
  130.     .height('100%')
  131.     .backgroundColor($r('app.color.light_gray'))
  132.   }
  133. }
复制代码

以上就是本篇文章所带来的鸿蒙开辟中一小部分技能解说;想要学习完整的鸿蒙全栈技能。可以在末端找我可全部拿到!
下面是鸿蒙的完整学习蹊径,展示如下:

除此之外,根据这个学习鸿蒙全栈学习蹊径,也附带一整套完整的学习【文档+视频】,内容包含如下
   内容包含了:(ArkTS、ArkUI、Stage模型、多端摆设、分布式应用开辟、音频、视频、WebGL、OpenHarmony多媒体技能、Napi组件、OpenHarmony内核、鸿蒙南向开辟、鸿蒙项目实战)等技能知识点。资助大家在学习鸿蒙路上快速发展!
  鸿蒙【北向应用开辟+南向系统层开辟】文档

鸿蒙【基础+实战项目】视频

鸿蒙面经


为了制止大家在学习过程中产生更多的时间成本,对比我把以上内容全部放在了↓↓↓想要的可以自拿喔!谢谢大家观看!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4