You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo Media Library中createAssetAsync创建资源失败,PDF保存求助

解决expo-media-library createAssetAsync创建PDF资源失败的问题

问题场景

使用pdf-lib将图片转换为PDF,通过expo-file-system保存后,调用movePdfToDownloads函数尝试将PDF移动到设备下载文件夹时,抛出错误:Error moving the File to download folder : Could not create asset.

需要修改的关键部分

1. 补充Media Library权限申请

createAssetAsync依赖媒体库读写权限,必须先检查并申请权限,否则会直接执行失败。需在movePdfToDownloads开头添加权限校验逻辑。

2. 修正文件路径错误

原代码用FileSystem.documentDirectory + "Download/"指向App内部私有目录,Media Library无法识别该路径下的文件。需改为设备公共下载目录:

  • Android:直接使用FileSystem.downloadDirectory
  • iOS:无需手动指定私有目录,通过Media Library直接管理资产即可

3. 修复未定义的photoType变量

generatePdf函数中photoType变量未定义,导致图片嵌入逻辑异常,需从图片URI提取文件类型或传入该参数。

4. 修正Media Library拼写错误

代码中import * as MediaLibraray from "expo-media-library";存在拼写错误(少字母y),需改为MediaLibrary,否则所有Media Library的API调用都会失效。

修改后的完整代码

import * as FileSystem from "expo-file-system";
import * as MediaLibrary from "expo-media-library"; // 修正拼写错误
import { PDFDocument } from "pdf-lib";
import { Buffer } from "buffer";
import { Platform } from "react-native"; // 新增平台判断依赖

export const generatePdf = async (imageUri, dimensions) => {
  global.Buffer = Buffer;
  try {
    // 从图片URI提取文件类型(解决photoType未定义问题)
    const photoType = imageUri.split('.').pop().toLowerCase();
    
    const pdfDoc = await PDFDocument.create();

    const imageBytes = await FileSystem.readAsStringAsync(imageUri, {
      encoding: FileSystem.EncodingType.Base64,
    });

    // 根据实际文件类型嵌入图片(修正条件判断逻辑)
    const embeddedImage =
      photoType === "jpg" || photoType === "jpeg"
        ? await pdfDoc.embedJpg(imageBytes)
        : await pdfDoc.embedPng(imageBytes);

    const page = pdfDoc.addPage([dimensions.width, dimensions.height]);

    const scaleFactor = Math.min(
      dimensions.width / embeddedImage.width,
      dimensions.height / embeddedImage.height
    );

    const { width, height } = embeddedImage.scale(scaleFactor);
    page.drawImage(embeddedImage, {
      x: (page.getWidth() - width) / 2,
      y: (page.getHeight() - height) / 2,
      width,
      height,
    });

    const pdfBytes = await pdfDoc.save();
    const pdfBase64 = Buffer.from(pdfBytes).toString("base64");

    const fileUri = `${FileSystem.documentDirectory}generated_image.pdf`;
    await FileSystem.writeAsStringAsync(fileUri, pdfBase64, {
      encoding: FileSystem.EncodingType.Base64,
    });
    
    return fileUri;
  } catch (error) {
    console.error("Error generating the PDF : ", error.message);
    throw new Error("Failed to generate PDF !");
  }
};

export const movePdfToDownloads = async (pdfPath) => {
  try {
    // 检查并申请Media Library权限
    const { status } = await MediaLibrary.requestPermissionsAsync();
    if (status !== 'granted') {
      throw new Error("需要媒体库读写权限才能保存PDF");
    }

    const fileInfo = await FileSystem.getInfoAsync(pdfPath);
    if (!fileInfo.exists) {
      throw new Error(`指定文件不存在: ${pdfPath}`);
    }

    // 根据平台处理文件路径
    let downloadPath;
    if (Platform.OS === 'android') {
      // Android使用公共下载目录
      downloadPath = `${FileSystem.downloadDirectory}generated.pdf`;
      await FileSystem.copyAsync({ from: pdfPath, to: downloadPath });
    } else {
      // iOS直接使用App内生成的文件路径创建资产
      downloadPath = pdfPath;
    }

    // 创建媒体资产
    const asset = await MediaLibrary.createAssetAsync(downloadPath);
    
    // 获取或创建Download相册
    let album = await MediaLibrary.getAlbumAsync("Download");
    if (!album) {
      album = await MediaLibrary.createAlbumAsync("Download", asset);
    } else {
      await MediaLibrary.addAssetsToAlbumAsync([asset], album, false);
    }

    console.log(`PDF已成功保存到下载文件夹: ${downloadPath}`);
    return downloadPath;
  } catch (error) {
    console.error("Error moving the File to download folder :", error.message);
    throw new Error(`Failed to move the PDF to downloads : ${error.message}`);
  }
};

额外说明

  • iOS中,Media Library的Download相册是系统默认相册,无需手动创建路径,直接使用App内部生成的文件路径即可创建资产。
  • Android中,FileSystem.downloadDirectory指向设备公共下载目录,该目录下的文件会直接显示在系统文件管理器的下载文件夹中。

内容的提问来源于stack exchange,提问作者HETH CHHEDA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:55:56