【Android 权限检查】写业务代码写久了,权限问题都不记得了,还好意思么。。

Android权限管理详解
本文介绍了Android系统的权限管理机制,包括正常权限与危险权限的区别、权限分组的概念、不同API级别下的权限检测方法以及如何实现权限的动态申请。还提供了一些实用的代码示例。
###读完本篇blog,你将收获什么 1. 了解Android系统提供的权限申请相关api 2. 了解Android的权限分组 3. 了解23以下系统如果检测权限是否授权

###危险权限和普通权限
从Android 6.0开始,应用要使用危险权限的时候,需要动态获取权限,而不是安装的时候授权。
系统权限分为两类:正常权限危险权限

  • 正常权限只要在manifest中注册,系统就会自动授予
  • 危险权限不光要在manifest中注册,还要运行时用户批准才能使用

此外要注意的是,Google为了减少开发的工作量和权限申请对用户的骚扰,对危险权限进行了分组。例如,对于读SD卡和写SD卡,这两个权限被分到了一组,只有这一组中有一个权限被授予,就相当于授权了整组权限。下面为危险权限列表及其分组。
这里写图片描述

###权限检测
权限检测需要根据targetSdkVersion(是否大于6.0)不同,采取不同的处理方法。当targetSdkVersion大于23时,处理比较简单;可是当targetSdkVersion小于23时,处理就比较麻烦了,我们这里不做过多介绍,再参考文章里有一篇相关介绍。还好现在app的targetSdkVersion大都大于23了。哈哈。
####扫盲targetSdkVersion&Build.VERSION.SDK_INT
为什么首先要弄清这两个概念?因为targetSdkVersion>=23时,需要根据Build.VERSION.SDK_INT做不同操作;targetSdkVersion<=23时,也需要根据Build.VERSION.SDK_INT做不同操作。
Build.VERSION.SDK_INT是用来检测当前app运行的Android系统版本,而targetSdkVersion是开发者设定的,一般只有比较老的app才会把targetSdkVersion设为小于23,然后因为一些历史遗留问题,迟迟没有改成大于23的的版本。
####targetSdkVersion>=23的情况
这种情况是比较普遍的情况,只需要在6.0及以上版本动态检测是否获取了某一权限,在6.0以下版本通过try catch检测权限。

  • 在6.0及以上版本:
int permissionCheck = PermissionChecker.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

如果有此权限,方法返回PackageManager.PERMISSION_GRANTED,反之返回
PackageManager.PERMISSION_DENIED。

  • 在6.0以下版本:

正常情况下,6.0以下版本在应用安装时就会默认授予权限,但是,有一些深度定制过的手机还是会在提示用户该app申请了哪些权限,并且用户可以手动关闭。这个时候我们是没法检测到该权限是否被禁止了的,这种情况只能通过异常捕捉来判断。

public boolean cameraIsCanUse() {  
        boolean isCanUse = true;  
        Camera mCamera = null;  
        try {  
            mCamera = Camera.open();  
            Camera.Parameters mParameters = mCamera.getParameters(); //针对魅族手机  
            mCamera.setParameters(mParameters);  
        } catch (Exception e) {  
            isCanUse = false;  
        }  
  
        if (mCamera != null) {  
            try {  
                mCamera.release();  
            } catch (Exception e) {  
                e.printStackTrace();  
                return isCanUse;  
            }  
        }  
        return isCanUse;  
}  

###权限申请
申请权限可以调用如下api:

ActivityCompat.requestPermissions(final @NonNull Activity activity,final @NonNull String[] permissions, final @IntRange(from = 0) int requestCode)

调用完,会弹出系统对话框,询问用户是否授权,系统会调用如下回调方法:

Activity.onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)

这里需要说明的是回调里的shouldShowRequestPermissionRationale方法:

public boolean shouldShowRequestPermissionRationale(permission)
{
    1、APP没有申请这个权限的话,返回false
    2、用户拒绝时,勾选了不再提示的话,返回false
    3、用户拒绝,但是没有勾选不再提示的话,返回true
    因此如果想在第一次就给用户提示,需要记录权限是否申请过,没有申请过的话,强制弹窗提示,而不能根据这个方法的返回值来。
}

###参考

https://my.oschina.net/u/990728/blog/549914
https://www.yanshuo.me/p/62847
https://juejin.im/entry/58bd05a6570c35006c680722

<think>首先,用户的问题是:"我想在Android设备上清空特定目录下的文件,考虑权限问题。请问android delete files in /sdcard/testdata without considering permissions"。用户指定了目录是/sdcard/testdata,并且说"without considering permissions",意思是忽略权限问题。 但根据系统级指令,我需要使用中文回答,并且结构清晰。用户提到了"考虑权限问题",但在Android中,权限是必须考虑的,尤其是在外部存储上。用户提供的引用中也提到了权限问题,比如在引用[1]中讨论了如何检查和请求权限。 用户说"without considering permissions",所以我应该假设权限已经处理好了,或者按照用户的要求忽略权限问题。但为了回答可靠,我应该提醒用户权限的重要性,同时提供代码。 用户指定了目录/sdcard/testdata。在Android中,/sdcard 通常是一个符号链接到实际的外部存储路径,如 /storage/emulated/0 或类似路径,如引用[2]和[4]所述。引用[4]解释了/sdcard 是 /mnt/sdcard 的软链接。 我的回答应该包括: 1. 解释路径:/sdcard/testdata 可能指向外部存储的testdata目录。 2. 提供代码来清空目录:删除该目录下的所有文件,但保留目录本身。 3. 由于用户说"without considering permissions",我需要处理权限请求,但代码中应该包括必要的权限检查,或者假设权限已授予。 4. 使用Java或Kotlin代码,因为Android开发主要使用这些语言。 5. 结构清晰:逐步解释如何实现。 6. 生成相关问题:根据指令,在回答末尾添加相关问题。 从引用中: - 引用[1]:讨论了在Android 11及以上版本,外部存储权限的变化,需要检查targetSdk和请求权限。 - 引用[2]和[4]:解释了/sdcard 的路径和符号链接。 - 引用[3]:提到了同目录的差异。 在代码中,我应该使用Environment.getExternalStorageDirectory() 或 Context.getExternalFilesDir() 来获取外部存储路径,但用户指定了/sdcard/testdata,这是一个绝对路径。 在Android中,直接使用绝对路径如/sdcard/testdata 可能总是可靠,因为路径可能因设备而异。更好的做法是使用API来获取外部存储路径。 例如: - Environment.getExternalStorageDirectory() 返回根外部存储目录,如 /storage/emulated/0。 - 然后可以追加/testdata。 但Environment.getExternalStorageDirectory() 在Android 10及以上已废弃,推荐使用Context.getExternalFilesDir() 或 MediaStore。 用户指定了/sdcard/testdata,所以我应该使用这个路径。 为了清空目录: - 检查目录是否存在。 - 列出所有文件。 - 删除每个文件。 - 如果需要,删除子目录,但用户说"清空特定目录下的文件",所以可能只删除文件,或者递归删除所有内容。 用户说"清空特定目录下的文件",意思是删除目录下的所有文件,但保留目录。所以,只删除文件,包括子目录,除非指定。 但为了全面,我可以提供删除文件和子目录的选项。 代码步骤: 1. 获取目录路径:new File("/sdcard/testdata") 2. 检查目录是否存在。 3. 列出目录中的所有文件。 4. 遍历每个文件,如果是文件则删除,如果是目录则递归删除(可选)。 5. 处理异常。 由于用户忽略权限,我需要请求权限。 但为了代码完整,我应该包括权限检查的注释。 回答结构: - 介绍:解释/sdcard/testdata 在Android中的置。 - 步骤:如何清空目录。 - 代码示例:提供Java或Kotlin代码。 - 注意事项:提醒权限问题,尽管用户忽略。 - 相关问题:生成相关问题。 生成相关问题: 基于这个主题,相关问题可能包括: 1. 如何在Android中请求外部存储权限? 2. Android同存储路径的区别是什么? 3. 如何安全地删除文件以避免数据丢失? 4. 在Android 10及以上版本,如何管理外部存储? 5. 如何递归删除目录及其所有内容? 使用中文回答。 代码块:使用代码格式。</think>### 清空 Android 设备上特定目录的文件(忽略权限问题) 在 Android 中,清空特定目录(如 `/sdcard/testdata`)下的文件,可以通过 Java 或 Kotlin 代码实现。您指定了“考虑权限问题”,因此本回答假设权限(如 `WRITE_EXTERNAL_STORAGE`)已授予或已处理。但请注意,在实际开发中,权限是必须考虑的,尤其是在 Android 6.0(API 23)及以上版本,需要动态请求权限[^1]。此外,`/sdcard` 通常是一个软链接(symbolic link),指向实际外部存储路径(如 `/storage/emulated/0`),在同设备上可能略有差异[^2][^4]。 以下步骤和代码示例将帮助您实现清空 `/sdcard/testdata` 目录下的所有文件(包括子目录中的文件),但保留目录本身。代码使用 Java 编(兼容 Android 项目),并基于标准 `File` API。 #### 步骤详解 1. **获取目录对象**:使用绝对路径 `/sdcard/testdata` 创建 `File` 对象。 2. **检查目录有效性**:确认目录存在且可访问。 3. **遍历并删除文件**:递归删除目录下的所有文件和子目录(但保留根目录)。 4. **异常处理**:捕获可能的 `SecurityException` 或 `IOException`(尽管忽略权限,但基础错误仍需处理)。 #### 代码示例 以下是一个完整的 Java 方法,用于清空指定目录。您可以在 Activity 或工具类中调用它。 ```java import java.io.File; public class FileUtils { /** * 清空指定目录下的所有文件和子目录(保留根目录)。 * 注意:此方法假设权限已处理,忽略权限检查。 * * @param directoryPath 目录绝对路径,例如 "/sdcard/testdata" * @return true 如果清空成功,false 如果失败(如目录无效) */ public static boolean clearDirectory(String directoryPath) { File directory = new File(directoryPath); // 检查目录是否存在且是目录 if (!directory.exists() || !directory.isDirectory()) { return false; // 目录无效,直接返回 } try { // 获取目录下所有文件和子目录 File[] files = directory.listFiles(); if (files == null) { return true; // 空目录,无需操作 } for (File file : files) { deleteRecursively(file); // 递归删除每个条目 } return true; } catch (SecurityException e) { e.printStackTrace(); // 忽略权限问题,但仍打印日志以便调试 return false; } } /** * 递归删除文件或目录 * * @param file 要删除的文件或目录对象 */ private static void deleteRecursively(File file) { if (file.isDirectory()) { // 如果是目录,先清空其内容 File[] childFiles = file.listFiles(); if (childFiles != null) { for (File child : childFiles) { deleteRecursively(child); // 递归删除子项 } } } // 删除文件或空目录 file.delete(); } } ``` #### 调用示例 在您的 Activity 中调用上述方法(例如在按钮点击事件中): ```java // 在 Activity 中调用 String targetDirectory = "/sdcard/testdata"; // 指定目录路径 boolean isSuccess = FileUtils.clearDirectory(targetDirectory); if (isSuccess) { // 清空成功 } else { // 清空失败(目录无效或删除错误) } ``` #### 注意事项 - **路径可靠性**:`/sdcard/testdata` 是绝对路径,但在Android 版本或设备上,外部存储路径可能变化(如 Android 10+ 使用 Scoped Storage)。推荐使用 `Environment.getExternalStorageDirectory()` 获取根路径,但该方法已废弃。更现代的做法是使用 `Context.getExternalFilesDir()` 或 MediaStore,但您指定了绝对路径,因此代码中直接使用它[^2][^4]。 - **权限忽略的风险**:尽管您要求忽略权限,但如果实际权限未处理,代码可能抛出 `SecurityException`。在真实场景中,务必添加权限检查和请求逻辑(参考引用[1])。 - **性能**:递归删除大量文件可能耗时,建议在后台线程执行(如使用 `AsyncTask` 或 Kotlin 协程)。 - **Android 版本适配**:在 Android 10(API 29)及以上,即使忽略权限,Scoped Storage 限制可能导致访问失败。如果遇到问题,可降级 `targetSdkVersion`(推荐)或改用 App-specific 目录[^1]。 #### 相关问题 1. 如何在 Android 中动态请求外部存储权限? 2. Android 10+ 的 Scoped Storage 如何影响文件操作? 3. 如何安全地删除整个目录(包括根目录)? 4. Android同存储路径(如 `/sdcard` 和 `/storage/emulated/0`)有什么区别? 5. 在 Kotlin 中如何实现文件递归删除?
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值