I'm developing an app that can download some media files to the user selected folder (User selects folder using the SAF), targeting android 11+. It can download and create files on primary external shared storage (e.g. path: /storage/emulated/0/Download/) just fine. But when user selects a folder on the removable microSD card (e.g. path: /storage/XXXX-XXXX/Documents/) creating of files finishes with error (Cannot create file: /storage/9016-4EF8/...). Probably the reason of this error is denied permissions. I found tons of articles about android storage and came to the conclusion that apps can't create files at any folder on microSD card except the internal storage of the app on that sd card.
Summarising all above:
I can create files here:
path = "/storage/emulated/0/Download/" // primary external shared storage
path = "/storage/emulated/0/Android/data/com.app.app/files" // primary internal storage
path = "/storage/XXXX-XXXX/Android/data/com.app.app/files" // secondary internal storage on removabled microSD
I can't create files here:
path = "/storage/XXXX-XXXX/Download/" // secondary external shared storage
Since android 11+ internal storage of my app is no longer accesible from other apps. So for example picture downloaded using my app to the app folder can not be opened through any ImageEditor or Gallery. So the only way to correctly store files is to choose primary external shared storage.
The question is that some users has an external storage with max 2GB in size, they just need to download files to a microSD card. Is there any way to do it or is Android really such a dumb platform?
P.S. I am developing the app using QT C++, so files are created using standard C++ functions.
P.S.S. Sorry for my english
The MediaPlugin library creates files in
storage/emulated/0/Android/data/[app_name]/files/Pictures/18-Feb-19/1550503112_in.jpg
What would I use to get access to the picture in this path later?
I'm trying to avoid using a hard-coded string... I've tried googling it but I'm getting really confused as to how to get this path by using Android predefined values like android.os.environment.datadirectory or System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures); etc.
Android groups the filesystem into two different types of storage:
1 Internal Storage – this is a portion of the file system that can be accessed only by the application or the operating system.
You can access the internal storage using code like this
System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyPictures)
And the path is like this:
/data/user/0/MyApp.Android/files or /data/data/{package name}/files
2 External Storage – this is a partition for the storage of files that is accessible by all apps, the user, and possibly other devices. On some devices, external storage may be removable (such as an SD card).
You can access the external storage using code like this
Android.Content.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryPictures)
And the path is like this
/storage/emulated/0/Android/data/{package name}/files
So you can see the path Media Plugin has created is the external storage path. You can access it using
Android.Content.Context.GetExternalFilesDir(Android.OS.Environment.DirectoryPictures)
I have created one app which creates one file on external memory, but when I install it on different devices the files are created in internal sdcard in some device and not created in external(Physical) sd card.
My question is that. How do we decide between the internal or external sdcard.
Which has more preference to store file by default in android?
I use the
Environment.getExternalStorageDirectory()+ "PolicyTaskfile"+"/filename.txt";
It gives external or internal sdcard path depending on the device.
The short answer is that you do not get to pick. It's up to the OEM to decide whether external storage is truly SD card or just an internal storage device (for example: eMMC). With KitKat there is a notion of primary and secondary external storage, but no easy API to determine which you are using or which is really removable media.
When using Eclipse file explorer to navigate my android directories, I saw mnt/sdcard and mnt/sdcard2, see below image:
When callingEnvironment.getExternalStorageDirectory() it returns mnt/sdcard, so I think the mnt/sdcad is the external storage , and mnt/sdcard2 is my actual SD card, is that true? And how can I use code to access files under mnt/sdcard2 ?
P.S.
It seems that I can access the external sd card directly:
File extStorageDir = Environment.getExternalStorageDirectory();
String parent = extStorageDir.getParent();
File extSdCardDir = new File(parent+"/sdcard2");
File file = new File(extSdCardDir, "DemoFile.jpg");
But I wonder the extra sd card will change name in other cases.
You are correct, getExternalStorage will return your built-in external storage. Unfortunately, as of Jelly Bean applications are no longer able to utilize the SD card if the device also has built-in storage as well as an SD card. You can try working around it through shell commands or hardcoding paths, but without root there is no reliable way to access it anymore.
This was just recently added the Android CTS, which all OEMs must comply with in order to use the Play store.
Compatibility Program Overview | Android Developers
Section 9.5 (pg. 34) of Android 4.3 Compatibility Definition
Device implementations that include multiple external storage paths
MUST NOT allow Android applications to write to the secondary external
storage.
Storage Options | Android Developers
It's possible that a device using a partition of the internal storage
for the external storage may also offer an SD card slot. In this case,
the SD card is not part of the external storage and your app cannot
access it (the extra storage is intended only for user-provided media
that the system scans).
Android 4.2 APIs | Android Developers
Saving data in a multi-user environment
Whenever your app saves user preferences, creates a database, or
writes a file to the user’s internal or external storage space, that
data is accessible only while running as that user.
To be certain that your app behaves properly in a multi-user
environment, do not refer to your internal app directory or external
storage location using hard-coded paths and instead always use the
appropriate APIs:
For access to internal storage, use getFilesDir(), getCacheDir(), or openFileOutput().
For access to external storage, use getExternalFilesDir() or getExternalStoragePublicDirectory().
No matter which of these APIs you use to save data for a given user,
the data will not be accessible while running as a different user.
From your app’s point of view, each user is running on a completely
separate device.
From the official documentation:
Using the External Storage
Every Android-compatible device supports a shared "external storage"
that you can use to save files. This can be a removable storage
media (such as an SD card) or an internal (non-removable)
storage ...
I'm really confused about this subject. From what I understand, using external storage doesn't necessarily mean to use a removable card, am I right? However, when talking about external storage, it's always referred as "sd card".
I'm developing an app that downloads .mp3 files from the internet. I want to save those files in the phone memory (don't want to use any removable device) but for what I have learned, those files have to be saved in external memory.However, I would like to offer the possibility of importing a file from a removable device. Where and how should I save those files?
Thanks
Difference between Internal Storage, External Storage (aka primary external storage) and Secondary External Storage?
Internal Storage: is storage that is not accessible by the user, except via installed apps (or by rooting their device). Example: data/data/app_packageName
External Storage has two types:
Primary External Storage: In built shared storage which is "accessible by the user by plugging in a USB cable and mounting it as a drive on a host computer". Example: When we say Nexus 5 32 GB.
Secondary External Storage: Removable storage. Example: SD Card.
When building an app that uses the internal storage, the Android OS creates a unique folder, which will only be accessible from the app, so no other app, or even the user, can see what's in the folder.
The external storage is more like a public storage, so for now, it's the sdcard, but could become any other type of storage (remote hard drive, or anything else).
The internal storage should only be used for application data, (preferences files and settings, sound or image media for the app to work).
If you intent to download many mp3s, i'd reccomend saving them to external storage, as the external storage is often bigger. Besides, storing data on the internal storage may prevent the user to install other applications.
The Internal and External Storage terminology according to Google/official Android docs is quite different from what we think.
According to official Android docs:-
Internal Storage: By default, files saved to the internal storage are private to your application and other applications cannot access them. When the user uninstalls your application, these files are removed/deleted. Your app user also can't access them using file manager; even after enabling "show hidden files" option in file manager. To access files in Internal Storage, you have to root your Android phone. So, this is NOT what we think as internal memory of the phone - Nexus 5's 32 GB internal memory.
External Storage:
This can be a removable storage media (such as an SD card) or an
internal (non-removable) storage
That means, both storage types like Nexus 6P's 64 GB internal memory and removable microSD card which we insert in phone's card slot are considered as External Storage.
Removable Storage means just microSD card storage, not the internal memory.
To store your app files in SD card, you may use File[] getExternalFilesDirs (String type) method in Context class. Generally, second returned path would be the storage path for microSD card (if any).
Note: I have edited - made my answer more useful after #Tunaki's comment.
From the Developer docs
All Android devices have two file storage areas: "internal" and "external" storage. These names come from the early days of Android, when most devices offered built-in non-volatile memory (internal storage), plus a removable storage medium such as a micro SD card (external storage). Some devices divide the permanent storage space into "internal" and "external" partitions, so even without a removable storage medium, there are always two storage spaces and the API behavior is the same whether the external storage is removable or not.
I think in the operating system, it defines external storage as anything not related to the actual OS filestructure. If you recall, when you write to 'internal storage', Android will make a folder privately for your application. So basically, if this is a hidden folder of some kind, it would mean that external storage could qualify as anything not being automatically hidden or managed directly by the OS. So this would mean that it would be up to the phone manufacturer about the definition of internal storage, as they could have 1 main piece of internal flash memory with two partitions on it. One partition meant to hold the os and the other meant to let you store everything on the phone.
Basically what I'm saying is: That's more a hardware related thing, and that the concept of 'external storage' could extend even to extra internal storage (flash memory) that the manufacturer added in. You could even consider storage options defined by the user as external storage as well.
Here's an updated answer for the latest Android (currently Android 13).
Internal storage used to mean the phone's internal memory and external storage used to mean, among other things, any inserted SD cards. Nowadays, this is not really the case because phones don't have SD cards any more. Phones without SD card slots still have "external storage" from the point of view of an app (eg Environment.getExternalStorageDirectory() still returns a valid location), but it's emulated - meaning it's actually a slice of internal storage.
This means one of the big differences between external and internal storage - which was that external was slower but bigger and internal fast and small - is no longer true.
Since Android 11, external storage has been scoped. This means apps get a folder of their own which is readable to them and unreadable to any other app (though see below). They can access this folder without permissions. Again, this brings external storage in line with internal. (Note scoped storage actually appeared in Android 10 but has only been enforced since Android 11).
But there are remaining differences between internal and external.
One big difference is that apps can still get a permission to read/write across all of external storage (MANAGE_EXTERNAL_STORAGE). This is hard to come by - users need to manually enable it by going into Settings, and apps which implement it are severely limited on the Play Store.
But it does mean that data written to external storage is less secure than that written to internal. Other apps may be able to eavesdrop on external.
The above is the TL;DR but there's a bit more to it. Here's a good article: https://medium.com/#tdcolvin/demystifying-internal-vs-external-storage-in-modern-android-c9c31cb8eeec