react-native-photo-management
v0.1.3
Published
React Native photo management utilities with batch asset metadata and food detection
Maintainers
Readme
react-native-photo-management
react-native-photo-management is an Expo module for scanning the device photo library across projects.
It exposes:
- iOS-native batch asset metadata lookup via PhotoKit
- Android and iOS on-device image classification
- Cross-platform food detection built on Apple Vision and ML Kit labels
- Android JS fallback batching built on
expo-media-library - A streaming
scanPhotoLibrary()helper so app code owns persistence - Bulk album creation/update helpers that skip missing assets
- Bulk asset delete helpers with missing-asset tolerance
- A config plugin that wires
expo-media-librarypermissions from a single plugin entry
Install
npx expo install react-native-photo-management expo-media-library expo-deviceAdd the plugin to your app config:
{
"expo": {
"plugins": ["react-native-photo-management"]
}
}Optional plugin configuration:
{
"expo": {
"plugins": [
[
"react-native-photo-management",
{
"photosPermission": "Allow $(PRODUCT_NAME) to access your photos to scan and organize your library.",
"isAccessMediaLocationEnabled": true
}
]
]
}
}Platform Support
| Platform | getAssetInfoBatch | classifyImageBatch | detectFoodInImageBatch | createAlbumWithAssets / deleteAssetsBatch | scanPhotoLibrary |
| -------- | ------------------------------------ | -------------------- | ------------------------ | --------------------------------------------- | --------------------------------- |
| iOS | Native batch bridge | Apple Vision | Supported | Supported | Native batch metadata + streaming |
| Android | JS fallback via expo-media-library | ML Kit | Supported | Supported | JS fallback + streaming |
| Web | Unsupported | Unsupported | Unsupported | Unsupported | Unsupported |
API
isNativeBatchAssetInfoAvailable()
Returns true when the iOS native batch bridge is linked and available.
isFoodDetectionAvailable()
Returns true on iOS and Android when the native image classifier is linked.
requestPhotoLibraryPermission()
Requests photo-library access and resolves to true when access is granted.
hasPhotoLibraryPermission()
Checks current photo-library access.
countPhotoLibraryAssets(options?)
Counts assets for the requested media types. Defaults to photos and videos.
getAssetInfoBatch(assetIds)
Loads BatchAssetInfo[] for a set of asset IDs.
type BatchAssetInfo = {
id: string;
uri: string;
creationTime: number;
modificationTime: number;
width: number;
height: number;
mediaType: "photo" | "video" | "audio" | "unknown";
duration: number;
location: {
latitude: number;
longitude: number;
altitude?: number | null;
speed?: number | null;
heading?: number | null;
} | null;
};On Android, unreadable or deleted assets are skipped.
classifyImageBatch(assetIds, options?)
Runs on-device image labeling and returns platform-native labels.
type ClassificationResult = {
assetId: string;
labels: Array<{ label: string; confidence: number }>;
error?: string;
};On Android, non-photo assets are returned with an error instead of crashing the batch.
detectFoodInImageBatch(assetIds, options?)
Runs on-device classification and filters for food-related labels.
type FoodDetectionResult = {
assetId: string;
containsFood: boolean;
foodConfidence: number;
foodLabels: Array<{ label: string; confidence: number }>;
labels: Array<{ label: string; confidence: number }>;
error?: string;
};On web, this throws an UnsupportedPlatformError.
Label vocabularies differ between Apple Vision and ML Kit, so the exact label text may not match across platforms even though the API contract does.
createAlbumWithAssets(albumName, assetIds, options?)
Creates an album when missing or appends to an existing one. Missing or unreadable assets are skipped.
type CreateAlbumWithAssetsResult = {
success: boolean;
albumId?: string;
albumName: string;
assetCount: number;
created: boolean;
skippedAssets: number;
missingAssetIds: string[];
error?: string;
};deleteAssetsBatch(assetIds)
Deletes all readable assets in a batch and reports any missing ones without failing the whole request.
type DeleteAssetsBatchResult = {
requestedCount: number;
deletedCount: number;
skippedAssets: number;
missingAssetIds: string[];
success: boolean;
error?: string;
};scanPhotoLibrary(options)
Streams library assets in batches and reports progress after each page.
const progress = await scanPhotoLibrary({
onBatch: async (assets) => {
// Persist or process assets here
},
onProgress: (value) => {
console.log(value.processedAssets, value.totalAssets);
},
});scanPhotoLibrary() returns:
type ScanPhotoLibraryProgress = {
totalAssets: number;
processedAssets: number;
emittedAssets: number;
assetsWithLocation: number;
skippedAssets: number;
isComplete: boolean;
elapsedMs: number;
assetsPerSecond: number;
etaMs: number | null;
strategy: "ios-native-batch" | "js-fallback";
deviceTier: "low" | "medium" | "high";
};Example
The repo includes an Expo example app in example/App.tsx that exercises:
- permission checks
- asset counting
- streaming scan progress
- batch metadata lookup
- cross-platform image classification and food detection
- bulk album creation from sampled assets
Run it with:
npm run example:start
npm run example:ios
npm run example:androidAutomated npm Publishing
This repo is configured for npm trusted publishing from GitHub Actions in .github/workflows/publish.yml.
Before the workflow can publish, configure the npm package once on npmjs.com:
- Open the package settings for
react-native-photo-management. - In
Trusted Publisher, chooseGitHub Actions. - Set
Organization or usertojonluca. - Set
Repositorytoreact-native-photo-management. - Set
Workflow filenametopublish.yml.
npm trusted publishing uses GitHub OIDC, so no NPM_TOKEN secret is required. Because this repo is public and the package is public, npm will automatically attach provenance attestations when the workflow publishes.
After the first successful publish, npm recommends tightening package settings to Require two-factor authentication and disallow tokens so only trusted publishing remains available.
Release Flow
- Update
package.jsonandpackage-lock.jsonto the next version. - Commit the release.
- Push a matching Git tag such as
v0.1.1.
The workflow publishes only when the pushed tag matches the package.json version exactly.
Manual Validation
Validate the package contents before publishing:
npm run build
npm run typecheck
npm run lint
npm test
npm packThen publish:
npm publish --access publicManual local publishing is still available, but the intended release path is GitHub Actions trusted publishing via signed provenance.
