PdfViewer.Android
2.3.7
dotnet add package PdfViewer.Android --version 2.3.7
NuGet\Install-Package PdfViewer.Android -Version 2.3.7
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PdfViewer.Android" Version="2.3.7" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PdfViewer.Android" Version="2.3.7" />
<PackageReference Include="PdfViewer.Android" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PdfViewer.Android --version 2.3.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: PdfViewer.Android, 2.3.7"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PdfViewer.Android@2.3.7
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PdfViewer.Android&version=2.3.7
#tool nuget:?package=PdfViewer.Android&version=2.3.7
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
PdfViewer.Android - .NET for Android Binding
A .NET for Android (formerly Xamarin.Android) binding library for afreakyelf/Pdf-Viewer - a lightweight (~328KB) PDF viewer using Android's native PdfRenderer.
Features
- 📄 Load PDFs from URL, file path, assets, or content URI
- 🔍 Pinch-to-zoom with smooth rendering
- 📱 Full-screen activity or embeddable view
- 📊 Progress, page change, and zoom callbacks
- 🎨 Customizable themes and toolbar styles
- 💾 Download PDFs to storage
- 🔄 Page navigation with smooth scrolling
Installation
<PackageReference Include="PdfViewer.Android" Version="2.3.7" />
Quick Start
Option 1: Launch Full-Screen Viewer
using PdfViewer.Wrappers;
using PdfViewer.Util;
// From URL
PdfViewerManager.LaunchFromUrl(
context: this,
url: "https://example.com/document.pdf",
title: "My Document",
saveToDownloads: false,
enableDownload: true,
enableZoom: true);
// From local file path
PdfViewerManager.LaunchFromPath(
context: this,
filePath: "/path/to/document.pdf",
title: "Local PDF",
saveToDownloads: false,
fromAssets: false,
enableZoom: true);
// From Assets folder
PdfViewerManager.LaunchFromPath(
context: this,
filePath: "sample.pdf",
title: "Sample PDF",
fromAssets: true);
Option 2: Embed PdfRendererView in Layout
AXML Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.rajat.pdfviewer.PdfRendererView
android:id="@+id/pdfView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
C# Activity Code:
using Android.Content;
using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
using PdfViewer.Wrappers;
using PdfViewer.Util;
using PdfViewer;
[Activity(Label = "PDF Viewer", MainLauncher = true, Theme = "@style/Theme.AppCompat.Light.NoActionBar")]
public class MainActivity : AppCompatActivity
{
private PdfRendererView? _pdfView;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
_pdfView = FindViewById<PdfRendererView>(Resource.Id.pdfView);
if (_pdfView == null) return;
// Enable zoom
_pdfView.ZoomEnabled = true;
// Set up status listener
var statusListener = new PdfStatusListener();
statusListener.PageChanged += (s, e) =>
Console.WriteLine($"Page {e.CurrentPage + 1}/{e.TotalPages}");
statusListener.Error += (s, e) =>
Console.WriteLine($"Error: {e.Message}");
_pdfView.StatusListener = statusListener;
// Load PDF from URL
LoadPdfFromUrl("https://www.princexml.com/samples/icelandic/dictionary.pdf");
}
private void LoadPdfFromUrl(string url)
{
if (_pdfView == null) return;
// Get lifecycle scope for coroutine support
var scope = LifecycleOwnerKt.GetLifecycleScope(this);
_pdfView.InitWithUrl(
url,
new HeaderData(),
scope,
this.Lifecycle,
CacheStrategy.MaximizePerformance!);
}
}
Complete Example with All Features
using Android.Content;
using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
using PdfViewer.Wrappers;
using PdfViewer.Util;
using PdfViewer;
public class MainActivity : AppCompatActivity
{
private PdfRendererView? _pdfView;
private ProgressBar? _progressBar;
private int _currentPage;
private int _totalPages;
private const int FilePickerRequestCode = 100;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
_pdfView = FindViewById<PdfRendererView>(Resource.Id.pdfView);
_progressBar = FindViewById<ProgressBar>(Resource.Id.progressBar);
if (_pdfView == null) return;
// Enable zoom
_pdfView.ZoomEnabled = true;
// Set up comprehensive status listener
var statusListener = new PdfStatusListener();
statusListener.PdfLoadStarted += (s, e) =>
{
RunOnUiThread(() =>
{
_progressBar!.Progress = 0;
_progressBar.Visibility = Android.Views.ViewStates.Visible;
});
};
statusListener.PdfLoadProgress += (s, e) =>
{
RunOnUiThread(() =>
{
_progressBar!.Progress = e.Progress;
var totalMB = e.TotalBytes.HasValue
? $"/{e.TotalBytes.Value / 1024.0 / 1024.0:F2}MB"
: "";
Console.WriteLine($"Downloading: {e.Progress}% ({e.DownloadedBytes / 1024.0 / 1024.0:F2}MB{totalMB})");
});
};
statusListener.PdfLoadSuccess += (s, path) =>
{
RunOnUiThread(() =>
{
_progressBar!.Visibility = Android.Views.ViewStates.Gone;
Console.WriteLine($"PDF loaded: {System.IO.Path.GetFileName(path)}");
});
};
statusListener.PdfRenderSuccess += (s, e) =>
{
RunOnUiThread(() =>
{
_progressBar!.Visibility = Android.Views.ViewStates.Gone;
Console.WriteLine("PDF rendered successfully");
});
};
statusListener.PageChanged += (s, e) =>
{
_currentPage = e.CurrentPage;
_totalPages = e.TotalPages;
RunOnUiThread(() =>
{
Console.WriteLine($"Page {e.CurrentPage + 1}/{e.TotalPages}");
});
};
statusListener.Error += (s, e) =>
{
RunOnUiThread(() =>
{
_progressBar!.Visibility = Android.Views.ViewStates.Gone;
Console.WriteLine($"Error: {e.Message}");
});
};
_pdfView.StatusListener = statusListener;
// Set up zoom listener
var zoomListener = new PdfZoomListener();
zoomListener.ZoomChanged += (s, e) =>
{
RunOnUiThread(() =>
{
var zoomState = e.IsZoomedIn ? "Zoomed In" : "Normal";
Console.WriteLine($"Zoom: {e.Scale:P0} ({zoomState})");
});
};
_pdfView.ZoomListener = zoomListener;
// Load default PDF
LoadPdfFromUrl("https://www.princexml.com/samples/icelandic/dictionary.pdf");
}
private void LoadPdfFromUrl(string url)
{
if (_pdfView == null) return;
// Close any existing PDF before loading a new one
_pdfView.ClosePdfRender();
var scope = LifecycleOwnerKt.GetLifecycleScope(this);
_pdfView.InitWithUrl(
url,
new HeaderData(),
scope,
this.Lifecycle,
CacheStrategy.MaximizePerformance!);
}
// Page navigation
private void GoToPreviousPage()
{
if (_currentPage > 0)
_pdfView?.JumpToPage(_currentPage - 1, smoothScroll: true, delayMillis: 300);
}
private void GoToNextPage()
{
if (_currentPage < _totalPages - 1)
_pdfView?.JumpToPage(_currentPage + 1, smoothScroll: true, delayMillis: 300);
}
// Load from file picker
private void OpenFilePicker()
{
var intent = new Intent(Intent.ActionGetContent);
intent.SetType("application/pdf");
StartActivityForResult(intent, FilePickerRequestCode);
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent? data)
{
base.OnActivityResult(requestCode, resultCode, data);
if (requestCode == FilePickerRequestCode && resultCode == Result.Ok && data?.Data != null)
{
var uri = data.Data;
var filePath = CopyUriToTempFile(uri);
if (filePath != null)
{
_pdfView?.ClosePdfRender();
_pdfView?.InitWithFile(
new Java.IO.File(filePath),
CacheStrategy.MaximizePerformance!);
}
}
}
private string? CopyUriToTempFile(Android.Net.Uri uri)
{
try
{
var inputStream = ContentResolver?.OpenInputStream(uri);
if (inputStream == null) return null;
var tempFile = Java.IO.File.CreateTempFile("temp_pdf", ".pdf", CacheDir);
var outputStream = new Java.IO.FileOutputStream(tempFile);
var buffer = new byte[8192];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer)) > 0)
{
outputStream.Write(buffer, 0, bytesRead);
}
inputStream.Close();
outputStream.Close();
return tempFile.AbsolutePath;
}
catch (Exception ex)
{
Console.WriteLine($"Error copying file: {ex.Message}");
return null;
}
}
}
API Reference
PdfRendererView Properties
| Property | Type | Description |
|---|---|---|
StatusListener |
PdfRendererView.IStatusCallBack |
Set callbacks for load/render events |
ZoomListener |
PdfRendererView.IZoomListener |
Set callbacks for zoom events |
ZoomEnabled |
bool |
Enable/disable pinch-to-zoom |
PdfRendererView Methods
| Method | Description |
|---|---|
InitWithUrl(url, headers, scope, lifecycle, cacheStrategy) |
Load PDF from URL |
InitWithFile(file, cacheStrategy) |
Load PDF from local file |
JumpToPage(pageNumber, smoothScroll, delayMillis) |
Navigate to specific page |
ClosePdfRender() |
Close current PDF and release resources |
PdfStatusListener Events
| Event | Arguments | Description |
|---|---|---|
PdfLoadStarted |
EventArgs |
PDF loading started |
PdfLoadProgress |
PdfLoadProgressEventArgs |
Download progress update |
PdfLoadSuccess |
string (file path) |
PDF loaded successfully |
PdfRenderStarted |
EventArgs |
PDF rendering started |
PdfRenderSuccess |
EventArgs |
PDF rendered successfully |
PageChanged |
PageChangedEventArgs |
Current page changed |
Error |
Throwable |
Error occurred |
PdfZoomListener Events
| Event | Arguments | Description |
|---|---|---|
ZoomChanged |
ZoomChangedEventArgs |
Zoom level changed |
Event Arguments
// PdfLoadProgressEventArgs
public record PdfLoadProgressEventArgs(
int Progress, // 0-100 percentage
long DownloadedBytes, // Bytes downloaded
long? TotalBytes); // Total size (null if unknown)
// PageChangedEventArgs
public record PageChangedEventArgs(
int CurrentPage, // 0-based page index
int TotalPages); // Total page count
// ZoomChangedEventArgs
public record ZoomChangedEventArgs(
bool IsZoomedIn, // True if zoomed beyond 1.0
float Scale); // Current zoom scale
Requirements
- .NET 10.0 Android or later
- Minimum SDK: 21 (Android 5.0)
- Target SDK: 36 (Android 16)
Dependencies
The binding automatically includes required dependencies:
- Xamarin.Kotlin.StdLib
- Xamarin.AndroidX.Core
- Xamarin.AndroidX.AppCompat
- Xamarin.AndroidX.RecyclerView
- Xamarin.AndroidX.Lifecycle.Runtime.Ktx
- Xamarin.KotlinX.Coroutines.Android
- Square.OkHttp3
Permissions
Add to your AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
License
Original library: MIT License by afreakyelf
.NET Binding: MIT License
Credits
- Original Android library by Rajat Mittal (afreakyelf)
- .NET binding by Nkkinsoft
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0-android36.0 is compatible. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net10.0-android36.0
- Square.OkHttp3 (>= 5.3.0)
- Xamarin.AndroidX.Activity.Ktx (>= 1.11.0)
- Xamarin.AndroidX.AppCompat (>= 1.7.1.1)
- Xamarin.AndroidX.ConstraintLayout (>= 2.2.1.3)
- Xamarin.AndroidX.Core (>= 1.17.0)
- Xamarin.AndroidX.DataBinding.ViewBinding (>= 8.13.1)
- Xamarin.AndroidX.Lifecycle.Runtime.Ktx (>= 2.9.4)
- Xamarin.AndroidX.Lifecycle.ViewModel.Ktx (>= 2.9.4)
- Xamarin.AndroidX.RecyclerView (>= 1.4.0.3)
- Xamarin.Google.Android.Material (>= 1.13.0)
- Xamarin.Kotlin.StdLib (>= 2.2.21)
- Xamarin.KotlinX.Coroutines.Android (>= 1.10.2.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 |
|---|---|---|
| 2.3.7 | 490 | 12/10/2025 |