View a PDF document in Flutter

This guide will help you to view a document using the Apryse Flutter SDK for Apryse Mobile SDK.

Widget or Plugin

There are 2 different ways to use Apryse Flutter API:

  • Present a document via a plugin.
  • Show an Apryse document view via a Widget.

You must choose either the widget or plugin, and use it for all APIs. Mixing widget and plugin APIs will not function correctly. Whether you choose the widget or plugin is personal preference.

If you pick the Android widget, you will need to add padding for operating system intrusions like the status bar at the top of the device. One way is to set the enabled system UI, and then wrap the widget in a SafeArea or use an AppBar:

Dart

1// If using Flutter v2.3.0-17.0.pre or earlier.
2SystemChrome.setEnabledSystemUIOverlays(
3 SystemUiOverlay.values
4);
5// If using later Flutter versions.
6SystemChrome.setEnabledSystemUIMode(
7 SystemUiMode.edgeToEdge,
8);
9
10// If using SafeArea:
11return SafeArea (
12 child: DocumentView(
13 onCreated: _onDocumentViewCreated,
14 ));
15
16// If using AppBar:
17return Scaffold(
18 appBar: AppBar( toolbarHeight: 0 ),
19 body: DocumentView(
20 onCreated: _onDocumentViewCreated,
21 ));

Preparation

If you want to use local files, add the following dependency to myapp/pubspec.yaml:

YAML

1permission_handler: ^8.1.1

Usage

Replace lib/main.dart with what is shown here:

Dart

1import 'dart:async';
2import 'dart:io' show Platform;
3
4import 'package:flutter/material.dart';
5import 'package:flutter/services.dart';
6import 'package:pdftron_flutter/pdftron_flutter.dart';
7// If you are using local files, add the permission_handler
8// dependency to pubspec.yaml and uncomment the line below.
9// import 'package:permission_handler/permission_handler.dart';
10
11void main() => runApp(MyApp());
12
13class MyApp extends StatelessWidget {
14 @override
15 Widget build(BuildContext context) {
16 return MaterialApp(
17 home: Viewer(),
18 );
19 }
20}
21
22class Viewer extends StatefulWidget {
23 @override
24 _ViewerState createState() => _ViewerState();
25}
26
27class _ViewerState extends State<Viewer> {
28 String _version = 'Unknown';
29 String _document =
30 "https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_mobile_about.pdf";
31 bool _showViewer = true;
32
33 @override
34 void initState() {
35 super.initState();
36 initPlatformState();
37
38 showViewer();
39
40 // If you are using local files:
41 // * Remove the above line `showViewer();`.
42 // * Change the _document field to your local filepath.
43 // * Uncomment the section below, including launchWithPermission().
44 // if (Platform.isIOS) {
45 // showViewer(); // Permission not required for iOS.
46 // } else {
47 // launchWithPermission(); // Permission required for Android.
48 // }
49 }
50
51 // Uncomment this if you are using local files:
52 // Future<void> launchWithPermission() async {
53 // PermissionStatus permission = await Permission.storage.request();
54 // if (permission.isGranted) {
55 // showViewer();
56 // }
57 // }
58
59 // Platform messages are asynchronous, so initialize in an async method.
60 Future<void> initPlatformState() async {
61 String version;
62 // Platform messages may fail, so use a try/catch PlatformException.
63 try {
64 // Initializes the Apryse SDK, it must be called before you can use
65 // any functionality.
66 PdftronFlutter.initialize("your_pdftron_license_key");
67
68 version = await PdftronFlutter.version;
69 } on PlatformException {
70 version = 'Failed to get platform version.';
71 }
72
73 // If the widget was removed from the tree while the asynchronous platform
74 // message was in flight, we want to discard the reply rather than calling
75 // setState to update our non-existent appearance.
76 if (!mounted) return;
77
78 setState(() {
79 _version = version;
80 });
81 }
82
83 void showViewer() async {
84 // Opening without a config file will have all functionality enabled.
85 // await PdftronFlutter.openDocument(_document);
86
87 var config = Config();
88 // How to disable functionality:
89 // config.disabledElements = [Buttons.shareButton, Buttons.searchButton];
90 // config.disabledTools = [Tools.annotationCreateLine, Tools.annotationCreateRectangle];
91 // Other viewer configurations:
92 // config.multiTabEnabled = true;
93 // config.customHeaders = {'headerName': 'headerValue'};
94
95 // An event listener for document loading.
96 var documentLoadedCancel = startDocumentLoadedListener((filePath) {
97 print("document loaded: $filePath");
98 });
99
100 await PdftronFlutter.openDocument(_document, config: config);
101
102 try {
103 // The imported command is in XFDF format and tells whether to add,
104 // modify or delete annotations in the current document.
105 PdftronFlutter.importAnnotationCommand(
106 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
107 " <xfdf xmlns=\"http://ns.adobe.com/xfdf/\" xml:space=\"preserve\">\n" +
108 " <add>\n" +
109 " <square style=\"solid\" width=\"5\" color=\"#E44234\" opacity=\"1\" creationdate=\"D:20200619203211Z\" flags=\"print\" date=\"D:20200619203211Z\" name=\"c684da06-12d2-4ccd-9361-0a1bf2e089e3\" page=\"1\" rect=\"113.312,277.056,235.43,350.173\" title=\"\" />\n" +
110 " </add>\n" +
111 " <modify />\n" +
112 " <delete />\n" +
113 " <pdf-info import-version=\"3\" version=\"2\" xmlns=\"http://www.pdftron.com/pdfinfo\" />\n" +
114 " </xfdf>");
115 } on PlatformException catch (e) {
116 print("Failed to importAnnotationCommand '${e.message}'.");
117 }
118
119 try {
120 PdftronFlutter.importBookmarkJson('{"0":"Page 1"}');
121 } on PlatformException catch (e) {
122 print("Failed to importBookmarkJson '${e.message}'.");
123 }
124
125 // An event listener for when local annotation changes are committed to the document.
126 // xfdfCommand is the XFDF Command of the annotation that was last changed.
127 var annotCancel = startExportAnnotationCommandListener((xfdfCommand) {
128 String command = xfdfCommand;
129 print("flutter xfdfCommand:\n");
130 // Dart limits how many characters are printed onto the console.
131 // The code below ensures that all of the XFDF command is printed.
132 if (command.length > 1024) {
133 int start = 0;
134 int end = 1023;
135 while (end < command.length) {
136 print(command.substring(start, end) + "\n");
137 start += 1024;
138 end += 1024;
139 }
140 print(command.substring(start));
141 } else {
142 print("flutter xfdfCommand:\n $command");
143 }
144 });
145
146 // An event listener for when local bookmark changes are committed to
147 // the document. bookmarkJson is the JSON string containing all the
148 // bookmarks that exist when the change was made.
149 var bookmarkCancel = startExportBookmarkListener((bookmarkJson) {
150 print("flutter bookmark: $bookmarkJson");
151 });
152
153 var path = await PdftronFlutter.saveDocument();
154 print("flutter save: $path");
155
156 // To cancel event:
157 // annotCancel();
158 // bookmarkCancel();
159 // documentLoadedCancel();
160 }
161
162 @override
163 Widget build(BuildContext context) {
164 return Scaffold(
165 body: Container(
166 width: double.infinity,
167 height: double.infinity,
168 child:
169 // Uncomment this to use Widget version of the viewer:
170 // _showViewer
171 // ? DocumentView(
172 // onCreated: _onDocumentViewCreated,
173 // ):
174 Container(),
175 ),
176 );
177 }
178
179 // This function is used to control the DocumentView widget after it
180 // has been created. The widget will not work without a void
181 // Function(DocumentViewController controller) being passed to it.
182 void _onDocumentViewCreated(DocumentViewController controller) async {
183 Config config = new Config();
184
185 var leadingNavCancel = startLeadingNavButtonPressedListener(() {
186 // Uncomment this to quit viewer when leading navigation button is pressed:
187 // this.setState(() {
188 // _showViewer = !_showViewer;
189 // });
190
191 // Show a dialog when leading navigation button is pressed.
192 _showMyDialog();
193 });
194
195 controller.openDocument(_document, config: config);
196 }
197
198 Future<void> _showMyDialog() async {
199 print('hello');
200 return showDialog<void>(
201 context: context,
202 barrierDismissible: false, // User must tap button!
203 builder: (BuildContext context) {
204 return AlertDialog(
205 title: Text('AlertDialog'),
206 content: SingleChildScrollView(
207 child: Text('Leading navigation button has been pressed.'),
208 ),
209 actions: <Widget>[
210 TextButton(
211 child: Text('OK'),
212 onPressed: () {
213 Navigator.of(context).pop();
214 },
215 ),
216 ],
217 );
218 },
219 );
220 }
221}

Run

  1. Launch your Android emulator
  2. Run the app with the command:

sh

1flutter run

You should see the application start up:

Apryse Docs Image

To call other Apryse APIs, please check out our API page.

You can view the source code for this project here.

How to Build a Flutter PDF Viewer - 1/12/2023

How to Add a PDF, Word, Excel, and PowerPoint Viewer to a Flutter App - 2/8/2019

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales