Android11 无Root 访问data目录 实现
正文开始
关于Android11权限变化
谷歌在Android11及以上系统中采用了文件沙盒存储模式,导致第三方应用无法像以前一样访问Android/data目录,这是好事。但是我所不能理解的是已经获得"所有文件管理"权限的APP为何还是限制了,岂不是完全不留给清理、文件管理类软件后路?实在不应该!
作为普通安卓用户该如何方便快速地访问Android/data目录
众所周知,不能访问Android/data目录非常不方便,比如要管理QQ、微信接收到的文件、其他App下载的数据(如迅雷等等)。
现本人开发的应用已实现无Root访问Android/data目录(其中文件浏览器功能),并且可以方便地进行管理。
https://www.coolapk.com/apk/com.magicalstory.cleaner
欢迎安卓手机用户下载使用 和 Android开发者下载预览功能的实现。
App界面预览
开发者该如何实现无ROOT访问Data目录
1.首先,可根据需要获取所有文件管理权限:
在清单中声明:
<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" />
2.动态获取读写权限,这个不用多说了吧,如果觉得麻烦可以使用郭霖大神的permissionX库
Github
关于"管理所有文件"权限
这个权限可以让你的App跟Android11以前一样,通过File API访问所有文件(除Android/data目录)
如有需要,请在清单声明不启用沙盒存储
android:preserveLegacyExternalStorage="true"
android:requestLegacyExternalStorage="true"
相关判断
//判断是否需要所有文件权限
if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager())) {
//表明已经有这个权限了
}
获取权限
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivity(intent);
正式开始解决Android/data问题
首先,使用的方式是SAF框架(Android Storage Access Framework)
这个框架在Android4.4就引入了,如果没有了解过的话,可以百度。
获取某个文件目录的权限
方法很简单,使用android.intent.action.OPEN_DOCUMENT_TREE(调用SAF框架的文件选择器选择一个文件夹)的Intent就可以授权了
等下会放出工具类,现在看下例子:
//获取指定目录的访问权限
public static void startFor(String path, Activity context, int REQUEST_CODE_FOR_DIR) {
statusHolder.path = path;//这里主要是我的一个状态保存类,说明现在获取权限的路径是他,大家不用管。
String uri = changeToUri(path);//调用方法,把path转换成可解析的uri文本,这个方法在下面会公布
Uri parse = Uri.parse(uri);
Intent intent = new Intent("android.intent.action.OPEN_DOCUMENT_TREE");
intent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
| Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, parse);
}
context.startActivityForResult(intent, REQUEST_CODE_FOR_DIR);//开始授权
}
调用后的示意图:
回调并永久保存某个目录的权限
//返回授权状态
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Uri uri;
if (data == null) {
return;
}
if (requestCode == REQUEST_CODE_FOR_DIR && (uri = data.getData()) != null) {
getContentResolver().takePersistableUriPermission(uri, data.getFlags