Skip to content

Filtering files by extension on macOS incorrectly considers UTIs #134963

@jmatth

Description

@jmatth

Is there an existing issue for this?

What package does this bug report belong to?

file_selector

What target platforms are you seeing this bug on?

macOS

Have you already upgraded your packages?

Yes

Dependency versions

pubspec.lock
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
  async:
    dependency: transitive
    description:
      name: async
      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
      url: "https://pub.dev"
    source: hosted
    version: "2.11.0"
  boolean_selector:
    dependency: transitive
    description:
      name: boolean_selector
      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.1"
  characters:
    dependency: transitive
    description:
      name: characters
      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
      url: "https://pub.dev"
    source: hosted
    version: "1.3.0"
  clock:
    dependency: transitive
    description:
      name: clock
      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
      url: "https://pub.dev"
    source: hosted
    version: "1.1.1"
  collection:
    dependency: transitive
    description:
      name: collection
      sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
      url: "https://pub.dev"
    source: hosted
    version: "1.17.2"
  cross_file:
    dependency: transitive
    description:
      name: cross_file
      sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb
      url: "https://pub.dev"
    source: hosted
    version: "0.3.3+5"
  cupertino_icons:
    dependency: "direct main"
    description:
      name: cupertino_icons
      sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
      url: "https://pub.dev"
    source: hosted
    version: "1.0.6"
  fake_async:
    dependency: transitive
    description:
      name: fake_async
      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
      url: "https://pub.dev"
    source: hosted
    version: "1.3.1"
  file_selector:
    dependency: "direct main"
    description:
      name: file_selector
      sha256: "84eaf3e034d647859167d1f01cfe7b6352488f34c1b4932635012b202014c25b"
      url: "https://pub.dev"
    source: hosted
    version: "1.0.1"
  file_selector_android:
    dependency: transitive
    description:
      name: file_selector_android
      sha256: d41e165d6f798ca941d536e5dc93494d50e78c571c28ad60cfe0b0fefeb9f1e7
      url: "https://pub.dev"
    source: hosted
    version: "0.5.0+3"
  file_selector_ios:
    dependency: transitive
    description:
      name: file_selector_ios
      sha256: b3fbdda64aa2e335df6e111f6b0f1bb968402ed81d2dd1fa4274267999aa32c2
      url: "https://pub.dev"
    source: hosted
    version: "0.5.1+6"
  file_selector_linux:
    dependency: transitive
    description:
      name: file_selector_linux
      sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
      url: "https://pub.dev"
    source: hosted
    version: "0.9.2+1"
  file_selector_macos:
    dependency: transitive
    description:
      name: file_selector_macos
      sha256: "182c3f8350cee659f7b115e956047ee3dc672a96665883a545e81581b9a82c72"
      url: "https://pub.dev"
    source: hosted
    version: "0.9.3+2"
  file_selector_platform_interface:
    dependency: transitive
    description:
      name: file_selector_platform_interface
      sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262"
      url: "https://pub.dev"
    source: hosted
    version: "2.6.1"
  file_selector_web:
    dependency: transitive
    description:
      name: file_selector_web
      sha256: dc6622c4d66cb1bee623ddcc029036603c6cc45c85e4a775bb06008d61c809c1
      url: "https://pub.dev"
    source: hosted
    version: "0.9.2+1"
  file_selector_windows:
    dependency: transitive
    description:
      name: file_selector_windows
      sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
      url: "https://pub.dev"
    source: hosted
    version: "0.9.3+1"
  flutter:
    dependency: "direct main"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_lints:
    dependency: "direct dev"
    description:
      name: flutter_lints
      sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
      url: "https://pub.dev"
    source: hosted
    version: "2.0.3"
  flutter_test:
    dependency: "direct dev"
    description: flutter
    source: sdk
    version: "0.0.0"
  flutter_web_plugins:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.0"
  http:
    dependency: transitive
    description:
      name: http
      sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
      url: "https://pub.dev"
    source: hosted
    version: "1.1.0"
  http_parser:
    dependency: transitive
    description:
      name: http_parser
      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
      url: "https://pub.dev"
    source: hosted
    version: "4.0.2"
  js:
    dependency: transitive
    description:
      name: js
      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
      url: "https://pub.dev"
    source: hosted
    version: "0.6.7"
  lints:
    dependency: transitive
    description:
      name: lints
      sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.1"
  matcher:
    dependency: transitive
    description:
      name: matcher
      sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
      url: "https://pub.dev"
    source: hosted
    version: "0.12.16"
  material_color_utilities:
    dependency: transitive
    description:
      name: material_color_utilities
      sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
      url: "https://pub.dev"
    source: hosted
    version: "0.5.0"
  meta:
    dependency: transitive
    description:
      name: meta
      sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
      url: "https://pub.dev"
    source: hosted
    version: "1.9.1"
  path:
    dependency: transitive
    description:
      name: path
      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
      url: "https://pub.dev"
    source: hosted
    version: "1.8.3"
  plugin_platform_interface:
    dependency: transitive
    description:
      name: plugin_platform_interface
      sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d
      url: "https://pub.dev"
    source: hosted
    version: "2.1.6"
  sky_engine:
    dependency: transitive
    description: flutter
    source: sdk
    version: "0.0.99"
  source_span:
    dependency: transitive
    description:
      name: source_span
      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
      url: "https://pub.dev"
    source: hosted
    version: "1.10.0"
  stack_trace:
    dependency: transitive
    description:
      name: stack_trace
      sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
      url: "https://pub.dev"
    source: hosted
    version: "1.11.0"
  stream_channel:
    dependency: transitive
    description:
      name: stream_channel
      sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.1"
  string_scanner:
    dependency: transitive
    description:
      name: string_scanner
      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
      url: "https://pub.dev"
    source: hosted
    version: "1.2.0"
  term_glyph:
    dependency: transitive
    description:
      name: term_glyph
      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
      url: "https://pub.dev"
    source: hosted
    version: "1.2.1"
  test_api:
    dependency: transitive
    description:
      name: test_api
      sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
      url: "https://pub.dev"
    source: hosted
    version: "0.6.0"
  typed_data:
    dependency: transitive
    description:
      name: typed_data
      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
      url: "https://pub.dev"
    source: hosted
    version: "1.3.2"
  vector_math:
    dependency: transitive
    description:
      name: vector_math
      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
      url: "https://pub.dev"
    source: hosted
    version: "2.1.4"
  web:
    dependency: transitive
    description:
      name: web
      sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
      url: "https://pub.dev"
    source: hosted
    version: "0.1.4-beta"
sdks:
  dart: ">=3.1.1 <4.0.0"
  flutter: ">=3.7.0"

Steps to reproduce

  1. Run the provided example app
  2. Enter uvtt into the text box and press enter
  3. Click the FAB to summon the macOS file selector window
  4. Click Cancel to close the file selector window
  5. Click the X button in the chip to remove uvtt from the extensions list
  6. Enter jpeg in the text field and press enter
  7. Click the FAB to summon the macOS file selector window

Expected results

When uvtt is entered only files ending in .uvtt should be available for selection.

When .jpeg is entered only files ending in .jpeg should be available for selection.

Actual results

When uvtt is entered no files are available for selection.

When .jpeg is entered files ending in .jpeg and .jpg are available for selection.

Code sample

Code sample
import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter file picker test'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String? _path;
  final _extensionController = TextEditingController();
  final List<String> _extensions = [];

  @override
  dispose() {
    _extensionController.dispose();
    super.dispose();
  }

  Future<void> _pickFile() async {
    final file = await openFile(
      acceptedTypeGroups: [
        XTypeGroup(
          extensions: _extensions,
        ),
      ],
    );
    if (file == null) return;
    setState(() {
      _path = file.path;
    });
  }

  final _splitPattern = RegExp(r'(\s|,)');
  void _addExtensions(String extensionsStr) {
    _extensionController.value = TextEditingValue.empty;
    final extensions = extensionsStr
        .split(_splitPattern)
        .map((s) => s.trim())
        .where((s) => s.isNotEmpty)
        .where((s) => !_extensions.contains(s))
        .toList();
    if (extensions.isEmpty) return;
    setState(() {
      _extensions.addAll(extensions);
    });
  }

  void _removeExtension(String extension) {
    setState(() {
      _extensions.remove(extension);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Wrap(
            direction: Axis.horizontal,
            runSpacing: 10,
            spacing: 5,
            children: _extensionChips(context),
          ),
          Center(
            child: ConstrainedBox(
              constraints: const BoxConstraints(maxWidth: 500),
              child: TextField(
                controller: _extensionController,
                maxLines: 1,
                onSubmitted: _addExtensions,
                textInputAction: TextInputAction.none,
              ),
            ),
          ),
          const SizedBox(height: 20),
          Text(_path ?? '<No file selected>'),
        ],
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _pickFile,
        tooltip: 'Select file',
        child: const Icon(Icons.folder_open),
      ),
    );
  }

  List<Widget> _extensionChips(BuildContext context) => _extensions
      .map((e) => InputChip(
            key: ValueKey(e),
            label: Text(e),
            onDeleted: () => _removeExtension(e),
          ))
      .toList();
}

Screenshots or Videos

Screenshots / Video demonstration
Screen.Recording.2023-09-18.at.14.39.01.mov

Logs

Logs
flutter run -d macos
Launching lib/main.dart on macOS in debug mode...
Building macOS application...                                   
2023-09-18 14:44:52.485 xcodebuild[22547:5100579] DVTCoreDeviceEnabledState: DVTCoreDeviceEnabledState_Disabled set via user default (DVTEnableCoreDevice=disabled)
--- xcodebuild: WARNING: Using the first of multiple matching destinations:
{ platform:macOS, arch:arm64, id:00006001-001009DC2E02801E }
{ platform:macOS, arch:x86_64, id:00006001-001009DC2E02801E }
Syncing files to device macOS...                                    33ms

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

A Dart VM Service on macOS is available at: http://127.0.0.1:50039/CKbqVAUgSMw=/
The Flutter DevTools debugger and profiler on macOS is available at: http://127.0.0.1:9103?uri=http://127.0.0.1:50039/CKbqVAUgSMw=/
2023-09-18 14:45:05.557 test_file_selector_macos[22715:5101263] +[CATransaction synchronize] called within transaction
2023-09-18 14:45:11.977 test_file_selector_macos[22715:5101263] +[CATransaction synchronize] called within transaction
Lost connection to device.

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[!] Flutter (Channel stable, 3.13.4, on macOS 13.4 22F66 darwin-arm64, locale en-US)
    ! Warning: `flutter` on your path resolves to /Users/joshuamatthews/.fvm/versions/3.13.3/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/joshuamatthews/.fvm/versions/3.13.4. Consider adding /Users/joshuamatthews/.fvm/versions/3.13.4/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /opt/homebrew/Cellar/dart/3.1.1/libexec/bin/dart, which is not inside your current Flutter SDK checkout at /Users/joshuamatthews/.fvm/versions/3.13.4. Consider adding /Users/joshuamatthews/.fvm/versions/3.13.4/bin to the front of your path.
    ! Upstream repository /Users/joshuamatthews/projects/forks/flutter is not a standard remote.
      Set environment variable "FLUTTER_GIT_URL" to /Users/joshuamatthews/projects/forks/flutter to dismiss this error.
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.3)
[✓] Android Studio (version 2022.3)
[✓] IntelliJ IDEA Community Edition (version 2022.3.2)
[✓] VS Code (version 1.82.2)
[✓] Connected device (2 available)
[✓] Network resources

! Doctor found issues in 1 category.

Additional information

Based on my experimentation, it seems that the file_selector implementation is depending on information from Uniform Type Identifiers (UTIs) instead of just filtering based on extension. When I defined a custom UTI that included multiple extensions, specifying any of those extensions in XTypeGroup.extensions allowed me to select files with any of the other related extensions. I think this is the same behavior from the example when you specify jpeg and .jpg files are also made available.

Downgrading file_selector to 0.8.4+3 resolved the issue in my app.

Metadata

Metadata

Labels

P1High-priority issues at the top of the work listc: regressionIt was better in the past than it is nowp: file_selectorThe file_selector pluginpackageflutter/packages repository. See also p: labels.platform-macBuilding on or for macOS specificallyteam-ecosystemOwned by Ecosystem teamtriaged-ecosystemTriaged by Ecosystem team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions