Android存储权限完美适配(Android11及以上适配)

2023-09-18 21:30:20

一、Bug简述

一个很普通的需求,需要下载图片到本地,我的三个测试机(荣耀Android10,红米 11 和小米Android 13都没有问题)。

然后,主角登场了,测试的三星Android 13 死活拉不起存储权限弹窗。

想了下,三星的系统可能和小米的系统做了些区别。于是就是看了下存储权限的版本更迭,却是发现了些骚东西。

二、原因

很早以前,一直都是在manifest申明这两个权限就可以了,但是现在会有下面的警告!

这便是错误的原因:

 可以得知,在Android 13(sdkversion为33)的系统中,已经被废弃了!!!

但是如果你给Write和Read权限加上maxSdkVersion=32,他在11,12上是没有问题的,但是最新的App要求 target sdkversion必须是33了。

所以,在此就必须做一个适配:

Android 11 里将引入一个特别的权限叫做 MANAGE_EXTERNAL_STORAGE,该权限将授权读写所有共享存储内容,这也将同时包含非媒体类型的文件。但是获得这个权限的应用还是无法访问其他应用的应用专属目录 (app-specific directory),无论是外部存储还是内部存储。

那么,为了兼容Android版本,我就必须在Android11之前和之后分开做申请才会有用。

三、步骤

1).申明权限

manifest文件里:

<uses-permission
    android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" />

2).权限的判断

判断是否已经获得权限:

 private fun checkPer(activity: PreViewActivity): Boolean {
        return if (Build.VERSION.SDK_INT >= 30) {
            EasyPermissions.hasPermissions(
                activity,
                android.Manifest.permission.MANAGE_EXTERNAL_STORAGE
            )
        } else {
            EasyPermissions.hasPermissions(
                activity,
                android.Manifest.permission.WRITE_EXTERNAL_STORAGE
            )
        }
    }

未获得权限,申请权限

private fun aaa(activity: PreViewActivity, curImg: Int) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            
                val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
                intent.data = Uri.parse("package:" + activity.packageName)
                activity.startActivityForResult(intent, 200)
           
        } else {
            val perm = android.Manifest.permission.WRITE_EXTERNAL_STORAGE
            PaperThreeVariable.isToRequestPer = true
            EasyPermissions.requestPermissions(
                PermissionRequest.Builder(
                    activity,
                    200,
                    perm
                )
                    .build()
            )
        }
    }

权限申请回调

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
    }

    override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
        AppInitUtils().saveFreshAppImageToGallery(this, curImg)
        PaperThreeVariable.isToRequestPer = false
    }

    override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
        PaperThreeVariable.isToRequestPer = false
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            AppSettingsDialog.Builder(this)
                .setRationale("This function requires storage permission to be enabled")
                .setNegativeButton("No")
                .setPositiveButton("Yes")
                .build().show()
        }
    }

因为有时候用户会拒绝权限且永久弹窗,所以为了方便我就用了EasyPermission这个库,拒绝的情况下,弹窗跳转系统权限设置页面去让用户选择开启权限。

这样,就OK啦!(至于我的小米为啥Android 13也能正常拉起,我也不知道具体原因,但是在Android Studio的历史链接设备中,我发现它识别我的手机系统为Android 12,真是百思不得其解)

本文参考了郭霖大神的一篇文章,当时是想看下 Scoped Storage这个属性的内容,接过发现了Android 11的变更。

Android 11新特性,Scoped Storage又有了新花样

仅做个人工作总结,内容肯定不够全面,如有问题,欢迎大佬指正!

Android Permission 权限申请,EasyPermission和其他三方库_安卓权限申请_&岁月不待人&的博客-CSDN博客

更多推荐

haproxy工具,负载均衡配置,反向代理配置,动静分离,高可用等等

文章目录haproxyhaproxy概述haproxy配置文件解析haproxy实战haproxy配置过程haproxy负载均衡和反向代理haproxy查看状态信息Haproxy健康检查功能基于tcp端口的健康检查基于URL的健康检查haproxy的高可用--不需要keepalived获取真实ip地址haproxy动静

CSS 实现祥云纹理背景

🪴背景最近掘金出来一个中秋创意活动,我准备参加一下。作品方向选择用纯css做一个中秋贺卡,其中有一些中秋的元素和一些简单的动画,而贺卡背景的实现就是本文要讲的内容。中秋贺卡成果图(生成gif有点失真😵‍💫)如下:有兴趣的可以看我的另一篇文章:中秋贺卡传送门贺卡背景是我用css,仿照从网上搜到的祥云纹理背景图实现的

CSS中去掉li前面的圆点方法

1.引言在网页开发中,我们经常会使用无序列表(<ul>)来展示一系列的项目。默认情况下,每个列表项(<li>)前面都会有一个圆点作为标记。然而,在某些情况下,我们可能希望去掉这些圆点,以满足设计需求或者个性化要求。本文将介绍几种常见的方法来去掉<li>前面的圆点。2.使用CSS属性我们可以使用CSS的list-styl

CSS中的定位

position的属性与含义CSS中的position属性用于控制元素在页面中的定位方式,有四个主要的取值,每个取值都会影响元素的布局方式,它们是:static(默认值):这是所有元素的初始定位方式。在静态定位下,元素会按照它们在文档流中的顺序依次排列,不受top、right、bottom、left等属性的影响。静态定

实例说明接口测试的关键是什么?(含文档+视频)

接口测试的关键在于验证应用程序接口(API)是否按照预期工作,并且在不同组件之间传输数据的正确性和可靠性。以下是接口测试的一些关键要点,后面会实例说明。1.请求和响应验证:接口测试需要验证发送到API的请求和API返回的响应是否符合预期。这包括检查请求的参数、HTTP状态码和响应的数据结构等方面。2.数据一致性:确保A

JUC下的异步编程工具使用详情以及源码分析(FutureTask、CompletableFuture)

异步编程一、FutureTask应用&源码分析1.1FutureTask介绍FutureTask是一个可以取消异步任务的类。FutureTask对Future做的一个基本实现。可以调用方法区开始和取消一个任务一般是配合Callable去使用异步任务启动之后,可以获取一个绑定当前异步任务的FutureTask可以基于Fu

RK3568开发笔记(八):开发板烧写buildroot固件(支持hdmi屏),搭建Qt交叉编译开发环境,编译一个Demo,目标板运行Demo测试

若该文为原创文章,转载请注明原文出处本文章博客地址:https://hpzwl.blog.csdn.net/article/details/132826197红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中…瑞芯微开

QT JSON数据格式讲解

文章目录前言一、JSON是什么二、JSON在线解析三、QT中的JSON类四、构建JSON字符串五、解析JSON数据六.核心类QJsonDocument类详解总结前言本篇文章开始带大家学习一下什么是JSON,并且学习QT当中的JSON使用。一、JSON是什么JSON(JavaScriptObjectNotation)是一

Spring-AOP+入门案例(注解)+AOP切入点语法+AOP通知类型

一、简介+工作流程。简介SpringAop实际上就是代理模式工作流程二、导入依赖1.spring-aop包该包是在spring-context依赖下的子包,所以有context就有aop<dependency><groupId>org.springframework</groupId><artifactId>sprin

Qt day2

作业:点击登录按钮后,判断账号(admin)和密码(123456)是否一致,如果匹配失败,则弹出错误对话框,文本内容“账号密码不匹配,是否重新登录”,给定两个按钮ok和cancel,点击ok后,会清除密码框中的内容,继续进行登录;如果点击cancel按钮,则关闭界面。如果账号和密码匹配,则弹出信息对话框,给出提示信息为

面试算法3:前n个数字二进制形式中1的个数

题目输入一个非负数n,请计算0到n之间每个数字的二进制形式中1的个数,并输出一个数组。例如,输入的n为4,由于0、1、2、3、4的二进制形式中1的个数分别为0、1、1、2、1,因此输出数组[0,1,1,2,1]。分析1很多人在面试的时候都能想到直观的解法,使用一个for循环来计算从0到n的每个整数i的二进制形式中1的个

热文推荐