← Abdelrahman Saed · All case studies

flutter_cached_pdfview

An open-source cached PDF viewer for Flutter, adopted across thousands of apps

Creator & maintainer · 2020 — Present · iOS · Android

  • 134+ — GitHub stars
  • 501+ — pub.dev likes
  • 57K+ — Downloads
  • 100+ — Forks
  • 6 yrs — Maintained
  • MIT — Licensed
flutter_cached_pdfview — An open-source cached PDF viewer for Flutter, adopted across thousands of apps

The Problem

Displaying remote PDFs in a mobile app sounds trivial until you ship it. The common approaches each fall short:

  • Re-downloading on every open. Naively loading a PDF from a URL fetches the whole file again each time — slow for the user and wasteful of bandwidth and data plans.
  • No offline story. Once the network drops, documents a user already opened are simply gone.
  • Platform fragmentation. iOS and Android render PDFs through entirely different native components, so a consistent, performant viewer means bridging both.
  • Boilerplate everywhere. Loading states, error handling, and cache management get re-implemented in every app that needs a PDF.

I kept solving the same problem across projects, so I built it once, properly, and open-sourced it.

Constraints

The design had four hard requirements:

  • Zero-config correctness. The cached, offline-capable path had to be the default in a few lines — not an opt-in callers assemble from parts.
  • Two native renderers, one API. iOS and Android render PDFs through entirely different components; the public surface had to hide that split completely.
  • Small footprint. A dependency thousands of apps embed can't ship a heavyweight PDF engine — it had to lean on what the platforms already provide.
  • Maintainable for years. As a package others depend on, it had to survive Flutter breaking changes — null-safety, super.key, evolving cache-manager APIs — without breaking downstream apps.

The Solution

flutter_cached_pdfview renders remote PDFs natively while caching each downloaded file on-device — so a document opens instantly and works offline on every load after the first.

It wraps the native flutter_pdfview renderer with flutter_cache_manager, and exposes one small, declarative API over three sources — URL, asset, and file path — with progress placeholders, error widgets, and password-protected and gesture-zoom support built in:

// First open downloads + caches; every later open is served from disk.
const PDF().cachedFromUrl(
  'https://example.com/doc.pdf',
  placeholder: (progress) => Center(
    child: CircularProgressIndicator(value: progress / 100),
  ),
  errorWidget: (error) => const Center(child: Text('Failed to load PDF')),
);

The goal was to make the right behavior — cached, offline-capable, native rendering — the default, in a few lines, on both platforms.

Architecture

The package is a thin, deliberate composition rather than a reinvention:

  • Native rendering, not a Dart PDF engine. It delegates pixel-level rendering to the platform components through flutter_pdfview, so documents look and scroll the way users expect on each OS, and the package stays small.
  • Caching via flutter_cache_manager. Remote files are downloaded once and stored in a managed on-device cache; later reads resolve straight to a local file, which is what makes repeat opens instant and offline-safe.
  • A source abstraction. cachedFromUrl, fromAsset, and fromPath unify remote, bundled, and local documents behind one widget, so callers swap sources without touching their UI.
  • Lifecycle hooks as first-class API. placeholder (download progress) and errorWidget are part of the public surface, so loading and failure states are handled by design rather than bolted on.

It supports Android API 20+ and iOS 11+, ships under the MIT license, and has stayed maintained since 2020.

Performance

The entire point of the package is performance and resilience under real-world conditions:

  • Instant repeat opens. The first load downloads and caches the file; every subsequent open is served from disk, eliminating the network round-trip and the re-download.
  • Bandwidth saved. Documents are fetched once, not once per view — meaningful for users on metered or slow connections.
  • Offline by consequence. Because reads resolve to the on-device cache, previously opened PDFs keep working with no connection at all.
  • Small footprint. Leaning on the native renderers keeps the package lightweight and avoids shipping a heavyweight PDF engine inside every app that depends on it.

Results

The package became one of the go-to PDF solutions in the Flutter ecosystem:

  • 134+ GitHub stars, 501+ pub.dev likes, and 57,000+ downloads.
  • 100+ forks and contributions from the community.
  • Maintained continuously since 2020, kept current with modern Flutter (null-safety, super.key, current cache-manager APIs).
  • Adopted in production document readers, e-book apps, and EdTech products — including the PDF experiences I shipped at iStoria.

A small library with an outsized footprint: a focused tool that solved a recurring problem well enough that thousands of other apps now rely on it. The companion guide below walks through using it end-to-end.

Lessons Learned

Three things this package reinforced:

  • Compose, don't reinvent. Wrapping flutter_pdfview and flutter_cache_manager beat writing a Dart PDF engine — smaller, faster, and it inherited native rendering quality for free.
  • Make the right thing the default. Adoption came from removing decisions: cached, offline-capable, native rendering with no configuration. Good defaults are a feature.
  • Maintenance is the product. Six years of staying current with Flutter is the reason apps still depend on it. Publishing a package is a commitment, not a drop.

Tags: Flutter · Dart · Open Source · PDF · Plugin

Related reading: Building a Cached PDF Viewer in Flutter


Available for hire. Abdelrahman Saed is a Senior Mobile Engineer (Flutter) — open to full-time, fractional, contract, or advisory work. Hire me →

Book a 20-minute call · Download the CV (PDF) · See how I work