【Flutter】 PDFビューアー
1. はじめに
FlutterのPDFビューアのパッケージは色々あるが、結局どのパッケージが良いのか分からない方の記事です。
ざっと調べただけで5種類ほどあります。それ以外にwebview_flutterを使う方法もありそうです。
- advance_pdf_viewer
- syncfusion_flutter_pdfviewer
- flutter_full_pdf_viewer
- native_pdf_view
- flutter_pdfview
実際に使ってみると、Androidの特定の端末では、Warningが出たり、クラッシュしたり、様々な問題が発生しました。
flutter_pdfviewを採用
結論から言うと、今回は「Flutter_pdfview」を使いました。
私が想定していた、iOS14以上、Android6以上でも期待通りに動作しました。
今回は、ソースコード内にPDFを保持する場合のケースで実装方法をご説明します。
また、開発環境は、「2.10.0」です。
2. 準備作業
2.1. パッケージの準備
まずは、flutter_pdfviewパッケージを追加します。
ターミナルにて、下記のコマンドを実行します。
flutter pub add flutter_pdfview
実行後、pubspec.yamlに、該当のパッケージが追加されていることを確認します。
flutter_pdfview: ^1.2.1
合わせて、関連するパッケージも追加します。
サーバーからPDFファイルをダウンロードする場合は不要のため、スキップしてください。
ターミナルにて、下記のコマンドを実行します。
flutter pub add path_provider
flutter pub add path
実行後、pubspec.yamlに、該当のパッケージが追加されていることを確認します。
flutter_pdfview: ^1.2.1
path_provider: ^2.0.9
path: ^1.8.0
2.2. PDFファイルのパス指定
PDFファイルのパスをpubspec.yamlに設定します。
今回は、assets/docs/の配下に「sample.pdf」を配置します。
assets:
- assets/docs/
2.3. PDFファイルの設置
上記で指定したディレクトリを作成し、「sample.pdf」を配置します。
2.4. iOS用の設定
iPhoneで表示するために、info.plistに下記を追加します。
<key>io.flutter.embedded_views_preview</key>
<true/>
ここまで完了後、テーミナルにて、「pub get」してください。
3. PDFファイルの読み込み、保存
今回は、ソースコード内に配置したPDFをアプリケーション専用のディレクトリに保存します。
3.1. PDFファイルの保存
読み込んだファイルをアプリ内のディレクトリに保存するため、先に保存用のメソッドを作成します。
Future<File> _storeFile(String url, List<int> bytes) async {
final filename = basename(url);
final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/$filename');
await file.writeAsBytes(bytes, flush: true);
return file;
}
3.2. PDFファイルの読み込み
次に、PDFファイル読み込み用のメソッドを用意します。
Future<File?> _load(String url) async {
final data = await rootBundle.load(url);
final bytes = data.buffer.asUint8List();
return await _storeFile(url, bytes);
}
4. PDFビューアー画面の作成
4.1. 準備
PDFファイルのオブジェクト格納用の変数を用意します。
File? file;
4.2. PDFファイルの読み込み
今回は、StatefullウィジェットのinitStateにて、PDFファイルを読み込み、fileに保存します。
@override
void initState() {
_load('assets/docs/sample.pdf').then((value) {
setState(() {
file = value;
});
});
super.initState();
}
4.3. ビューアー画面の作成
PDFファイル読み込み中は、画面中央にCircularProgressIndicatorを表示します。
読み込み完了後に、PDFViewにファイルパスを指定し、PDFファイルを表示します。
今回は、その他のプロパティは割愛します。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('PDF Viewer'),
),
body: file == null
? const Center(
child: CircularProgressIndicator(),
)
: SizedBox(
height: MediaQuery.of(context).size.height,
child: PDFView(
filePath: file!.path,
),
),
);
}
5. まとめ
今回は、「Flutter_pdfview」の実装方法について、まとめました。
どのパッケージを使って良いか迷っている方は、こちらの記事を参考にしてみてください。
最後にソースコードの全体像を載せておきます。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_pdfview/flutter_pdfview.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File? file;
@override
void initState() {
_load('assets/docs/sample.pdf').then((value) {
setState(() {
file = value;
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('PDF Viewer'),
),
body: file == null
? const Center(
child: CircularProgressIndicator(),
)
: SizedBox(
height: MediaQuery.of(context).size.height,
child: PDFView(
filePath: file!.path,
),
),
);
}
Future<File> _storeFile(String url, List<int> bytes) async {
final filename = basename(url);
final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/$filename');
await file.writeAsBytes(bytes, flush: true);
return file;
}
Future<File?> _load(String url) async {
final data = await rootBundle.load(url);
final bytes = data.buffer.asUint8List();
return await _storeFile(url, bytes);
}
}
Discussion