In the last days I've been working on the development of a Capacitor Plugin that allows to launch a native file picker and I faced a new problematic that a lof of android developers seems to be having now. Since Android 11 (apps targeting SDK Version 30) which is by default the target API of a new Capacitor based applications, there's a new update on the Storage policies of apps. The Scoped Storage enforcement has been implemented to enhance the platform, giving better protection to your app and user's data on external storage. This will cause some modifications in which app works since this API as:
- On Android 11, apps can no longer access files in any other app's dedicated, app-specific directory within external storage.
- To protect user privacy, on devices that run Android 11 or higher, the system further restricts your app's access to other apps' private directories.
The reason why I faced this problem is because the plugin should allow to select any possible file in the device as it will be used inside a Code Editor application.
Accessing all files
There's a possibility to access all the files in the device using the new permission . However, this automatically will put a restriction in your application as Google Play should review if you really need the mentioned permission when trying to publish the application to the Play Store.
The permission won't be applied automatically to your app without the user's interaction as the user needs to obligatorily grant access to the files. You can do this in Android following these steps:
1. Request MANAGE_EXTERNAL_STORAGE permission
Modify your AndroidManifest.xml
file by requesting the following permissions:
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ourcodeworld.plugins.capacitornativefilepicker"
xmlns:tools="http://schemas.android.com/tools"
>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
</manifest>
The MANAGE_EXTERNAL_STORAGE permission allows an application a broad access to external storage in scoped storage. Intended to be used by few apps that need to manage files on behalf of the users.
2. Request External Storage Permissions
After declaring the permissions, you need to request the regular READ_EXTERNAL_STORAGE
and WRITE_EXTERNAL_STORAGE
permissions. Note that we don't include the MANAGE_EXTERNAL_STORAGE
, because if you request it, when verifying if you have access or not, the mentioned permission will always return denied, even though the user has already granted access:
ActivityCompat.requestPermissions(
this,
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.MANAGE_EXTERNAL_STORAGE
},
1
);
The logic of this step is up to you as you may know how to request permissions in your own application.
3. Checking permission of MANAGE_EXTERNAL_STORAGE
Now, instead of the regular permissions request to handle the mentioned permission, you need instead to verify whether the access to the external storage is allowed. In case it isn't, you need to launch a new activity showing the system's dialog where the user should manually allow the access to the external storage to your app like this:
import android.os.Environment;
import android.content.Intent;
import android.provider.Settings;
import android.net.Uri;
// If you have access to the external storage, do whatever you need
if (Environment.isExternalStorageManager()){
// If you don't have access, launch a new activity to show the user the system's dialog
// to allow access to the external storage
}else{
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
Uri uri = Uri.fromParts("package", this.getPackageName(), null);
intent.setData(uri);
startActivity(intent);
}
So when the user installs the app and try to access the file picker, if the access to all files isn't granted yet, the following system intent will be launched:
The user will have to explicitly allow access to all files if you want to read files from any source in the device and that should be enough.
Happy coding ❤️!