photo_manager
English | 中文
A Flutter plugin that provides assets abstraction management APIs without UI integration, you can get assets (image/video/audio) on Android, iOS, macOS and OpenHarmony.
Projects using this plugin
Articles about this plugin
Migration guide
For versions upgrade across major versions, see the migration guide for detailed info.
TOC
- photo_manager
- Projects using this plugin
- Articles about this plugin
- Migration guide
- Common issues
- Prepare for use
- Usage
- Filtering
- Cache mechanism
- Native extra configs
Common issues
Please search common issues in [GitHub issues][] for build errors, runtime exceptions, etc.
Prepare for use
Add the plugin reference to pubspec.yaml
Two ways to add the plugin to your pubspec:
- (Recommend) Run
flutter pub add photo_manager
. - Add the plugin reference in your
pubspec.yaml
'sdependencies
section:
dependencies:
photo_manager: $latest_version
The latest stable version is: [][pub package]
Import in your projects
import 'package:photo_manager/photo_manager.dart';
Configure native platforms
Minimum platform versions: Android 16, iOS 9.0, macOS 10.15.
- Android: Android config preparation.
- iOS: iOS config preparation.
- macOS: Pretty much the same with iOS.
Android config preparation
Kotlin, Gradle, AGP
We ship this plugin with Kotlin 1.7.22
.
If your projects use a lower version of Kotlin/Gradle/AGP,
please upgrade them to a newer version.
More specifically:
- Upgrade your Gradle version (
gradle-wrapper.properties
) to7.5.1
or the latest version. - Upgrade your Kotlin version (
ext.kotlin_version
) to1.7.22
or the latest version. - Upgrade your AGP version (
com.android.tools.build:gradle
) to7.2.2
or the latest version.
Android 10 (Q, 29)
If you're not setting your compileSdkVersion
or targetSdkVersion
to 29,
you can skip this section.
On Android 10, Scoped Storage was introduced, which causes the origin resource file not directly inaccessible through it file path.
If your compileSdkVersion
or targetSdkVersion
is 29
,
you can consider adding android:requestLegacyExternalStorage="true"
to your AndroidManifest.xml
in order to obtain resources:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.fluttercandies.photo_manager_example">
<application
android:label="photo_manager_example"
android:icon="@mipmap/ic_launcher"
android:requestLegacyExternalStorage="true">
</application>
</manifest>
Note: Apps that are using the flag will be rejected from the Google Play.
This is not a requirement, the plugin can still work with caching files.
But you'll need to control caches on your own, the best practice is to clear file caches
each time when you start your app by calling PhotoManager.clearFileCache()
.
Glide
The plugin use [Glide][] to create thumbnail bytes for Android.
If you found some warning logs with Glide appearing,
it means the main project needs an implementation of AppGlideModule
.
See [Generated API][] for the implementation.
iOS config preparation
Define the NSPhotoLibraryUsageDescription
key-value in the ios/Runner/Info.plist
:
<key>NSPhotoLibraryUsageDescription</key>
<string>In order to access your photo library</string>
If you want to grant only write-access to the photo library on iOS 11 and above,
define the NSPhotoLibraryAddUsageDescription
key-value in the ios/Runner/Info.plist
.
It's pretty much the same as the NSPhotoLibraryUsageDescription
.
Usage
Request for permission
Most of the APIs can only use with granted permission.
final PermissionState ps = await PhotoManager.requestPermissionExtend(); // the method can use optional param `permission`.
if (ps.isAuth) {
// Granted
// You can to get assets here.
} else if (ps.hasAccess) {
// Access will continue, but the amount visible depends on the user's selection.
} else {
// Limited(iOS) or Rejected, use `==` for more precise judgements.
// You can call `PhotoManager.openSetting()` to open settings for further steps.
}
But if you're pretty sure your callers will be only called after the permission is granted, you can ignore permission checks:
PhotoManager.setIgnorePermissionCheck(true);
For background processing (such as when the app is not in the foreground), ignore permissions check would be proper solution.
Limited entities access
Limited entities access on iOS
With iOS 14 released, Apple brought a "Limited Photos Library" permission
(PermissionState.limited
) to iOS.
The PhotoManager.requestPermissionExtend()
method will return PermissionState
.
See [PHAuthorizationStatus][] for more detail.
To reselect accessible entities for the app,
use PhotoManager.presentLimited()
to call the modal of
accessible entities' management.
This method only available for iOS 14+ and when the permission state
is limited (PermissionState.limited
).
To suppress the automatic prompting from the system
when each time you access the media after the app has restarted,
you can set the Prevent limited photos access alert
key to YES
in your app's Info.plist
(or manually writing as below):
<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<true/>
Limited entities access on Android
Android 14 (API 34) has also introduced the concept of limited assets similar to iOS.
However, there is a slight difference in behavior (based on the emulator):
On Android, the access permission to a certain resource cannot be revoked once it is granted,
even if it hasn't been selected when using presentLimited
in future actions.
Get albums/folders (AssetPathEntity
)
Albums or folders are abstracted as the [AssetPathEntity
][] class.
It represents a bucket in the MediaStore
on Android,
and the PHAssetCollection
object on iOS/macOS.
To get all of them:
final List<AssetPathEntity> paths = await PhotoManager.getAssetPathList();
See [getAssetPathList
][] for more detail.
Params of getAssetPathList
Name | Description | Default value |
---|---|---|
hasAll | Set to true when you need an album containing all assets. | true |
onlyAll | Use this property if you only need one album containing all assets. | false |
type | Type of media resource (video, image, audio) | RequestType.common |
filterOption | Used to filter resource files, see Filtering for details | FilterOptionGroup() |
pathFilterOption | Only valid for iOS and macOS, for the corresponding album type. See PMPathFilterOption for more detail. | Include all by default. |
PMPathFilterOption
Provide since 2.7.0, currently only valid for iOS and macOS.
final List<PMDarwinAssetCollectionType> pathTypeList = []; // use your need type
final List<PMDarwinAssetCollectionSubtype> pathSubTypeList = []; // use your need type
final darwinPathFilterOption = PMDarwinPathFilter(
type: pathTypeList,
subType: pathSubTypeList,
);
PMPathFilter pathFilter = PMPathFilter();
The PMDarwinAssetCollectionType
has a one-to-one correspondence with PHAssetCollectionType | Apple Developer Documentation.
The PMDarwinAssetCollectionSubtype
has a one-to-one correspondence with PHAssetCollectionSubType | Apple Developer Documentation.
Get assets (AssetEntity
)
Assets (images/videos/audios) are abstracted as the [AssetEntity
][] class.
It represents a series of fields with MediaStore
on Android,
and the PHAsset
object on iOS/macOS.
From AssetPathEntity
You can use [the pagination method][getAssetListPaged
]:
final List<AssetEntity> entities = await path.getAssetListPaged(page: 0, size: 80);
Or use [the range method][getAssetListRange
]:
final List<AssetEntity> entities = await path.getAssetListRange(start: 0, end: 80);
From PhotoManager
(Since 2.6)
First, You need get count of assets:
final int count = await PhotoManager.getAssetCount();
Then, you can use [the pagination method][PhotoManager.getAssetListPaged
]:
final List<AssetEntity> entities = await PhotoManager.getAssetListPaged(page: 0, pageCount: 80);
Or use [the range method][PhotoManager.getAssetListRange
]:
final List<AssetEntity> entities = await PhotoManager.getAssetListRange(start: 0, end: 80);
Note: page
and start
starts from 0.
From ID
The ID concept represents:
- The ID field of the
MediaStore
on Android. - The
localIdentifier
field of thePHAsset
on iOS.
You can store the ID if you want to implement features
that's related to persistent selections.
Use [AssetEntity.fromId
][] to retrieve the entity
once you persist an ID.
final AssetEntity? asset = await AssetEntity.fromId(id);
Be aware that the created asset might have limited access or got deleted in anytime, so the result might be null.
From raw data
You can create an entity from raw data, such as downloaded images, recorded videos, etc. The created entity will show as a corresponding resource on your device's gallery app.
final Uint8List rawData = yourRawData;
// Save an image to an entity from `Uint8List`.
final AssetEntity? entity = await PhotoManager.editor.saveImage(
rawData,
title: 'write_your_own_title.jpg', // Affects EXIF reading.
);
// Save an existed