| Crates.io | tauri-plugin-pldownloader |
| lib.rs | tauri-plugin-pldownloader |
| version | 1.0.1 |
| created_at | 2025-09-10 10:03:00.96853+00 |
| updated_at | 2025-09-20 04:46:40.814953+00 |
| description | Tauri plugin for cross-platform file downloading (Android/iOS) with public/private destinations and a TypeScript client. |
| homepage | https://github.com/lecaobaophuc0912/tauri-plugin-pldownloader |
| repository | https://github.com/lecaobaophuc0912/tauri-plugin-pldownloader |
| max_upload_size | |
| id | 1832323 |
| size | 206,159 |
A Tauri plugin for cross-platform file downloading with a unified API for Android and iOS. It supports public downloads (visible to users in Photos/Files) and private downloads (stored in app sandbox for internal use or sharing via share sheet).
| Platform | Status | Notes |
|---|---|---|
| iOS | ✅ Full | Save to Photos (media) or Files (non-media) |
| Android | ✅ Full | MediaStore (public) and app external files (private) |
| macOS | ❌ Not supported | Not supported yet |
| Windows | ❌ Not supported | Not supported yet |
| Linux | ❌ Not supported | Not supported yet |
Add to your app Cargo.toml:
[dependencies]
tauri-plugin-pldownloader = "0.1.0"
Or use cargo add:
cargo add tauri-plugin-pldownloader
(If you publish a separate guest-js package) install the client API:
npm install tauri-plugin-pldownloader-api
# or
yarn add tauri-plugin-pldownloader-api
Or call commands directly using @tauri-apps/api invoke (see API section).
In your app src-tauri/src/lib.rs:
fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_pldownloader::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
If you use helpers from tauri-plugin-pldownloader-api:
import {
downloadPrivate,
downloadPublic,
saveFilePrivateFromBuffer,
saveFilePublicFromBuffer,
ping,
copyFilePath,
} from "tauri-plugin-pldownloader-api";
// Ping
const echo = await ping("hello");
// Private download (stored in sandbox, not visible in Files/Photos)
const r1 = await downloadPrivate({
url: "https://example.com/file.pdf",
fileName: "document.pdf", // optional
});
// r1 => { fileName: 'document.pdf', path: '/var/mobile/.../Application Support/Downloads/document.pdf' }
// Public download
// - Media (image/video): save to Photos, return uri = localIdentifier
// - Non-media (pdf, docx, xlsx...): save to Files (On My iPhone > <AppName>)
const r2 = await downloadPublic({
url: "https://example.com/cat.jpg",
fileName: "cat.jpg", // optional
mimeType: "image/jpeg", // optional (helps accurate media detection)
});
// r2 media => { fileName: 'cat.jpg', uri: 'XXXXXXXX-XXXX...' }
// r2 non-media => { fileName: 'report.xlsx', path: '/var/mobile/.../Documents/<AppName>/report.xlsx' }
// Save from ArrayBuffer (for large files, avoids base64 overhead)
const response = await fetch("https://example.com/large-file.zip");
const blob = await response.blob();
const arrayBuffer = await blob.arrayBuffer();
// Save privately from buffer
const r3 = await saveFilePrivateFromBuffer({
data: arrayBuffer,
fileName: "large-file.zip",
});
// r3 => { fileName: 'large-file.zip', path: '/var/mobile/.../Application Support/Downloads/large-file.zip' }
// Save publicly from buffer
const r4 = await saveFilePublicFromBuffer({
data: arrayBuffer,
fileName: "large-file.zip",
mimeType: "application/zip", // optional
});
// r4 => { fileName: 'large-file.zip', path: '/var/mobile/.../Documents/<AppName>/large-file.zip' }
// Copy file from A to B (desktop/mobile)
const destPath = await copyFilePath(
"/path/src/file.pdf",
"/path/dest/file.pdf"
);
If you want to call invoke yourself:
import { invoke } from "@tauri-apps/api/core";
await invoke("plugin:pldownloader|download_public", {
payload: { url, fileName, mimeType },
});
await invoke("plugin:pldownloader|download_private", {
payload: { url, fileName },
});
await invoke("plugin:pldownloader|save_file_public_from_buffer", {
payload: { data: arrayBuffer, fileName, mimeType },
});
await invoke("plugin:pldownloader|save_file_private_from_buffer", {
payload: { data: arrayBuffer, fileName },
});
export interface DownloadPrivateRequest {
url: string;
fileName?: string;
}
export interface DownloadPublicRequest {
url: string;
fileName?: string;
mimeType?: string;
}
export interface SaveFilePrivateFromBufferRequest {
data: ArrayBuffer;
fileName: string;
}
export interface SaveFilePublicFromBufferRequest {
data: ArrayBuffer;
fileName: string;
mimeType?: string;
}
export interface DownloadResponse {
fileName: string;
path?: string; // When saved to Files/sandbox
uri?: string; // When saved to Photos (iOS) or a MediaStore URI (Android if applicable)
}
ping(value: string): Promise<string | null>
downloadPrivate(payload: DownloadPrivateRequest): Promise<DownloadResponse>
Application Support/Downloads (sandbox, not visible in Files/Photos). Returns path.path.downloadPublic(payload: DownloadPublicRequest): Promise<DownloadResponse>
PHPhotoLibrary, returns uri (localIdentifier).Documents/<AppName>/, visible in Files (On My iPhone), returns path.uri.saveFilePrivateFromBuffer(payload: SaveFilePrivateFromBufferRequest): Promise<DownloadResponse>
Application Support/Downloads (sandbox, not visible in Files/Photos). Returns path.path.saveFilePublicFromBuffer(payload: SaveFilePublicFromBufferRequest): Promise<DownloadResponse>
PHPhotoLibrary, returns uri (localIdentifier).Documents/<AppName>/, visible in Files (On My iPhone), returns path.uri.copyFilePath(src: string, dest: string): Promise<string>
downloadPublic or saveFilePublicFromBuffer with an image mimeType to save directly to Photos.downloadPublic (non-media) → appears in Files.downloadPrivate or saveFilePrivateFromBuffer then use the returned path for the share sheet.saveFilePublicFromBuffer or saveFilePrivateFromBuffer to avoid base64 encoding overhead when saving ArrayBuffer data.<key>NSPhotoLibraryAddUsageDescription</key>
<string>We need access to your photo library to save the downloaded file.</string>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
MediaStore to save to public Downloads; no write permission needed on Android 10+.# Build Rust plugin
cargo build
# Build JavaScript/TypeScript client (if applicable)
yarn build
# Run Rust tests
cargo test
# Run example app
cd examples/tauri-app
cargo tauri dev
PHPhotoLibrary. Ensure NSPhotoLibraryAddUsageDescription is present.PRs are welcome!
MIT – see LICENSE.