如何在 Flutter 中从 Web 加载和呈现 PDF 文件

Posted

技术标签:

【中文标题】如何在 Flutter 中从 Web 加载和呈现 PDF 文件【英文标题】:How to load and present a PDF file from the web in Flutter 【发布时间】:2020-10-10 01:15:59 【问题描述】:

我正在尝试从 URL 获取 PDF 文件,并将其呈现在我的 Flutter 应用程序中(适用于 androidios)。

我在网上搜索了有关如何在 Flutter 中呈现提取的 PDF 文件的答案,但我只能找到如何呈现本地预添加的 PDF 文件。

我也搜索过执行相同操作的软件包,但找不到有效的软件包。

示例

例如,我正在尝试获取this PDF 文件,并将其呈现在我的应用程序的 Flutter 小部件屏幕中。

有谁知道我怎样才能做到这一点?

谢谢!

【问题讨论】:

【参考方案1】:

使用flutter_pdfview包。

    在 android 清单中添加权限
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    在 pubspec.yaml 中添加依赖项
dependencies:
  flutter:
    sdk: flutter
  flutter_pdfview: ^1.0.1
  http: ^0.12.0+4
  path_provider: any
  permission_handler: 4.4.0 //For asking permission to load the pdf
    然后使用 PDFView

完整代码:

import 'package:flutter/material.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  String urlPDFPath = "";
  bool exists = true;
  int _totalPages = 0;
  int _currentPage = 0;
  bool pdfReady = false;
  PDFViewController _pdfViewController;
  bool loaded = false;

  Future<File> getFileFromUrl(String url, name) async 
    var fileName = 'testonline';
    if (name != null) 
      fileName = name;
    
    try 
      var data = await http.get(url);
      var bytes = data.bodyBytes;
      var dir = await getApplicationDocumentsDirectory();
      File file = File("$dir.path/" + fileName + ".pdf");
      print(dir.path);
      File urlFile = await file.writeAsBytes(bytes);
      return urlFile;
     catch (e) 
      throw Exception("Error opening url file");
    
  

  void requestPersmission() async 
    await PermissionHandler().requestPermissions([PermissionGroup.storage]);
  

  @override
  void initState() 
    requestPersmission();
    getFileFromUrl("http://www.africau.edu/images/default/sample.pdf").then(
      (value) => 
        setState(() 
          if (value != null) 
            urlPDFPath = value.path;
            loaded = true;
            exists = true;
           else 
            exists = false;
          
        )
      ,
    );
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    print(urlPDFPath);
    if (loaded) 
      return Scaffold(
        body: PDFView(
          filePath: urlPDFPath,
          autoSpacing: true,
          enableSwipe: true,
          pageSnap: true,
          swipeHorizontal: true,
          nightMode: false,
          onError: (e) 
            //Show some error message or UI
          ,
          onRender: (_pages) 
            setState(() 
              _totalPages = _pages;
              pdfReady = true;
            );
          ,
          onViewCreated: (PDFViewController vc) 
            setState(() 
              _pdfViewController = vc;
            );
          ,
          onPageChanged: (int page, int total) 
            setState(() 
              _currentPage = page;
            );
          ,
          onPageError: (page, e) ,
        ),
        floatingActionButton: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            IconButton(
              icon: Icon(Icons.chevron_left),
              iconSize: 50,
              color: Colors.black,
              onPressed: () 
                setState(() 
                  if (_currentPage > 0) 
                    _currentPage--;
                    _pdfViewController.setPage(_currentPage);
                  
                );
              ,
            ),
            Text(
              "$_currentPage + 1/$_totalPages",
              style: TextStyle(color: Colors.black, fontSize: 20),
            ),
            IconButton(
              icon: Icon(Icons.chevron_right),
              iconSize: 50,
              color: Colors.black,
              onPressed: () 
                setState(() 
                  if (_currentPage < _totalPages - 1) 
                    _currentPage++;
                    _pdfViewController.setPage(_currentPage);
                  
                );
              ,
            ),
          ],
        ),
      );
     else 
      if (exists) 
        //Replace with your loading UI
        return Scaffold(
          appBar: AppBar(
            title: Text("Demo"),
          ),
          body: Text(
            "Loading..",
            style: TextStyle(fontSize: 20),
          ),
        );
       else 
        //Replace Error UI
        return Scaffold(
          appBar: AppBar(
            title: Text("Demo"),
          ),
          body: Text(
            "PDF Not Available",
            style: TextStyle(fontSize: 20),
          ),
        );
      
    
  

【讨论】:

谢谢。我试过你的答案,但我得到这个错误:“名称'文件'不是类型,所以它不能用作类型参数。'尝试将名称更正为现有类型,或定义类型命名为“文件”。” 你必须先导入一些东西才能这样做,我更新了我的答案。对于文件,您需要导入“dart:io”。 谢谢。我尝试运行它,但不幸的是它不起作用,当我尝试呈现 PDF 文件时,我会出现以下错误:“[onError, error: cannot create document: File not in PDF format or损坏。 ]" "无法创建文档:文件不是 PDF 格式或已损坏。" “试图嵌入平台视图,但 PrerollContext 不支持嵌入” “试图嵌入平台视图,但 PaintContext 不支持嵌入” 请注意我试图以 PDF 格式呈现的 URL PDF(请参阅中的链接上面的问题)。谢谢!! 我已经解决了您的问题并更新了答案。问题是 pdfView 试图加载一个空字符串。 谢谢。似乎加载了文件(例如,我可以看到正确的页数),但它只是呈现一个空白文件(白色屏幕,底部有页面箭头)【参考方案2】:

你可以使用flutter_cached_pdfview

它是flutter_pdfview的超级 获得很多方法来帮助你更快地使用 pdf 这是一个从 URL 查看 pdf 并缓存它的示例

      PDF().cachedFromUrl('http://africau.edu/images/default/sample.pdf'),

它具有flutter_pdfview的所有功能

看看https://pub.dev/packages/flutter_cached_pdfview

【讨论】:

这个包不再是空安全,因此不认为它适合使用 @ZXERSTON pub.dev/packages/flutter_cached_pdfview/versions/…

以上是关于如何在 Flutter 中从 Web 加载和呈现 PDF 文件的主要内容,如果未能解决你的问题,请参考以下文章

如何从flutter中从异步任务中检索到的数据中将图像加载到卡片中?

在 Flutter/Dart 中从字节加载图像的问题

如何在 SpriteKit 中从 Web API 加载精灵表

在 Flutter Web 中从 JS 调用 Dart 方法

在 Flutter App 中从 Firebase 存储加载 PDF 文件

如何在 NOT UIViewController 中从 Web 服务加载数据?