NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
pub.dev · #3020 most downloaded on pub.dev
Flutter plugin for local iCloud Drive file operations with coordinated iOS and macOS access.
Last release 2 months ago
19 Jul 2026
Ships fairly regularly
a new release about every 3 weeks
Nearly every release is documented
notes for 13 of 13 stable releases
Nothing withdrawn
no release was ever pulled
8 months old
13 releases · first in 2026
One column per month.
feat!: release icloud_storage_plus 4.0.0
Harden coordinated Darwin writes and passive document observation, replace legacy APIs with the typed 4.0.0 contract, fix stream lifecycle ownership, and package privacy manifests.\n\nCo-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Preserve the native-supplied category (e.g. cancelled, initialization)
in decodePlatformException instead of collapsing every unmodeled
category into ICloudUnknownNativeException, so callers can distinguish
intentional cancellation from unknown native failures.
Close the transformed event stream after a malformed gather or
document-change payload, matching the transfer-progress stream and the
contract that malformed update payloads fail the stream.
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
Co-authored-by: Claude Fable 5 noreply@anthropic.com
Co-authored-by: Codesmith codesmith-bot@users.noreply.github.com
getDocumentMetadata; use getItemMetadata for typed metadata.PlatformExceptionCode constants. Match typed
ICloudOperationException subclasses and fields instead of transport codes.PlatformException failures now map to typed
ICloudOperationException values, including details-less native failures and
malformed method/event-channel contracts.onError callback
as typed exceptions. Remove ICloudTransferProgressType.error, isError, and
event.exception handling; data events are only progress and done.uploadFile and downloadFile named argument and method-channel
key from cloudRelativePath to relativePath.ICloudDocumentChangeKind.remoteChange and its native wire value to
ICloudDocumentChangeKind.invalidation / "invalidation". Treat it as a
refresh hint and reread coordinated state.ICloudDocumentChangeKind.unknown. Unsupported native wire values now
fail the change stream as a plugin-contract violation instead of using a
forward-compatibility fallback.GatherInvalidEntry and GatherResult.invalidEntries; malformed
gather payloads now fail the whole initial call or update stream.ICloudStorage.documentsDirectory and dataDirectory. Use the
literal Documents/ path convention for Files app visibility.null, notDownloaded,
downloaded, or current.readInPlace and readInPlaceBytes now return non-nullable String and
Uint8List values. Missing items throw ICloudItemNotFoundException instead
of returning null.ICloudStoragePlatform.getItemMetadata now returns
Future<ICloudItemMetadata?>; method-channel payloads are decoded exactly
once by the default platform implementation.ICloudOperationException subtype now has a public
constructor accepting normalized failure fields, including dedicated
cancellation and initialization exceptions. The raw PlatformException
mapper is internal to the method-channel implementation and is no longer part
of the public API.onUpdate, onProgress, and onChange callbacks must attach a stream
listener synchronously. Delayed or ignored streams throw
InvalidArgumentException before native event-channel allocation.pluginContract exceptions. All Future<void> channel operations require a
strictly null success response, including event-channel creation/start,
mutations, transfers, and conflict operations.NSFileCoordinator.WritingOptions empty) instead of
replacement-intent (.forReplacing) coordination. Complete content is still
staged outside the container and installed with FileManager.replaceItemAt;
unresolved conflict versions remain app-owned.NSDocument reload/revert handling. Non-conflict content callbacks are
de-duplicated using the on-disk modification date; conflict callbacks bypass
that filter and may repeat while unresolved.gather(onUpdate:) streams are best-effort
invalidation/update signals, not real-time or exactly-once change logs.Major release for the app-owned preserve-both conflict model and the final MYT-1321 publish cutover.
Major release for the app-owned preserve-both conflict model and the final MYT-1321 publish cutover.
ConflictResolver, write-path auto-resolve, and document-observer
auto-resolve no longer exist. The plugin never silently marks or deletes
losing NSFileVersions.enumerateUnresolvedConflictVersions, copyConflictVersion, and
markConflictResolved) to implement their own conflict policy.
The plugin exposes primitives only; apps own preserve-both copy-out and
resolution sequencing.NSFileVersion descriptors, caller-chosen
conflict-version copy-out, and explicit mark-resolved operations over the
Dart API.AsyncMutex.acquire() now removes a queued waiter immediately when the
waiting task is cancelled, preventing cancelled waiters from lingering in a
lane until normal FIFO hand-off reaches them.pubspec.yaml version.
This reconciles the previous podspec 2.1.3 versus pubspec 2.2.0 drift
before publishing the new major.Package.swift manifests remain source-list only, with no semantic version
field. The package source lists reference only files that are still present.Corrective release for the readiness/error-reporting API introduced in 2.0.0. That surface treated normal iCloud Drive lifecycle state as plugin-owned
Corrective release for the readiness/error-reporting API introduced in
2.0.0. That surface treated normal iCloud Drive lifecycle state as
plugin-owned failures; this release removes it and restores the intended local
file-operation boundary.
readInPlace and
readInPlaceBytes. Reads now perform local iCloud Drive file access instead
of waiting for Apple metadata to report a fresh remote state.copy() behavior on iOS and macOS: the copy
path no longer preflights iCloud download/current/conflict metadata or emits
retired readiness errors before replacement. Existing directory destinations
are rejected; placeholder, freshness, and conflict lifecycle states are left
to Foundation, and any actual replacement failure is surfaced from the local
operation..current before opening the local
document.iOS and macOS container operations now route through a shared UbiquityContainerResolver, including gather, so transient FileManager.url(forUbiquityCon
UbiquityContainerResolver, including gather, so transient
FileManager.url(forUbiquityContainerIdentifier:) nil responses retry
before surfacing a container-access failure.Task.sleep cancellation
instead of swallowing it, so cancelled calls stop before issuing an
unnecessary second container lookup.NSMetadataQuery completes.iOS readInPlace / readInPlaceBytes now marshal the post-download continuation back onto the main actor before invoking readInPlaceDocument / readInPla
readInPlace / readInPlaceBytes now marshal the post-download continuation back onto the main actor before invoking readInPlaceDocument / readInPlaceBinaryDocument. The 2.1.0 async rewrite of waitForDownloadCompletion inadvertently removed the DispatchQueue.main hop that the callback-based waiter guaranteed, letting UIDocument.open(completionHandler:) be called from the Swift cooperative pool. This restores the 1.2.2 invariant that UIDocument work runs under the main queue per Apple's completion-handler contract and avoids the _os_object_retain "Resurrection of an object" crash that motivated that fix.uploadFile, readInPlace, readInPlaceBytes, writeInPlace, writeInPlaceBytes now run their Task bodies on the main actor. Because the macOS FlutterMethodChannel is registered without a background task queue, FlutterResult must be invoked on the main thread; the previous Task { [self] in ... } blocks resumed on the cooperative pool after await, causing result(...) to be called off-main in preflight error paths.Closes the threading concerns raised on #27, #26, and #25.
Full Changelog: 2.1.1...2.1.2
readInPlace and readInPlaceBytes now marshal the post-materialization
continuation back onto the main actor before invoking
readInPlaceDocument / readInPlaceBinaryDocument. The 2.1.0 async
rewrite of the previous readiness helper inadvertently removed the
DispatchQueue.main hop that the callback-based helper guaranteed,
letting UIDocument.open(completionHandler:) be called from the Swift
cooperative pool. This restores the 1.2.2 invariant that UIDocument
work runs under the main queue per Apple's completion-handler contract
and avoids the _os_object_retain "Resurrection of an object" crash
that motivated that fix.uploadFile, readInPlace, readInPlaceBytes, writeInPlace,
and writeInPlaceBytes now run their Task bodies on the main actor.
Because the macOS FlutterMethodChannel is registered without a
background task queue, FlutterResult must be invoked on the main
thread; the previous Task { [self] in ... } blocks resumed on the
cooperative pool after await, causing result(...) to be called
off-main in preflight error paths.Added WriteEntrypointPreflight.swift to the explicit iOS plugin Package.swift source list so consumer builds that rely on the plugin's Swift package m
WriteEntrypointPreflight.swift to the explicit iOS plugin
Package.swift source list so consumer builds that rely on the plugin's
Swift package manifest can compile the 2.1.x write-path preflight helper.2.1.0 are unchanged.Non-breaking behavior upgrade: writeInPlace becomes symmetric with readInPlace by proactively preparing existing iCloud items before the coordinated r
Non-breaking behavior upgrade: writeInPlace becomes symmetric with
readInPlace by proactively preparing existing iCloud items before the
coordinated replace.
Public Dart API unchanged.
WriteEntrypointPreflight helpers and foundation tests on iOS and
macOS to move write-path container lookup and parent-directory creation off
the entry thread before coordinated writes begin.invalidArgument write failures via
ICloudInvalidArgumentException.writeInPlace and the binary / streaming overwrite paths now proactively
prepare existing ubiquitous destinations before the coordinated replace.NSFileVersion.unresolvedConflictVersionsOfItem → replaceItem →
isResolved = true → removeOtherVersionsOfItem) before invoking
replaceItemAt, symmetric with the existing readInPlace behavior.ICloudConflictException on the Dart side.CoordinatedReplaceWriter.swift into a single source of truth per
platform (iOS and macOS) shared via SPM target.sources.ICloudDocument.resolveConflicts() (iOS) and the equivalent macOS
observer both call the shared resolver; the duplicate implementation
on iOS has been removed.listContents on iOS and macOS now does less repeated work inside the
directory-enumeration loop by reusing the key set, reusing the parent
relative path, and skipping hidden files before metadata lookup.Drop the merged superpowers planning/spec files and top-level planning logs from main so the release branch documentation stays out of the published p
Drop the merged superpowers planning/spec files and top-level planning logs from main so the release branch documentation stays out of the published package history.
Breaking release that hardens the Dart API contract around known-path metadata, typed request/response failures, and coordinated overwrite behavior on iOS and macOS.
getMetadata() API in favor of getItemMetadata().ICloudOperationException subclasses across the Dart API.getDocumentMetadata() remains the raw metadata escape hatch and preserves
raw PlatformException behavior.ICloudItemMetadata as the typed known-path metadata model returned by
getItemMetadata().2.0.0
contract explicitly, including the separation between ICloudItemMetadata,
ICloudFile, and raw getDocumentMetadata() payloads.PlatformException-based error
payloads in 2.0.0; only request/response APIs use the new typed exception
mapping.copy() now document
separate existing-destination semantics: file writes target files only,
while copy() preserves file-or-directory copy behavior.doc/deepwiki/.writeDocument, writeInPlace, and
writeInPlaceBytes now stage replacement content outside the ubiquity
container and replace the destination through coordinated atomic replacement.1.2.2 document-open completion fix that dispatches
UIDocument completion back onto DispatchQueue.main, avoiding the
_os_object_retain resurrection crash from short-lived local queues.copy() now keep existing destinations inside coordinated
atomic replacement flows instead of removing the destination before copying.Merge branch 'fix/t5-ios-hang-seam'
Merge branch 'fix/t5-ios-hang-seam'
DispatchQueue. The short-lived queue could be deallocated before
UIDocument.openWithCompletionHandler: finished retaining it (via the
deprecated dispatch_get_current_queue call in UIKit internals), causing
an _os_object_retain crash with "API MISUSE: Resurrection of an object".
Completion is now dispatched on DispatchQueue.main, which is consistent
with UIDocument's own completion-handler contract.iOS method-channel filesystem work now uses Flutter's background task queue when that queue is available. Container lookup, iCloud path preflight, and
UIDocument initialization stay coordinated but no longer block the UI
thread during in-place reads and writes on supported runtimes.DispatchQueue.main.sync for event-channel state checks, reducing deadlock
risk when iCloud change notifications arrive while other native work is in
flight.FlutterResult delivery when
cancellation races with native completion.listContents() API for immediately-consistent container listings using FileManager.contentsOfDirectory with URL resource values. Unlike gather() (whic
listContents() API for immediately-consistent container listings using
FileManager.contentsOfDirectory with URL resource values. Unlike gather()
(which reads the Spotlight metadata index), listContents() reflects
filesystem mutations (rename, delete, copy) immediately.ContainerItem model with relativePath, downloadStatus, isDownloading,
isUploaded, isUploading, hasUnresolvedConflicts, isDirectory, and a
convenience isDownloaded getter..originalName.icloud stubs)
and macOS Sonoma+ (APFS dataless files) are handled transparently —
listContents returns the real filename and accurate download status.listContents suppresses system files (.DS_Store,
.Trash, etc.) by filtering entries whose resolved name starts with ..ICloudFile dartdoc now cross-references ContainerItem and explains the
eventual-consistency distinction.GatherResult dartdoc expanded to describe invalidEntries purpose.InvalidArgumentException doc comment ("ued" → "used").listContents documentation, gather vs listContents
comparison table, iCloud placeholder files section, and ContainerItem model
reference.GitHub Actions automated publishing trigger for tags like 1.2.3 (no v prefix).
1.2.3 (no v
prefix).dart pub publish
validation warnings.Major API update with path-based transfers for large files, coordinated in-place read/write APIs for small files, and a documentation overhaul.
Major API update with path-based transfers for large files, coordinated in-place read/write APIs for small files, and a documentation overhaul.
Byte-based transfer APIs have been removed in favor of file-path methods. Large file content is no longer sent over platform channels.
Removed: upload(), download(), and related byte/JSON helpers.
New: uploadFile() and downloadFile() using local paths plus
cloudRelativePath.
Migration:
uploadFile(localPath, cloudRelativePath).downloadFile(cloudRelativePath, localPath) and read the
local file in Dart.gather() now returns a GatherResult containing:
files: parsed ICloudFile entriesinvalidEntries: entries that could not be parsed (helps debug malformed
metadata payloads)ICloudFile now:
isDirectory: bool (directories are returned by metadata APIs)null for some fields when iCloud metadata is unavailable or the
entry represents a directory (for example sizeInBytes)documentExists() and getMetadata() return true/non-null for both files and
directories. Filter directories explicitly if your code expects only files.
Minimum deployment targets match Flutter 3.10+:
The native method channel name is icloud_storage_plus (was icloud_storage).
Dev linting moved to very_good_analysis.
uploadFile() (local → iCloud container)downloadFile() (iCloud container → local)readInPlace() / writeInPlace() (String, UTF-8)readInPlaceBytes() / writeInPlaceBytes() (Uint8List)rename() API (implemented in Dart via move()).ICloudFile:
downloadStatus, isDownloadingisUploading, isUploadedhasUnresolvedConflictsPlatformExceptionCode.initializationError (E_INIT)doc/ for GitHub navigationscripts/fix_deepwiki_links.py to keep exported docs linkabledoc/ research/plans removed (replaced by short notes under
doc/notes/)delete, move, copy) use coordinated file URL
operations (NSFileCoordinator) rather than relying on metadata queries.documentExists, getDocumentMetadata) use direct
filesystem checks (FileManager / URL resource values) rather than metadata
queries.documentExists() is a filesystem existence check; it does not force a
download. Use gather() for a remote-aware view of container contents.ICloudTransferProgressType.error
data events (not stream onError).gather() now verifies the event channel handler exists before registering
query observers (prevents leaked observers on early-return).getDocumentMetadata() now serializes download status keys as strings
(.rawValue) for correct transport to Dart.delete(), move(),
rename(), etc.uploadFile() / downloadFile() reject cloudRelativePath values that end
with / (directory-style paths)..saveOperation for existing files to avoid
unintended “Save As” behavior.uploadFile() /
downloadFile().readInPlace/writeInPlace) for “transparent sync”.ICloudFile.isDirectory and
add null checks for optional metadata fields.onProgress (streams are listener-driven and may miss early events).flutter analyze to address any very_good_analysis lint findings.Your coding agent can read these notes before it upgrades. Set up the MCP server →