---
title: "Flutter SDK 6 migration guide"
canonical_url: "https://www.nutrient.io/guides/flutter/migration-guides/flutter-6-migration-guide/"
md_url: "https://www.nutrient.io/guides/flutter/migration-guides/flutter-6-migration-guide.md"
last_updated: "2026-07-08T00:00:00.000Z"
description: "Migrate to Nutrient Flutter SDK 6, rebuilt on generated native bindings. Adopt the new bindings API while the legacy method-channel API is deprecated but still supported."
---

# Flutter SDK 6 migration guide

Nutrient Flutter SDK 6 uses generated native bindings. The new bindings API drives each platform’s native SDK directly — Java Native Interface (JNI) on Android, Foreign Function Interface (FFI) on iOS, and JavaScript (JS) interop on the web — instead of routing every call through a Pigeon method channel. Use it for new work.

The legacy method-channel API (`Nutrient.present()`, `NutrientView`, `PdfConfiguration`, `PdfDocument`) is deprecated but not removed. Existing apps keep working without changes, and you can migrate one screen at a time.

## What’s new in the bindings API

Nutrient Flutter SDK 6 adds these bindings API changes:

- Use a single import, `package:nutrient_flutter/bindings.dart`, for the bindings surface.

- Use the built-in default adapter for a standard viewer. You only need `await Nutrient.initialize()` — no license key or adapter required.

- Use `NutrientDocumentView`, a widget backed by a per-platform _adapter_ that also acts as its controller.

- Listen to typed events with the `controller.events` stream, which uses the sealed `NutrientEvent` type.

- Add custom native behavior through a typed controller. Register your adapter type with `Nutrient.addAdapterClass<T>()` and select it with `NutrientDocumentView<T>`.

- Access native objects through platform adapters for capabilities not yet available on the cross-platform API.

## Map legacy APIs to the bindings API

Each legacy API in `package:nutrient_flutter/nutrient_flutter.dart` has a bindings equivalent in `package:nutrient_flutter/bindings.dart`:

| Legacy (method-channel API)                                          | Bindings API                                                                     |
| -------------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| `import 'package:nutrient_flutter/nutrient_flutter.dart';`           | `import 'package:nutrient_flutter/bindings.dart';`                               |
| `NutrientView`                                                       | `NutrientDocumentView`                                                           |
| `Nutrient.present(path)`                                             | `NutrientDocumentView(documentPath: path)`                                       |
| `Nutrient.presentInstant(...)`                                       | `NutrientInstantView`                                                            |
| `PdfConfiguration(...)`                                              | `NutrientViewConfiguration(...)`                                                 |
| `onViewCreated: (controller) {... }`                                | `onControllerReady: (controller) {... }`                                        |
| `NutrientViewController`                                             | `NutrientController`                                                             |
| `onDocumentLoaded`/`onPageChanged`/`onPageClicked` widget callbacks  | `controller.events` (typed `NutrientEvent` stream)                               |
| `controller.addEventListener(NutrientEvent.annotationsCreated,...)` | `controller.events.listen(...)` over sealed events (`AnnotationCreatedEvent`, …) |
| `NutrientView(customToolbarItems:, onCustomToolbarItemTapped:)`      | `controller.setMainToolbarItems([CustomToolbarItem(onPressed:)])`                |
| Headless `PdfDocument`                                               | `Nutrient.openDocument(path)`/`controller.document`                              |

The following sections cover the most common conversions.

## Update annotation and form APIs

Document, annotation, and form operations moved from `PdfDocument` to the loaded document’s controller: `controller.document`, `controller.document.annotations`, and `controller.document.forms`. Access them from `NutrientDocumentView` in `onControllerReady`.

Several methods also changed shape:

| Legacy (`PdfDocument`)                                   | Bindings                                                                                                                                                                                         |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `getAnnotations(page, type)`                             | `controller.document.annotations.getAnnotations(page)` — returns typed `Annotation` models; the type argument is now optional and defaults to all types                                          |
| `addAnnotation(annotation)`                              | `controller.document.annotations.addAnnotation(annotation)`                                                                                                                                      |
| `addAnnotations([...])`                                  | **Removed** — call `addAnnotation` in a loop                                                                                                                                                     |
| `removeAnnotation(annotation)`                           | `controller.document.annotations.removeAnnotation(pageIndex, annotationId)`                                                                                                                      |
| `importXfdf(path)`                                       | `controller.document.annotations.importXfdf(xfdfString)` — takes the XFDF (XML Forms Data Format) content, not a file path                                                                       |
| `exportXfdf(path)`                                       | `controller.document.annotations.exportXfdf()` — **returns the XFDF as a string** (no path argument)                                                                                             |
| `applyInstantJson(json)` / `exportInstantJson()`         | `controller.document.applyInstantJson(json)` / `exportInstantJson()`                                                                                                                             |
| `processAnnotations(AnnotationType.all, mode, path)`     | `Nutrient.processAnnotations(sourcePath:, type: AnnotationType.all, mode: AnnotationProcessingMode.flatten, destinationPath:)` — a static operation; no open document required (Android and iOS) |
| `getFormFieldValue(name)` / `setFormFieldValue(v, name)` | `controller.document.forms.getFormFieldValue(name)` / `setFormFieldValue(v, name)`                                                                                                               |
| `getFormFields()`                                        | Moved to the forms manager: `controller.document.forms.getFormFields()`                                                                                                                          |

For the full annotation and form APIs, refer to the [annotations](https://www.nutrient.io/guides/flutter/annotations.md) and [forms](https://www.nutrient.io/guides/flutter/forms.md) guides.

## Update configuration

`NutrientViewConfiguration` replaces `PdfConfiguration`. Cross-platform options keep the same names. Platform-prefixed options move into nested platform blocks:

| Legacy (`PdfConfiguration`)                                  | Bindings (`NutrientViewConfiguration`)                                                                      |
| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
| `iOS*`-prefixed options (`iOSRightBarButtonItems`, …)        | `iosConfig: IOSViewConfiguration(rightBarButtonItems:...)`                                                 |
| `android*`-prefixed options (`androidShowSearchAction`, …)   | `androidConfig: AndroidViewConfiguration(showSearchAction:...)`                                            |
| `webConfiguration: PdfWebConfiguration(...)`                 | `webConfig: WebViewConfiguration(...)`                                                                      |
| `iOSFileConflictResolution:`                                 | `iosConfig: IOSViewConfiguration(fileConflictResolution:...)`                                              |
| `androidDefaultThemeResource:` / `androidDarkThemeResource:` | `androidConfig: AndroidViewConfiguration(defaultThemeResource:..., darkThemeResource:...)`                |
| `signatureSavingStrategy:`/`signatureCreationConfiguration:` | Same names — carried over, and the creation configuration now also applies on Web and adds a `fonts` option |

## Update document saving

The bindings API moves document saving and bookmark operations to `controller.document`:

| Legacy (`PdfDocument`)                                                                       | Bindings                                                                                               |
| -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| Save As via `processAnnotations('all', 'embed', path)`                                       | `controller.document.save(outputPath: path)` on Android and iOS                                        |
| `save()` on Web with a path                                                                  | `save(outputPath:)` throws `UnsupportedError` on Web — use `exportPdf()` for the browser download flow |
| `hasUnsavedChanges()`                                                                        | Same name — now on `controller.document`                                                               |
| Granular dirty-state methods (`iOSGetAnnotationIsDirty()`, `androidGetBookmarkIsDirty()`, …) | **Not bridged** — use `hasUnsavedChanges()`, event-based tracking, or the platform adapters            |
| `getBookmarks()`/`addBookmark()`/`removeBookmark()`/`updateBookmark()`                       | Moved to the bookmark manager: `controller.document.bookmarks.*`                                       |

## Review APIs without a bindings equivalent

The following legacy APIs have no counterpart on the bindings surface. They continue to work on the deprecated method-channel API. Where noted, use platform adapters as the extension point:

- `Nutrient.generatePdf()`, `generatePdfFromHtmlString()`, and `generatePdfFromHtmlUri()` — Refer to the [PDF generation][] guide. PDF generation stays on the legacy API for now. Nutrient plans to add a bindings equivalent. In the meantime, reach the native processors through the platform adapters.

- `Nutrient.getTemporaryDirectory()` — Use the [`path_provider`](https://pub.dev/packages/path_provider) package instead.

- `Nutrient.analyticsEventsListener`/`enableAnalytics()` — Legacy only.

- `PdfConfiguration.defaultZoomScale`, `settingsMenuItems`, and `toolbarTitle` — Removed with no replacement.

- `setAnnotationConfigurations` with the typed preset classes (`InkAnnotationConfiguration`, `MarkupAnnotationConfiguration`, …) — Not implemented on the bindings controller. Use the platform adapters for preset customization.

- iOS `ThemeConfiguration`/`ToolbarTheme`/`AnnotationToolbarTheme` — Use `appearanceMode` for light or dark mode, and use platform adapters for custom iOS colors.

- `annotationToolsGrouping` with `AnnotationToolbarItem`/`AnnotationToolsGroup` — Replaced by `controller.setAnnotationToolbarItems([...])` with `AnnotationTool` and `AnnotationToolGroup(representative:, items:)`.

## Make required changes for every app

These changes apply to all apps that upgrade to SDK 6, including apps that stay on the legacy API.

### Change AnnotationProperties color fields to int?

`AnnotationProperties.strokeColor` and `AnnotationProperties.fillColor` changed from `String?` (hex) to `int?` (ARGB — alpha, red, green, blue). This aligns the type with how `withColor`, `withFillColor`, and the `color` / `fillColorValue` getters already worked.

```dart

// Before.
final props = AnnotationProperties(strokeColor: '#FF0000');

// After.
final props = AnnotationProperties(strokeColor: 0xFFFF0000);
// or
final props = AnnotationProperties(strokeColor: Colors.red.toARGB32());

```

### Set the iOS deployment target to 17

Set your iOS deployment target to 17.0 or higher in Xcode and your `Podfile`:

```diff

-platform :ios, '16.0'
+platform :ios, '17.0'

```

### Stop importing Pigeon-generated classes

`package:nutrient_flutter/nutrient_flutter.dart` no longer reexports the Pigeon-generated `*Api`/`*Callbacks` proxy classes. Nutrient never intended these classes as public APIs. If you imported them directly, switch to the public `PdfDocument`/`NutrientViewController` interfaces instead.

### Remove Pspdfkit.useLegacy

SDK 6 removes the legacy `MethodChannel` bridge. All cross-platform communication now goes through the Pigeon-generated APIs and the platform-adapter bindings, so the `useLegacy` flag no longer exists. It only selected the now-removed method-channel widget controller.

If you set `useLegacy`, remove the argument. It has no replacement, and the Pigeon-backed controller is always used.

```dart

// Before.
await Pspdfkit.initialize(androidLicenseKey: key, useLegacy: true);

// After.
await Pspdfkit.initialize(androidLicenseKey: key);

```

The deprecated `Nutrient.present()`/`NutrientView` Dart APIs are unaffected. They now route through Pigeon and keep working.

## Adopt the bindings API

Migration is optional and incremental. The steps below convert one screen to the bindings API. Screens that still use `NutrientView` or `Nutrient.present()` keep working alongside it.

### 1. Add the federated packages

The bindings API is split across federated packages that must be listed as direct dependencies so their native plugins register at runtime. Refer to the [getting started][] guide for the full dependency and platform setup. Then return here to convert your screens.

### 2. Switch the import

Replace the legacy barrel with the bindings library.

```dart

// Before.
import 'package:nutrient_flutter/nutrient_flutter.dart';

// After.
import 'package:nutrient_flutter/bindings.dart';

```

Keep `import 'package:nutrient_flutter/nutrient_flutter.dart';` in any file that still uses the legacy API. The two libraries are independent.

### 3. Initialize the SDK and present a document

The bindings API registers a built-in default adapter, so initialization no longer requires arguments for a standard viewer. Replace `NutrientView`/`Nutrient.present()` with `NutrientDocumentView`.

```dart

// Before — legacy method-channel API.
await Nutrient.initialize(androidLicenseKey: key, iosLicenseKey: key);
NutrientView(documentPath: path);

// After — bindings API.
await Nutrient.initialize(); // Pass license keys to remove the trial watermark.
NutrientDocumentView(documentPath: path);

```

`NutrientDocumentView` accepts an asset path (`assets/doc.pdf`), a file path, or a remote URL and resolves asset paths internally.

### 4. Move event handling to controller.events

`NutrientDocumentView` exposes a typed controller through `onControllerReady`. A single `controller.events` stream replaces the legacy per-widget callbacks (`onDocumentLoaded`, `onPageChanged`, …) and the enum-keyed `controller.addEventListener(...)`. `controller.document` handles document operations.

```dart

// Before — per-widget callbacks + enum-keyed listeners.
NutrientView(
  documentPath: path,
  onDocumentLoaded: (document) => print('Loaded'),
  onPageChanged: (pageIndex) => print('Page: $pageIndex'),
  onViewCreated: (controller) {
    controller.addEventListener(
      NutrientEvent.annotationsCreated,
      (event) => print('Annotation created'),
    );
  },
);

```

```dart

// After — one typed stream on the controller.
NutrientDocumentView(
  documentPath: path,
  onControllerReady: (controller) async {
    final pageCount = await controller.document.getPageCount();

    // Filtered subscription.
    controller.events.pageChanged.listen((e) => print('Page ${e.pageIndex}'));

    // Or handle the sealed `NutrientEvent` type exhaustively.
    controller.events.listen((event) {
      switch (event) {
        case PageChangedEvent(:final pageIndex):
          print('Page: $pageIndex');
        case DocumentLoadedEvent():
          print('Loaded');
        default:
          break;
      }
    });
  },
);

```

Platform-specific events are available on the platform adapter: `androidEvents` on `AndroidAdapter`, `iosEvents` on `IOSAdapter`, and `webEvents` on `NutrientWebAdapter`.

### 5. Update the Android launcher activity

Bindings apps host the viewer in `NutrientFlutterActivity`, which `nutrient_flutter_android` provides, rather than a custom `MainActivity` or `FlutterAppCompatActivity`. Point the launcher activity at it and enable trial-mode auto-initialization in `AndroidManifest.xml`:

```diff

 <activity

-       android:name=".MainActivity"

+       android:name="com.nutrient.nutrient_flutter_android.NutrientFlutterActivity"
        android:exported="true"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"...>...
 </activity>

+   <meta-data

+       android:name="nutrient_automatic_initialize"

+       android:value="true"

+       tools:replace="android:value" />

```

The viewer requires an AppCompat-descendant theme, so keep your `LaunchTheme`/`NormalTheme` on a `PSPDFKit.Theme*` parent. The `nutrient_automatic_initialize` metadata is required because the bindings API initializes the SDK through `NutrientDocumentView` rather than the method channel.

## Customize the viewer with platform adapters

You don’t need an adapter for the default viewer. To customize the viewer’s configuration, listen to native lifecycle events, or reach platform-specific APIs, subclass the platform adapter (`AndroidAdapter`, `IOSAdapter`, or `NutrientWebAdapter`). The adapter _is_ the controller.

Register your controller type once with `Nutrient.addAdapterClass<T>()` and select it with `NutrientDocumentView<T>`, or pass a per-view `adapter:` instance you own. Adapters also expose accessors to the underlying native objects — the native `PdfFragment`, `PSPDFViewController`, or web `Instance`, plus form providers — for advanced features.

For details, refer to the [platform adapters][] guide.

## Review deprecations

Nutrient Flutter SDK 6 includes these deprecations and version-reporting changes:

- The legacy `Nutrient`/`NutrientView` method-channel API is marked `@Deprecated`. It still works, but new code should use `package:nutrient_flutter/bindings.dart`.

- `Nutrient.frameworkVersion` reports the underlying native SDK version on the current platform.
---

## Related pages

- [Flutter 1 10 4 Migration Guide](/guides/flutter/migration-guides/flutter-1-10-4-migration-guide.md)
- [Flutter 3 12 Migration Guide](/guides/flutter/migration-guides/flutter-3-12-migration-guide.md)
- [Flutter 3 2 Migration Guide](/guides/flutter/migration-guides/flutter-3-2-migration-guide.md)
- [Flutter 3 3 Migration Guide](/guides/flutter/migration-guides/flutter-3-3-migration-guide.md)
- [Flutter 3 6 Migration Guide](/guides/flutter/migration-guides/flutter-3-6-migration-guide.md)
- [Flutter 3 9 Migration Guide](/guides/flutter/migration-guides/flutter-3-9-migration-guide.md)
- [Flutter SDK 3 migration guide](/guides/flutter/migration-guides/flutter-3-migration-guide.md)
- [Flutter SDK 4.2 migration guide](/guides/flutter/migration-guides/flutter-4-2-migration-guide.md)
- [Flutter SDK 4 migration guide](/guides/flutter/migration-guides/flutter-4-migration-guide.md)
- [Download and run the migration script.](/guides/flutter/migration-guides/flutter-5-migration-guide.md)
- [Upgrade to the latest Flutter version](/guides/flutter/migration-guides/upgrading.md)

