栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android R存储机制简析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android R存储机制简析

Android 11(API 级别 30)进一步增强了平台功能,为外部存储设备上的应用和用户数据提供了更好的保护,此版本强制执行分区存储(Scoped Stroage),无论APP的targetsdkversion是多少,都将无法访问Android/data和Android/obb这二个应用私有目录。这无疑对会部分APP的业务场景及用户体验造成冲击,如文件管理类软件的清理缓存功能。

https://developer.android.com/about/versions/11/privacy/storage?hl=zh-cn

关于分区存储

为了让用户更好地管理自己的文件并减少混乱,以 Android 10(API 级别 29)及更高版本为目标平台的应用在默认情况下被赋予了对外部存储空间的分区访问权限(即分区存储)。此类应用只能访问外部存储空间上的应用专属目录,以及本应用所创建的特定类型的媒体文件,不能访问其他应用的外部存储空间。

https://developer.android.com/training/data-storage?hl=zh-cn#scoped-storage

暂时停用分区存储

在您的应用与分区存储完全兼容之前,您可以使用以下方法之一暂时停用分区存储:

  • 以 Android 9(API 级别 28)或更低版本为目标平台。
  • 如果您以 Android 10(API 级别 29)或更高版本为目标平台,请在应用的清单文件中将 requestLegacyExternalStorage 的值设置为 true

当您将应用更新为以 Android 11(API 级别 30)为目标平台后,如果应用在搭载 Android 11 的设备上运行,系统会忽略 requestLegacyExternalStorage 属性。

https://developer.android.com/training/data-storage/use-cases?hl=zh-cn#opt-out-scoped-storage

关于SAF (Storage Access framework)

Android 4.4(API 级别 19)引入了存储访问框架 (SAF)。借助 SAF,用户可轻松浏览和打开各种文档、图片及其他文件,而不用管这些文件来自其首选文档存储提供程序中的哪一个。用户可通过易用的标准界面,跨所有应用和提供程序以统一的方式浏览文件并访问最近用过的文件。云存储服务或本地存储服务可实现用于封装其服务的 documentsProvider,从而加入此生态系统。客户端应用如需访问提供程序中的文档,只需几行代码即可与 SAF 集成。

https://developer.android.google.cn/guide/topics/providers/document-provider

Android R实现访问外部存储的Android/data方案

1.通过Intent启动SAF授权界面,导航到Android/data目录,注意URI的百分号编解码(%3A和%2F)

public void requestAccessAndroidData(Activity activity){		
    try {		
        Uri uri = Uri.parse("content://com.android.externalstorage.documents/document/primary%3AAndroid%2Fdata");		
        Intent intent = new Intent(Intent.ACTION_OPEN_document_TREE);		
        intent.putExtra(documentsContract.EXTRA_INITIAL_URI, uri);		
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION		
                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION	
                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);	
        activity.startActivityForResult(intent, REQUEST_CODE);	
    } catch (Exception e) {	
        e.printStackTrace();		
    }	

}

2.在用户同意授权后,持久化uri权限(否则关机重启或授权界面finish后,APP就无权限访问了),并只能通过documentFile进行业务操作,File API操作是无效的,此授权只是授权uri操作,并未授权文件系统

private static final int REQUEST_CODE = 8082;
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    switch (requestCode) {	
        case REQUEST_CODE:		
            if (resultCode == Activity.RESULT_OK) {		
                getContentResolver().takePersistableUriPermission(data.getData(),	
                        Intent.FLAG_GRANT_READ_URI_PERMISSION	
                                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);	
                Log.i(TAG,"Access persist uri permission to Android/data");	
            }	
            break;
        default:
            break;
    }
}

3.注意这个授权用户是可以撤回的,通过点击应用信息界面的存储,就会看到撤回界面,所以业务需要去动态判断

public boolean isGrantAndroidData(Context context) {	
    for (UriPermission persistedUriPermission : context.getContentResolver().getPersistedUriPermissions()) {		
        if (persistedUriPermission.getUri().toString().		
                equals("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata")) {		
            return true;		
        }	
    }		
    return false;		
}

4.清理缓存

public void deletePackagesCache(String packageName){	
    String filePath= Environment.getExternalStorageDirectory() + "/Android/data/" + packageName +"/cache";		
    String pathUri = filePath.replace("/storage/emulated/0/", "").replace("/", "%2F");		
    Uri dirUri=Uri.parse("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata/document/primary%3A" + pathUri);	
    Cursor cursor=mContext.getContentResolver().query(dirUri, new String[]{documentsContract.document.COLUMN_document_ID}, null, null, null);		
    try{		
        while (cursor.moveToNext()) {	
            String documentId = cursor.getString(0);		
            Uri uri = documentsContract.builddocumentUriUsingTree(dirUri, documentId);		
            documentFile documentFile=documentFile.fromSingleUri(mContext,uri);		
            Boolean isDeleteSuccess = documentFile.delete();		
            Log.e(LOG_TAG,"ACTION_GARBAGE_CACHE delete file="+documentFile.getName() + " isDeleteSuccess="+isDeleteSuccess);	
        }		
    }finally {		
        if(cursor!=null){		
            cursor.close();	
        }	
    }	
} 
MANAGE_EXTERNAL_STORAGE 权限

1.在AndroidManifest.xml中声明MANAGE_EXTERNAL_STORAGE权限。
2. 发出一个action为Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION的Intent,引导用户手动授权。
3. 调用Environment.isExternalStorageManager()来判断用户是否已授权。

Android访问文件的方式
  • MediaStore
  • File
  • documentFile
相关参考

https://www.jianshu.com/p/d02bc6266198

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/281440.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号