Best/usual practices for android app directories - android

Is there any sort of consensus on creating/using directories for storing/accessing data for android apps.
For example on windows a new application (say MyApp) would go in the "Program files" directory in a new "MyApp" directory.
I'm writing an app that allows the user to analyse photo and xml files. Is it usual to expect MyApp to just look for those files in Environment.getExternalStorageDirectory(), require the user to move the photos/xmls to Environment.getExternalStorageDirectory()/MyApp or something else? Should you always just provide a file explorer to look anywhere on the device?
I can do any of the above means of accessing but it's better to stick with the user's expectations.
Any pointer to a UI preferred practices would be useful (assuming they're widely followed).

To store your pictures (assuming you are using API >= 8), you should use:
getExternalFilesDir(Environment.DIRECTORY_PICTURES);
Check the documentation which contains an example.
If you want to keep your images in a separate folder you can create one named after your package name inside this one.
Otherwise, if you are using API <= 7, use getExternalFilesDir() to obtain the root of the tree from where you should start looking for images.

Related

Cleaning up a folder on a phone

first question on this site, if improper just tell me.
I am creating an app on an adroid platform. With this app I create some files and folders in the shared document folder.
What happens is this: with every build, at least with the -cleaninstall parameter set, it is impossible to overwrite existing files and/or folders. Even after deleting them on the phone.
Probably this is due to the fact that the filesystem thinks that the new build is not the original owner of the file/folder and is therefore not authorized to delete or overwrite.
As a bypass solution I am using an "appname" variable to create a folder to store data in, if necessary I update the "appname" variable so a fresh set of folders is created, based on the "appname" but this a pretty crooked way to work.
DocumentFolder := System.IOUtils.TPath.GetSharedDocumentsPath;
AppName := 'ExpensesV2';
AppFolder := DocumentFolder+PathDelim+AppName;
if NOT DirectoryExists(AppFolder) then ForceDirectories(AppFolder);
Is there a proper way to really remove/clean up that specific folder OR get the proper autorisation.
Thank you for your valued responses!!
You don't specify how you're going about creating the folders and writing the files. There are different mechanisms for doing so depending upon the type of file you want to write (media files, documents, generic files) and who you want to have access to it (public vs app private storage). There are also additional complications with permissions and things depending upon what OS version you're targetting.
Given the information available, the best I can suggest is having a look at these links:
https://developer.android.com/training/data-storage
https://developer.android.com/training/data-storage/use-cases
The latter gives some sample cases of types of file and purpose and suggests the mechanism to use to write/read it.
In the most general of senses, if you want to write to public external storage then use getExternalStoragePublicDirectory(); but the warning note here is that the user can do as they wish with the files in the storage area; putting their own files there, renaming files, deleting files etc etc It is beyond the control of your app to manage.
If you want your app to manage the storage space properly then you need to use something like Context#getExternalFilesDir(), but then if you want those files to be externally visible you will have to share them with the system and look into things like file sharing or content providers.

System.IO write operations not working in Android 11 outside of app sandbox

I have read about and think I understand the essentials of changes in Android 10 and 11. Gone are the days of accessing folders and files outside of the Android app sandbox willy nilly. That's fine. Just need a way forward and that's become difficult.
I have 2+ apps that share a local Sqlite database and related files in a folder. One or more of the apps in the group might be installed - no guarantee on which of the apps are present. On iOS and Windows (UWP) there is a nice "app group" (iOS name for it) style concept that supports this kind of arrangement formally in the platform. First one installed/run will create the local storage files. Last app in the group uninstalled and the OS cleans up the shared storage location. Android never had this concept so a common location was created outside of the app specific sandbox.
After studying the options available going forward, seems like the "Best" option was to use the Storage Access Framework (SAF) to get permission from the user for some common folder to use. Note that although there are many different "sharing" options in Android, none of them are great for this use case, and most are not friendly to cross platform Xamarin C# without wrapping them somehow. This "Best" option using SAF still requires the user to independently pick the SAME folder from each app that wants to share the local db/files. You know users are going to mess that up, but that's beside the point at the moment.
In testing this approach, I have been able to use the SAF picker to get the user to choose a folder. The Documents folder is what I've been choosing to test with as a folder. From there the app attempts to create a subfolder where all this shared "app group" content would go. Unfortunately simply doing a Directory.CreateDirectory(path) gives a System.IO.IOException: 'Read-only file system'. I checked am I am still able to do Directory.CreateDirectory(path) in the app sandbox (GetExternalFilesDir), just not the SAF chosen location.
I am also able to create a directory in the SAF location if I stick to the SAF API, such as illustrated in the Xamarin Android sample here: https://github.com/xamarin/monodroid-samples/blob/master/android5.0/DirectorySelection/DirectorySelectionFragment.cs#L169-L188.
Is there any way to treat the SAF location chosen by the user just like a normal file system and use System.IO operation to manipulate it? The app has been given permission but those ops don't seem to work in that location. Or is there a better overall approach to this problem that I've totally missed?
Normal Java File I/O does not work with Scoped Storage. File paths and File or Directory objects do not worked in Storage Access Framework, you have to do everything through the DocumentFile API. DocumentFile has the ability to create files and directories in locations that the user has granted your app access to through the File-picker dialog.
There IS a way for normal/traditional System.IO file I/O to work after converting the SAF content to a classic file system path. Using the FileUtil logic in this answer https://stackoverflow.com/a/36162691/1735721 I was first able to get permission to a folder from the user:
var intent = new Intent(Intent.ActionOpenDocumentTree);
StartActivityForResult(intent, 1);
The in OnActivityResult(_, _, Intent resultData) use the file util logic:
var folderPath = FileUtil.GetFullPathFromTreeUri(resultData.Data, this);
var filePath = Path.Combine(folderPath, "test.txt");
At that point filePath represents the path and filename in the chosen directory tree, and normal C# System.IO operations are available to the app for that file e.g. StreamWriter and StreamReader.
NOTE: I was creating "test.txt" directly in the chosen folder. This worked to create the file in "A" but then "B" couldn't read that same file (Unauthorized exception). At some point I created a subfolder and "test.txt" was created there instead...then both "A" and "B" could read and write the same file. Unfortunately, a couple days later, I couldn't repeat that. So as it stands this is only a partial solution.

Android - How to create folders/files in internal storage

I want to be able to create a folder for my app within "Internal Storage/" (on startup, if required) and later, within this folder, create any files (.txt) the user creates in the app.
These files must remain if the app is uninstalled, so use of getExternalFilesDir() - while it works - is not possible. I should note I don't want the user to have to use the file picker to create the folder or any files - ideally the app will take care of saving it to the app's public folder for them. So far I've tried using MediaStore and Storage Access Framework but have had little success. Just need a push in the right direction.
Note: I'm aware of getExternalStoragePublicDirectory(). It worked for what I need quite well, but I'd prefer not to use deprecated functions if possible. I also have the required permission in my manifest file, just having a hard time creating these files outside of my app's own folder within /data/
Thanks in advance anyone who can help :)
Try this,
private fun getInternalLogFile(filename: String): File? =
File(
context.getDir(INTERNAL_DIRECTORY_NAME, Context.MODE_PRIVATE),
filename
)
INTERNAL_DIRECTORY_NAME is your folder name

Save files locally, but prevent them from showing up in the users file manager

Using PhoneGap 3.2 and the File API, I'm downloading a set of images to display in the app. I create a folder named "Appname" and put all the files there. On Android this folder is accessible through the file manager, and on some models the images show up in the users image gallery.
Is it possible to save files locally, but prevent them from showing up to the user outside of the app?
Technically, no. Especially if the client has root access.
You may try the followings to mitigate the problem:
a) Name your files to start with a DOT (.) so that it is recognized as hidden file. (Still, a file manager configured to show hidden files can show it).
b) Store the file instead on some databases in the /data/data/your.app.packages path, which is by default only accessible to your app. (Still a root user can see it).
c) A linux trick. Create a file, open it, hold the file descriptor but remove the file. In this way the file is removed from the directory structure so that it doesn't show up in the FS layer (and thus inaccessible). To make it permanent, use the file descriptor you hold to create a link (or dig into the /proc directory tree to make links with files under fd.
Since this trick works on linux, I guess it should work on Android. But it's probably overkill.
d) Other stopgaps include encryption, obfuscation, etc. But they don't exactly fall into the kind you are looking for.

Android Add/Remove File Directory

I'm creating an App where I will import files the app will use, then remove and replace them with new ones when available. What folder should those be stored in?
The Android dev documentation have a page about how to handle files: http://developer.android.com/training/basics/data-storage/files.html
Maybe you should take a look at that.
It depends on how the user will get the files for the app, and the type of files you are talking about.
If for example the app is going to download the files from a server for the user, and the files are of a type that are only going to be used by your app, then either the Internal Private or External Private storage are probably best. If the file type is something that other apps will also use, then one of the appropriate External Public directories is best (for example Music, Pictures, Movies, Downloads etc).

Categories

Resources