Harmony OS Next实现文件分享

Laughing
2025-01-15 / 0 评论 / 5 阅读 / 正在检测是否收录...

在日常开发过程中,将数据导出到Excel是常见的一种需求。爱车记App有个数据导出功能,可以将用户的充电记录导出Excel,因为Harmony OS Next的沙盒机制,默认导出的文件只能保存到App自己的目录中,为了方便用户保存数据,我们可以通过文件分享功能,用户可以将文件保存到手机的任意位置。

image-20250115214455257

一、后端导出Excel文件

后端代码我们不做过多介绍,就是使用EasyExcel导出Excel文件并下载。

/**
     * 数据导出
     *
     * @throws IOException IO异常
     */
    @GetMapping(value = "export", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void export() throws IOException {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletResponse response = null;
        HttpServletRequest request = null;
        if (servletRequestAttributes != null) {
            response = servletRequestAttributes.getResponse();
            request = servletRequestAttributes.getRequest();
        }
        if (response == null) {
            throw new CustomException("未获取到用户信息");
        }
        response.setContentType("application/x-msdownload");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("充电记录.xlsx", "UTF-8"));
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        // 创建excel对象
        CarUser user = tokenUtil.getLoginUser(request);
        List<CarEnergyExportVO> carEnergyList4Export = carEnergyService.selectCarEnergyList4Export(user.getId());

        //内容样式策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        //垂直居中,水平居中
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);

        //设置 自动换行
        contentWriteCellStyle.setWrapped(true);
        // 字体策略
        WriteFont contentWriteFont = new WriteFont();
        // 字体大小
        contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteFont.setFontName("仿宋");
        contentWriteCellStyle.setWriteFont(contentWriteFont);

        //头策略使用默认 设置字体大小
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 12);
        headWriteFont.setFontName("仿宋");
        headWriteCellStyle.setWriteFont(headWriteFont);
        headWriteCellStyle.setFillForegroundColor(IndexedColors.TAN.getIndex());

        ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream(), CarEnergyExportVO.class)
                .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle))
                .build();
        //创建sheet
        WriteSheet writeSheet = EasyExcel.writerSheet("充电记录").head(CarEnergyExportVO.class).build();
        //导出
        excelWriter.write(carEnergyList4Export, writeSheet);
        excelWriter.finish();
    }

二、下载文件

文件下载我们调用downloadFile(context: BaseContext, config: DownloadConfig)方法,context是上下文信息,DownloadConfig是参数信息,其中url是我们的后台地址,filePath是文件保存到本地的路径,header是传递到后端的头部信息,比如我这里的token是传递的认证信息。

在下载文件的回调方法中,我们监听downloadTask事件,complete代表文件下载完成,文件下载文成后,调用分装的公共的文件分享方法shareFile对文件进行分享。

                        IBestToast.show({
              icon: $r("app.media.mine_exporting_data"),
              message: getStringFromResource($r("app.string.exporting"))
            })
            try {
              // 判断文件是否存在,存在就删除
              let context = getContext(this) as common.UIAbilityContext;
              let filesDir = context.filesDir;
              let path = filesDir + '/爱车记.xlsx';
              if (fs.accessSync(path)) {
                fs.unlinkSync(path);
              }
              request.downloadFile(context, {
                url: Constants.API + '/common/export',
                filePath: path,
                header: {
                  "token": PreferencesUtil.readDataSync<string>("token")
                }
              }).then((downloadTask: request.DownloadTask) => {
                downloadTask.on('complete', () => {
                  IBestToast.hide()
                  shareFile(path)
                  // let file = fs.openSync(filesDir + '/car_expense.xlsx', fs.OpenMode.READ_WRITE);
                  // let arrayBuffer = new ArrayBuffer(1024);
                  // let readLen = fs.readSync(file.fd, arrayBuffer);
                  // let buf = buffer.from(arrayBuffer, 0, readLen);
                  // console.info(`The content of file: ${buf.toString()}`);
                  // fs.closeSync(file);
                })
              }).catch((err: BusinessError) => {
                IBestToast.hide()
                console.error(`Invoke downloadTask failed, code is ${err.code}, message is ${err.message}`);
              });
            } catch (error) {
              IBestToast.hide()
              let err: BusinessError = error as BusinessError;
              console.error(`Invoke downloadFile failed, code is ${err.code}, message is ${err.message}`);
            }

三、文件分享方法

文件分享时,我们传递文件的路径,这里有两个注意事项:

action:这个地方我们需要使用ohos.want.action.viewData,如果调用ohos.want.action.sendData,会使用默认的程序打开,比如我这里是Excel文件,如果安装了WPS,会直接调用WPS打开

type:这个是MIME Type,比如Excel 2007后续版本(xlsx后缀)默认为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet

/**
 * 分享文件
 */
export async function shareFile(filePath: string) {
  let context = AppStorage.get('context') as common.UIAbilityContext;
  // 获取文件沙箱路径
  // let filePath = this.context.filesDir + '/test.txt';
  // 将沙箱路径转换为 URI
  let uri = fileUri.getUriFromPath(filePath);
  // 创建分享意图
  let want: Want = {
    flags: wantConstant.Flags.FLAG_AUTH_WRITE_URI_PERMISSION | wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION,
    action: 'ohos.want.action.viewData',
    uri: uri,
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  };
  // 启动分享
  context.startAbility(want)
    .then(() => {
      console.log('Share file successfully');
    })
    .catch((err: BusinessError) => {
      console.error('Failed to share file:', err);
    });
}

四、配置权限

为了实现分享,我们需要在模块下的module.json5文件中配置相应的权限,在skillsuris添加如下内容

{
    "scheme": "file",
    "host": "*",
    "path": "/storage/*"
}

image-20250115214406732

0

评论 (0)

取消