Skip to content

[file_selector] Updates cross_file to 0.4.0 and updates to platform interface to latest standard - #13147

Open
bparrishMines wants to merge 104 commits into
flutter:mainfrom
bparrishMines:file_selector_2
Open

bparrishMines wants to merge 104 commits into
flutter:mainfrom
bparrishMines:file_selector_2

Conversation

@bparrishMines

@bparrishMines bparrishMines commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Because file_selector exports cross_file, a breaking change is needed to update the dependency. Since a breaking change is needed anyway, this also removes deprecated methods and API and adds support for XDirectorys.

List of changes in the platform interface (also included in CHANGELOG.md):

  • Updates cross_file dependency to 0.4.0.
  • Removes MethodChannel implementation.
  • Replaces FileSelectorPlatform's of implementation PlatformInterface with the base keyword.
  • Changes openFile and openFiles to take a OpenFileDialogOptions and OpenFilesDialogOptions, respectively.
  • Removes getSavePath. Replaced by getSaveLocation.
  • Changes getSaveLocation to take a SaveLocationOptions.
  • Replaces FileSaveLocation.path with FileSaveLocation.file.
  • Replaces getDirectoryPath with getDirectory and now returns a XDirectory.
  • Replaces getDirectoryPaths with getDirectories and now returns List<XDirectory.
  • Changes getDirectory and getDirectories to take a GetDirectoryDialogOptions and GetDirectoriesDialogOptions, respectively.
  • Removes XTypeGroup.macUTIs. Use XTypeGroup.uniformTypeIdentifiers instead.

Every platform functionally remains the same except for Android. Android no longer copies a file from a content provider to a temporary directory. It now only returns the original content URIs for files and directories. cross_file now handles using those files directly.

Part of flutter/flutter#193154

Related Issues this fixes or allows to be fixed:

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2

if (kIsWeb) {
return Image.network(file.uri);
} else if (defaultTargetPlatform == TargetPlatform.macOS) {
return Image.file(File(Uri.parse(file.uri).toFilePath()));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pattern has drawbacks:

  1. It depends on knowledge of the Darwin cross file implementation.
  2. It doesn't extend to out-of-tree platforms

An alternative might be to add an API to XFile to try to convert it to a File. If that operation succeeds, we can use Image.file, otherwise we fallback to Image.memory. What would you think of that approach?

@bparrishMines bparrishMines Nov 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true, but you also need to know that web only works with Image.network anyways. I don't know if there is a way to avoid needing platform specific knowledge without proving an Image toImage(XFile) somewhere or adding XFile support to Image directly.

Added a TODO that includes flutter/flutter#196306 for this. I think it could still be worthwhile for a platform implementation to handle returning a file path if possible. That would at least make it so Uri.parse(file.uri).toFilePath() doesn't need to be called everywhere. Also, just attempting to create a File with the URI from XFile wouldn't be enough. One could make a valid file path from any URI like 123 and the user wouldn't know that you cant access the file that way. So the issue leaves it up to the platform implementation to handle whether the URI can be provided as a file path.

I also don't want to return a File in XFile because i think I want to avoid importing dart:io in the app-facing package. I could be wrong, but I remember a weird interaction with pub where if a package imports dart:io, it removes the flag that web is supported for a package.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong, but I remember a weird interaction with pub where if a package imports dart:io, it removes the flag that web is supported for a package.

Ah that's a very good point 👍

Added a TODO that includes flutter/flutter#196306 for this.

Ah nice, after this TODO I imagine the code will look something like this?

Future<Image> _getImage() async {
  if (kIsWeb) {
    return Image.network(file.uri);
  } else if (file.asFilePath case String path) {
    return Image.file(File(path));
  } else {
    return Image.memory(await file.readAsBytes());
  }
}

If so, that addresses my concern and SGTM 👍

final XFile? file = await openFile(
acceptedTypeGroups: <XTypeGroup>[typeGroup],
initialDirectory: initialDirectory,
);

@loic-sharma loic-sharma Nov 9, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is a ScopedStorageXFile, we need to dispose() it. On iOS/macOS, forgetting to call NSURL.stopAccessingSecurityScopedResource can result in the OS preventing the app from accessing more resources. Some thoughts:

  • We should update the examples to properly dispose XFiles
  • It seems we should add a XFile.dispose method. Apps shouldn't need to cast an XFile to check whether they need to dispose the XFile.
  • Your app now needs to call dispose() when it didn't need before. This is a breaking change (even though your app will continue to compile). The CHANGELOG.md should explain this and provide migration instructions

@bparrishMines bparrishMines Nov 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was also brought up in the cross_file 1.0 PR and the design doc. To avoid requiring users to call dispose or potentially just forgetting, cross_file_darwin and cross_file_web automatically clean up resources when the ScopedStorageXFile is garbage collected. (cross_file_android doesn't need it)

I didn't consider this a breaking change because web and macOS need to clean up resources with the current implementation, but they don't. I think it's more of a bug:

Web: https://github.com/flutter/packages/blob/main/packages/file_selector/file_selector_web/lib/src/dom_helper.dart#L70
MacOS: NSURL.startAccessingSecurityScopedResource is called automatically and NSURL.stopAccessingSecurityScopedResource is supposed to be called.

I prefer not requiring calling dispose with every XFile and I don't want ScopedStorage platforms to expect the user to remember to do it. Unfortunately, requiring to call dispose affects more than just file_selector. Any API that returns or uses a XFile would have to remember to call dispose. But I think this is more of a cross_file plugin discussion and shouldn't affect this PR since it's currently handled automatically on all platforms.

I added documentation to the file_selector methods to recommend calling the dispose method though:

/// If the returned [XFile] is a [ScopedStorageXFile], it is recommended that
/// the [ScopedStorageXFile.dispose] is called when the app no longer needs
/// access to the resource.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maurice and I discussed this offline. Adding XFile.dispose() has the following concerns:

  • It complicates XFile. One could argue this complexity is good: you get one API that works well across all implementations. Also, Flutter uses this pattern (e.g., BoxPainter has an empty dispose method that not all subclasses implement).
  • XFile.dispose() could cause different implementations to behave differently. Calling a method after dispose() would error for ScopedStorageXFile but not FileSystemXFile. We can mitigate this by adding a debugDisposed property so that FileSystemXFile can error if methods are called after dispose().

We agreed to add XFile.dispose() after this discussion.


* **BREAKING CHANGES**:
* Updates `file_selector_platform_interface` to `3.0.0` which updates `cross_file` dependency to
`0.4.0`. See its breaking changes in its [CHANGELOG](https://pub.dev/packages/cross_file/changelog#040).

@loic-sharma loic-sharma Nov 9, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine that an app that uses file_selector might mock FileSelectorPlatform with an implements. This is no longer possible now that FileSelectorPlatform is an abstract base class. Could we add a quick migration guide for how to mock the file selector plugin?

/// Opens a directory selection dialog and returns a list of the paths chosen
/// by the user.
///
/// This always returns an empty array on the web.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like FileSelectorWeb web doesn't implement getDirectories, so it throws an UnimplementedError. This is a pre-existing bug, but since we're introducing a new getDirectories method could you update FileSelectorWeb to return an empty array with a test?

cross_file_platform_interface: ^1.0.0
flutter_test:
sdk: flutter
plugin_platform_interface: ^2.1.7

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this now?

///
/// Returns `null` if user cancels the operation.
@async
String? getDirectoryPath(String? initialDirectory);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename this to getDirectoryUri? If yes, don't forget to update the doc above :)

/// An API to call to native code to select files or directories.
@HostApi()
abstract class FileSelectorApi {
/// Opens a file dialog for loading files and returns a file path.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be update to returns a file URI.? Same comment for openFiles below

@@ -8,10 +8,9 @@ import 'package:file_selector_platform_interface/file_selector_platform_interfac
import 'package:flutter/cupertino.dart';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we replace this with import 'package:flutter/foundation.dart';? It doesn't look like we use Cupertino here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@bparrishMines bparrishMines removed the CICD Run CI/CD label Nov 10, 2026
AshutoshSajan added a commit to AshutoshSajan/mise_gui that referenced this pull request Nov 12, 2026
- Render the static logo from the existing PNG and drop flutter_svg; this removes vector_graphics, vector_graphics_compiler, xml, and six more packages
- Allowlist the remaining transitive pins with concrete reasons: cross_file (file_selector upstream PR flutter/packages#13147), material_color_utilities and test_api (Flutter SDK pins)
- Make deps:check fail on undocumented transitive drift; deps:outdated now prints the full annotated report
- Bump file_selector to ^1.1.0
- Document the allowlist workflow and the no-overrides rule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants