在 React Native 中下载并打开 PDF 文件

问题描述 投票:0回答:1

我尝试在单击按钮时从我的应用程序下载 PDF 文件,并在下载完成后立即打开它。我使用 expo-file-system 来保存下载的文件,并使用 expo-linking 在为 iOS 设备下载文件后触发文件的打开。我还使用 expo-intent-launcher 来触发 Android 设备上的文件打开。这对于 Android 来说非常有效,但在 iOS 上却不起作用,我已经研究了几个小时了。我不确定我做错了什么。我的代码片段如下所示:

import * as FileSystem from "expo-file-system";
import * as Linking from "expo-linking";
import * as IntentLauncher from "expo-intent-launcher";
import { Button } from "react-native"

export default function PdfDocumentsScreen() {
   const { isAndroid } = useDevicePlatform();

   const downloadPDF = async () => {
    try {
      const uri =
        "https://${name}.s3.amazonaws.com/${bucket_name}/Certificate1.pdf";

      const fileUri = FileSystem.documentDirectory + "Certificate.pdf";

      const downloadObject = FileSystem.createDownloadResumable(uri, fileUri);

      const response = await downloadObject.downloadAsync();
      console.log(response);

      if (response?.status === 200) {
        openPDF(fileUri);
      } else {
        console.error("Failed to download the PDF");
      }
    } catch (error) {
      console.error("Error downloading the PDF: ", error);
    }
  };

 const openPDF = async (fileUri: string) => {
    try {
      const contentUri = await FileSystem.getContentUriAsync(fileUri);
      console.log("Content URI: ", contentUri);

      if (!isAndroid) {
        if (await Linking.canOpenURL(contentUri)) {
          Linking.openURL(contentUri);
        }
      } else {
        IntentLauncher.startActivityAsync("android.intent.action.VIEW", {
          data: contentUri,
          flags: 1,
        });
      }
    } catch (error) {
      console.error("Error opening the PDF: ", error);
    }
  };

  return (
    <Button title="Download PDF" onPress={downloadPDF} />
  )
}
javascript android ios react-native expo
1个回答
0
投票

更新!!

我早就解决了这个问题,但我认为发布我如何解决这个问题会很棒,因为这个问题没有得到有用的答案。

这适用于 Android 而不是 iOS 的原因是因为 expo-file-system

FileSystem.getContentUriAsync()
仅适用于 Android,如文档中所述:https://docs.expo.dev/versions/latest/sdk /文件系统/#filesystemgetcontenturiasyncfileuri

为了解决这个问题,我决定在 iOS 上使用 expo-sharing 来触发 PDF 的打开,在 Android 上使用 expo-intent-launcher 来触发打开。

更新后的代码如下所示:

  const callback = (
    downloadProgress: {
      totalBytesExpectedToWrite: number;
      totalBytesWritten: number;
    },
    id: string
  ) => {
    const progress =
      downloadProgress.totalBytesWritten /
      downloadProgress.totalBytesExpectedToWrite;

    setDownloadProgress({
      progress,
      id: item._id!,
    });
  };

const downloadPDF = async () => {
    try {
      const uri = item.url;
      const fileUri = FileSystem.documentDirectory + `${fileName}.${extension}`;

      const downloadObject = FileSystem.createDownloadResumable(
        uri,
        fileUri,
        {},
        (downloadOption) => {
          callback(downloadOption, id);
        }
      );

      const response = await downloadObject.downloadAsync();

      if (response?.status === 200) {
        await openPDF(response.uri, response.mimeType);
      } else {
        setDownloadProgress({ progress: 0, id: "" });
        setDownloadError("Failed to download the PDF");
      }
    } catch (error) {
      console.error("Error downloading the PDF: ", error);
      if (error instanceof Error) {
        setDownloadError(error.message);
      } else {
        setDownloadError(`Error: ${JSON.stringify(error)}`);
      }
      setDownloadProgress({ progress: 0, id: "" });
    }
  };

  const openPDF = async (fileUri: string, mimeType: string | null) => {
    try {
      const contentUri = await FileSystem.getContentUriAsync(fileUri);

      if (!isAndroid) {
        Sharing.shareAsync(contentUri, { UTI: mimeType! });
      } else {
        IntentLauncher.startActivityAsync("android.intent.action.VIEW", {
          data: contentUri,
          flags: 1,
        });
      }
    } catch (error) {
      if (error instanceof Error) {
        setDownloadError(error.message);
      } else {
        setDownloadError(`Error: ${JSON.stringify(error)}`);
      }
    }
  };

© www.soinside.com 2019 - 2024. All rights reserved.