
Unified, type-safe API for picking, saving, capturing, sharing and reading files: single/multi/directory selection, camera photo/video, save dialog, share sheets, compose-first integration and runtime capability checks.
Complete File Operations for Kotlin Multiplatform
A unified, type-safe API for file picking, saving, camera capture, and sharing across Android, iOS, Desktop, and Web.
| Feature | Android | iOS | Desktop | Web (JS) | WASM |
|---|---|---|---|---|---|
| Pick Files | ✅ | ✅ | ✅ | ✅ | ❌ |
| Pick Multiple | ✅ | ✅ | ✅ | ✅ | ❌ |
| Pick Directory | ✅ | ✅ | ✅ | ✅ | ❌ |
| Save Files | ✅ | ✅ | ✅ | ✅ | ❌ |
| Capture Photo | ✅ | ✅ | ❌ | ❌ | ❌ |
| Capture Video | ✅ | ✅ | ❌ | ❌ | ❌ |
| Share | ✅ | ✅ | ❌ | ||
| Read Files | ✅ | ✅ | ✅ | ❌ | ❌ |
dependencies {
implementation("in.sitharaj.parcel:parcel:1.0.0")
}@Composable
fun FilePickerDemo() {
val launcher = rememberParcelLauncher(
onPickResult = { result ->
result.onSuccess { file ->
println("Picked: ${file.name} (${file.size} bytes)")
}.onCancelled {
println("Cancelled")
}.onError { e ->
println("Error: ${e.message}")
}
}
)
Button(onClick = {
launcher.pickFile(PickConfig.build {
types(FileType.Images, FileType.Documents)
title("Select a file")
})
}) {
Text("Pick File")
}
}launcher.pickMultiple(PickConfig.build {
types(FileType.Images)
maxCount(5)
})launcher.pickDirectory("Select folder") { result ->
result.onSuccess { dir ->
println("Selected: ${dir.name}")
}
}val data = "Hello, World!".encodeToByteArray()
launcher.saveFile(data, SaveConfig.build {
suggestedName("document.txt")
mimeType("text/plain")
}) { result ->
result.onSuccess { file ->
println("Saved to: ${file.uri}")
}
}// Capture photo
launcher.capturePhoto(CaptureConfig.build {
useFrontCamera(false)
}) { result ->
result.onSuccess { photo ->
println("Photo: ${photo.uri}")
}
}
// Capture video
launcher.captureVideo(CaptureConfig.build {
maxDuration(60)
videoQuality(VideoQuality.High)
}) { result ->
result.onSuccess { video ->
println("Video: ${video.uri}")
}
}// Share text
launcher.share(ShareContent.Text(
text = "Check this out!",
subject = "Amazing content"
))
// Share URL
launcher.share(ShareContent.Url(
url = "https://github.com/sitharaj88/parcel-kmp"
))
// Share file
launcher.share(ShareContent.File(
uri = fileUri,
mimeType = "image/png"
))
// Share files
launcher.share(ShareContent.Files(
uris = listOf(file1, file2),
mimeType = "image/*"
))launcher.readText(file) { result ->
result.onSuccess { content ->
println("Content: $content")
}
}
launcher.readBytes(file) { result ->
result.onSuccess { bytes ->
println("Size: ${bytes.size}")
}
}FileType.All // All files
FileType.Images // jpg, png, gif, webp, heic...
FileType.Videos // mp4, mov, avi, mkv...
FileType.Audio // mp3, wav, aac, flac...
FileType.Documents // pdf, doc, docx, txt, csv...
FileType.Custom(listOf("application/json"))PickConfig.build {
types(FileType.Images) // File type filters
maxCount(10) // Max for multi-select
title("Select") // Dialog title
initialDirectory("/path") // Start directory
}SaveConfig.build {
suggestedName("doc.pdf") // Default filename
mimeType("application/pdf")
title("Save As")
}CaptureConfig.build {
useFrontCamera(true) // Front/back camera
videoQuality(VideoQuality.High)
maxDuration(120) // Seconds (video)
}Check platform support at runtime:
if (ParcelCapabilities.canCapturePhoto) {
// Show camera button
}
if (ParcelCapabilities.canShare) {
// Show share button
}┌─────────────────────────────────────────────────────────────────┐
│ Parcel API (Common) │
│ ┌─────────┐ ┌──────┐ ┌─────────┐ ┌───────┐ ┌───────┐ ┌──────┐ │
│ │ pick │ │ save │ │ capture │ │ share │ │ read │ │ dir │ │
│ └─────────┘ └──────┘ └─────────┘ └───────┘ └───────┘ └──────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Android │ iOS │ Desktop │ Web (JS) │ WASM │
│ ──────────── │ ─────────── │ ────────── │ ────────── │ ─────── │
│ ActivityRes │ UIDocument │ JFileChoos │ input │ Stub │
│ TakePicture │ Picker+Cam │ FileDialog │ Web Share │ │
│ Intent.SEND │ UIActivity │ Desktop │ Blob │ │
└─────────────────────────────────────────────────────────────────┘
Copyright 2024 Sitharaj Seenivasan
Licensed under the Apache License, Version 2.0
Complete File Operations for Kotlin Multiplatform
A unified, type-safe API for file picking, saving, camera capture, and sharing across Android, iOS, Desktop, and Web.
| Feature | Android | iOS | Desktop | Web (JS) | WASM |
|---|---|---|---|---|---|
| Pick Files | ✅ | ✅ | ✅ | ✅ | ❌ |
| Pick Multiple | ✅ | ✅ | ✅ | ✅ | ❌ |
| Pick Directory | ✅ | ✅ | ✅ | ✅ | ❌ |
| Save Files | ✅ | ✅ | ✅ | ✅ | ❌ |
| Capture Photo | ✅ | ✅ | ❌ | ❌ | ❌ |
| Capture Video | ✅ | ✅ | ❌ | ❌ | ❌ |
| Share | ✅ | ✅ | ❌ | ||
| Read Files | ✅ | ✅ | ✅ | ❌ | ❌ |
dependencies {
implementation("in.sitharaj.parcel:parcel:1.0.0")
}@Composable
fun FilePickerDemo() {
val launcher = rememberParcelLauncher(
onPickResult = { result ->
result.onSuccess { file ->
println("Picked: ${file.name} (${file.size} bytes)")
}.onCancelled {
println("Cancelled")
}.onError { e ->
println("Error: ${e.message}")
}
}
)
Button(onClick = {
launcher.pickFile(PickConfig.build {
types(FileType.Images, FileType.Documents)
title("Select a file")
})
}) {
Text("Pick File")
}
}launcher.pickMultiple(PickConfig.build {
types(FileType.Images)
maxCount(5)
})launcher.pickDirectory("Select folder") { result ->
result.onSuccess { dir ->
println("Selected: ${dir.name}")
}
}val data = "Hello, World!".encodeToByteArray()
launcher.saveFile(data, SaveConfig.build {
suggestedName("document.txt")
mimeType("text/plain")
}) { result ->
result.onSuccess { file ->
println("Saved to: ${file.uri}")
}
}// Capture photo
launcher.capturePhoto(CaptureConfig.build {
useFrontCamera(false)
}) { result ->
result.onSuccess { photo ->
println("Photo: ${photo.uri}")
}
}
// Capture video
launcher.captureVideo(CaptureConfig.build {
maxDuration(60)
videoQuality(VideoQuality.High)
}) { result ->
result.onSuccess { video ->
println("Video: ${video.uri}")
}
}// Share text
launcher.share(ShareContent.Text(
text = "Check this out!",
subject = "Amazing content"
))
// Share URL
launcher.share(ShareContent.Url(
url = "https://github.com/sitharaj88/parcel-kmp"
))
// Share file
launcher.share(ShareContent.File(
uri = fileUri,
mimeType = "image/png"
))
// Share files
launcher.share(ShareContent.Files(
uris = listOf(file1, file2),
mimeType = "image/*"
))launcher.readText(file) { result ->
result.onSuccess { content ->
println("Content: $content")
}
}
launcher.readBytes(file) { result ->
result.onSuccess { bytes ->
println("Size: ${bytes.size}")
}
}FileType.All // All files
FileType.Images // jpg, png, gif, webp, heic...
FileType.Videos // mp4, mov, avi, mkv...
FileType.Audio // mp3, wav, aac, flac...
FileType.Documents // pdf, doc, docx, txt, csv...
FileType.Custom(listOf("application/json"))PickConfig.build {
types(FileType.Images) // File type filters
maxCount(10) // Max for multi-select
title("Select") // Dialog title
initialDirectory("/path") // Start directory
}SaveConfig.build {
suggestedName("doc.pdf") // Default filename
mimeType("application/pdf")
title("Save As")
}CaptureConfig.build {
useFrontCamera(true) // Front/back camera
videoQuality(VideoQuality.High)
maxDuration(120) // Seconds (video)
}Check platform support at runtime:
if (ParcelCapabilities.canCapturePhoto) {
// Show camera button
}
if (ParcelCapabilities.canShare) {
// Show share button
}┌─────────────────────────────────────────────────────────────────┐
│ Parcel API (Common) │
│ ┌─────────┐ ┌──────┐ ┌─────────┐ ┌───────┐ ┌───────┐ ┌──────┐ │
│ │ pick │ │ save │ │ capture │ │ share │ │ read │ │ dir │ │
│ └─────────┘ └──────┘ └─────────┘ └───────┘ └───────┘ └──────┘ │
├─────────────────────────────────────────────────────────────────┤
│ Android │ iOS │ Desktop │ Web (JS) │ WASM │
│ ──────────── │ ─────────── │ ────────── │ ────────── │ ─────── │
│ ActivityRes │ UIDocument │ JFileChoos │ input │ Stub │
│ TakePicture │ Picker+Cam │ FileDialog │ Web Share │ │
│ Intent.SEND │ UIActivity │ Desktop │ Blob │ │
└─────────────────────────────────────────────────────────────────┘
Copyright 2024 Sitharaj Seenivasan
Licensed under the Apache License, Version 2.0