最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

react-native-blob-util: filename from api headers - Stack Overflow

programmeradmin3浏览0评论

Yeap, I know, that we can set storeInDownloads into addAndroidDownloads. But in my case, it doesn't work.

I should use a dynamic filename from the API headers (Content-Disposition) and I write a function to download the file and move it to another folder with the final filename/path, if this is correct, but works.

On iOS +/- I implemented with react-native-share, but on Android, it always saves in the app folder Download: /storage/emulated/0/Android/data/com.awesome.staging/files/Download/final-name.pdf

How I see in this case, after download the file moves to the root Download on Android, how can it be implemented? There is no flag storeInDownloads for addCompleteDownload function. So in the final result, I should always take the filename from headers on both platforms, please help.

import { useCallback, useState } from 'react';
import { Platform } from 'react-native';
import RNBlobUtil, { ReactNativeBlobUtilConfig } from 'react-native-blob-util';
import Share, { ShareOptions } from 'react-native-share';
import config from '../config';

const isAndroid = Platform.OS === 'android';
const isIos = Platform.OS === 'ios';

type DownloadPDFProps = {
  id: string;
};

function getFilePath(fileName: string) {
  const dir = isIos ? RNBlobUtil.fs.dirs.DocumentDir : RNBlobUtil.fs.dirs.DownloadDir;
  return `${dir}/${fileName}`;
}

const mimeType = 'application/pdf';

const getFileNameFromContentDisposition = (
  contentDisposition: string | undefined,
): string | null => {
  if (!contentDisposition) return null;
  const fileNameMatch = contentDisposition.match( /filename\*?=["']?(?:UTF-8'')?([^;"']+)/i);
  return fileNameMatch ? decodeURIComponent(fileNameMatch[1]) : null;
};

/*
  Downloads a PDF.
  On iOS opens a "save to Files" sheet to choose where to store the file.
  Android use DownloadManager to save into Download folder.
*/
export const useDownloadPDF = () => {
  const [isPDFLoading, setIsPDFLoading] = useState(false);

  const downloadPDF = useCallback(async ({ id }: DownloadPDFProps) => {
    if (!id) return;

    const tempFileName = 'temp_file.pdf';
    const url = `${baseURL}/${id}/blank?format=pdf`;
    const tempFilePath = getFilePath(tempFileName);
    let finalPath = '';

    setIsPDFLoading(true);

    const blobConfig: ReactNativeBlobUtilConfig = {
      fileCache: true,
      path: tempFilePath,
      overwrite: true,
    };

    try {
      const resp = await RNBlobUtil.config(blobConfig).fetch('GET', url, {});

      const contentDisposition = resp.info().headers['Content-Disposition'] || resp.info().headers['content-disposition'];
      const apiFileName = getFileNameFromContentDisposition(contentDisposition) || tempFileName;
      finalPath = getFilePath(apiFileName);

      if (tempFilePath !== finalPath) {
        await RNBlobUtil.fs.mv(tempFilePath, finalPath);

        if (isAndroid) {
          await RNBlobUtil.android.addCompleteDownload({
            title: apiFileName,
            description: 'PDF file',
            mime: mimeType,
            path: finalPath,
            showNotification: true,
          });
        }
      }
      if (isIos) {
        const shareOptions: ShareOptions = {
          type: mimeType,
          url: finalPath,
          saveToFiles: true,
          failOnCancel: false,
          filename: apiFileName,
        };
        await Share.open(shareOptions);
      }
    } catch (error) {
      console.error('Error downloading PDF:', error);
      throw error;
    } finally {
      setIsPDFLoading(false);
      try {
        await RNBlobUtil.fs.unlink(finalPath);
      } catch (cleanupError) {
        console.error('Could not delete temp file:', cleanupError);
      }
    }
  }, []);

  return { downloadPDF, isPDFLoading };
};
发布评论

评论列表(0)

  1. 暂无评论