My app is letting users select audio files with an Intent.ACTION_OPEN_DOCUMENT from within their document hierarchy (ordinarily on internal storage and not in my app's storage). The files, once selected, are then processed natively in OBOE.
I have JNI working. I can open the file in java and copy the bytecode over to native.
But if I want to open a file directly in the Native code then I must set the app to ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION. This seems a bit clumsy, it is probably because I'm sending the file path - using getPath() on the uri - to native and using fopen()?
Is it possible for me to inherit the permission from the java side to open the file natively without requiring All Files Acess permission? I tried sending a FileDescriptor over but that wasn't successful, although could have been my implementation.
Related
We are writing a C++ app that is cross compiled for Android. This app uses native libraries (namely gdal and Qt) to read and write files.
These files often have references to each other (e.g. a xml file, referencing other files next to it; or shapefiles, where multiple files have a common base name). The above mentioned libraries need to be able to open files by path (fopen(name)) to get access to all information.
Common use cases are:
download a zip file using a browser, unzip it using an file manage (e.g. amaze) and open the contents in our app
use a file sharing app like nextcloud, syncthing, ... to sync a folder. The files in this folder are then edited by our app.
Since API level 30 Google PlayStore restricts file access and only allows unrestricted direct file access in an specific app-specific directory.
In shared folders (e.g. the Download folder, root folders in external storage devices, etc.) only a subset of file types is accessible through direct file access.
The Acess media files from shared storage documentation mentions
If you don't have any storage-related permissions, you can access files in your app-specific directory, as well as media files that are attributed to your app, using the File API.
Media files in our tests include images, videos, ... but not the file types required here (.dbf, .shp, .qgs).
There is also the storage access framework where a DocumentProvider can be used to stream data of individual files and intents like OPEN_DOCUMENT_TREE these will however generate access via URI which is not compatible with native fopen(name) calls.
The only option we found capable of opening files by name (through native labraries) is to use the all files permission (MANAGE_EXTERNAL_STORAGE). This works well but needs to be whitelisted to be published on Google Play Store.
Google support suggests using the system file picker (and sometimes extends the suggestion to "or other privacy friendly approaches").
Q: If your libraries could work with paths before then they still can. Where is it that the problem starts?
A: On Android 11, without a MANAGE_EXTERNAL_STORAGE permission, what we have seen in our multiple tests is that directly opening non-media files in shared locations via their path strings is not working anymore.
The file opening fails.
We have also noticed that doing a directory listing (using Qt APIs) only shows media file extensions, skipping all other types.
How is it possible to open files by file path (string) in shared locations with native libraries without the all files permission (MANAGE_EXTERNAL_STORAGE)?
I am adjusting code of my Android app (Java + native) to Android 10 Scoped Storage changes.
I declared required permissions in my manifest:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I launched ACTION_OPEN_DOCUMENT_TREE to let the user pick a directory.
What I do is I create file on external storage, detach file desciptor and pass to native code:
DocumentFile df = documentFile.createFile("text/plain", "my_file");
ParcelFileDescriptor pfd = getApplicationContext().getContentResolver().openFileDescriptor(df.getUri(), "rw");
myNativeFunction(pfd.detachFd());
Now, native side reads/writes from/to the file. And is responsible for closing the file descriptor.
My question is how to delete that file by native code?
Normally, in order to delete file one needs to pass pathname to it (remove(), unlink() functions take it as parameter). With Uri I failed to do that - I get "No such file or directory" error.
Thank you.
Thanks to CommonsWare I realized that I need to re-think my app design.
So, for this case I decided to keep all the code operating on DocumentFile(s) at the Java side (including deletion) and read/write from/to files using read()/write() C functions at native side (using file descriptors previously detached from Java). In my case it is actually like that:
Android app:
launch ACTION_OPEN_DOCUMENT_TREE to pick document tree and pass corresponding tree Uri to my Android AAR library
request AAR library for deletion of files under tree Uri
AAR library (Java + native):
create DocumentFile object from passed tree Uri
create DocumentFile(s) under Document tree and pass file descriptors to native code (App does not have to know anything about actual files)
delete DocumentFile(s)
I have a doubt I read these tutorials just to get the clear understanding of the SAF introduced in kitkat in higher version of android How to use the new SD card access API presented for Android 5.0 (Lollipop)?
How to persist permission in android API 19 (KitKat)?
Android API below 19 equivalent for ContentResolver takePersistableUriPermission
Android Gallery on KitKat returns different Uri for Intent.ACTION_GET_CONTENT
Now i have a question when the intent is fired and i get select the sd card to get the uritree from the intent which i am getting but is the root tree I will have to iterate through the uri to get the specific file uri.
Now the question is I have mp3 files in my phone and I want to edit that specific file which is selected so how can i get that selected files uri from the tree and edit it?I tried editing directly using file but it makes my mp3 file disappear and i dont want to fire SAF intent again n again so how to check is user has given permission to sd card or not?
P.S. I am using jaudio tagger for editing the tags of mp3 files.
THANK YOU!!
I have got answers of almost everything in this question Now the issue if I am using jaudio tagger library for tagging mp3 files which takes File as a objects but android 4.4 and above wont let u modify File objects so I just want to knw the alternative how can i edit File objects in 4.4 above?
This is how I did it,
first copy the file from the sdcard to the phone memory and then do the desired changes and cut and paste the file again at its original place.
Example is here where I am editing the tag of mp3 file which is in the sdcard:-
https://github.com/reyanshmishra/Rey-MusicPlayer/tree/master/app/src/main/java/com/boom/music/player/TagEditor
The library you refer to is called JaudioTagger, and it does not and most probably will never accept DocumentFile. The Storage Access Framework is Google's invention and far from any standard. And JaudioTagger is written for portability.
However, I finally managed to get JaudioTagger mostly running with SAF, but had to substantially modify it, even to rewrite some functions. Basically I replaced all File and RandomAccessFile with my own classes, and additionally the handling of temporary files and renaming must be rewritten (e.g. the scheme: copy original file, change copy, remove original file, rename copy to original name).
In fact it might be easier to use the native TagLib instead, because that already accepts a special C++ class as input. All I did was to create such C++ class whose basis is a file descriptor derived from ParcelFileDescriptor derived from Uri derived from DocumentFile.
Finally one might come to the conclusion that the Storage Access Framework is somewhat suboptimal.
I'm working with one of the many Android FFmpeg libraries on GitHub, which each involve an NDK wrapper around a C binary. I'm trying to give other apps access to the video file I have edited with FFmpeg (and saved in External Storage), but at least on Android 6.0, the new permissions system prevents them from being able to access the shared file unless they themselves have the External Storage permission granted. The solution here would be to use content providers to open up a directory for other apps to access. However...
My FFmpeg binary is contained within the app's data directory, but it fails when I try to access or modify a video file saved there. As mentioned above, it has no problem accessing external storage.
Is there a way to give FFmpeg access to my app's data directory, giving it read and write permissions? Would naming the library with the same package name do the trick?
Any ideas? Thanks for any advice!
I have android application which uses a lot of c++ native code. Application needs to work with files located on sdcard(read, create, append). But Kitkat+ denied writing to sdcard for 3rd party applications. Android 5 introduced new API which allows that again.
How to use the new SD card access API presented for Android 5.0 (Lollipop)?
All examples and documentation what I found are mostly for Java side. Examples for native code don't exist or are very unclear. So I want ask few questions.
The link above contains valuable example how to get DocumentFile which can return ParcelFileDescriptor. From this object I am able to receive native file descriptor - ParcelFileDescriptor.getFd(). It's integer which I am sending to c++ code through jni.
In c++ I am opening file with fdopen(fd).
My questions are :
Is fdopen function correct way how to open the file with new api? Or the DocumentFile already opens the file and I should only use fd in further operations.
It's enough to close the file descriptor inside native code with fclose? or should I close it on java side with ParcelFileDescriptor.detachFd(). Or both.
Thank you
EDIT : I getFD and detachFD works. But I never found answer how to correctly replace ftruncate, which needs write access too, and I did not found ftruncate version which takes file descriptor like a input
1) yes, use file descriptors and fdopen
2)
Open the ParcelFileDescriptor.
getFd().
Pass the Fd to native code.
Close the ParcelFileDescriptor. (this is closing your java reference)
Fd is just an int representing a linux id for a file. In native:
Fdopen
Do stuff
Fclose (note this is closing your native file pointer)
The two closes are doing different things.
Note: You still need the SAF permission for the file or a higher root.
Try Below Links:
Android - writing/saving files from native code only:
Android - writing/saving files from native code only
Android NDK Write File:
Android NDK Write File
File Operations in Android NDK:
File Operations in Android NDK