问题
I am trying to read a file from the download folder on Android Q by doing this:
File downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
File f = new File(downloadDir, "some-existing-file");
if(!f.exists()) {
throw new IllegalStateException();
}
Uri furi = Uri.fromFile(f);
try {
ParcelFileDescriptor des = getContentResolver().openFileDescriptor(
furi, "r", null);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
I also set android:requestLegacyExternalStorage="true"
in the manifest, and requested WRITE_EXTERNAL_STORAGE
and READ_EXTERNAL_STORAGE
runtime permissions.
The file exists but when trying to open the file descriptor, an exception arises:
java.io.FileNotFoundException: open failed: EACCES (Permission denied)
.
I read the changes made in Android Q storage, but could not figure out how can I just read the file without having user interaction.
Thanks!
回答1:
From Android 6 (Marshmallow) some of critical permissions should be granted at runtime by the user so he/she will know what things can your app access.
this link is all what you need
EDIT
add these to manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
then add this code to your oncreate method
if (android.os.Build.VERSION.SDK_INT >= 23 && (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED)) {
ActivityCompat.requestPermissions(
this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
2000);
}
this will popup the user a dialog to agree permissions. if the user agrees onRequestPermissionsResult
method will be called, so override onRequestPermissionsResult
like this
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED && requestCode == 2000) {
//do what you want with files
}
}
just pay attention that I set request code to 2000. it's optional.
回答2:
This method was deprecated in API level 29. To improve user privacy, direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
Copied from Android documents.docs
回答3:
After too many hours of trying to figure out what the hell is going on, I managed to find a solution.
I addded to the manifest:
android:requestLegacyExternalStorage="true"
When rebuilding and reinstalling directly from Android Studio, the build system or android runtime does not register a change in the manifest, and the request for requestLegacyExternalStorage
does not register.
I fixed it by completely uninstalling the app: adb uninstall com.example.app
and installing it again from android studio.
来源:https://stackoverflow.com/questions/60855299/how-to-read-a-file-directly-from-external-download-directory-on-android-10-q