TheBetterPdfViewer.MAUI
1.7.0
See the version list below for details.
dotnet add package TheBetterPdfViewer.MAUI --version 1.7.0
NuGet\Install-Package TheBetterPdfViewer.MAUI -Version 1.7.0
<PackageReference Include="TheBetterPdfViewer.MAUI" Version="1.7.0" />
<PackageVersion Include="TheBetterPdfViewer.MAUI" Version="1.7.0" />
<PackageReference Include="TheBetterPdfViewer.MAUI" />
paket add TheBetterPdfViewer.MAUI --version 1.7.0
#r "nuget: TheBetterPdfViewer.MAUI, 1.7.0"
#:package TheBetterPdfViewer.MAUI@1.7.0
#addin nuget:?package=TheBetterPdfViewer.MAUI&version=1.7.0
#tool nuget:?package=TheBetterPdfViewer.MAUI&version=1.7.0
TheBetterPdfViewer.MAUI
A .NET MAUI PDF viewer control with native rendering and embedded-video playback.
Features
- Annotations (highlight, ink, sticky notes, free text, signatures)
- User bookmarks + document outline navigation
- Form fields (text, checkbox, radio, signature) with XFDF export
- Save an annotated copy —
SaveDocumentAsync(path)flattens annotations, signatures and form-field ink into the pages. The result matches what the viewer displayed, and matches across devices: a file saved on Android and one saved on an iPad look the same. Form values, links, embedded video and the outline are preserved. UseExportAnnotationsAsyncinstead if you need the marks to stay editable. - Text search and selection
- Embedded video detection + playback — surfaces
/Movie,/Screen,/RichMedia, and/FileAttachmentannotations as well as document-level/Names /EmbeddedFilesentries. SetEnableInPageVideoOverlay="True"to mount tap-to-play ▶ buttons over each video's annotation rect on visible pages. - Tap-to-show toolbar — the floating toolbar starts hidden and
appears when the user taps the page, fading out again after five
seconds. Set
AutoShowToolbar="True"for the earlier behaviour: shown when the document opens and again whenever the page changes. - Zoom controls — zoom in / out / reset buttons in the built-in
toolbar on all platforms, alongside pinch-to-zoom. Bounds are
configurable via
MinZoomFactorandMaxZoomFactor;ResetZoom()returns to fit-page (SinglePage) or fit-width (Continuous). On iOS, MacCatalyst, and Android, the toolbar scrolls horizontally on narrow screens so every control stays reachable.
Platforms
- iOS 15+ (PDFKit + CoreGraphics CGPDFDocument; PDFium for saving)
- MacCatalyst 15+ (PDFKit + CoreGraphics CGPDFDocument; PDFium for saving)
- Android 33+ (PDFium)
- Windows (PDFium)
Annotations are drawn by one shared SkiaSharp painter on every platform, so they render identically wherever they are shown or saved.
Embedded video usage
// MauiProgram.cs - this also registers CommunityToolkit.Maui.MediaElement.
builder.UseTheBetterPdfViewer();
// XAML / code-behind
viewer.EmbeddedVideosChanged += (s, e) =>
{
foreach (var video in e.Videos)
Console.WriteLine($"p.{video.PageNumber} {video.AnnotationKind} {video.FileName}");
};
// Option 1: open a video at the user's request via the modal player.
await viewer.PlayEmbeddedVideoAsync(viewer.EmbeddedVideos[0]);
// Option 2: let the viewer overlay tappable ▶ buttons over each video
// annotation. Tapping a button opens the same modal player.
viewer.EnableInPageVideoOverlay = true;
License
MIT
1.7.0 notes
New: headless document API (all platforms, PDFium). PdfDocumentTools
reads page counts, page sizes and the outline, and ExtractPage writes one page
as a new unencrypted PDF. PdfDocumentBuilder builds a PDF by importing pages
from other files and composing simple pages: Helvetica text, images (a JPEG is
embedded as-is) and invisible link annotations, in top-left-origin point
coordinates. Text outside the WinAnsi (Western European) set is drawn as ?.
Calls are serialized with the library's other background PDFium work (such as
saving), but not with the viewer's own rendering on Android and Windows, so call
them from the viewer's (UI) thread.
PdfDocumentTools.ExtractPage(source, pageIndex: 2, "page3.pdf");
using var deck = new PdfDocumentBuilder();
deck.ImportPage("page3.pdf", 0);
var page = deck.AddPage(); // A4
var (w, _) = page.MeasureText("Intro video", 20);
page.DrawText("Intro video", (page.Width - w) / 2, 40, 20);
page.DrawImage(thumbnail, 60, 80, 475, 267);
page.AddLink(60, 80, 475, 267, "https://example.com/intro");
deck.Save("deck.pdf");
XFDF export is standard, and never empty. ExportAnnotationsAsync and
ExportFormDataAsync always write a complete document (<annots/> /
<fields/> when there is nothing). Annotations now carry rect and, for
highlights, coords (one quad per line) as attributes, with comma-separated ink
points — the shape Adobe and other XFDF readers expect; 1.6 wrote <rect>
elements and ;-separated points. Signed signature form fields are exported
as <ink subject="Signature"> in page coordinates (1.6 exported only
"[Signed]" in the form data), and signature annotations land where they were
drawn.
Links. PdfHyperlinkClickedEventArgs.RawUri is the link's /URI exactly as
stored in the PDF, and Uri is a safe parse that may be relative or null. A
relative link such as playvideo/123, or one with spaces, used to throw
(crashing Android and Windows) or be dropped (Apple). When no handler sets
Handled, iOS and MacCatalyst open only absolute http, https, mailto and
tel links; Android and Windows never open links themselves, as in 1.6. This
changes behaviour on Apple, which used to open every link: sms:, itms-apps:
and custom schemes are no longer opened by default, so handle HyperlinkClicked
to open them.
Load failures. PdfDocumentLoadFailedEventArgs.Reason says why a document
did not open (PasswordRequired, InvalidPassword, InvalidFormat,
FileNotFound, Unknown). Set Password and call the new Reload() to retry.
Android no longer raises DocumentLoaded for a document it could not open, and
iOS no longer shows a locked document as blank pages.
Page events. PageChanged.IsUserInitiated is now accurate on every
platform. A host GoToPage is programmatic, even when called from inside a
PageChanged handler, so reverting the user's flip works (on iOS and Mac it used
to leave the screen on the other page). The viewer's own controls (toolbar
page entry, QuickSwipe, bookmark taps, links to other pages) count as the user.
Android no longer reports every frame of a continuous-mode jump, iOS and Mac no
longer report a fake user change to page 1 when a document is reloaded, and
Windows no longer snaps the page back into place after the user scrolls.
Also: ClearFormData() resets the fields without re-raising
DocumentLoaded and keeps the page; ShowAnnotationButton now works on
Android, Windows and MacCatalyst (it was iOS only). On Windows, the code that
opens a PDF by path now accepts non-ASCII paths: the headless API,
PdfToImageConverter and embedded-video attachments. The Windows viewer itself
already loaded documents from memory and was not affected. Mac Catalyst: clicking
a link works (PDFKit there ignores link clicks); a page link raises
HyperlinkClicked with PageNumber, then navigates unless handled. iOS and Mac
Catalyst: documents open fitted (page in SinglePage, width in Continuous) and stay
fitted as the view resizes, and setting MinZoomFactor/MaxZoomFactor no longer
turns fitting off (Mac opened at scale 1; iOS drew its first frame at scale 1).
Breaking changes. new PdfHyperlinkClickedEventArgs(null, 3) no longer
compiles: null is ambiguous between the (Uri?, int?) and new
(string?, int?) constructors, so cast it ((Uri?)null).
ITheBetterPdfViewer gains Reload(), which implementers of the interface must
add. ClearFormData() no longer raises DocumentLoaded. The XFDF shape changed
(rect/coords attributes, comma-separated ink points; see above). On iOS and
MacCatalyst, unhandled links other than http, https, mailto and tel are
no longer opened (see Links).
1.6.6 notes
Fixes two iOS crashes.
- Closing a PDF crashed older iPads (iOS 15-17). 1.6.3 reduced this but did
not end it. The viewer listens for scroll changes on PDFKit's internal scroll
view, and that listener was never removed on close: .NET's
AddObserveronly unregisters while the scroll view's .NET wrapper is alive, and nothing kept it alive. When iOS freed the view it notified the dead listener. The handler now holds the scroll view until the listener is removed. - Drawing a page tile with no context crashed the app. PDFKit occasionally asks a page to draw with no context; the tile is now skipped instead.
1.6.5 notes
Behaviour change: the toolbar starts hidden. The floating toolbar no
longer appears when a document opens or when the page changes; the user taps
the page to bring it up, and it still fades after five seconds. Set
AutoShowToolbar="True" to keep the old behaviour.
Form-field text is one size everywhere. Text and choice fields used to size their text from the field's height, so a tall multi-line box drew its value several times bigger than a single-line field on the same form. Every field now draws at 12pt in black, shrinking only in a field too short to hold that. On iOS and macCatalyst the text was also drawn in Times, because the system font's name does not survive into the field's appearance; it is Helvetica now, which also reads correctly in a saved copy opened in another viewer.
1.6.2 notes
Fixes iOS App Store validation. 1.6.0 shipped PDFium as a loose dylib, which
Apple rejects (error 90171); 1.6.1 wrapped it in a framework whose declared
minimum OS did not match its binary, which Apple also rejects (ITMS-90208).
1.6.2 ships a signed pdfium.xcframework retargeted to iOS 15.0 with matching
metadata. Do not use 1.6.0 or 1.6.1 for iOS — both fail upload.
Regenerate it with build/make-pdfium-xcframework.sh after a PDFium bump.
1.6.0 notes
Saving. SaveDocumentAsync(Stream) and SaveDocumentAsync(string) write a
copy with annotations flattened in; the source file is never modified. The
flattened marks are not editable annotations in the saved file — that is the
trade that makes the file match the screen.
One exception, iOS and macCatalyst only: a document that has form fields loses its embedded video when saved. Live form values exist inside PDFKit's widgets and nowhere else, so those documents must be serialized by PDFKit, and that serializer drops embedded media. Documents without form fields are read from the original file and keep everything. Android and Windows are never affected.
Cross-device rendering, measured. Annotating the same document on an Android tablet and an iPhone simulator and diffing the two saved PDFs: highlights, ink, notes and signatures come out pixel-identical. Text annotations do not quite — glyph-edge antialiasing differs, 2,165 pixels of a 1600x900 render (0.15%), entirely inside the text's own bounding box and indistinguishable side by side at 4x magnification. It is not hinting or edging settings, and not the glyph rasterizer (drawing glyphs as filled outlines instead changed almost nothing); the likeliest cause is a sub-pixel baseline difference from font metrics. If you need text bit-identical too, that is where to look.
Behaviour change: annotation anchors. Note and text annotations now anchor
consistently across platforms — NoteX/NoteY is the top-left corner for
both. Annotations persisted by an earlier version will shift the first time
1.6.0 displays them: notes on iOS and macCatalyst, text on Android. This is a
one-time correction and nothing needs migrating.
Fixed, Windows only: ink drew at half the requested width, the note icon was fixed at 16 device pixels and never scaled with zoom, and signatures ignored the chosen colour in favour of hardcoded dark blue. Text annotations were XAML overlays above the page image, so they never appeared in exported or bitmap output at all.
Fixed, iOS and macCatalyst: a large ink stroke's bounding box no longer swallows taps on links drawn inside it.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-android36.0 is compatible. net10.0-ios26.0 is compatible. net10.0-maccatalyst26.0 is compatible. net10.0-windows10.0.19041 is compatible. |
-
net10.0-android36.0
- bblanchon.PDFium.Android (>= 146.0.7678)
- CommunityToolkit.Maui.MediaElement (>= 8.0.0)
- Microsoft.Maui.Controls (>= 10.0.40)
- PdfPig (>= 0.1.10)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.NativeAssets.Android (>= 3.116.1)
-
net10.0-ios26.0
- bblanchon.PDFium.iOS (>= 146.0.7678)
- CommunityToolkit.Maui.MediaElement (>= 8.0.0)
- Microsoft.Maui.Controls (>= 10.0.40)
- PdfPig (>= 0.1.10)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.NativeAssets.iOS (>= 3.116.1)
-
net10.0-maccatalyst26.0
- bblanchon.PDFium.iOS (>= 146.0.7678)
- CommunityToolkit.Maui.MediaElement (>= 8.0.0)
- Microsoft.Maui.Controls (>= 10.0.40)
- PdfPig (>= 0.1.10)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.NativeAssets.MacCatalyst (>= 3.116.1)
-
net10.0-windows10.0.19041
- bblanchon.PDFium.Win32 (>= 146.0.7678)
- CommunityToolkit.Maui.MediaElement (>= 8.0.0)
- Microsoft.Maui.Controls (>= 10.0.40)
- PdfPig (>= 0.1.10)
- SkiaSharp (>= 3.116.1)
- SkiaSharp.NativeAssets.Win32 (>= 3.116.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.7.1 | 47 | 9/25/2026 |
| 1.7.0 | 45 | 9/25/2026 |
| 1.6.6 | 48 | 9/24/2026 |
| 1.6.5 | 99 | 9/18/2026 |
| 1.6.4 | 89 | 9/16/2026 |
| 1.6.3 | 103 | 9/10/2026 |
| 1.6.2 | 122 | 8/22/2026 |
| 1.6.1 | 98 | 8/21/2026 |
| 1.5.1 | 106 | 8/19/2026 |
| 1.5.0 | 96 | 8/19/2026 |
| 1.4.7 | 139 | 7/22/2026 |
| 1.4.6 | 121 | 7/17/2026 |
| 1.4.5 | 114 | 7/17/2026 |
| 1.4.4 | 113 | 7/16/2026 |
| 1.4.3 | 110 | 7/13/2026 |
| 1.4.2 | 117 | 7/13/2026 |
| 1.4.1 | 126 | 7/10/2026 |
| 1.4.0 | 152 | 5/28/2026 |
| 1.3.0 | 128 | 5/8/2026 |