接口返回二进制下载的url,RN项目中如何下载保存到本地

 // 请求存储权限
  const requestStoragePermission = async () => {
    if (Platform.OS === 'android') {
      try {
        if (Platform.Version >= 33) {
          // Android 13+ 下载PDF不需要请求任何权限!
          // 只需检查是否可访问下载目录
          const dir = ReactNativeBlobUtil.fs.dirs.DownloadDir;
          const testFile = `${dir}/permission_test_${Date.now()}.tmp`;
          try {
            await ReactNativeBlobUtil.fs.writeFile(testFile, 'test', 'utf8');
            await ReactNativeBlobUtil.fs.unlink(testFile);
            return true;
          } catch {
            Alert.alert(
              '存储访问失败',
              '无法访问下载目录,请检查系统文件权限设置',
              [{text: '去设置', onPress: () => Linking.openSettings()}],
            );
            return false;
          }
        } else {
          const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE,
            {
              title: '存储权限请求',
              message: '应用需要访问存储空间以下载文件',
              buttonPositive: '确定',
              buttonNegative: '取消',
            },
          );
          return granted === PermissionsAndroid.RESULTS.GRANTED;
        }
      } catch (err) {
        console.warn('请求存储权限时出错:', err);
        return false;
      }
    }
    return true; // iOS不需要显式权限
  };
  // 下载PDF文件
  const downloadFile = async (pdfUrl: string, data: any) => {
    try {
      setIsDownloading(true);
      setProgress(0);
      // 1. 检查并请求权限
      const hasPermission = await requestStoragePermission();
      if (!hasPermission) {
        Alert.alert('权限被拒绝', '需要存储权限才能下载文件');
        return;
      }
      // 2. 获取文件名
      let fileName = 'document.pdf';
      if (data?.name) {
        fileName = data?.name;
        if (!fileName.toLowerCase().endsWith('.pdf')) {
          fileName += '.pdf';
        }
      } else {
        try {
          // 尝试从URL获取文件名
          const urlParts = pdfUrl.split('/');
          const lastPart = urlParts[urlParts.length - 1];
          if (lastPart.includes('.pdf')) {
            fileName = decodeURIComponent(lastPart.split('?')[0]);
          }
        } catch (e) {
          console.warn('无法从URL获取文件名,使用默认文件名');
        }
      }

      // 3. 设置保存路径
      let filePath = '';
      if (Platform.OS === 'android') {
        // Android: 保存到Downloads目录
        filePath = `${ReactNativeBlobUtil.fs.dirs.DownloadDir}/${fileName}`;
      } else {
        // iOS: 保存到Documents目录
        filePath = `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/${fileName}`;
      }

      // 4. 下载配置
      const config = {
        fileCache: true,
        path: filePath,
        appendExt: 'pdf',
        addAndroidDownloads: {
          useDownloadManager: false, // 使用Android下载管理器
          notification: true, // 显示通知
          title: fileName,
          description: 'PDF文件下载中...',
          mime: 'application/pdf',
          mediaScannable: true, // 允许媒体扫描
          path: filePath, // 明确指定路径
          visibleInDownloadsUi: true,
        },
        overwrite: true, // 覆盖已存在文件
      };

      // 5. 执行下载
      const task = ReactNativeBlobUtil.config(config)
        .fetch('GET', pdfUrl)
        .progress((received, total) => {
          const percent = (received / total) * 100;
          setProgress(percent);
          console.log(`下载进度: ${percent.toFixed(1)}%`);
        });

      const response = await task;
      // 6. 验证下载结果
      // 1.1. 检查HTTP状态码
      if (response.info().status < 200 || response.info().status >= 300) {
        throw new Error(`服务器返回错误状态码: ${response.info().status}`);
      }
      // 2.1. 检查文件是否实际存在
      const fileExists = await ReactNativeBlobUtil.fs.exists(response.path());
      if (!fileExists) {
        throw new Error('文件下载后未找到');
      }

      // 3.1. 检查文件大小是否合理
      const fileInfo = await ReactNativeBlobUtil.fs.stat(response.path());
      console.log('文件状态:', fileInfo);
      if (fileInfo.size === 0) {
        throw new Error('文件大小为0,可能下载失败');
      }
      if (response.info().status === 200) {
        // Android需要将文件添加到媒体库
        if (Platform.OS === 'android') {
          try {
            await ReactNativeBlobUtil.MediaCollection.copyToMediaStore(
              {
                name: fileName,
                parentFolder: '', // 空字符串表示根目录
                mimeType: 'application/pdf',
              },
              'Download', // 文件类型为Download
              filePath,
            );
          } catch (e) {
            console.warn('添加到媒体库失败:', e);
          }
        }
        //  Alert.alert('下载成功', `PDF文件已保存到: ${filePath}`);
        showCustomToast({
          topOffset: -80,
          textStyle: {marginLeft: 4},
          message: '合同下载成功',
          imageSource: Common.MessageSucIcon,
        });
        console.log('文件路径:', filePath);
      } else {
        throw new Error(`服务器返回状态码: ${response.info().status}`);
      }
    } catch (error: any) {
      console.error('下载失败:', error);
      let errorMsg = error.message;

      // 提供更友好的错误提示
      if (error.message.includes('403')) {
        errorMsg = '没有下载权限(403)';
      } else if (error.message.includes('404')) {
        errorMsg = '文件不存在(404)';
      } else if (error.message.includes('ENOENT')) {
        errorMsg = '文件路径无效';
      } else if (error.message.includes('EACCES')) {
        errorMsg = '没有写入权限';
      }

      Alert.alert('下载失败', errorMsg);
    } finally {
      setIsDownloading(false);
    }
  };
  // 打开文件
  const openPDF = async (filePath: any) => {
    try {
      if (Platform.OS === 'android') {
        // Android使用文件查看器打开
        await ReactNativeBlobUtil.android.actionViewIntent(
          filePath,
          'application/pdf',
        );
      } else {
        // iOS使用Document Viewer打开
        await ReactNativeBlobUtil.ios.openDocument(filePath);
      }
    } catch (error) {
      console.error('打开文件失败:', error);
      Alert.alert('错误', '没有找到可以打开PDF的应用');
    }
  };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值