- No license key is requird for trial. However, a valid commercial license key is required after trial.
- PDFTron SDK >= 6.9.0
- Flutter >= 1.0.0
Android | iOS |
---|---|
![]() |
![]() |
Version 0.0.6
is the last stable release for the legacy UI.
The release can be found here: https://github.com/PDFTron/pdftron-flutter/releases/tag/legacy-ui.
The complete installation and API guides can be found at https://www.pdftron.com/documentation/android/flutter
-
First follow the Flutter getting started guides to install, set up an editor, and create a Flutter Project. The rest of this guide assumes your project is created by running
flutter create myapp
. -
Add the following dependency to your Flutter project in
myapp/pubspec.yaml
:dependencies: flutter: sdk: flutter + pdftron_flutter: + git: + url: git://github.com/PDFTron/pdftron-flutter.git + permission_handler: '3.0.1'
-
Now add the following items in your
myapp/android/app/build.gradle
file:android { compileSdkVersion 29 lintOptions { disable 'InvalidPackage' } defaultConfig { applicationId "com.example.myapp" - minSdkVersion 16 + minSdkVersion 21 targetSdkVersion 29 + multiDexEnabled true + manifestPlaceholders = [pdftronLicenseKey:PDFTRON_LICENSE_KEY] versionCode flutterVersionCode.toInteger() versionName flutterVersionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } ... }
-
In your
myapp/android/gradle.properties
file. Add the following line to it:# Add the PDFTRON_LICENSE_KEY variable here. # For trial purposes leave it blank. # For production add a valid commercial license key. PDFTRON_LICENSE_KEY=
-
In your
myapp\android\app\src\main\AndroidManifest.xml
file, add the following lines to the<application>
tag:... <application android:name="io.flutter.app.FlutterApplication" android:label="myapp" android:icon="@mipmap/ic_launcher" + android:largeHeap="true" + android:usesCleartextTraffic="true"> <!-- Add license key in meta-data tag here. This should be inside the application tag. --> + <meta-data + android:name="pdftron_license_key" + android:value="${pdftronLicenseKey}"/> ...
Additionally, add the required permissions for your app in the
<manifest>
tag:... + <uses-permission android:name="android.permission.INTERNET" /> <!-- Required to read and write documents from device storage --> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- Required if you want to record audio annotations --> + <uses-permission android:name="android.permission.RECORD_AUDIO" /> ...
5a. (Optional, required if using DocumentView
widget) In your MainActivity
file (either kotlin or java), change the parent class to FlutterFragmentActivity
:
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity : FlutterFragmentActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}
- Replace
lib/main.dart
with what is shown here - Check that your Android device is running by running the command
flutter devices
. If none are available, follow the device set up instructions in the Install guides for your platform. - Run the app with the command
flutter run
.
-
First, follow the official getting started guide on installation, setting up an editor, and create a Flutter project, the following steps will assume your app is created through
flutter create myapp
-
Open
myapp
folder in a text editor. Then openmyapp/pubspec.yaml
file, add:dependencies: flutter: sdk: flutter + pdftron_flutter: + git: + url: git://github.com/PDFTron/pdftron-flutter.git + permission_handler: '3.0.1'
-
Run
flutter packages get
-
Open
myapp/ios/Podfile
, add:# Uncomment this line to define a global platform for your project -# platform :ios, '9.0' +platform :ios, '10.0' ... target 'Runner' do ... + # PDFTron Pods + use_frameworks! + pod 'PDFNet', podspec: 'https://www.pdftron.com/downloads/ios/cocoapods/pdfnet/latest.podspec' end
-
Run
flutter build ios --no-codesign
to ensure integration process is sucessful -
Replace
lib/main.dart
with what is shown here -
Run
flutter emulators --launch apple_ios_simulator
-
Run
flutter run
Open lib/main.dart
, replace the entire file with the following:
import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pdftron_flutter/pdftron_flutter.dart';
import 'package:permission_handler/permission_handler.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _version = 'Unknown';
String _document = "https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_mobile_about.pdf";
@override
void initState() {
super.initState();
initPlatformState();
if (Platform.isIOS) {
// Open the document for iOS, no need for permission
showViewer();
} else {
// Request for permissions for android before opening document
launchWithPermission();
}
}
Future<void> launchWithPermission() async {
Map<PermissionGroup, PermissionStatus> permissions = await PermissionHandler().requestPermissions([PermissionGroup.storage]);
if (granted(permissions[PermissionGroup.storage])) {
showViewer();
}
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String version;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
PdftronFlutter.initialize("Insert commercial license key here after purchase");
version = await PdftronFlutter.version;
} on PlatformException {
version = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
_version = version;
});
}
void showViewer() {
// Shows how to disable functionality. Uncomment to configure your viewer with a Config object.
// var disabledElements = [Buttons.shareButton, Buttons.searchButton];
// var disabledTools = [Tools.annotationCreateLine, Tools.annotationCreateRectangle];
// var config = Config();
// config.disabledElements = disabledElements;
// config.disabledTools = disabledTools;
// config.customHeaders = {'headerName': 'headerValue'};
// PdftronFlutter.openDocument(_document, config: config);
// Open document without a config file which will have all functionality enabled.
PdftronFlutter.openDocument(_document);
}
bool granted(PermissionStatus status) {
return status == PermissionStatus.granted;
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('PDFTron flutter app'),
),
body: Center(
child: Text('Running on: $_version\n'),
),
),
);
}
}
For APIs that states "PdftronFlutter only", these would only be callable in a plugin fashion. Below is an example for initialize;
PdftronFlutter.initialize('your_license_key');
But for those that are not specified, these would be callable in both plugin and widget versions. For example, openDocument is accessible in 2 ways:
Plugin:
void showViewer() async {
PdftronFlutter.openDocument('https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_about.pdf');
}
Widget (DocumentViewController):
void _onDocumentViewCreated(DocumentViewController controller) {
controller.openDocument('https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_about.pdf');
}
We suggest that you stick with either version for the APIs that are callable in both versions, to avoid unnecessary problems.
There are several custom classes used in these APIs: Annot
, AnnotWithRect
, Field
, Rect
, AnnotFlag
,AnnotWithFlag
and CustomToolbar
. These classes together with constants that are used in the examples below are all listed here.
Obtains PDFTron SDK version. PdftronFlutter only.
String version = PdftronFlutter.version;
print('Current PDFTron SDK version is: ' + version);
Obtains the current platform version. PdftronFlutter only.
String platformVersion = PdftronFlutter.platformVersion;
print('App is currently running on: ' + platformVersion);
Initializes PDFTron SDK with your PDFTron commercial license key. You can run PDFTron in demo mode by passing an empty string. PdftronFlutter only.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
key | String | true | your PDFTron license key |
Returns a Future.
PdftronFlutter.initialize('your_licensey_key');
Opens a document in the viewer with options to remove buttons and disable tools.
Parameters:
Name | Type | Required | Description |
---|---|---|---|
document | String | true | path to the document |
password | String | false | password to an encrypted document |
config | Config | false | viewer configuration options |
Returns a Future that would resolve when document is loaded.
For configs (more info could be found here):
array of Buttons constants, defaults to none.
Defines buttons to be disabled for the viewer.
var disabledElements = [Buttons.shareButton, Buttons.searchButton];
config.disabledElements = disabledElements;
array of Tools constants, defaults to none.
Defines tools to be disabled for the viewer.
var disabledTools = [Tools.annotationCreateLine, Tools.annotationCreateRectangle];
config.disabledTools = disabledTools;
bool, defaults to false.
Defines whether viewer will use tabs in order to have more than one document open simultaneously (like a web browser). Calling openDocument with this value being true will cause a new tab to be opened with the associated document.
config.multiTabEnabled = true;
map<string, string>, defaults to empty.
Defines custom headers to use with HTTP/HTTPS requests.
config.customHeaders = {'headerName': 'headerValue'};
array of CustomToolbar
objects or DefaultToolbars
constants.
Defines custom toolbars. If passed in, the set of default toolbars will no longer appear. It is possible to mix and match with default toolbars. See example below:
// Viewer will use a custom defined toolbar and a default annotate toolbar in this case
var customToolbar = new CustomToolbar('myToolbar', 'myToolbar', [Tools.annotationCreateArrow, Tools.annotationCreateCallout], ToolbarIcons.favorite);
var annotationToolbars = [DefaultToolbars.annotate, customToolbar];
array of DefaultToolbars
constants, defaults to none.
Defines which default annotation toolbars should be hidden. Note that this should be used when annotationToolbars is not defined.
// Viewer will use all the default toolbars except annotate or draw in this case
var hideDefaultAnnotationToolbars = [DefaultToolbars.annotate, DefaultToolbars.draw];
config.hideDefaultAnnotationToolbars = hideDefaultAnnotationToolbars;
bool, defaults to false.
Defines whether to show the toolbar switcher in the top toolbar.
config.hideAnnotationToolbarSwitcher = true;
bool, defaults to false.
Defines whether to hide both the top app nav bar and the annotation toolbar.
config.hideTopToolbars = true;
bool, defaults to false.
Defines whether to hide the top navigation app bar.
config.hideTopAppNavBar = true;
bool, defaults to true.
Defines whether to show the leading navigation button.
config.showLeadingNavButton = true;
bool, defaults to false.
Defines whether the viewer is read-only. If true, the UI will not allow the user to change the document.
config.readOnly = true;
bool, defaults to true.
Defines whether user can modify the document using the thumbnail view (eg add/remove/rotate pages).
config.thumbnailViewEditingEnabled = false;
String.
Defines the author name for all annotations created on the current document. Exported xfdfCommand will include this piece of information.
config.annotationAuthor = 'PDFTron';
bool, defaults to true.
If true, the active annotation creation tool will remain in the current annotation creation tool. Otherwise, it will revert to the "pan tool" after an annotation is created.
config.continuousAnnotationEditing = true;
String, default is the file name.
Sets the tab title if multiTabEnabled is true. (For Android, tabTitle is only supported on the widget viewer)
config.tabTitle = 'tab1';
Example:
var disabledElements = [Buttons.shareButton, Buttons.searchButton];
var disabledTools = [Tools.annotationCreateLine, Tools.annotationCreateRectangle];
var hideDefaultAnnotationToolbars = [DefaultToolbars.annotate, DefaultToolbars.draw];
var config = Config();
config.disabledElements = disabledElements;
config.disabledTools = disabledTools;
config.multiTabEnabled = false;
config.customHeaders = {'headerName': 'headerValue'};
config.hideDefaultAnnotationToolbars = hideDefaultAnnotationToolbars;
config.hideAnnotationToolbarSwitcher = true;
config.continuousAnnotationEditing = true;
var password = 'pdf_password';
await PdftronFlutter.openDocument(_document, password: password, config: config);
Imports XFDF annotation string to current document.
Parameters:
Name | Type | Description |
---|---|---|
xfdf | String | annotation string in XFDF format for import |
Returns a Future.
var xfdf = '<?xml version="1.0" encoding="UTF-8"?>\n<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">\n\t<annots>\n\t\t<circle style="solid" width="5" color="#E44234" opacity="1" creationdate="D:20190729202215Z" flags="print" date="D:20190729202215Z" page="0" rect="138.824,653.226,236.28,725.159" title="" /></annots>\n\t<pages>\n\t\t<defmtx matrix="1.333333,0.000000,0.000000,-1.333333,0.000000,1056.000000" />\n\t</pages>\n\t<pdf-info version="2" xmlns="http://www.pdftron.com/pdfinfo" />\n</xfdf>';
PdftronFlutter.importAnnotations(xfdf);
Extracts XFDF from the current document. If annotationList
is null, export all annotations from the document; Else export the valid ones specified.
Parameters:
Name | Type | Description |
---|---|---|
annotationList | List<Annot > |
If not null, export the XFDF string for the valid annotations; Otherwise, export the XFDF string for all annotations in the current document. |
Returns a Future.
Future Parameters:
Name | Type | Description |
---|---|---|
xfdf | String | annotation string in XFDF format |
Exports all annotations:
var xfdf = await PdftronFlutter.exportAnnotations(null);
Exports specified annotations:
List<Annot> annotList = new List<Annot>();
list.add(new Annot('Hello', 1));
list.add(new Annot('World', 2));
var xfdf = await PdftronFlutter.exportAnnotations(annotList);
Flattens the forms and (optionally) annotations in the current document.
Parameters:
Name | Type | Description |
---|---|---|
formsOnly | bool | Defines whether only forms are flattened. If false, all annotations will be flattened. |
Returns a Future.
PdftronFlutter.flattenAnnotations(true);
Deletes the specified annotations in the current document.
Parameters:
Name | Type | Description |
---|---|---|
annotations | List<Annot > |
the annotations to be deleted |
Returns a Future.
List<Annot> annotList = new List<Annot>();
list.add(new Annot('Hello', 1));
list.add(new Annot('World', 2));
PdftronFlutter.deleteAnnotations(annotList);
Selects the specified annotation in the current document.
Parameters:
Name | Type | Description |
---|---|---|
annotation | Annot |
the annotation to be selected |
Returns a Future.
PdftronFlutter.selectAnnotation(new Annot('Hello', 1));
Sets flags for specified annotations in the current document.
Parameters:
Name | Type | Description |
---|---|---|
annotationWithFlagsList | List<AnnotWithFlags > |
a list of annotations with respective flags to be set |
Returns a Future.
List<AnnotWithFlags> annotsWithFlags = new List<AnnotWithFlags>();
Annot hello = new Annot('Hello', 1);
Annot world = new Annot('World', 3);
AnnotFlag printOn = new AnnotFlag(AnnotationFlags.print, true);
AnnotFlag unlock = new AnnotFlag(AnnotationFlags.locked, false);
// you can add an AnnotWithFlags object flexibly like this:
list.add(new AnnotWithFlags.fromAnnotAndFlags(hello, [printOn, unlock]));
list.add(new AnnotWithFlags.fromAnnotAndFlags(world, [unlock]));
// Or simply use the constructor like this:
list.add(new AnnotWithFlags('Pdftron', 10, AnnotationFlags.no_zoom, true));
PdftronFlutter.setFlagsForAnnotations(annotsWithFlags);
Imports remote annotation command to local document. The XFDF needs to be a valid command format with <add>
<modify>
<delete>
tags.
Parameters:
Name | Type | Description |
---|---|---|
xfdfCommand | String | the XFDF command string for import |
Returns a Future.
var xfdfCommand = 'xfdfCommand <?xml version="1.0" encoding="UTF-8"?><xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve"><add><circle style="solid" width="5" color="#E44234" opacity="1" creationdate="D:20201218025606Z" flags="print" date="D:20201218025606Z" name="9d0f2d63-a0cc-4f06-b786-58178c4bd2b1" page="0" rect="56.4793,584.496,208.849,739.369" title="PDF" /></add><modify /><delete /><pdf-info import-version="3" version="2" xmlns="http://www.pdftron.com/pdfinfo" /></xfdf>';
PdftronFlutter.importAnnotationCommand(xfdfCommand);
Imports user bookmarks into the document. The input needs to be a valid bookmark JSON format.
Parameters:
Name | Type | Description |
---|---|---|
bookmarkJson | String | The bookmark json for import. It needs to be in valid bookmark JSON format, for example {"0": "Page 1"}. The page numbers are 1-indexed |
Returns a Future.
PdftronFlutter.importBookmarkJson("{\"0\": \"Page 1\", \"3\": \"Page 4\"}");
Saves the currently opened document in the viewer and get the absolute path to the document. Must only be called when the document is opened in the viewer.
Returns a Future.
Future Parameters:
Name | Type | Description |
---|---|---|
path | String | the location of the saved document |
var path = await PdftronFlutter.saveDocument();
Commits the current tool, only available for multi-stroke ink and poly-shape.
Returns a Future.
Future Parameters:
Name | Type | Description |
---|---|---|
committed | bool | true if either ink or poly-shape tool is committed, false otherwise |
var committed = await PdftronFlutter.commitTool();
print("Tool committed: $committed");
Gets the total number of pages in the currently displayed document.
Returns a Future.
Future Parameters:
Name | Type | Description |
---|---|---|
pageCount | int | the page count of the current document |
var pageCount = await PdftronFlutter.getPageCount();
print("The current doc has $pageCount pages");
Handles the back button in search mode. Android only.
Returns a Future.
Future Parameters:
Name | Type | Description |
---|---|---|
handled | bool | whether the back button is handled successfully |
var handled = await PdftronFlutter.handleBackButton();
print("Back button handled: $handled");
Gets a map object of the crop box for specified page.
Parameters:
Name | Type | Description |
---|---|---|
pageNumber | int | the page number for the target crop box. It is 1-indexed |
Returns a Future.
Future Parameters:
Name | Type | Description |
---|---|---|
cropBox | Rect |
the crop box information map. It contains information for position (bottom-left: x1 , y1 ; top-right: x2 , y2 ) and size (width , height ) |
var cropBox = await PdftronFlutter.getPageCropBox(1);
print('The width of crop box for page 1 is: ' + cropBox.width.toString());
Sets the current tool mode.
Parameters:
Name | Type | Description |
---|---|---|
toolMode | String | One of Tools string constants, representing to tool mode to set |
Returns a Future.
PdftronFlutter.setToolMode(Tools.annotationCreateEllipse);
Sets a field flag value on one or more form fields.
Parameters:
Name | Type | Description |
---|---|---|
fieldNames | List<String > |
list of field names for which the flag should be set |
flag | int | the flag to be set, one of the constants from FieldFlags |
flagValue | bool | value to set for flag |
Returns a Future.
PdftronFlutter.setFlagForFields(['First Name', 'Last Name'], FieldFlags.Required, true);
Sets field values on one or more form fields of different types.
Parameters:
Name | Type | Description |
---|---|---|
fields | List<Field > |
A list of fields with name and the value that you would like to set to, could be in type number, bool or string |
Returns a Future.
PdftronFlutter.setValuesForFields([
new Field('textField1', "Pdftron"),
new Field('textField2', 12.34),
new Field('checkboxField1', true),
new Field('checkboxField2', false),
new Field('radioField', 'Yes'),
new Field('choiceField', 'No')
]);
Sets the file name of the icon to be used for the leading navigation button. The button will use the specified icon if showLeadingNavButton (which by default is true) is true in the config.
Parameters:
Name | Type | Description |
---|---|---|
leadingNavButtonIcon | String | the icon path to the navigation button |
Returns a Future.
PdftronFlutter.setLeadingNavButtonIcon(Platform.isIOS ? 'ic_close_black_24px.png' : 'ic_arrow_back_white_24dp');
Note: to add the image file to your application, please follow the steps below:
- Add the image resource to the example/android/app/src/main/res/drawable directory. For details about supported file types and potential compression, check out here.
- Now you can use the image in the viewer. For example, if you add
button_close.png
to drawable, you could use'button_close'
in leadingNavButtonIcon.
- After pods has been installed, open the .xcworkspace file for this application in Xcode (in this case, it's Runner.xcworkspace), and navigate through the list below. This would allow you to add resources, in this case, an image, to your project.
- "Project navigator"
- "Runner" (or the app name)
- "Build Phases"
- "Copy Bundle Resources"
- "+".
- Now you can use the image in the viewer. For example, if you add
button_open.png
to the bundle, you could use'button_open.png'
in leadingNavButtonIcon.
Closes all documents that are currently opened in a multiTab environment (that is, multiTabEnabled is true in the config).
PdftronFlutter.closeAllTabs();
Event is raised when local annotation changes committed to the document.
Event Parameters:
Name | Type | Description |
---|---|---|
xfdfCommand | String | the XFDF command string exported |
var annotCancel = startExportAnnotationCommandListener((xfdfCommand) {
// local annotation changed
// upload XFDF command to server here
print("flutter xfdfCommand: $xfdfCommand");
});
Event is raised when user bookmark changes committed to the document.
Event Parameters:
Name | Type | Description |
---|---|---|
bookmarkJson | String | the bookmark json string exported |
var bookmarkCancel = startExportBookmarkListener((bookmarkJson) {
print("flutter bookmark: ${bookmarkJson}");
});
Event is raised when the document finishes loading.
Event Parameters:
Name | Type | Description |
---|---|---|
path | String | the path to where the document is saved |
var documentLoadedCancel = startDocumentLoadedListener((path)
{
print("flutter document loaded: ${path}");
});
Event is raised when the document has errors when loading.
var documentErrorCancel = startDocumentErrorListener((){
print("flutter document loaded unsuccessfully");
});
Event is raised when there is a change to annotations to the document.
Event Parameters:
Name | Type | Description |
---|---|---|
action | String | the action that occurred (add, delete, modify) |
annotations | List<Annot > |
the annotations that have been changed |
var annotChangedCancel = startAnnotationChangedListener((action, annotations)
{
print("flutter annotation action: ${action}");
for (Annot annot in annotations) {
print("annotation has id: ${annot.id}");
print("annotation is in page: ${annot.pageNumber}");
}
});
Event is raised when annotations are selected.
Event Parameters:
Name | Type | Description |
---|---|---|
annotationWithRects | List<AnnotWithRect > |
The list of annotations with their respective rects |
var annotsSelectedCancel = startAnnotationsSelectedListener((annotationWithRects)
{
for (AnnotWithRect annotWithRect in annotationWithRects) {
print("annotation has id: ${annotWithRect.id}");
print("annotation is in page: ${annotWithRect.pageNumber}");
print("annotation has width: ${annotWithRect.rect.width}");
}
});
Event is raised when there are changes to form field values.
Event Parameters:
Name | Type | Description |
---|---|---|
fields | List<Field > |
the fields that are changed |
var fieldChangedCancel = startFormFieldValueChangedListener((fields)
{
for (Field field in fields) {
print("Field has name ${field.fieldName}");
print("Field has value ${field.fieldValue}");
}
});
Event is raised when the leading navigation button is pressed.
var navPressedCancel = startLeadingNavButtonPressedListener(()
{
print("flutter nav button pressed");
});
Event is raised when page changes.
Event Parameters:
Name | Type | Description |
---|---|---|
previousPageNumber | int | the previous page number |
pageNumber | int | the current page number |
var pageChangedCancel = startPageChangedListener((previousPageNumber, pageNumber)
{
print("flutter page changed. from $previousPageNumber to $pageNumber");
});
Event is raised when zoom ratio is changed in the current document.
Event Parameters:
Name | Type | Description |
---|---|---|
zoom | double | the zoom ratio in the current document viewer |
var zoomChangedCancel = startZoomChangedListener((zoom)
{
print("flutter zoom changed. Current zoom is: $zoom");
});
See Contributing
See License