HarmonyOS 鸿蒙Next中download下载直接走到了fail

HarmonyOS 鸿蒙Next中download下载直接走到了fail

let context = getContext(this) as common.UIAbilityContext;
this.testIndex = this.testIndex + 1;
let filePath = context.cacheDir + param.fileName;
let url = param.downloadUrl

try {
  request.downloadFile(context, {
    url: url,
    filePath: filePath
  }).then((data: request.DownloadTask) => {
    let downloadTask: request.DownloadTask = data;
    //  下载进度的回调函数
    let progressCallback = (receivedSize: number, totalSize: number) => {
      console.info("download receivedSize:" + receivedSize + " totalSize:" + totalSize);
    };
    downloadTask.on('progress', progressCallback);

    downloadTask.on('complete', () => {
      console.info('download complete');
      let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
      let arrayBuffer = new ArrayBuffer(4096000);
      let readLen = fs.readSync(file.fd, arrayBuffer);
      let buf = buffer.from(arrayBuffer, 0, readLen);
      console.info(`content of File: ${buf.toString()}`);
      let writeLen = fs.writeSync(file.fd, arrayBuffer);
      fs.closeSync(file);
      // this.filePath = filePath;
      //以上可以下载到沙箱了
    })
    let failCallback = () => {
      console.info('Download task fail.');
    };
    downloadTask.on('fail', failCallback);

  }).catch((err: BusinessError) => {
    console.error(`downLoadFileTask failed, code is ${err.code}, message is ${err.message}`);
  });
} catch (error) {
  console.error(`downLoadFileTask failed, code is ${error.code}, message is ${error.message}`);
}

更多关于HarmonyOS 鸿蒙Next中download下载直接走到了fail的实战教程也可以访问 https://www.itying.com/category-93-b0.html

9 回复

download下载直接走到了fail,具体报了什么错嘛,或者可以参考下面示例request.downloadFile下载文件是可以成功下载的

【背景知识】

request.downloadFile接口用于下载任务,支持配置后台下载(后台任务下载成功或者失败界面都会有弹窗提示,前台任务没有任何提示信息),支持暂停恢复下载,用on(‘complete’)成功回调之后可以做一些业务操作,比如将图片保存到相册、进行页面展示等。

request接口中的filePath参数配置只支持沙箱路径,不支持用户uri地址

常用设置文件下载路径有两种方式:

filesDir获取应用的文件路径:

context = this.getUIContext().getHostContext() as common.UIAbilityContext; //context需在组件内获取
...
filePath = this.context.filesDir + '/' + fileName // /data/storage/el2/base/haps/entry/files/1751420076162987800.png

cacheDir获取应用的文件路径:

context = this.getUIContext().getHostContext() as common.UIAbilityContext; 
...
filePath = this.context.cacheDir + '/' + fileName // /data/storage/el2/base/haps/entry/cache/1751420076162987800.png

【解决方案】

完整示例

import { request, systemDateTime } from '@kit.BasicServicesKit';
import { common } from '@kit.AbilityKit';
import { promptAction } from '@kit.ArkUI';

interface DownloadResult {
  isSuccess: boolean,
  msg: string
}

@Entry
@Component
struct Index {
  context = this.getUIContext().getHostContext() as common.UIAbilityContext;
  @State downloadUrl: string ='https://www.example.com' // 需要手动将url替换为真实服务器的HTTP协议地址
  @State filePath: string = ''
  @State current: number = 0
  @State total: number = 0
  @State downloadTask: request.DownloadTask = {} as request.DownloadTask
  @State downloadImage: string = ''

  DownloadFile(url: string):Promise<DownloadResult>{
    return new Promise(async(resolve,reject)=>{
      const fileName = `${systemDateTime.getTime(true)}.png`
      this.filePath = this.context.filesDir + '/' + fileName
      this.downloadTask = await request.downloadFile(this.context, { url, filePath: this.filePath })
      // 监听下载进度
      this.downloadTask.on('progress', (receivedSize: number, totalSize: number) => {
        this.current = receivedSize
        this.total = totalSize
      })

      // 监听下载是否失败
      this.downloadTask.on('fail', (err) => {
        if (err){
          return reject({ isSuccess: false, msg: "下载失败" });
        }
      })

      // 监听下载是否完成
      this.downloadTask.on('complete', () => {
        this.downloadImage = "file://" + this.filePath
        return resolve({ isSuccess: true, msg: 'Download task completed.' });
      })
    })
  }

  build() {
    Column({ space: 10 }) {
      Row({ space: 20 }) {
        Progress({ value: this.current, total: this.total, type: ProgressType.ScaleRing }).width(100).height(100)
          .backgroundColor(Color.Black)
          .style({ strokeWidth: 15, scaleCount: 20, scaleWidth: 5 })
        Row() {
          Image(this.downloadImage)
        }.width(100).height(100)
      }

      Button('download下载').onClick(() => {
        this.DownloadFile(this.downloadUrl).then((result)=>{
          if (result.isSuccess) {
           console.log('下载成功');
          } else {
            console.error(`失败: ${result.msg}`);
            console.log('下载失败');
          }
        })
      })
    }
    .height('100%')
    .width('100%')
  }
}

更多关于HarmonyOS 鸿蒙Next中download下载直接走到了fail的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


背景知识:

首先使用 request.downloadFile() 是需要网络权限的,如下图提示,

cke_4954.png

需要在 module.json5 文件添加网络权限:

cke_7822.png

问题解决:

我按照你的代码写了一个例子,没有出现问题:

import { common } from '@kit.AbilityKit';
import { BusinessError, request, systemDateTime } from '@kit.BasicServicesKit';
import { buffer } from '@kit.ArkTS';
import fs from '@ohos.file.fs';

@Entry
@Component
struct DownloadPage {
    @State message: string = '下载';

    build() {
        Column() {
            Button(this.message)
                .fontSize(20)
                .fontWeight(FontWeight.Bold)
                .onClick(() => {
                    this.downloadFile("http://192.168.20.198:8000/test.txt",systemDateTime.getTime(false) + ".text")
                })
        }
        .height('100%')
        .width('100%')
    }

    downloadFile(url: string,fileName:string) {
        let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
        let filePath = context.cacheDir + "/" + fileName;

        try {
            request.downloadFile(context, {
                url: url,
                filePath: filePath
            }).then((data: request.DownloadTask) => {
                let downloadTask: request.DownloadTask = data;
                //  下载进度的回调函数
                let progressCallback = (receivedSize: number, totalSize: number) => {
                    console.info("DownloadPage receivedSize:" + receivedSize + " totalSize:" + totalSize);
                };
                downloadTask.on('progress', progressCallback);

                downloadTask.on('complete', () => {
                    console.info('DownloadPage complete');
                    let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
                    let arrayBuffer = new ArrayBuffer(4096000);
                    let readLen = fs.readSync(file.fd, arrayBuffer);
                    let buf = buffer.from(arrayBuffer, 0, readLen);
                    console.info(`DownloadPage content of File: ${buf.toString()}`);
                    let writeLen = fs.writeSync(file.fd, arrayBuffer);
                    fs.closeSync(file);
                    // this.filePath = filePath;
                    //以上可以下载到沙箱了
                })
                let failCallback = (err: number) => {
                    console.error('DownloadPage task fail. err:'+JSON.stringify(err));
                };
                downloadTask.on('fail', failCallback);

            }).catch((err: BusinessError) => {
                console.error(`DownloadPage downLoadFileTask failed, code is ${err.code}, message is ${err.message}`);
            });
        } catch (error) {
            console.error(`DownloadPage downLoadFileTask failed, code is ${error.code}, message is ${error.message}`);
        }
    }
}

日志:

cke_10219.png

如果还是出现问题,你可以在 failCallback 函数中添加一个返回值,将值打印出来到论坛上进行查询。

context.cacheDir路径可能未正确创建父级目录,或应用缺少存储权限。

沙箱环境下需确保路径符合规范(如filePath必须完整且父目录已存在)

// 确保路径父目录存在(以同步方式创建目录)
let parentDir = context.cacheDir;
if (!fs.accessSync(parentDir)) {
  fs.mkdirsSync(parentDir);
}
// 完整文件路径示例
let filePath = parentDir + '/' + param.fileName;

完整参考代码

let context = getContext(this) as common.UIAbilityContext;
let filePath = context.cacheDir + '/' + param.fileName;

// 确保目录存在
if (!fs.accessSync(context.cacheDir)) {
  fs.mkdirsSync(context.cacheDir);
}

try {
  request.downloadFile(context, {
    url: param.downloadUrl,
    filePath: filePath,
    timeout: 30000,
    retry: 2
  }).then((downloadTask: request.DownloadTask) => {
    downloadTask.on('progress', (received, total) => {
      console.info(`Progress: ${received}/${total}`);
    });
    
    downloadTask.on('complete', async () => {
      console.info('Download complete');
      // 异步处理文件
    });
    
    downloadTask.on('fail', (err: BusinessError) => {
      console.error(`Download failed. Code: ${err.code}, Msg: ${err.message}`);
    });
  }).catch((err: BusinessError) => {
    console.error(`Task creation failed: ${err.message}`);
  });
} catch (error) {
  console.error(`Download init error: ${error.message}`);
}

楼主先在src/main/modules.json中下面权限:

"requestPermissions": [
 { "name": "ohos.permission.INTERNET" },
 { "name": "ohos.permission.WRITE_MEDIA" },
 { "name": "ohos.permission.READ_MEDIA" }
]

filePath必须为包含完整父目录的绝对路径,要提前创建父目录:

let parentDir = context.cacheDir;
if (!fs.accessSync(parentDir)) {
 fs.mkdirsSync(parentDir); // 这里确保目录存在
}

另外你的沙箱路径规范一下

let filePath = `internal://app/cache/${param.fileName}`;

文件打开模式仅使用READ_WRITE模式

let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE);

如果还不行增强一下错误捕获

try {
 request.downloadFile(context, {
   url: url,
   filePath: filePath
 }).then((downloadTask: request.DownloadTask) => {
   downloadTask.on('fail', (err: BusinessError) => {
     console.error(`Download failed. Code: ${err.code}, Message: ${err.message}`);
     // 重点排查2300023写入失败和13400001文件操作错误
   });
 });
} catch (error) {
 // 捕获同步错误
 console.error(`Init failed. Code: ${error.code}, Message: ${error.message}`);
}
downloadTask.on('fail', (err: BusinessError) => {
  console.error(`Download failed. Code: ${err.code}, Message: ${err.message}`);
});

为什么我写这句代码直接报错,

【背景知识】

[@ohos.request](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-request):给应用提供上传下载文件、后台代理传输的基础功能。

【参考方案】

可参考文件下载预览示例,通过[@ohos.request](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-request)实现对文件的下载并保存至沙箱。

  1. 利用[@ohos.request](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-request)并通过网络路径从网页上下载对应的文件。
  2. 将下载的文件保存至沙箱中并储存路径。
request.downloadFile(context, {
  url: url,
  filePath: filePath,
  enableMetered: true
})

还是不行啊,

鸿蒙Next中download下载直接进入fail回调,通常由网络权限未配置或下载路径问题导致。请检查以下配置:在module.json5中确认已添加ohos.permission.INTERNET权限;确保下载路径使用正确的沙箱路径(如context.filesDir),避免使用无权限的存储路径。同时验证网络连接状态及服务器地址有效性。

从代码来看,downloadFile直接进入fail回调可能有几个原因:

  1. 网络权限问题:检查config.json中是否声明了ohos.permission.INTERNET权限,并确保设备已开启网络访问。

  2. URL格式或可达性:确认param.downloadUrl是有效的HTTP/HTTPS地址,且服务器可正常响应。建议先用浏览器测试URL有效性。

  3. 文件路径权限:context.cacheDir路径需要确保应用有写入权限,虽然cacheDir通常可写,但可尝试改用其他目录如filesDir测试。

  4. 同步错误处理:代码中使用了try-catch,但downloadFile是异步操作,异常可能出现在Promise链中。检查catch块输出的error.code和message,这是关键调试信息。

  5. 资源释放:在fail回调中未处理可能的半成品文件,若多次失败可能导致存储问题,但这不是直接失败原因。

建议先捕获并输出err.code和err.message,根据具体错误码进一步排查。常见错误如权限未授权(201)、网络不可达(2300001)或URL无效(2300002)等。

回到顶部