iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >安卓学习笔记:安卓11访问/读写 Android/data 目录
  • 129
分享到

安卓学习笔记:安卓11访问/读写 Android/data 目录

androidandroidstudioPoweredby金山文档 2023-09-09 10:09:08 129人浏览 安东尼
摘要

省流提示:采用Android studio工具开发,记录一次低级的开发,避免以后忘记或者踩坑。 最近有个业余项目开发到一小半,过程中需要读写 Android/data目录的文件,采用常规的文件操作总是提示权限被拒绝,无奈上网参考了

省流提示:采用Android studio工具开发,记录一次低级的开发,避免以后忘记或者踩坑。


  • 最近有个业余项目开发到一小半,过程中需要读写 Android/data目录的文件,采用常规的文件操作总是提示权限被拒绝,无奈上网参考了很多资料,终于得到了解决。

  • 无法访问Android/data 的原因

  • 安卓11谷歌采用了文件沙盒存储模式,这就导致我的app无法直接访问android/data目录,即使我在清单文件中加了所有文件的读写权限、在程序中动态申请了所有文件的读写权限。当然如果有root权限那就另当别论了。

  • 作为开发者该如何访问Android/data

  1. 第一步当然是在清单文件中申请所有文件权限

                
  1. 在java中动态申请:MainActivity.java的onCreate()周期中:

  if (Build.VERSION.SDK_INT >= 23) {            //检测是否有写的权限            int permission = ActivityCompat.checkSelfPermission(this,                    "android.permission.WRITE_EXTERNAL_STORAGE");            if (permission != PackageManager.PERMISSION_GRANTED) {                // 没有写的权限,去申请写的权限,会弹出对话框,这里就不展示了,可以自己写个申请权限的弹窗                      }
  1. 做完上面两步,接下来就是申请android/data的权限了,这里说明一下我的情况:

  1. 我的主页就一个:mainactivity,全部采用了动态替换Fragment的方法切换页面,而且需要申请特殊权限的还是fragment中的子framgent,这就需要在他们所依赖的activity中重写回调方法,并设置给fragment,然后通过这个fragment再次设置给子fragment。

  1. 在子fragment中某个按钮的点击事件中去调用SAF框架(Android Storage Access Framework),这个框架据说在4.4就引入了,可以自行百度了解。

  1. 获取Android/data的权限:子fragment中:

//在某个按钮的点击事件中: @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.xxxx:                //把需要授权的目录转为Uri                Uri uri = DocumentFileUtil.pathToUri("/storage/emulated/0/Android/data");                Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);                intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI,uri1);                 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION                         | Intent.FLAG_GRANT_WRITE_URI_PERMISSION                         | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);                //这里的第二个参数是标志的意思,用来判断是谁把结果回调过来的。               requiReactivity().startActivityForResult(intent, 1001);            break;        }}
  1. 这时候会调出这个页面:

  1. 在点击授权后,程序会返回到MainActivity,所以要在这个活动中重写onActivityResult:

     @Override    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {        super.onActivityResult(requestCode, resultCode, data);        //把onActivityResult设置fragment        Fragment f = getSupportFragmentManager().findFragmentByTag("HOME_FRAGMENT");        assert f != null;        f.onActivityResult(requestCode, resultCode, data);        switch (requestCode) {            case 1001:                if (resultCode == Activity.RESULT_OK) {                    //固定永久权限,否则当重启app时权限就没有了                    assert data != null;                    getContentResolver().takePersistableUriPermission(data.getData(),Intent.FLAG_GRANT_READ_URI_PERMISSION        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);                }                break;            default:                break;        }
  1. 通过activity设置onActivityResult给framgent后,如果子fragment也需进行相关操作,则需要通过父fragment再把onActivityResult设置给子framgent。这里有一点需注意,当我们的子fragment是父fragment通过viewPager容器添加进去的时候,没有Tag也没有ID,如何精准的设置给需要的这个回调的子fragment呢?

  1. 如果适配器是继承的FragmentStatePagerAdapter,这就要用到fragment适配器的instantiateItem了。具体做法:在父fragment中寻找没有tag和id的子fragment:

  @Override    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {        super.onActivityResult(requestCode, resultCode, data);        //实例化适配器        MyFragmentAdapter fragmentAdapter = (MyFragmentAdapter) vp.getAdapter();        assert fragmentAdapter != null;        //通过子fragment在viewPager的position来定位。        UpDataMsgFragment fragment = (UpDataMsgFragment) fragmentAdapter.instantiateItem(vp, 1);        //设置        fragment.onActivityResult(requestCode, resultCode, data);}
  1. 这样一来子fragment就有了回调,然后看他何如使用:

//回调事件,可以得到上个活动或fragment返回的结果    @Override    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {        super.onActivityResult(requestCode, resultCode, data);        //判断文件是否存在 DocumentFile        switch (requestCode) {            case 6666:                if (resultCode == Activity.RESULT_OK) {                    //persist uri                    //固定永久权限                    assert data != null;                    requireActivity().getContentResolver().takePersistableUriPermission(data.getData(),Intent.FLAG_GRANT_READ_URI_PERMISSION        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);                    Log.i("回调事件:", "Access persist uri permission to Android/data");                }        }}

  1. 此时子fragment就有了回调结果,可以通过Document来操作andriod/data的文件了

  1. 注意:用户可以随时取消你的data访问权限,所以避免闪退,还需要在用到Document的地方寄一个判断有无相关目录的权限。

 public boolean isHaveAndroidDataGrant(Context context) {        boolean b = true;        for (UriPermission persistedUriPermission : context.getContentResolver().getPersistedUriPermissions()) {            b = persistedUriPermission.getUri().toString().equals("content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata");                //这里的content://com.android.externalstorage.documents/tree/primary%3AAndroid%2Fdata不渴随意更改里面的%3Ahe %2F字符,可按此格式自行拼接需要的目录。        }        return  b;    }

总结:先在清单文件申请权限,然后在程序中动态申请,其次在需要授权的activity(或fragment)中启用SFA框架,最后在回调回来的activity中重写onActivityResult,如果是多层嵌套的fragment,则通过tag或id或position找到对应的fragment,一层一层的传递过去。

来源地址:https://blog.csdn.net/qq_14826519/article/details/129154939

--结束END--

本文标题: 安卓学习笔记:安卓11访问/读写 Android/data 目录

本文链接: https://www.lsjlt.com/news/401268.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作