@daniele-rolli/capacitor-scoped-storage
v0.0.3
Published
A Capacitor plugin adds support for scoped storage on Android and iOS.
Downloads
173
Readme
🗂️ Capacitor Scoped Storage
A Capacitor plugin for secure, user-approved file and folder access on iOS and Android, built on top of platform-native Security Scoped Bookmarks (iOS) and Storage Access Framework (SAF) (Android).
This plugin lets your app request a folder from the user and then perform safe file operations (read, write, append, delete, move, copy, stat, etc.) within that scope, with persistent access across app restarts.
👉 For a real-world setup, check out the example-app with a full implementation.
✨ Features
- 🔒 Scoped access: Operates only within the folder the user selects
- 📂 Cross-platform:
- iOS → Security-scoped bookmarks
- Android → Storage Access Framework (SAF)
- 📑 File operations:
readFile,writeFile,appendFile,deleteFile - 📦 Directory management:
mkdir,rmdir,readdir - 🔍 Metadata utilities:
stat,exists - 📎 Path management:
move,copy,getUriForPath - Persistent folder permissions (reusable bookmarks/tree URIs)
- UTF-8 and Base64 encoding support
📦 Installation
npm install @daniele-rolli/capacitor-scoped-storage
npx cap syncRequirements:
- iOS deployment target: 14.0+
- Android: API 21+
🛠 Usage
Pick a Folder
const { folder } = await ScopedStorage.pickFolder();
// { folder: { id: "...", name: "Documents" } }Write & Read a File
await ScopedStorage.writeFile({
folder,
path: 'notes/today.txt',
data: 'Hello world!',
});
const res = await ScopedStorage.readFile({
folder,
path: 'notes/today.txt',
});
console.log(res.data); // "Hello world!"List Directory Contents
const { entries } = await ScopedStorage.readdir({ folder, path: 'notes' });
console.log(entries);
// [{ name: "today.txt", isDir: false, size: 123, mtime: 1710000000 }]Move & Copy
await ScopedStorage.move({
folder,
from: 'notes/today.txt',
to: 'archive/today.txt',
overwrite: true,
});
await ScopedStorage.copy({
folder,
from: 'archive/today.txt',
to: 'backup/today.txt',
});📚 API Reference
pickFolder()writeFile(...)appendFile(...)readFile(...)mkdir(...)rmdir(...)readdir(...)stat(...)exists(...)deleteFile(...)move(...)copy(...)getUriForPath(...)- Interfaces
- Type Aliases
pickFolder()
pickFolder() => Promise<PickFolderResult>Returns: Promise<PickFolderResult>
writeFile(...)
writeFile(options: WriteOptions) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------- |
| options | WriteOptions |
appendFile(...)
appendFile(options: AppendOptions) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------- |
| options | WriteOptions |
readFile(...)
readFile(options: ReadOptions) => Promise<{ data: string; }>| Param | Type |
| ------------- | --------------------------------------------------- |
| options | ReadOptions |
Returns: Promise<{ data: string; }>
mkdir(...)
mkdir(options: MkdirOptions) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------- |
| options | MkdirOptions |
rmdir(...)
rmdir(options: RmdirOptions) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------- |
| options | RmdirOptions |
readdir(...)
readdir(options: ReaddirOptions) => Promise<ReaddirResult>| Param | Type |
| ------------- | --------------------------------------------------------- |
| options | ReaddirOptions |
Returns: Promise<ReaddirResult>
stat(...)
stat(options: StatOptions) => Promise<StatResult>| Param | Type |
| ------------- | --------------------------------------------------- |
| options | StatOptions |
Returns: Promise<StatResult>
exists(...)
exists(options: ExistsOptions) => Promise<ExistsResult>| Param | Type |
| ------------- | ------------------------------------------------------- |
| options | ExistsOptions |
Returns: Promise<ExistsResult>
deleteFile(...)
deleteFile(options: DeleteOptions) => Promise<void>| Param | Type |
| ------------- | ------------------------------------------------------- |
| options | DeleteOptions |
move(...)
move(options: MoveCopyOptions) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | MoveCopyOptions |
copy(...)
copy(options: MoveCopyOptions) => Promise<void>| Param | Type |
| ------------- | ----------------------------------------------------------- |
| options | MoveCopyOptions |
getUriForPath(...)
getUriForPath(options: UriForPathOptions) => Promise<UriForPathResult>| Param | Type |
| ------------- | --------------------------------------------------------------- |
| options | UriForPathOptions |
Returns: Promise<UriForPathResult>
Interfaces
PickFolderResult
| Prop | Type |
| ------------ | ----------------------------------------------- |
| folder | FolderRef |
FolderRef
| Prop | Type | Description |
| ---------- | ------------------- | ------------------------------------------------------- |
| id | string | Android: tree URI; iOS: base64 security-scoped bookmark |
| name | string | |
WriteOptions
| Prop | Type |
| -------------- | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
| data | string |
| encoding | 'utf8' | 'base64' |
| mimeType | string |
ReadOptions
| Prop | Type |
| -------------- | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
| encoding | 'utf8' | 'base64' |
MkdirOptions
| Prop | Type |
| --------------- | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
| recursive | boolean |
RmdirOptions
| Prop | Type |
| --------------- | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
| recursive | boolean |
ReaddirResult
| Prop | Type |
| ------------- | ----------------------------------------------------------------------------------------------- |
| entries | { name: string; isDir: boolean; size?: number | null; mtime?: number | null; }[] |
ReaddirOptions
| Prop | Type |
| ------------ | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
StatResult
| Prop | Type |
| ----------- | ----------------------------------------------- |
| uri | string |
| size | number | null |
| mtime | number | null |
| type | 'file' | 'directory' | 'unknown' |
StatOptions
| Prop | Type |
| ------------ | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
ExistsResult
| Prop | Type |
| ----------------- | -------------------- |
| exists | boolean |
| isDirectory | boolean |
ExistsOptions
| Prop | Type |
| ------------ | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
DeleteOptions
| Prop | Type |
| ------------ | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
MoveCopyOptions
| Prop | Type |
| --------------- | ----------------------------------------------- |
| folder | FolderRef |
| from | string |
| to | string |
| overwrite | boolean |
UriForPathResult
| Prop | Type |
| --------- | --------------------------- |
| uri | string | null |
UriForPathOptions
| Prop | Type |
| ------------ | ----------------------------------------------- |
| folder | FolderRef |
| path | string |
Type Aliases
AppendOptions
WriteOptions
📄 License
MIT Author: Daniele Rolli
