Flutter package to render PDF in Mac, Android, Web and iOS


Flutter Plugin to render PDF and show a PDF file on Web, MacOs 10.11+, Android 5.0+ and iOS.



Getting Started

In your flutter project add the dependency:

pub package

  native_pdf_view: any

For web add lines in index.html before importing main.dart.js:

<script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script>
<script type="text/javascript">
  pdfjsLib.GlobalWorkerOptions.workerSrc = "//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.worker.min.js";

Usage example

It very simple!

import 'package:native_pdf_view/native_pdf_view.dart';

final pdfController = PdfController(
  document: PdfDocument.openAsset('assets/sample.pdf'),

Widget pdfView() => PdfView(
  controller: pdfController,



documentThe document to be displayed-
initialPageThe page to show when first creating the PdfView1
viewportFractionThe fraction of the viewport that each page should occupy.1.0


controllerPages control. See page control and additional pdf info-
onPageChangedCalled whenever the page in the center of the viewport changes. See Document callbacks-
onDocumentLoadedCalled when a document is loaded. See Document callbacks-
onDocumentErrorCalled when a document loading error. Exception is passed in the attributes-
documentLoaderWidget showing when pdf document loadingSizedBox()
pageLoaderWidget showing when pdf page loadingSizedBox()
builderCallback called to render a widget for each page. See custom page builderDefault builder
errorBuilderShow document loading error message inside PdfViewCentered error text
rendererCustom PdfRenderer library options. See custom renderer optionswidth: page.width 2
height: page.height
format: PdfPageFormat.JPEG
backgroundColor: '#ffffff'
scrollDirectionPage turning directionAxis.horizontal
physicsHow the widgets should respond to user input-
pageSnappingSet to false for mouse wheel scroll on webtrue

Additional examples

Open another document


Page control:

// Jump to specified page

// Animate to specified page
_pdfController.animateToPage(3, duration: Duration(milliseconds: 250), curve: Curves.ease);

// Animate to next page 
_pdfController.nextPage(duration: Duration(milliseconds: 250), curve: Curves.easeIn);

// Animate to previous page
_pdfController.previousPage(duration: Duration(milliseconds: 250), curve: Curves.easeOut);

Additional pdf info:

// Actual showed page

// Count of all pages in document

Document callbacks

int _actualPageNumber = 0, _allPagesCount = 0;

  controller: pdfController,
  onDocumentLoaded: (document) {
    setState(() {
      _allPagesCount = document.pagesCount;
  onPageChanged: (page) {
    setState(() {
      _actualPageNumber = page;

/// Now you can use these values to display the reading status of the document.
Text('Read: $_actualPageNumber of $_allPagesCount');

Custom renderer options

  controller: pdfController,
  renderer: (PdfPage page) => page.render(
    width: page.width * 2,
    height: page.height * 2,
    format: PdfPageFormat.JPEG,
    backgroundColor: '#FFFFFF',

Custom page builder:

  controller: pdfController,
  document: snapshot.data,
  pageBuilder: (
    PdfPageImage pageImage, 
    bool isCurrentIndex, 
    AnimationController animationController,
  ) {
    // Double tap scales
    final List<double> _doubleTapScales = <double>[1.0, 2.0, 3.0]
    // Double tap animation
    Animation<double> _doubleTapAnimation;
    void Function() _animationListener;

    Widget image = ExtendedImage.memory(
      key: Key(pageImage.hashCode.toString()),
      fit: BoxFit.contain,
      mode: ExtendedImageMode.gesture,
      initGestureConfigHandler: (_) => GestureConfig(
        minScale: 1,
        maxScale: 3.0,
        animationMinScale: .75,
        animationMaxScale: 3.0,
        speed: 1,
        inertialSpeed: 100,
        inPageView: true,
        initialScale: 1.0,
        cacheGesture: false,
      onDoubleTap: (ExtendedImageGestureState state) {
        final pointerDownPosition = state.pointerDownPosition;
        final begin = state.gestureDetails.totalScale;
        double end;



        if (begin == _doubleTapScales[0]) {
          end = _doubleTapScales[1];
        } else {
          if (begin == _doubleTapScales[1]) {
            end = _doubleTapScales[2];
          } else {
            end = _doubleTapScales[0];

        _animationListener = () {
              scale: _doubleTapAnimation.value,
              doubleTapPosition: pointerDownPosition);
        _doubleTapAnimation = animationController
            .drive(Tween<double>(begin: begin, end: end))

    if (isCurrentIndex) {
      image = Hero(
        tag: 'pdf_view' + pageImage.pageNumber.toString(),
        child: image,
    return image;

Rendering additional info

On Web

This plugin uses the PDF.js

On Android

This plugin uses the Android native PdfRenderer

On Ios & MacOs

This plugin uses the IOS native CGPDFPage

Check it on GitHub