Skip to content

PDF-SDK 2.4.1 is out.See what’s new

PDF-SDK
Skip to Content
Docs

Flutter

The pdf_editor plugin opens the native PDF-SDK editor full screen and hands back the edited file. It's a thin binding over the iOS and Android SDKs, so your Flutter app gets exactly the same editor, on both platforms.

Every class, option and method: Flutter API reference.

NeedsVersion
Flutter3.44 or later (tested on 3.47), with Swift Package Manager enabled
iOS15 or later
Android8.0 (API 26) or later, arm64-v8a devices

1. Add the plugin

The plugin comes with your license, as a folder or a Git repository. Add it to pubspec.yaml, and turn on Swift Package Manager for iOS — PDF-SDK ships as a Swift package only, never through CocoaPods:

# pubspec.yaml
dependencies:
  pdf_editor:
    path: vendor/pdf_editor   # the plugin folder that comes with your license
    # or, from Git:  git: { url: <the plugin URL that comes with your license> }

flutter:
  config:
    enable-swift-package-manager: true

Swift Package Manager can also be switched on for every project on your machine with flutter config --enable-swift-package-manager. See Flutter's Swift Package Manager guide.

On iOS the plugin fetches the PDF-SDK Swift package itself, from the same package URL as the iOS guide; there's nothing to add in Xcode. If that URL is a private repository, sign in to it once in Xcode (Settings ▸ Accounts) so the build can fetch it.

Android: where the SDK comes from

Gradle doesn't let a plugin add a repository to your app, so add the Maven repository that comes with your license, and set the minimum SDK to 26:

// android/build.gradle.kts
allprojects {
    repositories {
        google(); mavenCentral()
        maven { url = uri("${rootDir}/../vendor/pdfsdk/maven") }   // the unzipped bundle, or your registry URL
    }
}
// android/app/build.gradle.kts
android {
    defaultConfig { minSdk = 26 }
}

2. Set your license key

Once, before the first editor — main() is the natural place. The key lists your app's iOS bundle identifier and Android package name.

import 'package:flutter/widgets.dart';
import 'package:pdf_editor/pdf_editor.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final license = await PdfEditor.setLicenseKey('PE1.eyJ2Ijox…');
  if (!license.isLicensed) debugPrint('PDF-SDK: ${license.reason}');
  runApp(const MyApp());
}

3. Open the editor

Give it a PDF on disk. It resolves with the path of the edited file, or null if the user closed without saving.

final String? edited = await PdfEditor.open(
  path: file.path,
  mode: PdfEditorMode.annotate,            // optional: the mode to open in
  tool: PdfEditorTool.highlight,           // optional: a tool to arm
);
if (edited != null) {
  final bytes = await File(edited).readAsBytes();
  await upload(bytes);
}

The result is a new file in the temporary directory, yours to move or delete. Pass inPlace: true to overwrite path instead. A file path rather than bytes, because a real document is far larger than a platform channel or an Android Intent should carry.

Opening fails with a PlatformException whose code is bad_args, not_found, already_open, no_activity, write_failed (the edited file couldn't be written) or, on Android, unsupported (a device without arm64-v8a). A user simply closing the editor is not an error.

4. Customize the editor

Pass a PdfEditorConfiguration. Leave a field out and the editor keeps its own behaviour. The options narrow, rename or restyle what the editor offers — fonts also adds your own — and out-of-range values are clamped.

final edited = await PdfEditor.open(
  path: file.path,
  configuration: const PdfEditorConfiguration(
    modes: [PdfEditorMode.annotate, PdfEditorMode.fillAndSign],
    colorScheme: PdfEditorColorScheme.dark,
    hiddenTools: {PdfEditorTool.stamp},
    hiddenMenuItems: {PdfEditorMenuItem.print},
    toolTitles: {PdfEditorTool.signature: 'Approve'},
    modeTitles: {PdfEditorMode.fillAndSign: 'Sign'},
    selectionColor: Color(0xFFFF2D55),
    handleShape: PdfEditorHandleShape.circle,
    toolDefaults: PdfEditorToolDefaults(
      highlight: PdfEditorMarkupStyle(color: Color(0xFF00C853), opacity: 0.4),
    ),
    minZoom: 1,
    maxZoom: 2,
  ),
);
AreaOptions
Modes, tools, menumodes, hiddenTools, hiddenMenuItems, toolOrder, menuOrder
NamestoolTitles, modeTitles, menuItemTitles
AppearancecolorScheme, selectionColor, selectionColorDark (Android), handleFillColor, handleShape, handleScale, selectionBorderWidth, searchHighlightColor, searchCurrentHighlightColor
FontsinterfaceFontFamily (iOS), fonts, fontsTitle, showsStandardFonts (Android), showsDocumentFonts, showsDeviceFonts, allowsFontImport, newTextFont — fonts are file paths
Tool stylestoolDefaults: highlight, underline, strikeout, squiggly and the pen
BehaviourminZoom, maxZoom, haptics, showsUsageHints
SigningsignaturePlacement: where the e-Sign tab's Placement picker starts (bottomRight by default, bottomLeft, topRight, topLeft, invisible)

Every option, with what it does: PdfEditorConfiguration in the Flutter API reference. The names and meanings are the native ones (iOS, Android). Custom icons and your own toolbar buttons need images and callbacks, which a platform channel can't carry, so they stay native-only.

Edit documents from code

Everything a user can do in the editor can be done from code, with no UI: read every layer of a page and its properties, replace text in any script (the layer keeps its font, size, colour and position, and the system's fonts fill in letters its font lacks), restyle, move, resize, rotate and restack layers, add text, images and shapes, mark text up, fill and author forms, edit metadata and pages, search, render a page, and save. Every method: PdfDocument in the API reference.

A layer is addressed by its page and an id that keeps naming it while other layers change. Geometry is in page points from the page's top-left corner. Each change is one undo step.

final doc = await PdfDocument.open(bytes);
for (final block in await doc.textBlocks(0)) {
  final text = await translate(block.text ?? '');
  await doc.setText(block, text, shrinkToFit: true);
}
final Uint8List edited = await doc.save();
await doc.close();

Pass onDocumentReady to PdfEditor.open to get the document the editor is showing: changes appear on screen at once and the user can undo them. It stops working when the editor closes.

await PdfEditor.open(path: file.path, onDocumentReady: (doc) async {
  await doc.addText('Approved', 0, 40, 120);
});

Failures throw PdfDocumentException with a code: notFound (read the layers again), unsupportedGlyphs, failed, badArguments or cannotOpen.

Localize the editor

Every word the editor shows has a stable key, the same on every platform, with English as its built-in text. Give text for the keys you want translated; the rest stay English. The editor checks a dictionary first, then the app's own translations (iOS PDFEditor.strings, Android pe_<key> resources) in its current language, then English. Right-to-left languages mirror the editor; the page navigator stays left to right, like the pages it turns.

await PdfEditor.open(
  path: file.path,
  configuration: PdfEditorConfiguration(
    localization: PdfEditorLocalization(language: 'hi', strings: {'cancel': 'रद्द करें'}),
  ),
);

Placeholders are positional (Page {1} of {2}), so a translation can reorder them. A count has two keys: <key>_one and <key>. Names you set per tool, mode or menu item win over translations.

Version and support

final version = await PdfEditor.nativeVersion();   // log it next to your build number
final ok = await PdfEditor.isSupported();          // false only for an ABI the app shipped without

Troubleshooting

SymptomFix
iOS build can't find PDFEditorUI, or Flutter asks for CocoaPodsSwift Package Manager isn't on: add enable-swift-package-manager: true (above) and rebuild.
Could not find com.pdfsdk:pdfeditorYour app's Gradle build doesn't list the PDF-SDK Maven repository — see Android: where the SDK comes from.
Manifest merger error about minSdkSet minSdk = 26.
The editor shows "not licensed for this app"The key doesn't list this bundle identifier or package name; PdfEditor.license() says which one it checked.