My app is not yet published and since it is large I would like to use android:installLocation="preferExternal" in the manifest to allow the OS to install on external storage.
I also have an assets folder as part of the APK and I am using the AssetManager to access them from code.
Given these, do I need to add to the manifest android.permission.READ_EXTERNAL_STORAGE as well?
I found the answer here:
http://www.doubleencore.com/2013/11/whats-changed-in-android-4-4-kitkat/
and a careful read of the docs here:
http://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
On versions earlier than KitKat (4.4) it is required to have the READ_EXTERNAL_STORAGE if external storage paths were read by the app (regardless if they come from calling Context or Environment methods). Since KitKat, the app gets its own "external" locations (which can in fact be either on the internal or the external storage if available) which are accessible without the need for permissions to read or write.
Related
I want to find an updated answer that works from android 5/6/7 to 13 with less possible permission. I know there are answers like Android saving file to external storage storage but those are very old.
You can understand accessing and storing files on android better from the google's official documentation here, mainly app-specific storage vs permission requirement, i.e. if you want to save file which are app specific, you won't need permission whether it being internal or external storage, but if you want to access locations which are not your app-specific, you will need permission for both internal and external storage.
Also, this behavior of permission requirement has been adopted after a particular API level, so you can start writing you code as per your targetSdk version and keep including options down to your minSdk versions and have a common method for permission for reusing it wherever is required.
I am using Samsung A30s phone for accessing phone storage files. My files location in device is /storage/emulated/0/MY_FILES/. I kept some files in MY_FIlES directory but my below code does
not show any containing files under this directory.
So how can I get all files belong to this MY_FIlES directory in phone storage?
File Directory = new File("/storage/emulated/0/MY_FIlES/");
File[] files = Directory.listFiles();
But files return null;
Note: I have a permission(READ_EXTERNAL_STORAGE) to access file.
One important thing, I updated my phone in latest API. But before update, I used this path, " /sdcard/MY_FIlES/ and it worked fine.
First, never hardcode paths for apps that you plan to distribute. For those, please use methods on Context, Environment, or StorageVolume (Android 11 only) to find the base directory to use.
For Android 10 and 11, you need to add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work.
Note that in Android 11+, you will not be able to write to that directory, regardless of whether you have requested WRITE_EXTERNAL_STORAGE or not. Google would vastly prefer that you use the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT), so that users have more control over where files get placed on their devices or in their chosen cloud storage providers.
I would like to add something more to the #CommonsWare answer. As per the Android's storage update, they enforce scoped storage in the Android 11
version.
But to give developers additional time for testing, apps that target Android 10(API level 29) can still request the requestLegacyExternalStorage attribute. This flag allows apps to temporarily opt-out of the changes associated with scoped storage, such as granting access to different directories and different types of media files. After you update your app to target Android 11, the system ignores the requestLegacyExternalStorage flag.
If your app opts out of scoped storage when running on Android 10 devices, it's recommended that you continue to set requestLegacyExternalStorage to true in your app's manifest file. That way, your app can continue to behave as expected on devices that run Android 10.
For more info on this, please check documentation
Can we write data to external storage without adding write permission in the manifest ? Does Storage access Framework or Download manager gives any support for this?
It depends where you want to write the files and what SDK(s) you are targeting. If you want to write the files in your app's external directories (getExternalFilesDir(String) and getExternalCacheDir()) and you are targeting SDK19+, then the permission is not required. If you want to write in other areas or targeting SDK<19, then you need the permission. HOWEVER, based on my experience, there is a bug in some Lollipop versions out there that is causing the permission to still be required. So I usually put <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="22"/> in my manifest.
Short answer: no. If there was an easy way to bypass required permissions they'd be pretty pointless. See the documentation below:
https://developer.android.com/training/basics/data-storage/files.html
To write to external storage, you need permission to write to external storage.
Why would you want to take an action you haven't received permission for anyway?
Maybe FileProvider is what you are looking for.
FileProvider is part of Support Library, available for all Android versions starting 2.3. The main goal of this API is to temporary open a private file to some targeted apps: you keep the file in your private folder, and let some other apps read or even write it via a secured ContentProvider. Permissions are revoked when your activity is destroyed.
More info
In my android app, I save some files to Environment.getExternalStorageDirectory() + "\MyApp" directory. This worked fine until android 6 marshmallow update. After marshmallow update, I cannot write to this directory.
As described in this answer, in marshmallow, apps need to ask for the permission from user at runtime before writing to external storage.
But, when I use context.getExternalFilesDir(null) instead of Environment.getExternalStorageDirectory(), I don't need to ask for any permission at runtime and it just works (path returned from context.getExternalFilesDir(null) is also inside the external storage directory).
Is this some kind of a coincidence or can I continue to write to context.getExternalFilesDir(null) without asking permission at runtime?
The documentation states:
Starting in KITKAT, no permissions are required to read or write to
the returned path; it's always accessible to the calling app. This
only applies to paths generated for package name of the calling
application. To access paths belonging to other packages,
WRITE_EXTERNAL_STORAGE and/or READ_EXTERNAL_STORAGE are required.
You will have read/write access to getExternalFilesDir() on Android 4.4+ without requiring any permissions.
I would recommend using a FileProvider if you need to support lower API levels.
<uses-permission
android:maxSdkVersion="18"
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
reference: uses-permission-element
As i know PERMISSIONS are presented started since Android 6 and above
So no need to check permissions for API 16
On Android 4.4.2 Environment.getExternalStorageDirectory().getPath() returns /storage/emulated/0 but this path does not exist on my Nexus5 Android 4.4.2. Environment.getExternalStorageDirectory().getPath() worked up until Android 4.4.2.
How can I get the /sdcard path on Android 4.4.2?
This path does not exist on my Nexus5 Android 4.4.2.
Yes, it does, for your process at runtime.
For example, this sample project downloads a file to Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS). If you log the location at runtime, when running it on a Nexus 5, it is reported as /storage/emulated/0/Download. And the download succeeds.
If you are looking for /storage/emulated/0 via DDMS or adb shell, you will not find it. For those tools, default external storage is /mnt/shell/emulated/0. Hence, the downloaded file from the above sample appears in the /mnt/shell/emulated/0/Download directory.
AFAIK, the difference is tied to providing separate external storage to secondary accounts.
The Storage Options documentation says to use Environment.getExternalStorageDirectory() (as you are already correctly using). This function is available on all versions of Android.
Are you seeing it return a path that isn't actually available on a 4.2 device?
Please note (from Environment.getExternalStorageDirectory()):
Applications should not directly use this top-level directory, in order to avoid polluting the user's root namespace. Any files that are private to the application should be placed in a directory returned by Context.getExternalFilesDir, which the system will take care of deleting if the application is uninstalled. Other shared files should be placed in one of the directories returned by getExternalStoragePublicDirectory(String).
Writing to this path requires the WRITE_EXTERNAL_STORAGE permission, and starting in read access requires the READ_EXTERNAL_STORAGE permission, which is automatically granted if you hold the write permission.
Starting in KITKAT, if your application only needs to store internal data, consider using getExternalFilesDir(String) or getExternalCacheDir(), which require no permissions to read or write.
Sometimes /storage/emulated/0 can be written to, but reads fail... so tests for "writability" are not sufficient. This is such an annoying problem, I have come up with an equally annoying but effective solution.
Hardcode "/mnt/sdcard" Yea, I said it.
Looks like someone else said it first ... storing android application data on SD Card
More joy... http://forums.bignerdranch.com/viewtopic.php?f=414&t=7407