Android 6.0 权限管理

    xiaoxiao2025-10-25  8

    运行时权限(Runtime permission)

    android的权限系统一直是首要的安全概念,因为这些权限只在安装的时候被询问一次。一旦安装了,app可以在用户毫不知晓的情况下访问权限内的所有东西。 这是极其危险的事情 所以,在Android M 权限请求设计改版了,有点类似iOS的权限请求

    1461651981945.jpg

    在android6.0棉花糖,app将不会在安装的时候授予权限。取而代之的是,app不得不在运行时一个一个询问用户授予权限。

    注意权限询问对话框不会自己弹出来。开发者不得不自己调用。如果开发者要调用的一些函数需要某权限而用户又拒绝授权的话,函数将抛出异常甚至导致程序崩溃.

    旧版兼容

    为了与旧版本兼容,比如你的 build.gradle 中的 targetSdkVersion 设置为 23 之前,比如22. 也能在Android6.0 的手机上面跑,并且权限请求机制使用6.0之前的 安装时请求 的模式. 吐槽一下: Excuse Me? 这到底是兼容还是漏洞... targetSdkVersion 设置为23以前,不让跑6.0不是更合理? 可能处于市场应用的API版本考虑,不兼容估计大部分应用都不能跑6.0 所以,如果你觉得运行时弹出权限框让用户勾选很不友好,那么就取巧使用targetSdkVersion <23 吧,但这绝对不是长久之计...(丑陋...)

    android { 
    compileSdkVersion 23 
    buildToolsVersion "23.0.2" 
     
    defaultConfig { 
    minSdkVersion 8 
    targetSdkVersion 22 
    versionCode 1 
    versionName "1.0" 

    buildTypes { 
    release { 
    minifyEnabled false 
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 



    1461662965441.jpg

    6.0权限弹框的两种模式

    1.初次请求,弹出对话框叫你勾选

    1461654947945.jpg

    2,第二次请求之后,弹出对话框,出现不再提醒字样

    1461655014689.jpg

    当用户点击了不再提醒,你再次请求权限的时候,就不会弹出对话框,所以这时,你需要根据需求另做处理 下面会如何处理

    6.0之后的权限分类

    分为两类 Normal permissions 和 Dangerous permissions

    Normal permissions(普通权限)

    只需要在xml中申请就可以了,与6.0之前没什么区别 包括的权限有

    android.permission.ACCESS_LOCATION_EXTRA_COMMANDS 
    android.permission.ACCESS_NETWORK_STATE 
    android.permission.ACCESS_NOTIFICATION_POLICY 
    android.permission.ACCESS_WIFI_STATE 
    android.permission.ACCESS_WIMAX_STATE 
    android.permission.BLUETOOTH 
    android.permission.BLUETOOTH_ADMIN 
    android.permission.BROADCAST_STICKY 
    android.permission.CHANGE_NETWORK_STATE 
    android.permission.CHANGE_WIFI_MULTICAST_STATE 
    android.permission.CHANGE_WIFI_STATE 
    android.permission.CHANGE_WIMAX_STATE 
    android.permission.DISABLE_KEYGUARD 
    android.permission.EXPAND_STATUS_BAR 
    android.permission.FLASHLIGHT 
    android.permission.GET_ACCOUNTS 
    android.permission.GET_PACKAGE_SIZE 
    android.permission.INTERNET 
    android.permission.KILL_BACKGROUND_PROCESSES 
    android.permission.MODIFY_AUDIO_SETTINGS 
    android.permission.NFC 
    android.permission.READ_SYNC_SETTINGS 
    android.permission.READ_SYNC_STATS 
    android.permission.RECEIVE_BOOT_COMPLETED 
    android.permission.REORDER_TASKS 
    android.permission.REQUEST_INSTALL_PACKAGES 
    android.permission.SET_TIME_ZONE 
    android.permission.SET_WALLPAPER 
    android.permission.SET_WALLPAPER_HINTS 
    android.permission.SUBSCRIBED_FEEDS_READ 
    android.permission.TRANSMIT_IR 
    android.permission.USE_FINGERPRINT 
    android.permission.VIBRATE 
    android.permission.WAKE_LOCK 
    android.permission.WRITE_SYNC_SETTINGS 
    com.android.alarm.permission.SET_ALARM 
    com.android.launcher.permission.INSTALL_SHORTCUT 
    com.android.launcher.permission.UNINSTALL_SHORTCUT 

    其实不需要记,记住哪些是危险权限就是了

    Dangerous permissions(危险权限)

    危险权限,需要在运行时请求. 注意: 危险权限是按组来分的,所以,当你申请了多个同组的危险权限时,运行时只需要申请一个就行 例如:

    <!-- 电话 --> 
    <uses-permission android:name="android.permission.READ_CALL_LOG" /> 
    <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
    <uses-permission android:name="android.permission.CALL_PHONE" /> 
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> 
    <uses-permission android:name="android.permission.USE_SIP" /> 
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
    <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> 

    你申请了关于电话的那么多权限,在动态申请的时候,它只会弹出

    1461654947945.jpg

    这一个权限框 所以,这是一个权限组的概念,运行时选择你申请的同组权限的一个就行

    目前所有的危险权限组集合

    <!-- Dangerous Permissions. --> 
    <!-- 联系人 --> 
    <uses-permission android:name="android.permission.WRITE_CONTACTS" /> 
    <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 
    <uses-permission android:name="android.permission.READ_CONTACTS" /> 
     
    <!-- 录音 --> 
    <uses-permission android:name="android.permission.RECORD_AUDIO" /> 
     
    <!-- 电话 --> 
    <uses-permission android:name="android.permission.READ_CALL_LOG" /> 
    <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 
    <uses-permission android:name="android.permission.CALL_PHONE" /> 
    <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> 
    <uses-permission android:name="android.permission.USE_SIP" /> 
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> 
    <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" /> 
     
    <!-- 日历 --> 
    <uses-permission android:name="android.permission.READ_CALENDAR" /> 
    <uses-permission android:name="android.permission.WRITE_CALENDAR" /> 
     
    <!-- 相机 --> 
    <uses-permission android:name="android.permission.CAMERA" /> 
     
    <!-- 传感器 --> 
    <uses-permission android:name="android.permission.BODY_SENSORS" /> 
     
    <!-- 定位 --> 
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 
     
    <!-- 存储 --> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
     
    <!-- 短信 --> 
    <uses-permission android:name="android.permission.READ_SMS" /> 
    <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH" /> 
    <uses-permission android:name="android.permission.RECEIVE_MMS" /> 
    <uses-permission android:name="android.permission.RECEIVE_SMS" /> 
    <uses-permission android:name="android.permission.SEND_SMS" /> 

    对应的java code

    // 联系人 
    Manifest.permission.WRITE_CONTACTS, 
    Manifest.permission.GET_ACCOUNTS, 
    Manifest.permission.READ_CONTACTS, 
     
    // 电话 
    Manifest.permission.READ_CALL_LOG, 
    Manifest.permission.READ_PHONE_STATE, 
    Manifest.permission.CALL_PHONE, 
    Manifest.permission.WRITE_CALL_LOG, 
    Manifest.permission.USE_SIP, 
    Manifest.permission.PROCESS_OUTGOING_CALLS, 
    Manifest.permission.ADD_VOICEMAIL, 
     
    // 日历 
    Manifest.permission.READ_CALENDAR, 
    Manifest.permission.WRITE_CALENDAR, 
     
    // 相机 
    Manifest.permission.CAMERA, 
     
    // 传感器 
    Manifest.permission.BODY_SENSORS, 
     
    // 定位 
    Manifest.permission.ACCESS_FINE_LOCATION, 
    Manifest.permission.ACCESS_COARSE_LOCATION, 
     
    // 存储 
    Manifest.permission.READ_EXTERNAL_STORAGE, 
    Manifest.permission.WRITE_EXTERNAL_STORAGE, 
     
    // 录音 
    Manifest.permission.RECORD_AUDIO, 
     
    // 短信 
    Manifest.permission.READ_SMS, 
    Manifest.permission.RECEIVE_WAP_PUSH, 
    Manifest.permission.RECEIVE_MMS, 
    Manifest.permission.RECEIVE_SMS, 
    Manifest.permission.SEND_SMS, 

    运行时权限请求的基本步骤

    1.在xml中注册 2. 运行时请求权限

    以下是权限检查的帮助类

    /** 
    * 检查权限是否已请求到 (6.0) 
    */ 
    public void checkPermissions(String... permissions)
    // 版本兼容 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M 
    // 判断缺失哪些必要权限 
    && lacksPermissions(permissions)) { 
    // 如果缺失,则申请 
    requestPermissions(permissions); 


     
    /** 
    * 判断是否缺失权限集合中的权限 
    */ 
    private boolean lacksPermissions(String... permissions)
    for (String permission : permissions) { 
    if (lacksPermission(permission)) { 
    return true


    return false

     
    /** 
    * 判断是否缺少某个权限 
    */ 
    private boolean lacksPermission(String permission)
    return ContextCompat.checkSelfPermission(context, permission) == 
    PackageManager.PERMISSION_DENIED; 

     
    /** 
    * 请求权限 
    */ 
    private void requestPermissions(String... permissions)
    ActivityCompat.requestPermissions(context, permissions, PERMISSION_REQUEST_CODE); 

     
    /** 
    * 启动应用的设置,进入手动配置权限页面 
    */ 
    private void startAppSettings()
    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 
    Uri uri = Uri.fromParts("package", context.getPackageName(), null); 
    intent.setData(uri); 
    context.startActivity(intent); 

    注意: 其中的 requestPermissions 方法,它会弹出权限提示框( 没有点击不再提醒的话 ),然后调用 public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) 方法,该方法在Activity或者Fragment中回调

    3.在onRequestPermissionsResult回调中处理

    在 public void onRequestPermissionsResult() 方法中,你可以捕获到用于是点击了 不再提醒 还是 拒绝 ,然后做出不同的操作..

    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    // 版本兼容 
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M || 
    requestCode != PermissionsChecker.PERMISSION_REQUEST_CODE) 
    return
     
    for (int i = 0, len = permissions.length; i < len; i++) { 
    String permission = permissions[i]; 
    // 缺失的权限 
    if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 
    boolean showRationale = shouldShowRequestPermissionRationale(permission); 
    if (!showRationale) { 
    // 用户点击不再提醒 
    // TODO 
    break
    } else {  
    // 用户点击了取消... 
    // possibly check more permissions...  




    权限请求策略

    下面提供一种我认为还不错的策略 在需要某权限的Activity的 onStrart() 中去请求权限 在 onRequestPermissionsResult 回调中,如果用户点击了拒绝,则继续请求权限 如果用户点击了不再提醒,则弹出自定义对话框,引导用户手动去开启权限,如果用户不授权,则退出当前页面 注意:适用于没有权限就无法使用该功能的情况

    1461661615410.jpg

    Activity代码

    public class BaseActivity extends AppCompatActivity
    private static final String TAG = "BaseActivity"
    private PermissionsChecker checker; 
     
    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState)
    super.onCreate(savedInstanceState); 
    checker = new PermissionsChecker(this); 

     
    public PermissionsChecker getChecker()
    return checker; 

     
    /** 
    * 在该声明周期,检查权限申请情况 
    */ 
    @Override 
    protected void onStart()
    super.onStart(); 
    checker.checkPermissions(PermissionsChecker.PERMISSIONS); 

     
    /** 
    * 请求权限检查完后回调的结果 
    * 
    * @param requestCode . 
    * @param permissions 所请求的权限 
    * @param grantResults . 
    */ 
    @TargetApi(Build.VERSION_CODES.M) 
    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || 
    requestCode != PermissionsChecker.PERMISSION_REQUEST_CODE) 
    return
     
     
    for (int i = 0, len = permissions.length; i < len; i++) { 
    String permission = permissions[i]; 
    if (grantResults[i] == PackageManager.PERMISSION_DENIED) { 
    boolean showRationale = shouldShowRequestPermissionRationale(permission); 
    if (!showRationale) { 
    // 用户点击不再提醒,弹出权限框,引导其手动开启权限 
    checker.showMissingPermissionDialog(); 
    break
    } else
    // 用户点击取消,继续提示 
    checker.checkPermissions(PermissionsChecker.PERMISSIONS); 
    break





     
    转载请注明原文地址: https://ju.6miu.com/read-1303509.html
    最新回复(0)