Last updated:
0 purchases
pick or save
Word from creator #
Hello👋, This package is completely compatible with flutter and it also provides option to disable copying of file in cache when picking and provide Android Uri of picked file to work with which offer some real benifits such as getting original file metadata, filtering files before caching or caching them anytime later using Uri.
Yes, without a doubt, giving a free 👍 or ⭐ will encourage me to keep working on this plugin.
Package description #
A Flutter file picking and saving package that enables you to pick or save a single file and multiple files.
Features #
Works on Android 5.0 (API level 21) or later.
Pick single file, multiple files with certain extensions or mime types.
Supports photo picker on supported devices.
Supports picking directory with persistent permission and traversing the picked directory documents.
Get meta data like name, size and last modified from from android uri or file path.
Saves single file while allowing user to choose location and name.
Saves multiple file while allowing user to choose location or directory for saving all files.
Saves file from either file path or file data(Uint8List).
Could limit picking a file to the local device only.
Get cached file path from android uri or file path.
Note: If you are getting errors in you IDE after updating this plugin to newer version and the error contains works like Redeclaration, Conflicting declarations, Overload resolution ambiguity then to fix that you probably need to remove the older version of plugin from pub cache C:\Users\username\AppData\Local\Pub\Cache\hosted\pub.dev\older_version or simply run flutter clean.
Getting started #
In pubspec.yaml, add this dependency:
pick_or_save:
copied to clipboard
Add this package to your project:
import 'package:pick_or_save/pick_or_save.dart';
copied to clipboard
Basic Usage #
Note: To try the demos shown in below gifs run the example included in this plugin.
Note: For most below examples we set getCachedFilePath = false to get uri path instead of absolute file path from picker. A Uri path can only be used in android native code. By default getCachedFilePath = true which will provide cached file path from picker.
Picking #
Picking single file
Picking multiple files
Picking single file and getting uri
List<String>? result = await PickOrSave().filePicker(
params: FilePickerParams(getCachedFilePath: false),
);
String filePath = result[0];
copied to clipboard
Picking single file and getting cache path
List<String>? result = await PickOrSave().filePicker(
params: FilePickerParams(getCachedFilePath: true),
);
String filePath = result[0];
copied to clipboard
Note:-
If getCachedFilePath = true then the returned path file name will be different from picked file name. This was done to avoid deleting or rewriting existing cache files with same name. But you can still get the original name by following the pattern.
For example:- If you pick a file with name "My Test File.pdf" then the cached file will be something like this "My Test File.8190480413118007032.pdf". From that we see the pattern would be "original name prefix"+"."+"random numbers"+"."+"file extension". So what we need to do is to just remove the "."+"random numbers" to get the real name. Look at the below code to do that:
String getRealName(String pickOrSaveCachedFileName) {
int indexOfExtDot = pickOrSaveCachedFileName.lastIndexOf('.');
if (indexOfExtDot == -1) {
return pickOrSaveCachedFileName;
} else {
String fileExt =
pickOrSaveCachedFileName.substring(indexOfExtDot).toLowerCase();
String fileNameWithoutExtension = pickOrSaveCachedFileName.substring(
0, pickOrSaveCachedFileName.length - fileExt.length);
int indexOfRandomNumDot = fileNameWithoutExtension.lastIndexOf('.');
if (indexOfRandomNumDot == -1) {
return pickOrSaveCachedFileName;
} else {
String dotAndRandomNum =
fileNameWithoutExtension.substring(indexOfRandomNumDot).toLowerCase();
String fileNameWithoutDotAndRandomNumAndExtension =
fileNameWithoutExtension.substring(
0, fileNameWithoutExtension.length - dotAndRandomNum.length);
return fileNameWithoutDotAndRandomNumAndExtension + fileExt;
}
}
}
copied to clipboard
Picking multiple files
List<String>? filesPaths = await PickOrSave().filePicker(
params: FilePickerParams(getCachedFilePath: false, enableMultipleSelection: true),
);
copied to clipboard
Resticting picking files to certain mime types
List<String>? filesPaths = await PickOrSave().filePicker(
params: FilePickerParams(getCachedFilePath: false, mimeTypesFilter: ["image/*", "application/pdf"]),
);
copied to clipboard
Resticting picking files to certain extensions
List<String>? filesPaths = await PickOrSave().filePicker(
params: FilePickerParams(getCachedFilePath: false, allowedExtensions: [".txt", ".png"]),
);
copied to clipboard
Note: This plugin automatically tries to convert the extensions to their respective mime types if supported so that only those become selectable but that may fail if it fails to convert them. Still if a user manages to select other extension files then this plugin automatically discards those other extension files from selection.
Photo Picker
List<String>? filesPaths = await PickOrSave().filePicker(
params: FilePickerParams(getCachedFilePath: false, pickerType: PickerType.photo, mimeTypesFilter: ["*/*"]),
);
copied to clipboard
Note: This will show new photo picker only on supported android devices and for unsupported android devices it will show default picker. And it always needs mime type and only first mime type in mimeTypesFilter list is used. So if you want to filter multiple types of files then make sure to provide allowedExtensions as that automatically discards other extension files from selection if selected by user.
Photo picker on supported devices
Photo picker on unsupported devices
Picking Directory
String? pickedDirectoryUri = await PickOrSave().directoryPicker(
params: DirectoryPickerParams()
);
copied to clipboard
The obtained uri will have persistent permissions with these flags: Intent.FLAG_GRANT_READ_URI_PERMISSION, Intent.FLAG_GRANT_WRITE_URI_PERMISSION. In short it preserves access to uri across device restarts. You can learn more about it here.
Note: In DirectoryPickerParams() you can also optionally provide initialDirectoryUri which will be used to start the directory picker from a speific location. Generally we give it the uri which we stored from previous directory pickings.
Also, For traversing the picked directory, releasing-checking persistent permissions for a uri then go here.
Saving #
Saving single file from file path
List<String>? result = await PickOrSave().fileSaver(
params: FileSaverParams(
saveFiles: [
SaveFileInfo(
filePath: filePath,
fileName: "File.png")
],
)
);
String savedFilePath = result[0];
copied to clipboard
Saving multiple files from file path
List<String>? result = await PickOrSave().fileSaver(
params: FileSaverParams(
saveFiles: [
SaveFileInfo(
filePath: filePath,
fileName: "File 1.png"),
SaveFileInfo(
filePath: filePath,
fileName: "File 2.png")
],
)
);
copied to clipboard
Saving multiple files from Uint8List
List<String>? result = await PickOrSave().fileSaver(
params: FileSaverParams(
saveFiles: [
SaveFileInfo(
fileData: uint8List,
fileName: "File 1.png"),
SaveFileInfo(
fileData: uint8List,
fileName: "File 2.png")
],
)
);
copied to clipboard
Saving single file
Saving multiple files
File Metadata #
FileMetadata? result = await PickOrSave().fileMetaData(
params: FileMetadataParams(filePath: filePath),
);
copied to clipboard
Picking file and get its metadata
Get cache file path from file Uri or absolute file path #
String? result = await PickOrSave().cacheFilePathFromPath(
params: CacheFilePathFromPathParams(filePath: filePath),
);
copied to clipboard
Picking file and get its cached file path
Operations on picked directory uri #
Get uris of documents or sub documents inside a picked directory
List<DocumentFile>? documentFiles = await PickOrSave().directoryDocumentsPicker(
params: DirectoryDocumentsPickerParams(
directoryUri: pickedDirectoryUri,
recurseDirectories: false,
allowedExtensions: [".pdf"],
mimeTypesFilter: ["image/*"],
),
);
DocumentFile documentFile = documentFiles[0];
String documentId = documentFile.id;
String documentUri = documentFile.uri;
String? documentMimeType = documentFile.mimeType;
String documentName = documentFile.name;
bool isDocumentDirectory = documentFile.isDirectory;
bool isDocumentFile = documentFile.isFile;
copied to clipboard
DirectoryDocumentsPickerParams can take these parameters:
Provide directoryUri the picked directory uri or uri of documents(sub directory) inside picked directory obtained from previous runs.
Provide documentId the id of documents(sub directory) inside picked directory obtained from previous runs. This is important if you want to start traversing from a sub directory instead of root directory.
Set recurseDirectories to true if you want to traverse inside sub directories of provided directory. This is recursive.
Provide allowedExtensions to filter the returned documents to certain file extensions. It has no effect on performance.
Provide mimeTypesFilter to filter the returned documents to certain mime types. It has no effect on performance.
Cancelling traversing a picked directory
String? result = await PickOrSave().cancelActions(
params: CancelActionsParams(cancelType: CancelType.directoryDocumentsPicker),
);
copied to clipboard
Cancelling traversing a picked directory
String? result = await PickOrSave().cancelActions(
params: CancelActionsParams(cancelType: CancelType.directoryDocumentsPicker),
);
copied to clipboard
Check if a uri has persistent permission
bool? persistentPermStatus = await PickOrSave().uriPermissionStatus(
params: UriPermissionStatusParams(uri: uriToCheck, releasePermission: false),
);
copied to clipboard
Get all uri which have persistent permission
List<String>? persistentPermUris = await PickOrSave().urisWithPersistedPermission();
copied to clipboard
Remove or relase persistent permission for a uri
bool? persistentPermStatus = await PickOrSave().uriPermissionStatus(
params: UriPermissionStatusParams(uri: uriToRelease, releasePermission: true),
);
copied to clipboard
Note: It is very important to remove unused persited uris as android tracks uri permissions individual apps for setting a hardcoded limit to it. Till Android 10 the limit is set to 128 persisted permission grants and from Android 11 that limit updated to 512. So, if we reach that limit then future requests will get failed.
For more details follow the nice article here.
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.