Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ui-document-picker returns file path that can't be used to open a file #21

Open
BikeBr0 opened this issue Feb 18, 2022 · 16 comments
Open

Comments

@BikeBr0
Copy link

BikeBr0 commented Feb 18, 2022

On both iOS and Android I cannot open the file using the path returned by openFilePicker. For example, using {N} 8.1.5:

ns create test-app
> Angular
> Hello World
ns plugin add @nativescript-community/ui-document-picker

Then edit src/app/item/item-detail.component.html to open a filePicker:

...
<Label class="h2" [text]="item.name" (tap)="handleTap()"></Label>
...

And add the corresponding handler to src/app/item/item-detail.component.ts:

...
  handleTap(): void {
    openFilePicker().then((val) => {
      if (!val.files || val.files.length === 0) {
        throw new Error('No file selected.');
      } else {
        const path = val.files[0];
        console.log(`Path: ${path}`);
        const file = File.fromPath(path);
        console.log(`File: ${file.name}`);
      }
    });
  }
...

Then:

ns build android
ns run android

And test on the device.

Expected result: File name is printed to the console

Actual result: ERROR Error: Uncaught (in promise): Error: java.io.IOException: No such file or directory

Here is a more detailed stack trace:

JS: ERROR Error: Uncaught (in promise): Error: java.io.IOException: No such file or directory
JS: ensureFile(file: src\webpack:\test-app\node_modules\@nativescript\core\file-system\file-system-access.android.js:388:0)
JS:     at getFile(file: src\webpack:\test-app\node_modules\@nativescript\core\file-system\file-system-access.android.js:41:0)
JS:     at fromPath(file: src\webpack:\test-app\node_modules\@nativescript\core\file-system\index.js:136:0)
JS:     at (file: src\webpack:\test-app\src\app\item\item-detail.component.ts:26:29)
JS:     at invoke(file: src\webpack:\test-app\node_modules\zone.js\fesm2015\zone.js:372:0)
JS:     at onInvoke(file: src\webpack:\test-app\node_modules\@angular\core\fesm2015\core.mjs:25457:0)
JS:     at invoke(file: src\webpack:\test-app\node_modules\zone.js\fesm2015\zone.js:371:0)
JS:     at run(file: src\webpack:\test-app\node_modules\zone.js\fesm2015\zone.js:134:0)
JS:     at (file: src\webpack:\test-app\node_modules\zone.js\fesm2015\zone.js:1276:0)
JS:     at invokeTask(file: src\webpack:\test-app\node_modules\zone.js\fesm2015\zone.js:406:0)
JS:     at onInvokeTask(file: src\webpack:\test-app\node_modules\@angular\core\fesm2015\core.mjs:25444:0)
JS:     at invokeTas...

The path returned on Android is, "content://com.android.providers.media.documents/document/image%3A122" and on iOS is "file:///private/var/mobile/Containers/Shared/AppGroup/1EA300C8-AE93-45E0-BE2F-4CF58C832464/File%20Provider%20Storage/Downloads/some-file.hex"

@farfromrefug
Copy link
Member

@BikeBr0 you ll need to give more details. code, logs...

@BikeBr0
Copy link
Author

BikeBr0 commented Feb 18, 2022

Yep, I'm working on that. Sorry for the delay.

@farfromrefug
Copy link
Member

@BikeBr0 android 12?

@BikeBr0
Copy link
Author

BikeBr0 commented Feb 18, 2022

Broken on Android 12 and iOS 15.2. Works on Android 8.1. iOS 12.5 is acting weird in general...

@farfromrefug
Copy link
Member

@BikeBr0 sadly the error is on N side. N does not support android 12 scope storage (opening files outside of the scope of your app).
ios dont know but again seems to be on N side.
would need the ios error log but i think it might be N. or maybe a permission ?

@BikeBr0
Copy link
Author

BikeBr0 commented Feb 18, 2022

Thanks @farfromrefug. I can live without Android support but I really need to get this feature working on iOS. I'll add more comments with my iOS debug info.

@BikeBr0
Copy link
Author

BikeBr0 commented Feb 18, 2022

After resolving xCode issues, I was able to get my test-app to run on iOS again.

iOS 12.5

  • Threw an error when no FilePickerOptions were supplied (noteworthy since Android did not complain)
  • Opens a file picker but all files greyed out and I cannot select a file

iOS 15.2

  • Opens a file picker but all files greyed out and I cannot select a file

Are extensions mandatory on iOS? Is it not possible to select any file?

@farfromrefug
Copy link
Member

@BikeBr0 thanks for the details! should be fixed in 1.1.12

@BikeBr0
Copy link
Author

BikeBr0 commented Feb 18, 2022

Great! 1.1.12 fixed the undefined error when not supplying the FilePickerOptions to openFilePicker().

Even better, I am able to open files on iOS. The secret is to remove the leading 'file://' from the path:

openFilePicker().then((val) => {
    console.log(JSON.stringify(val));

    if (!val.files || val.files.length === 0) {
        throw new Error('No file selected.');
    } else {
        const suppliedPath = val.files[0];
        console.log(`suppliedPath: ${suppliedPath}`);

        const scrubbedPath = suppliedPath.replace('file://', '');
        console.log(`scrubbedPath: ${scrubbedPath}`);

        const file = File.fromPath(scrubbedPath);
        console.log(`File: ${file.name}`);
    }
});

This will allow you to browse the filesystem and select well known files (images, txt files, etc.). If you need to access uncommon/proprietary file types, you will need to define UTIs in App_Resources/iOS/Info.plist. Here's an example of a binary file type:

<key>UTExportedTypeDeclarations</key>
<array>
	<dict>
		<key>UTTypeIdentifier</key>
		<string>YOUR_IDENTIFIER_HERE</string>
		<key>UTTypeConformsTo</key>
		<array>
			<string>public.data</string>
		</array>
		<key>UTTypeDescription</key>
		<string>YOU_DESCRIPTION_HERE</string>
		<key>UTTypeTagSpecification</key>
		<dict>
			<key>public.filename-extension</key>
			<array>
				<string>EXTENSION</string>
			</array>
			<key>public.mime-type</key>
			<string>application/octet</string>
		</dict>
	</dict>
</array>

And the code that uses it:

let extensions = [];
if (isIOS) {
    extensions = ['YOUR_IDENTIFIER_HERE'];
} else {
    // Do something else in the future when {N} supports it...
}

openFilePicker({extensions: extensions})

This should let the user browse the file system but only select a file specified by extensions.

UPDATE: This doesn't work for all users. Some users (not iOS version dependent) cannot select the file specified by the UTI.

@ray007
Copy link

ray007 commented Feb 24, 2022

Just tested on iOS 15.3.1 with version 1.1.12 and the file is greyed out and not selectable.

@farfromrefug
Copy link
Member

@ray007 please you will need to give more details. Saying it does not work wont really allow us to help you.

@ray007
Copy link

ray007 commented Feb 24, 2022

@farfromrefug what information would you like me to provide?
I've tried on iOS with

let files = await openFilePicker({extensions: ['json'], multipleSelection: false});

and I can browse to the file I want to select, but it's greyed out and I cannot choose it.

@farfromrefug
Copy link
Member

@ray007 that ;) On ios you can do what you are trying to do. You need to use https://developer.apple.com/documentation/uniformtypeidentifiers/system_declared_uniform_type_identifiers?language=objc

@ray007
Copy link

ray007 commented Feb 24, 2022

Apple really seems to hate casual apple-developers.

@rubenhr
Copy link

rubenhr commented Aug 29, 2024

Is this still worked on?

@farfromrefug
Copy link
Member

@rubenhr yes and it is all working. On iOS the issue is on N side. N does not support path with file:// at the beginning. You can manually remove it.
On Android it should work perfectly. The only issue might be that if the file picker returns content:// on old android versions then N does not support it (when it could).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants