Bridge Nutrient native Android, iOS, and Web APIs in Flutter
Nutrient Flutter SDK is built on top of the Nutrient iOS, Android, and Web SDKs, which offer a comprehensive set of APIs to interact with document viewers and editors. Nutrient Flutter SDK exposes a subset of the most frequently used APIs, but in some cases, you may need to access additional native APIs that aren’t directly available. This guide will show you how to bridge Nutrient’s native APIs for iOS and Android using Pigeon and for the Web using the dart:js
package.
Prerequisites
Before proceeding, ensure your development environment includes the following:
-
Basic knowledge of Flutter and Dart
-
Basic understanding of iOS (Swift) and Android (Kotlin) development
Forking and cloning the Nutrient Flutter plugin repository
The Nutrient Flutter plugin source code is publicly available on GitHub. Follow the steps below.
-
Fork the repository— Fork the Nutrient Flutter repository to your GitHub account.
-
Clone the forked repository — Clone the repository to your local machine:
git clone https://github.com/<YOUR-GITHUB-USERNAME>/pspdfkit-flutter.git
-
If you’re new to forking repositories, check out this guide on GitHub for detailed instructions on forking and keeping your fork in sync with the upstream repository.
Once you have your fork ready, proceed to set up the project structure.
Setting up the project structure
For ease of development, organize your project in a structure where the Flutter app and the plugin sit as sibling directories:
app-root/ ├── myapp/ ├── pspdfkit-flutter/
-
Create a new Flutter app — In the
app-root
directory, run the following commands to create a new Flutter app and clone the forked repository:
flutter create myapp
-
Add the Nutrient Flutter plugin as a dependency in your
pubspec.yaml
file:
dependencies:
pspdfkit_flutter:
path: ../pspdfkit-flutter
Defining a new API in Dart with Pigeon
Pigeon is a code generator that simplifies the process of bridging APIs between Flutter and native platforms. It generates platform-specific code for iOS and Android based on the API definitions you provide in Dart.
To bridge a new API, you need to define the API in a Dart file and then generate the platform-specific code using the Pigeon tool.
-
Edit the Pigeon file — Open the
pspdfkit-flutter/pigeons/pspdfkit.dart
file and define the new API. As an example, this guide will show how to bridge thePdfDocument.getPageCount()
API :
abstract class PdfDocumentApi { // Other existing APIs. @async int getPageCount(); }
-
For more information on how to define APIs, refer to the Pigeon documentation.
Generating platform-specific code using Pigeon
With the API defined, generate the platform-specific code using the Pigeon tool.
-
Install Pigeon — Ensure an up-to-date version of the Pigeon package is added to the
pspdfkit-flutter
pubspec.yaml
file under thedev_dependencies
section:
dev_dependencies:
pigeon: ^22.4.0
-
Run the Pigeon command — Switch to the
pspdfkit-flutter
directory and run the following command:
dart run pigeon --input pigeons/pspdfkit.dart
This will generate or update the following files to include the new API:
-
./lib/api/pspdfkit.g.dart
— The Dart API file interface -
./ios/Classes/api/PspdfkitApis.g.swift
— The iOS API interface file -
./android/src/main/java/com/pspdfkit/flutter/pspdfkit/api/PspdfkitApi.g.kt
— The Android API interface file
These generated files will contain all the necessary code to bridge the new API between Flutter and the native platforms.
Implementing the API on Android
To implement the API on Android, go to the Kotlin file where the native Android code will interact with Flutter: pspdfkit-flutter/android/src/main/java/com/pspdfkit/flutter/pspdfkit/FlutterPdfDocument.kt
.
-
Edit the
FlutterPdfDocument
class — This class implements the generatedPdfDocumentApi
interface. Implement thegetPageCount()
method as follows:
class FlutterPdfDocument ( private val pdfDocument: PdfDocument ) : PdfDocumentApi { // Other existing API implementations. override fun getPageCount(callback: (Result<Long>) -> Unit) { // The `PdfDocument` instance is already available, so you can get the page count directly. callback(Result.success(pdfDocument.pageCount.toLong())) } }
Here, pdfDocument
is an instance of the PdfDocument
class, which is already available in the Android codebase. You just had to call the getPageCount
property to get the total number of pages in the document.
Implementing the API on iOS
To implement the API on iOS, you need to update the Swift file at pspdfkit-flutter/ios/Classes/FlutterPdfDocument.swift
.
-
Edit the
FlutterPdfDocument
class — This class implements the generatedPdfDocumentApi
protocol. Implement thegetPageCount()
method as follows:
class FlutterPdfDocument: NSObject, PdfDocumentApi { // Other existing API implementations. func getPageCount(completion: @escaping (Result<Int64, any Error>) -> Void) { if let pageCount = document?.pageCount { completion(.success(Int64(pageCount))) } else { let error = PspdfkitApiError(code: "", message: "Failed to get page count.", details: nil ) completion(.failure(error)) } } }
Here, document
is an instance of the Document
class, which is already available in the iOS codebase. You just had to call the pageCount
property to get the total number of pages in the document.
Implementing the API in Flutter
Now, you’ll update the Dart files to expose the newly added getPageCount
method in the Flutter Nutrient plugin.
-
Update the
PdfDocument
interface — Editlib/src/document/pdf_document.dart
and define the new API method as follows:
abstract class PdfDocument { // Other existing APIs Future<int> getPageCount(); }
-
Update the
PdfDocumentNative
class — Implement the new method inlib/src/document/pdf_document_native.dart
:
class PdfDocumentNative extends PdfDocument { // Other existing APIs. @override Future<int> getPageCount() { return _api.getPageCount(); } }
Implementing the API for Web
Unlike iOS and Android, the Web platform doesn’t require platform channels or Pigeon to communicate with the JavaScript APIs. Instead, use the built-in dart:js
package to interact with the Web platform.
To implement the getPageCount
API for the Web platform, update the following files.
-
Edit the
PspdfkitWebInstance
class — This is where you’ll add the web-specific logic to get the document title. Updatelib/src/web/pspdfkit_web_instance.dart
as follows:
class PspdfkitWebInstance { // Other existing APIs. Future<int> getPageCount() async { try { // Access the PSPDFKit JavaScript instance to get the page count. var count = _pspdfkitInstance['totalPageCount']; return Future.value(count); } catch (e) { throw Exception('Failed to get document title: $e'); } } }
Here _pspdfkitInstance
is the JsObject
reference to the JavaScript instance of the PSPDFKit.Instance
, which is already available in the Web codebase. You just had to access the totalPageCount
property to get the total number of pages in the document. To learn more about dart:js
, refer to the official documentation.
-
Edit
PdfDocumentWeb
— Next, updatelib/src/document/pdf_document_web.dart
to add access to the new API on the Web platform:
class PdfDocumentWeb extends PdfDocument { // Other existing APIs. @override Future<int> getPageCount() { return _instance.getPageCount(); } }
Using the new API in your Flutter app
Now that you’ve implemented the getPageCount
method across all platforms, you can use it in your Flutter app. For example:
PspdfkitWidget( document: document, onDocumentLoaded: (pdfDocument) async { var pageCount = await pdfDocument.getPageCount(); print('Document page count: $pageCount'); }, )
Backward compatibility
If you’re currently using method channels for bridging APIs and aren’t ready to fully transition to Pigeon, you can continue using the existing method channels alongside the new Pigeon APIs. To do this, set useLegacy
to true
when initializing Nutrient:
await Pspdfkit.initialize(
useLegacy: true,
);
This will ensure the existing method channels are used for communication with the native platform.