Nutrient Flutter SDK

repository·master·Indexed 41 days ago

https://github.com/pspdfkit/pspdfkit-flutter

A SDK for adding PDF viewing, annotating, and editing functionality to Flutter applications across Android, iOS, and Web. Features include the NutrientView widget, AI Assistant integration via AIAssistantConfiguration, and programmatic annotation creation modes.

Tokens
36.6K
Snippets
98
Records
132
Agent score
50%

What's inside Nutrient Flutter

  1. Use the Headless Document API

    master

    The Headless Document API allows you to open and manipulate PDF documents without displaying a viewer. This is ideal for batch processing, annotation management, and server-side operations.

    Important: Always wrap document operations in a try-finally block and call await document.close() in the finally block to release native resources.

    // Open a document without displaying a viewer
    final document = await Nutrient.openDocument('/path/to/document.pdf');
    
    try {
      // Perform operations...
      final pageCount = await document.getPageCount();
      final annotations = await document.getAnnotations(0, AnnotationType.all);
    
      // Save changes
      await document.save();
    } finally {
      // Always close headless documents to release resources
      await document.close();
    }
  2. Compare PSPDFKit and Nutrient Flutter SDK components

    master

    As part of the rebranding from PSPDFKit to Nutrient, several core components have been renamed. While most old APIs are marked as @Deprecated and remain functional for backward compatibility, it is recommended to transition to the new names for new projects and long-term compatibility.

    ComponentOld NameNew NameStatus
    Package Namepspdfkit_flutternutrient_flutter⚠️ Use nutrient_flutter
    Main WidgetPspdfkitWidgetNutrientView✅ Both work
    ControllerPspdfkitWidgetControllerNutrientViewController✅ Both work
    Plugin ClassPspdfkitNutrient✅ Both work
    Importpspdfkit_flutter.dartnutrient_flutter.dart✅ Both work
  3. Platform differences for annotation menu customization

    master

    The capabilities of annotation menu customization vary between iOS and Android.

    iOS

    • Supports: Removing items, disabling items, style picker control, grouping markup items, and suggesting maximum visible items.
    • Note: Some system actions (like copy/paste) may be protected by iOS. maxVisibleItems is a suggestion and may be overridden by iOS UI guidelines.

    Android

    • Supports: Removing items (by ID), disabling items, and style picker control.
    • Does NOT support: Grouping markup items or setting maximum visible items.
  4. Configure NutrientViewConfiguration

    master

    NutrientViewConfiguration is the primary configuration object for Nutrient widgets using bindings-based implementations (NutrientInstantView and NutrientView). It controls layout, UI chrome, editing capabilities, and appearance.

    All fields are optional. Unset fields use the native SDK's built-in defaults. Configuration is hierarchical:

    • Top-level fields: Apply to all platforms (Android, iOS, Web).
    • Platform-specific fields: Grouped under androidConfig, iosConfig, or webConfig to target specific platforms.
    NutrientInstantView(
      serverUrl: serverUrl,
      jwt: jwt,
      configuration: const NutrientViewConfiguration(
        pageLayoutMode: PageLayoutMode.single,
        thumbnailBarMode: ThumbnailBarMode.floating,
        enableAnnotationEditing: true,
        enableFormEditing: true,
        androidConfig: AndroidViewConfiguration(
          showSearchAction: true,
          showOutlineAction: true,
        ),
        iosConfig: IOSViewConfiguration(
          spreadFitting: SpreadFitting.adaptive,
        ),
      ),
    )
  5. How to reconnect or change documents in NutrientInstantView

    master

    The serverUrl and jwt parameters are fixed at construction time. The native SDK establishes the WebSocket connection once and does not observe changes to these values if they are updated in a parent widget.

    To switch to a different document or refresh an expired JWT, you must force the NutrientInstantView widget to fully rebuild by changing its key. A common pattern is to use a ValueKey with an incrementing counter in your state.

    int _viewKey = 0;
    
    void _applyNewConnection(String serverUrl, String jwt) {
      setState(() {
        _serverUrl = serverUrl;
        _jwt = jwt;
        _viewKey++; // Forces NutrientInstantView to rebuild with new values.
      });
    }
    
    // In build method:
    NutrientInstantView(
      key: ValueKey(_viewKey),
      serverUrl: _serverUrl!,
      jwt: _jwt!,
    )
  6. Automated Migration using the migration script

    master

    The fastest way to migrate is using the provided Dart migration script. This script updates pubspec.yaml, import statements, and can optionally update class names and enum prefixes.

    Usage Examples:

    • Preview changes (Dry Run): dart migrate_to_nutrient.dart --dry-run

    • Standard migration (Imports and Package only): dart migrate_to_nutrient.dart

    • Full migration (Includes API updates like Pspdfkit $\rightarrow$ Nutrient): dart migrate_to_nutrient.dart --update-apis

    • Migrate a specific directory: dart migrate_to_nutrient.dart lib/

    # Download and run the migration script
    curl -O https://raw.githubusercontent.com/PSPDFKit/pspdfkit-flutter/refs/heads/master/tools/migrate_to_nutrient.dart
    
    # Or if you've cloned the repository
    dart path/to/pspdfkit-flutter/tools/migrate_to_nutrient.dart
  7. Track unsaved changes with hasUnsavedChanges()

    master

    Use the cross-platform hasUnsavedChanges() method to determine if a document has modifications that haven't been saved yet. This is useful for prompting users to save before they navigate away or close the document.

    Platform implementation details:

    • iOS: Checks document.hasDirtyAnnotations.
    • Android: Checks annotation, form, and bookmark providers.
    • Web: Checks instance.hasUnsavedChanges().
    final hasChanges = await document.hasUnsavedChanges();
    if (hasChanges) {
      final shouldSave = await showSaveDialog();
      if (shouldSave) {
        await document.save();
      }
    }
  8. Update annotation properties safely

    master

    To update annotation properties without losing attachment data or custom fields, use the getAnnotationProperties and saveAnnotationProperties workflow. This involves retrieving the current properties, applying changes using the with* builder methods, and then saving the resulting object back to the document.

    Workflow:

    1. Retrieve properties using document.getAnnotationProperties(pageIndex, annotationId).
    2. Apply updates using chained methods like .withColor(), .withOpacity(), etc.
    3. Save the updated properties using document.saveAnnotationProperties(updated).

    Note on Migration: Do not use the deprecated document.updateAnnotation() method with copyWith, as it causes metadata loss. Always use the AnnotationProperties API to preserve all data.

    // Get annotation properties
    final properties = await document.getAnnotationProperties(pageIndex, annotationId);
    
    // Update properties (chain multiple updates)
    final updated = properties
        ?.withColor(Colors.red)
        .withOpacity(0.7)
        .withLineWidth(3.0);
    
    // Save changes
    if (updated != null) {
      await document.saveAnnotationProperties(updated);
    }
  9. Configure Web for Nutrient Flutter SDK

    master

    You can set up the Web SDK using one of two methods:

    Add the Nutrient Web SDK script to your web/index.html. Replace 1.13.0 with the latest version.

    Option 2: Local Installation

    1. Download the Nutrient Web SDK archive.
    2. Extract the archive and copy the contents of the dist folder into your project's web/assets folder.
    3. Ensure your server is configured to serve .wasm files with the Content-Type: application/wasm MIME type.
    4. Add the local script to web/index.html.
    <!-- web/index.html (CDN Option) -->
    <script src="https://cdn.cloud.nutrient.io/pspdfkit-web@1.13.0/nutrient-viewer.js"></script>
    
    <!-- web/index.html (Local Option) -->
    <script src="assets/nutrient-viewer.js"></script>
  10. Common AnnotationProperty operations

    master

    Below are specific patterns for common property updates.

    Toggle Flags: To toggle a flag (like readOnly), retrieve the existing flags set, create a new set, and add or remove the flag based on its current state.

    Update Custom Data: To add or update custom data without overwriting existing keys, spread the existing customData map into a new map containing your changes.

    Update Visuals: Use withColor, withOpacity (0.0 to 1.0), and withLineWidth for visual styling.

    // Toggle Flags
    final flags = properties?.flagsSet ?? {};
    final newFlags = Set<AnnotationFlag>.from(flags);
    newFlags.contains(AnnotationFlag.readOnly)
        ? newFlags.remove(AnnotationFlag.readOnly)
        : newFlags.add(AnnotationFlag.readOnly);
    
    final updated = properties?.withFlags(newFlags);
    await document.saveAnnotationProperties(updated);
    
    // Update Custom Data
    final data = {
      ...(properties?.customData ?? {}),
      'key': 'value',
    };
    
    final updated = properties?.withCustomData(data);
    await document.saveAnnotationProperties(updated);