miguelpruivo / flutter_file_picker

File picker plugin for Flutter, compatible with mobile (iOS & Android), Web, Desktop (Mac, Linux, Windows) platforms with Flutter Go support.
MIT License
1.33k stars 665 forks source link

Crashing on iOS with getDirectoryPath() #1345

Closed huynguyennovem closed 1 year ago

huynguyennovem commented 1 year ago

Describe the bug Crashing when picking a directory path FilePicker.platform.getDirectoryPath()

Platform

Platform OS version iPhone 7, iOS 15.7.2

How are you picking? Snippet code from example project

String? path = await FilePicker.platform.getDirectoryPath(
  dialogTitle: _dialogTitleController.text,
  initialDirectory: _initialDirectoryController.text,
  lockParentWindow: _lockParentWindow,
);

Details to reproduce the issue

  1. Run the example in this plugin
  2. Click on Pick folder button
  3. Select one folder in On My iPhone menu section > Done
  4. App crash with below trace log

Error Log

Connecting to VM Service at ws://127.0.0.1:62594/IpigRfWW35c=/ws
“Share files” couldn’t be moved because you don’t have permission to access “tmp”.
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(0x180d7fc80 0x1985a3ee4 0x180e7a6b4 0x180d19f6c 0x10026cb80 0x1839b33a8 0x1833acca8 0x1838b899c 0x183252d8c 0x1834510ec 0x1832b8518 0x1841dc428 0x1832d24e4 0x1831a6cf0 0x1831ba6b8 0x1831ba80c 0x1848a8730 0x180a40094 0x1809ecd44 0x1809ec994 0x180d3b034 0x180cf8538 0x180d0b194 0x1a183e988 0x18350da88 0x1832a6fc8 0x100117798 0x1006344d0)
libc++abi: terminating with uncaught exception of type NSException
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00000001bb654bbc libsystem_kernel.dylib`__pthread_kill + 8
libsystem_kernel.dylib`:
->  0x1bb654bbc <+8>:  b.lo   0x1bb654bd8               ; <+36>
    0x1bb654bc0 <+12>: stp    x29, x30, [sp, #-0x10]!
    0x1bb654bc4 <+16>: mov    x29, sp
    0x1bb654bc8 <+20>: bl     0x1bb65060c               ; cerror_nocancel
Target 0: (Runner) stopped.
Lost connection to device.
Exited

Flutter Version details

flutter doctor -v ```console [✓] Flutter (Channel stable, 3.10.6, on macOS 13.5 22G74 darwin-x64, locale en-VN) • Flutter version 3.10.6 on channel stable at /Users/huynq/Documents/GitHub/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision f468f3366c (3 weeks ago), 2023-07-12 15:19:05 -0700 • Engine revision cdbeda788a • Dart version 3.0.6 • DevTools version 2.23.1 [✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0) • Android SDK at /Users/huynq/Library/Android/sdk • Platform android-33, build-tools 32.0.0 • ANDROID_HOME = /Users/huynq/Library/Android/sdk • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 15.0) • Xcode at /Applications/Xcode-beta.app/Contents/Developer • Build 15A5195m • CocoaPods version 1.11.3 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2022.2) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694) [✓] VS Code (version 1.80.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.68.0 [✓] Connected device (2 available) • macOS (desktop) • macos • darwin-x64 • macOS 13.5 22G74 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 115.0.5790.114 [✓] Network resources • All expected network resources are available. • No issues found! ```
huynguyennovem commented 1 year ago

Debugging this on XCode and have some insights:

Detail of error:

Error Domain=NSCocoaErrorDomain Code=513 "“Share files” couldn’t be moved because you don’t have permission to access “tmp”." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Shared/AppGroup/ABCE53E4-9874-43C8-A3A8-F03F7A02B101/File Provider Storage/Share files, NSUserStringVariant=(
    Move
), NSDestinationFilePath=/private/var/mobile/Containers/Data/Application/55B0AB85-8B5A-491A-9200-E3BA1E72D693/tmp/Share files, NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/ABCE53E4-9874-43C8-A3A8-F03F7A02B101/File Provider Storage/Share files, NSUnderlyingError=0x283886c40 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}

The fix: In ios/Classes/FilePickerPlugin.m:

update

[[NSFileManager defaultManager] moveItemAtPath:url.path toPath:tempURL.path error:&error];

to

if([tempURL startAccessingSecurityScopedResource])
{
    [[NSFileManager defaultManager] moveItemAtPath:url.path toPath:tempURL.path error:&error];
    [tempURL stopAccessingSecurityScopedResource];
}

My fix is available at https://github.com/huynguyennovem/flutter_file_picker/tree/getpathdir-crash-1345. PR: https://github.com/miguelpruivo/flutter_file_picker/pull/1346

It would be appreciated if someone can test this on your iOS device to make sure it's compatible with diff iOS versions.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open for 14 days with no activity.

github-actions[bot] commented 1 year ago

This issue was closed because it has been inactive for 14 days since being marked as stale.

ujwalbasnet1 commented 1 year ago

any update on this?

huynguyennovem commented 1 year ago

I fixed this with PR https://github.com/miguelpruivo/flutter_file_picker/pull/1346. You can try using it

tomekit commented 11 months ago

This https://github.com/miguelpruivo/flutter_file_picker/pull/1346 addressed the crash issue on my end, tested on iPhone 8 (16.7), however after I get the folder path and try to list files inside I get: "PathNotFoundException: Directory listing failed".

Shouldn't this also prompt user to give permission to the directory or perhaps are there any additional permission requests that needs to be done prior to calling dir listing?

rohintonc commented 2 months ago

This needs to be reopened I think. As per @tomekit you can get a directory path, but cannot list the contents without calling [url startAccessingSecurityScopedResource]; This should be matched by a [url stopAccessingSecurityScopedResource]; Reference: https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories

I confirmed the problem/fix by adding startAccessingSecurityScopedResource:

- (void)documentPicker:(UIDocumentPickerViewController *)controller
didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls{
...
    if(controller.documentPickerMode == UIDocumentPickerModeOpen) {
        NSURL* url = newUrls.firstObject;
        [url startAccessingSecurityScopedResource];
        _result(url.path);
        _result = nil;
        return;
    }

However, another method channel will be required to call stopAccessingSecurityScopedResource on the selected folder when the Dart code has finished iterating the contents.

rohintonc commented 2 months ago

I have opened a new issue: https://github.com/miguelpruivo/flutter_file_picker/issues/1568