NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #844 most downloaded on pub.dev
A multi-platform background file downloader and uploader. Define the task, enqueue and monitor progress
Last release today
07 Oct 2026
Release timing varies
gaps range from 8 days to 3 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
4 years old
139 releases · first in 2022
[Android] Reuse pre-created notification channel and preserve its importance (#732, #733)
Raise HTTP redirect limit to 10 for desktop and foreground requests
androidx.test:monitor from implementation dependenciesGroupNotification registry cleanup is executed upon group completion regardless of whether error or complete notification contents are configured, preventing an unconfigured slot from permanently suppressing subsequent group completion notifications (fixes #728)isFinished == true), bypassing delivered notification de-duplication so consecutive batches with identical completion text are not skipped (fixes #729)One column per quarter.
Fix task updates stream suppression when task tracking or transfers is enabled: isolate internal Transfers callbacks from user-registered callbacks us
Transfers callbacks from user-registered callbacks using dedicated groupTransfer callback maps in BaseDownloader, preventing internal callbacks from suppressing events on FileDownloader().updates, and preserving callback reference equality in registerCallbacks/unregisterCallbacks (fixes #727)Models.kt, remove unnecessary safe calls in UIDTJobService.kt, and streamline UriUtils.ktExpand connectivity_plus version constraint to >=6.1.3 <8.0.0 to support connectivity_plus 7.x (fixes #722)
connectivity_plus version constraint to >=6.1.3 <8.0.0 to support connectivity_plus 7.x (fixes #722)BDPlugin.onNativeTaskStatusChange and BDPlugin.onNativeTaskProgressChange to allow native iOS host apps to observe task status and throttled progress directly in Swift (e.g. for Live Activities and WidgetKit) when the Dart isolate is suspended during background URLSession wake-ups (closes #702, refs #705)FileHandle.seek(toOffset:) instead of reading and discarding leading bytes in createTempFileWithRange, eliminating quadratic disk reads when slicing chunked uploads (#723)NetworkRequest on Android API 28+: require TRANSPORT_WIFI and NET_CAPABILITY_INTERNET for tasks requiring Wi-Fi, preventing downloads over cellular even when reported as unmetered by the carrier, with fallback to NETWORK_TYPE_UNMETERED on older Android versions (fixes #717)requiresWiFi behavior on Android API 28+ vs earlier Android versionsAdd test/mtls_test.dart to the false_secrets allowlist in pubspec.yaml to prevent package publish validation from flagging the dummy mTLS test private
Add test/mtls_test.dart to the false_secrets allowlist in pubspec.yaml
to prevent package publish validation from flagging the dummy mTLS test
private key as a leaked secret.
transfers Object and Transfer API: A major new high-level reactive abstraction for managing background downloads, uploads, and data tasks via FileDownloader().transfers:
FileDownloader().transfers (Transfers class), providing methods to start, batch start, reconnect to, and query background transfersTransfer handle returned by transfers.start, startAll, getOrStart, and startOrGetAlltransfers are automatically ensured to provide status updates (Updates.statusAndProgress or Updates.status) for reliable lifecycle trackinggetOrStart and startOrGetAll re-attach to existing active transfers or rehydrate matching records from the persistent database across app restarts; transfers.rehydrateFromDatabase({group}) restores previously tracked transfers into active handlestransfer.file (resolves to the completed File, dynamically tracking server-suggested filenames if renamed upon completion), transfer.result (resolves to final TaskStatusUpdate), and transfer.responseBodyValueNotifier properties for Flutter UI: statusNotifier, progressNotifier (normalized 0.0–1.0), networkSpeedNotifier (MB/s), timeRemainingNotifier, holdReasonNotifier, exceptionNotifier, and notificationTapNotifierpause(), resume(), cancel(), and allowCellular()resume() and allowCellular() fall back to re-enqueuing if resume data is missing; resets result completers cleanly upon retry and re-enqueue; native handling for Wi-Fi and network constraintsTransferHint presets (userInitiated, largeFile, smallFile, lowPriority, useSuggestedFilename, binaryUpload) with automatic Android 14+ UIDT JobScheduler configuration and pause resilienceTransferProgressBar (with accurate 100% completion display), TransferButton (with optional onCancel callback), and TransferListTiletransfers.notifier (ValueNotifier<List<Transfer>>), transfers.all(), active(), completed(), failed(), forId(), forTask(), and forUrl()transfers.remove(), removeById(), cancelAll(), and clear({cancelActive}) with automatic disposal of transfer instancesautoClean) on first transfer start when task tracking is enabledFileDownloader.scoped('namespace') for modular apps, plugins, and feature isolationTransferHoldReason.offline, waitingForWiFi) with auto-resumption and configurable stallTimeout watchdogdoc/transfers.md and overhauled example app demonstrating Transfer best practices^3.13.0 and Flutter requirement to >=3.47.0flutter_lints to ^6.0.0 with updated analysis optionswhen) to task creation time, set task ID as deterministic sort key, and enable onlyAlertOnce, preventing notifications from jittering and swapping positions on every progress update (closes #714)android.defaults.buildfeatures.buildconfig property from example app gradle.properties (closes #674 / AGP 9 compatibility)readTimeout matching requestTimeout on HttpURLConnection and properly classify SocketTimeoutException as a connection exception, preventing tasks from blocking indefinitely when waiting for response headersgroupNotification.notificationId rather than task.taskId in updateGroupNotification to properly dismiss group notifications (fixes #718).runningWithoutPause, .complete, or .error category so UNUserNotificationCenterDelegate.willPresent recognizes and delivers running and finished group notifications (fixes #718)FlutterFramework dependency in Package.swift, expand permissions bypass documentation for SwiftPM, and transition example app (ios and macos) to pure SwiftPMrequestTimeout to client.send(request) in doDownloadTask and doDataTask, and to head in doParallelDownloadTask, preventing tasks from hanging indefinitely in running status if the network drops or the server stalls while waiting for response headers (fixes #721)DesktopDownloaderrequireWiFi platform behavior: enforces an unmetered network connection constraint (NETWORK_TYPE_UNMETERED) on Android (excluding cellular and metered Wi-Fi hotspots), while disabling cellular access (allowsCellularAccess = false) on iOS (allowing any Wi-Fi or Ethernet connection regardless of metered status)android.permission.RUN_USER_INITIATED_JOBS requirementConfig.tempFilePath for custom temporary download file storage on Android and DesktopserverCertificatePath / serverCertificateBytes)-d/--device, --ios, --android, --macos) and --dry-run flag to run_tests.sh, grouping test runs by device to prevent redundant app rebuildsload_test.dart, database_test.dart, and general_test.dartBump package version to 9.5.9 in pubspec.yaml
Config.mTLS and MTLSConfig data class to support mutual TLS client authentication on desktop platforms (closes #711)Config.tempFilePath to allow configuring a custom temporary directory path for downloads (closes #712)HoldingQueue and batch-drains available concurrency slotsCallbacks when callback handle is missing or invalidDownloadTaskRunnerInputStream resource leaks in UploadTaskRunnermoveToSharedStorage failureUploadTaskRunnerstateLock contention during network I/O in HoldingQueue and batch-drains concurrency slotspauseSingleTask race condition and stalled task stateuploaderForUrlSessionTaskIdentifierFileDownloader.updates stream (fixes #708)Merge pull request #697 from 781flyingdutchman/issue-695-require-wifi…
Merge pull request #697 from 781flyingdutchman/issue-695-require-wifi…
alsoRestartUploads parameter to FileDownloader.requireWiFi to optionally cancel and restart running upload tasks when updating WiFi requirement (fixes #695)PrivacyInfo.xcprivacy for photos and videos data collection key (NSPrivacyCollectedDataTypePhotosorVideos), resolving App Store submission validation errors (fixes #694)TaskStatusUpdate and TaskProgressUpdate in doc/status_updates.md (fixes #684)Fixes group notification sticking in running state when cancelling tasks from holding queue
ConcurrentModificationException in canSendCancellation when processing concurrent status updatesEXC_BAD_ACCESS race condition under concurrent status updatesJsonProcessor idle shutdown while requests are pending to prevent unexpected background isolate shutdown errors[Chore / Maintenance] Updated GitHub Actions workflow configurations to resolve Node 20 deprecation warnings
kotlin-android plugin in Gradle build if builtInKotlin is configured to false (closes #674)FlutterFramework dependency path in Package.swiftAppDelegate.swift[Android] Bug fixes and performance improvements:
Add TaskOptions to DataTask with similar functionality as in DownloadTask
TaskOptions to DataTask with similar functionality as in DownloadTaskV9.5.3 Fix race condition in TaskWorker where setForeground could…
V9.5.3 Fix race condition in TaskWorker where setForeground could…
TaskWorker where setForeground could crash for finished tasksV9.5.2 Moves LocalStorePersistentStorage to isolate model to off-load…
V9.5.2 Moves LocalStorePersistentStorage to isolate model to off-load…
[iOS] Support for UISceneDelegate in iOS 13.0 and above
Introduces Android User Initiated Data Transfer (UIDT), triggered when task priority is set to 0 (max priority) on Android 14+, provided a notificatio
allowPause is true, in which case it will pause and resume).Config.runInForeground. Displays a persistent notification and is not subject to the 9-minute limit on many Android versions. Requires FOREGROUND_SERVICE_DATA_SYNC permission on Android 14+.priority: 0 on Android 14+. This is a specialized JobScheduler mode that does not have the 9-minute limit and is designed for large, user-aware data transfers. It requires a notification to be shown.
RUN_USER_INITIATED_JOBS permission to your AndroidManifest.xml, as well as a service declaration for .UIDTJobService. See the README for details.HoldingQueue logic to correctly include UIDT jobs and prevent race conditionsLocalStorePersistentStorage to prevent UI stutterdoc/ directory[Android] MinSDK is now 23 (was 21), required because the latest Android WorkManager is required to properly support Android 15+
Task.filePath, Task.split and ParallelDownloadTask pauseImprove JSON processing to reduce UI jank
database.cleanUp() to simplify and automate database maintenance, and added database clean-up to start() commandImprove Android notification handling
Refine TaskQueue pauseAll/resumeAll to support specific tasks and groups. Updated TaskQueue interface to accept optional tasks and group parameters in
TaskQueue interface to accept optional tasks and group parameters in pauseAll and resumeAll and implemented this for the MemoryTaskQueuePlatform.isAndroid etc to defaultTargetPlatform which should lead to better tree shaking and smaller memory sizeImproves concurrency on mobile platforms by moving JSON encoding and decoding to an isolate, and introducing a job queue to ensure ordered message exe
Config.skipExistingFiles configuration option to skip the download if the destination file already exists (and conditionally does this only for files greater than a certain size)Main change is in Android concurrency, triggered by the Great Thread Merge that causes UI blocking issues for recent versions of Flutter. The concurre
Main change is in Android concurrency, triggered by the Great Thread Merge that causes UI blocking issues for recent versions of Flutter. The concurrency approach has been changed, but note this can cause minor changes in - for example - the sequence in which certain events happen.
Feature improvements
pauseAll and resumeAll. These methods are now called when pausing or resuming all tasks using the FileDownloaderBug fixes
[Android] Fix Tap to open (on notification) bug, introduced in 9.2.4
Bug fix
Version upgrades
[iOS] catch file write errors in multi-part uploads
[iOS] Notification update after killed app resumes
post fieldenqueAll and similar calls when no Activity attached[Android] Unmarking temp files as cache after move to download destination
Adds option to set the Content-Disposition header for binary uploads
Content-Disposition header for binary uploadsopenFile with a filepath containing spacesFor binary uploads, the Content-Disposition header will be:
task.headers['Content-Disposition'] in all other cases* Minor bug fixes
Adds updates broadcast stream to the database property, which emits every TaskRecord update made to the database.
updates broadcast stream to the database property, which emits every TaskRecord update made to the database.start and rescheduleKilledTasks when using group names for tasksAdds optional group parameter to resumeAll
group parameter to resumeAllAdds pauseAll, cancelAll and resumeAll
pauseAll, cancelAll and resumeAllenqueuAll to not starve the UI threadIntroduces URI operations, including file/photo/video/directory pickers, under the uri property, and UriDownloadTask and UriUploadTask. See Working wi
uri property, and UriDownloadTask and UriUploadTask. See Working with URIs.asAndroidUri - use the new methods on the uri property insteadenqueueAll to enqueue a list of tasks (non-blocking and with better performance when compared to calling enqueue for each task)beforeTaskStartCallback to TaskOptions, that is called just before the task starts executing. If it returns a non-null TaskStatusUpdate then this forces the task to finish before it starts, with that TaskStatusUpdatecanceled notification (instead of cancellation defaulting to the error notification)request when using PUT or PATCH requestsUri operations abstract away platform differences, including content provider on Android (used for the Storage Access Framework), and file, photo and directory pickers on iOS and Android. This enables largely platform-independent code for file operations, and on Android downloads directly to destination, bypassing the temp file in internal storage.
The FileDownloader().uri property provides access to a set of utility functions for working with URIs, including:
pickDirectory(): Opens a directory picker dialog and returns the selected directory's URI.pickFile(): Opens a file picker dialog and returns the selected file's URI.pickFiles(): Opens a file picker dialog and allows selection of multiple files, returning their URIs in a list.createDirectory(): Creates a new directory within a specified parent directory URI.getFileBytes(): Retrieves the file data (bytes) for a given URI.copyFile(): copies a file from a source uri to a destination. Destination can be a Uri, a File or a String containing a file pathmoveFile(): moves a file from a source uri to a destination. Destination can be a Uri, a File or a String containing a file path. If the move fails, it is possible that the file was copied but the source was not deleteddeleteFile(): Deletes the file at the given URI.openFile(): Opens the file at a given URI.moveToSharedStorage(): Moves a file to a shared storage location.activate(): Activates a previously accessed directory or file. Only relevant if you use persistedUriPermission or use the photo/video picker.The pick... methods and createDirectory take an optional persistedUriPermission argument (defaults to false) that when true registers the picked directory with the OS, allowing access in a later session.
New/modified Task types:
UriDownloadTask: Downloads a file to a specified directory URI. On Android, this bypasses the temp file used in the traditional approach and downloads directly to the destination.UriUploadTask: Uploads a file from a given file URI. If the filename is omitted, it will be based on the task's URL.MultiUploadTask: now accepts Uri where previously only filename or file path was allowedFixes issue with start and rescheduleKilledTasks when using group names for tasks
start and rescheduleKilledTasks when using group names for tasksModifies the interval between TaskProgressUpdate such that an update is sent at least once every 2.5 seconds if progress has been made, even if it les
TaskProgressUpdate such that an update is sent at least once every 2.5 seconds if progress has been made, even if it less than 2% of the file sizerescheduleKilledTasks to also reschedule tasks marked as waitingToRetry but not registered as suchAdds start which ensures the various start-up calls are executed in the correct order. Use this instead of calling trackTasks, resumeFromBackground an
start which ensures the various start-up calls are executed in the correct order. Use this instead of calling trackTasks, resumeFromBackground and rescheduleKilledTasks separatelyrescheduleKilledTasks which will compare enqueued/running tasks in the database with those active in the downloader, and reschedules those that have been killed by the userAdds rescheduleMissingTasks, which compares tasks in the database with tasks in the native downloader, and reschedules those tasks that are present in
rescheduleMissingTasks, which compares tasks in the database with tasks in the native downloader, and reschedules those tasks that are present in the database (and therefore should be enqueued or running) but are not present in the native downloader. Returns two lists of Task - successfully rescheduled ones, and tasks that failed to reschedule.[iOS] Adds support for Swift Package Manager and defaults the example app to using it
Adds options field to Task, which take a TaskOptions object to configure less common task specific options - currently onTaskStart, onTaskFinished and
options field to Task, which take a TaskOptions object to configure less common task specific options - currently onTaskStart, onTaskFinished and auth
onTaskStart is a callback with signatureFuture<Task?> Function(Task original), called just before the task starts executing. Your callback receives the original task about to start, and can modify this task if necessary. If you make modifications, you return the modified task - otherwise return null to continue execution with the original task. You can only change the task's url (including query parameters) and headers properties - making changes to any other property may lead to undefined behavior.onTaskFinished is a callback with signature Future<void> Function(TaskStatusUpdate taskStatusUpdate), called when the task has reached a final state (regardless of outcome). Your callback receives the final TaskStatusUpdate and can act on that.auth is an optional Auth object that helps manage accessToken and accessToken refresh - see the README for detailsnumTotal is calculated for group notifications: numTotal is now increment when a task is enqueued, instead of when it starts running. Note that this can lead to a '0/20 files' type notification if the tasks are enqueued but cannot start due to a constraint such as requiring WiFiFixes Android bug where timeout timer is not cleaned up after use
[iOS] Adds configuration option to exclude downloaded files from iCloud backup
allGroups parameter to allTasks and allTaskIds methods, to retrieve all tasks regardless of groupFix for compilation issue on Kotlin 2
Adds option to specify a file location for upload using a Mediastore URI on Android, using UploadTask.fromUri. A Mediastore URI can also be requested
UploadTask.fromUri. A Mediastore URI can also be requested from methods moveToSharedStorage and pathInSharedStorage by adding asAndroidUri = true to the call.dependency_overrides in pubspec.yaml to resolve (background_downloader works with 1.0 and 2.0)Adds option for partial uploads, for binary uploads only. Set the byte range by adding a "Range" header to your binary UploadTask, e.g. a value of "by
UploadTask, e.g. a value of "bytes=100-149" will upload 50 bytes starting at byte 100. You can omit the range end (but not the "-") to upload from the indicated start byte to the end of the file. The "Range" header will not be passed on to the server. Note that on iOS an invalid range will cause enqueue to fail, whereas on Android and Desktop the task will fail when attempting to start.Fixes desktop upload cancellation bug
Fixes concurrent database write bug for TaskRecords
If the value of a fields entry of an UploadTask is in JSON format (defined as start/end with {} or []) then the field's mime-type will be set to appli
fields entry of an UploadTask is in JSON format (defined as start/end with {} or []) then the field's mime-type will be set to application/json, whereas it would not have been set priorBaseDirectory.root, fixes an issue with Task.split and Task.baseDirectoryPath. When using BaseDirectory.root on Windows, your task's directory must contain the drive letter.* Bug fixes * Improvements to documentation
Removes references to dart:html to allow web compilation using WASM. Note the package still does not work on the web
dart:html to allow web compilation using WASM. Note the package still does not work on the webpost field if Map or List. Throws if jsonEncode cannot convert the object, in which case you have to encode it yourself using a custom encoderFixes an issue where temporary files were not deleted when canceling a paused parallel download task
Adds DataTask for scheduled server requests
DataTask for scheduled server requestsThe downloader already supported server requests for immediate execution using FileDownloader.request(Request request). This change adds the option to scheduled a server request similar to scheduling any other Task.
To schedule a server request using the background mechanism (e.g. if you want to wait for WiFi to be available), create and enqueue a DataTask.
A DataTask is similar to a DownloadTask except it:
post data as a String, orjson data, which will be converted to a String and posted as content type application/jsoncontentType which will set the Content-Type header valueresponseBody, responseHeaders and possible taskException in the final TaskStatusUpdate fieldsTypically you would use enqueue to enqueue a DataTask and monitor the result using a listener or callback, but you can also use transmit to enqueue and wait for the final result of the DataTask.
Fixes iOS/Android issue where retrieveLocallyStoredData retrieves only a basic TaskStatusUpdate, without responseCode, responseBody etc
retrieveLocallyStoredData retrieves only a basic TaskStatusUpdate, without responseCode, responseBody etcFixes iOS/Android bug with ParallelDownloadTask hanging when number of chunks exceeds ~10
Fixes Android bug when using Config.runInForeground that can lead to a crash
Config.runInForeground that can lead to a crashAdds optional holding queue to manage how many tasks are executed concurrently
unique parameter in context of server suggested filenameOnce you enqueue a task with the FileDownloader it is added to an internal queue that is managed by the native platform you're running on (e.g. Android). Once enqueued, you have limited control over the execution order, the number of tasks running in parallel, etc, because all that is managed by the platform. If you want more control over the queue, you need to use a TaskQueue or a HoldingQueue:
TaskQueue is a Dart object that you can add to the FileDownloader. You can create this object yourself (implementing the TaskQueue interface) or use the bundled MemoryTaskQueue implementation. This queue sits "in front of" the FileDownloader and instead of using the enqueue and download methods directly, you now simply add your tasks to the TaskQueue. Because this is a Dart object, the queue will suspend when the OS suspends your application, and if the app gets killed, tasks held in the TaskQueue will be lost (unless you have implemented persistence)HoldingQueue is native to the OS and can be configured using FileDownloader().configure to limit the number of concurrent tasks that are executed (in total, by host or by group). When using this queue you do not change how you interact with the FileDownloader, but you cannot implement your own holding queue. Because this queue is native, it will continue to run when your app is suspended by the OS, but if the app is killed then tasks held in the holding queue will be lost (unlike tasks already enqueued natively, which persist)This update adds the holding queue.
Use a holding queue to limit the number of tasks running concurrently. Calling await FileDownloader().configure(globalConfig: (Config.holdingQueue, (3, 2, 1))) activates the holding queue and sets the constraints maxConcurrent to 3, maxConcurrentByHost to 2, and maxConcurrentByGroup to 1. Pass null for no constraint for that parameter.
Using the holding queue adds a queue on the native side where tasks may have to wait before being enqueued with the Android WorkManager or iOS URLSessions. Because the holding queue lives on the native side (not Dart) tasks will continue to get pulled from the holding queue even when the app is suspended by the OS. This is different from the TaskQueue, which lives on the Dart side and suspends when the app is suspended by the OS
When using a holding queue:
maxConcurrent valuesTaskStatus.enqueued update immediately upon enqueuing. Once the task gets enqueued with the Android WorkManager or iOS URLSessions you will not get another "enqueue" update, but if that enqueue fails the task will fail. Once the task starts running you will get TaskStatus.running as usualtaskForId and cancelTasksWithIds. There is no way to determine whether a task is in the holding queue or already enqueued with the Android WorkManager or iOS URLSessionsAdds responseStatusCode to TaskStatusUpdate for tasks that result in TaskStatus.complete or TaskStatus.notFound (null otherwise).
responseStatusCode to TaskStatusUpdate for tasks that result in TaskStatus.complete or TaskStatus.notFound (null otherwise).Task.split to extract the baseDirectory, directory and filename from an absolute filePath or a File. This is saver than using .fromFile and preferredUploadTask.fromFile to create an UploadTask from an existing File object. Note that this will create a task with an absolute path reference and BaseDirectory.root, which can cause problems on mobile platforms, so use with careConfig.runInForegroundIf you already have a path to a file or a File object, you can extract the values for baseDirectory, directory and filename using Task.split to create the task:
final (baseDirectory, directory, filename) = await Task.split(filePath: yourPath);
final task = UploadTask(
url: 'https://yourserver.com',
baseDirectory: baseDirectory,
directory: directory,
filename: filename);
If targeting API 34 or greater, you must add to your AndroidManifest.xml a permission declaration <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> and the foreground service type definition (under the application element):
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
Adds option to specify multiple values for a single field name in the UploadTask.fields property by formatting the value as '"value1", "value2", "valu
UploadTask.fields property by formatting the value as '"value1", "value2", "value3"' (note the double quotes and the comma to separate the values).Adds Future requireWiFi(RequireWiFi requirement, {final rescheduleRunningTasks = true}) to set a globally enforced WiFi requirement, and pause/resume
Future<bool> requireWiFi(RequireWiFi requirement, {final rescheduleRunningTasks = true}) to set a globally enforced WiFi requirement, and pause/resume or cancel/restart tasks accordingly. This is helpful when implementing a global toggle switch to prevent data download over metered (cellular) networks. iOS and Android onlyAdds responseHeaders to TaskStatusUpdate for tasks that complete successfully (null otherwise). Per Dart convention, header names are lower-cased
responseHeaders to TaskStatusUpdate for tasks that complete successfully (null otherwise). Per Dart convention, header names are lower-casedext.kotlin_version back to build.gradleAndroid minSdk now 21 (was 24) and compileSdk now 34 (was 33)
Android minSdk now 21 (was 24) and compileSdk now 34 (was 33)
Kotlin compiler version moved from 1.8 to 1.9, typically this means changing your project's build.gradle entry: `agsl buildscript { ext.kotlin_version
Kotlin compiler version moved from 1.8 to 1.9, typically this means changing your project's build.gradle entry:
buildscript {
ext.kotlin_version = '1.9.0' # changed from '1.8.0'
repositories {
google()
mavenCentral()
}
android:launchMode="standard" in Android manifestBy default, the downloader allows any of the permissions to be requested, but that also means that Apple requires you to add things like Photo Library
By default, the downloader allows any of the permissions to be requested, but that also means that Apple requires you to add things like Photo Library Usage Description to your Info.plist, even if you never move files to the Photo Library.
On iOS, to bypass the permission code altogether at compile time (and therefore remove the need to provide the Info.plist entry) modify your app's Podfile as follows:
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
# The following loop has been added to bypass compilation of specific
# permissions.
# If you want to bypass one or more permissions (so that you don't
# have to include things like a Photo Library Usage Description
# if you don't add files to the Photo Library) then add this loop
# and uncomment the permissions you want to bypass.
# If you bypass (by including the line below) then the
# check will not happen, and the permission is aways denied. If you
# bypass you do not need to include the associated entry in your
# Info.plist file
target.build_configurations.each do |config|
config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['$(inherited)']
#config.build_settings['OTHER_SWIFT_FLAGS'] << '-D BYPASS_PERMISSION_NOTIFICATIONS'
#config.build_settings['OTHER_SWIFT_FLAGS'] << '-D BYPASS_PERMISSION_IOSADDTOPHOTOLIBRARY'
#config.build_settings['OTHER_SWIFT_FLAGS'] << '-D BYPASS_PERMISSION_IOSCHANGEPHOTOLIBRARY'
end
end
end
and uncomment the line items that you want to bypass by deleting the # mark at the start of the line.
Your coding agent can read these notes before it upgrades. Set up the MCP server →