如何在 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 应用程序中(适用于 android 和 ios)。
我在网上搜索了有关如何在 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中从异步任务中检索到的数据中将图像加载到卡片中?
如何在 SpriteKit 中从 Web API 加载精灵表
在 Flutter Web 中从 JS 调用 Dart 方法